解析JavaScript中instanceof对于不同的构造器或许都返回true


Posted in Javascript onDecember 03, 2013

我们知道 instanceof 运算符用来检查对象是否为某构造器的实例。下面列举它返回true的各种情景。

1、对象obj是通过new Constructor创建的,那么 obj instanceof Constructor 为true

function Person(n, a) { 
    this.name = n; 
    this.age = a; 
} 
var p = new Person('John Backus', 82); 
console.log(p instanceof Person); // true

2、如果存在继承关系,那么 子类实例 instanceof 父类 也会返回true
function A(){} 
function B(){} 
B.prototype = new A(); // B继承于A var b = new B(); 
console.log(b instanceof A); // true

3、由于Object是根类,所有其它自定义类都继承于它,因此 任意构造器的实例 instanceof Object 都返回true
function A() {} 
var a = new A(); 
console.log(a instanceof Object); // true var str = new String('hello'); 
console.log(str instanceof Object); // true 
var num = new Number(1); 
console.log(num instanceof Object); // true

甚至包括构造器自身
function A() {} 
console.log(A instanceof Object); // true 
console.log(String instanceof Object); // true 
console.log(Number instanceof Object); // true

4、所有构造器 instanceof Function 返回true
function A() {} 
console.log(A instanceof Function); // true 
console.log(String instanceof Function); // true 
console.log(Number instanceof Function); // true

以上四点总结为一句话:如果某实例是通过某类或其子类的创建的,那么instanceof就返回true。或者说某构造函数的原型 存在与对象obj的内部原型链上,那么返回true。即instanceof的结果与构造器自身并无直接关系。这在许多语言中都是通用的。

Java中定义了一个类Person,实例p对于Person和Object都返回true

class Person { 
    public String name; 
    public int age; 
    Person (String n, int a) { 
        this.name = name; 
        this.age = a; 
    } 
    public static void main(String[] args) { 
        Person p = new Person("John Backus", 82); 
        System.out.println(p instanceof Person); // true 
        System.out.println(p instanceof Object); // true 
    } 
}

Java中如果存在继承关系,那么 子类实例 instanceof 父类 也返回true
// 父类 
class Person { 
    public String name; 
    public int age; 
    Person (String n, int a) { 
        name = name; 
        age = a; 
    } 
} 
// 子类 
public class Man extends Person{ 
    public String university; 
    Man(String n, int a, String s) { 
        super(n, a); 
        university = s; 
    } 
    public static void main(String[] args) { 
        Man mm = new Man("John Resig", 29, "PKU"); 
        System.out.println(mm instanceof Man); // true 
        System.out.println(mm instanceof Person); // 也是true 
    } 
}

知道了这些,JS中以下的表现就不奇怪了
// 定义两个构造器 
function A(){} 
function B(){} 
A.prototype = B.prototype = {a: 1}; // 分别创建两个不同构造器的实例 
var a = new A(); 
var b = new B(); 
console.log(a instanceof B); // true 
console.log(b instanceof A); // true

我们看到a, b分别是用A和B创建的,但a instanceof B和 b instanceof A都是true。即a虽然不是用构造器B创建的,但仍然返回true。因为B.prototype存在于a的内部原型链上。

由于JS的动态语言特性,可以在运行时修改原型,因此下面返回false也不足为奇了。因为A.prototype已经不在a的内部原型链中,链条被打断了。

function A(){} 
var a = new A(); 
A.prototype = {}; // 动态修改原型,注意必须在创建a后 
console.log(a instanceof A); // false

注意这么写也打破了上面总结的第一条:对象obj是通过new Constructor创建的,那么obj instanceof Constructor 为true

实际在ECMAScript标准中(以5.1为准),instanceof 内部实现会调用构造器的内部方法[[HasInstance]],描述如下

解析JavaScript中instanceof对于不同的构造器或许都返回true

假如F是一个函数对象,当F(V)执行时,以下步骤将发生:

1、如果instanceof左运算元V不是对象类型,直接返回false

var a, b = 1, c = true, d = 'hello'; 
console.log(a instanceof Object); // false 这里a值为undefined 
console.log(b instanceof Object); // false 
console.log(c instanceof Object); // false 
console.log(d instanceof Object); // false

2/3、取构造器F的prototype属性,如果不是对象类型,须抛出TypeError异常,
function A(){} 
A.prototype = 1; // A的prototype设为非对象类型 
var a = new A(); 
console.log(a instanceof A);

各浏览器抛出的异常提示不同,

Firefox18:

