解析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 相关文章推荐
又一个图片自动缩小的JS代码
Mar 10 Javascript
jquery获得下拉框值的代码
Aug 13 Javascript
js 输出内容到新窗口具体实现代码
May 31 Javascript
Jquery遍历Json数据的方法
Apr 20 Javascript
理解JavaScript的变量的入门教程
Jul 07 Javascript
JavaScript中的this引用(推荐)
Aug 05 Javascript
遍历js中对象的属性和值的实例
Nov 21 Javascript
vue单页缓存方案分析及实现
Sep 25 Javascript
详解vue如何使用rules对表单字段进行校验
Oct 17 Javascript
JavaScript遍历数组的三种方法map、forEach与filter实例详解
Feb 27 Javascript
微信小程序页面渲染实现方法
Nov 06 Javascript
JavaScript进阶(四)原型与原型链用法实例分析
May 09 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函数的实现原理及性能分析(二)
2015/05/13 PHP
Yii基于CActiveForm的Ajax数据验证用法示例
2016/07/14 PHP
Laravel使用支付宝进行支付的示例代码
2017/08/16 PHP
PHP实现微信商户支付企业付款到零钱功能
2018/09/30 PHP
Javascript select控件操作大全(新增、修改、删除、选中、清空、判断存在等)
2008/12/19 Javascript
javascript KeyDown、KeyPress和KeyUp事件的区别与联系
2009/12/03 Javascript
jquery中防刷IP流量软件影响统计的一点对策
2011/07/10 Javascript
JS 毫秒转时间示例代码
2013/09/22 Javascript
使用HTML+CSS+JS制作简单的网页菜单界面
2015/07/27 Javascript
JS实现合并两个数组并去除重复项只留一个的方法
2015/12/17 Javascript
浅谈Node.js之异步流控制
2017/10/25 Javascript
JavaScript实现点击出现图片并统计点击次数功能示例
2018/07/23 Javascript
微信小程序canvas拖拽、截图组件功能
2018/09/04 Javascript
vue实现Input输入框模糊查询方法
2021/01/29 Javascript
JS实现炫酷轮播图
2020/11/15 Javascript
[02:42]完美大师赛主赛事淘汰赛第三日观众采访
2017/11/25 DOTA
Python数据类型详解(三)元祖:tuple
2016/05/08 Python
Python使用pymysql小技巧
2017/06/04 Python
python实现猜数字小游戏
2020/03/24 Python
python [:3] 实现提取数组中的数
2019/11/27 Python
Python Pickle 实现在同一个文件中序列化多个对象
2019/12/30 Python
python中for in的用法详解
2020/04/17 Python
python使用多线程+socket实现端口扫描
2020/05/28 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
2021/03/03 Python
详解如何使用CSS3中的结构伪类选择器和伪元素选择器
2020/01/06 HTML / CSS
HTML5 实现图片上传预处理功能
2020/02/06 HTML / CSS
俄罗斯马克西多姆家居用品网上商店:Максидом
2020/02/06 全球购物
社区食品安全实施方案
2014/03/28 职场文书
大学学风建设方案
2014/05/04 职场文书
公司口号大全
2014/06/11 职场文书
庆祝新中国成立65周年“向国旗敬礼”网上签名寄语
2014/09/27 职场文书
2014年服务员个人工作总结
2014/12/23 职场文书
车队安全员岗位职责
2015/02/15 职场文书
大学运动会通讯稿
2015/07/18 职场文书
Python如何使用循环结构和分支结构
2022/04/13 Python
CSS使用Flex和Grid布局实现3D骰子
2022/08/05 HTML / CSS