解析JavaScript中instanceof对于不同的构造器或许都返回true

Chrome24:

解析JavaScript中instanceof对于不同的构造器或许都返回true

Safari6:

解析JavaScript中instanceof对于不同的构造器或许都返回true

Opera12:

解析JavaScript中instanceof对于不同的构造器或许都返回true

IE10:

解析JavaScript中instanceof对于不同的构造器或许都返回true

4、不断的执行以下逻辑:将V设为内部原型的V,如果V是null则返回false,如果V和O都指向同一个对象,则返回true。

Javascript 相关文章推荐
利用腾讯的ip地址库做ip物理地址定位
Jul 24 Javascript
jQuery前端框架easyui使用Dialog时bug处理
Dec 05 Javascript
Node.js中child_process实现多进程
Feb 03 Javascript
jquery中toggle函数交替使用问题
Jun 22 Javascript
代码分析jQuery四种静态方法使用
Jul 23 Javascript
浅析JS异步加载进度条
May 05 Javascript
纯js实现倒计时功能
Jan 06 Javascript
canvas时钟效果
Feb 16 Javascript
Three.js基础学习教程
Nov 16 Javascript
Vue实现侧边菜单栏手风琴效果实例代码
May 31 Javascript
超轻量级的js时间库miment使用解析
Aug 02 Javascript
layui之table checkbox初始化时选中对应选项的方法
Sep 02 Javascript
探讨JavaScript中声明全局变量三种方式的异同
Dec 03 #Javascript
解析JavaScript中delete操作符不能删除的对象
Dec 03 #Javascript
解析Javascript小括号“()”的多义性
Dec 03 #Javascript
解析Javascript中中括号“[]”的多义性
Dec 03 #Javascript
jquery将一个表单序列化为一个对象的方法
Dec 02 #Javascript
jQuery获得内容和属性方法及示例
Dec 02 #Javascript
jquery如何实现锚点链接之间的平滑滚动
Dec 02 #Javascript
You might like
php XMLWriter类的简单示例代码(RSS输出)
2011/09/30 PHP
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
php实现递归与无限分类的方法
2015/02/16 PHP
php如何连接sql server
2015/10/16 PHP
PHP实现字母数字混合验证码功能
2019/07/11 PHP
Javascript模块模式分析
2008/05/16 Javascript
JavaScript全局函数使用简单说明
2011/03/11 Javascript
jquery实现的一个导航滚动效果具体代码
2013/05/27 Javascript
js获取某月的最后一天日期的简单实例
2013/06/22 Javascript
jQuery Validate 验证,校验规则写在控件中的具体实例
2014/02/27 Javascript
jquery实现效果比较好的table选中行颜色
2014/03/25 Javascript
javascript实现的简单计时器
2015/07/19 Javascript
浅谈js基本数据类型和typeof
2016/08/09 Javascript
Vue2.0 组件传值通讯的示例代码
2017/08/01 Javascript
详解JS中的柯里化(currying)
2017/08/17 Javascript
webpack4的迁移的使用方法
2018/05/25 Javascript
Vue项目查看当前使用的elementUI版本的方法
2018/09/27 Javascript
vue两组件间值传递 $router.push实现方法
2019/05/15 Javascript
使用JS判断页面是首次被加载还是刷新
2019/05/26 Javascript
使用localStorage替代cookie做本地存储
2019/09/25 Javascript
JS this关键字在ajax中使用出现问题解决方案
2020/07/17 Javascript
[01:38]DOTA2辉夜杯 欢乐的观众现场采访
2015/12/26 DOTA
简单介绍Python中利用生成器实现的并发编程
2015/05/04 Python
Python正则表达式经典入门教程
2017/05/22 Python
在NumPy中创建空数组/矩阵的方法
2018/06/15 Python
python机器学习之KNN分类算法
2018/08/29 Python
python批量下载网站马拉松照片的完整步骤
2018/12/05 Python
keras之权重初始化方式
2020/05/21 Python
python 密码学示例——理解哈希(Hash)算法
2020/09/21 Python
土耳其玩具商店:Toyzz Shop
2019/08/02 全球购物
美国在线购买空气净化器、除湿器、加湿器网站:AllergyBuyersClub
2021/03/16 全球购物
简历里的自我评价
2014/01/31 职场文书
火锅店创业计划书范文
2014/02/02 职场文书
学生喝酒检讨书
2014/02/06 职场文书
乡镇精神文明建设汇报材料
2014/08/15 职场文书
房屋租赁授权委托书范本
2014/09/20 职场文书