解析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 相关文章推荐
jquery 多行滚动代码(附详细解释)
Jun 17 Javascript
不使用中间变量,交换int型的 a, b两个变量的值。
Oct 29 Javascript
JavaScript原型继承之基础机制分析
Aug 26 Javascript
动态添加删除表格行的js实现代码
Feb 28 Javascript
15个jquery常用方法、小技巧分享
Jan 13 Javascript
javascript实现在指定元素中垂直水平居中
Sep 13 Javascript
原生JS获取元素集合的子元素宽度实例
Dec 14 Javascript
js如何判断是否在iframe中及防止网页被别站用iframe嵌套
Jan 11 Javascript
es6的数字处理的方法(5个)
Mar 16 Javascript
vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)
Jul 11 Javascript
Vue2.0父组件与子组件之间的事件发射与接收实例代码
Sep 19 Javascript
JavaScript实现复选框全选功能
Apr 11 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入门
2006/10/09 PHP
修改php.ini不生效问题解决方法(上传大于8M的文件)
2013/06/14 PHP
php实现保存周期为1天的购物车类
2017/07/07 PHP
windows下的WAMP环境搭建图文教程(推荐)
2017/07/27 PHP
Laravel使用原生sql语句并调用的方法
2019/10/09 PHP
用cookies实现的可记忆的样式切换效果代码下载
2007/12/24 Javascript
javascript GUID生成器实现代码
2009/10/31 Javascript
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
精通Javascript系列之数据类型 字符串
2011/06/08 Javascript
jQuery实现渐变下拉菜单的简单方法
2015/03/11 Javascript
jQuery的bind()方法使用详解
2015/07/15 Javascript
JavaScript职责链模式概述
2016/09/17 Javascript
在网页中插入百度地图的步骤详解
2016/12/02 Javascript
Angular2学习教程之组件中的DOM操作详解
2017/05/28 Javascript
基于canvas粒子系统的构建详解
2017/08/31 Javascript
jquery animate动画持续运动的实例
2017/11/29 jQuery
Vue响应式原理深入解析及注意事项
2017/12/11 Javascript
JavaScript 复制对象与Object.assign方法无法实现深复制
2018/11/02 Javascript
你不知道的SpringBoot与Vue部署解决方案
2020/11/09 Javascript
python的Tqdm模块的使用
2018/01/10 Python
python实现音乐下载器
2018/04/15 Python
Python实现的txt文件去重功能示例
2018/07/07 Python
Python小游戏之300行代码实现俄罗斯方块
2019/01/04 Python
使用python库xlsxwriter库来输出各种xlsx文件的示例
2020/09/01 Python
法国票务网站:Ticketmaster法国
2018/07/09 全球购物
电钳专业个人求职信
2014/01/04 职场文书
小学红领巾中秋节广播稿
2014/01/13 职场文书
食堂个人先进事迹
2014/01/22 职场文书
校庆活动策划方案
2014/06/05 职场文书
文明礼仪标语
2014/06/13 职场文书
2014年六五普法工作总结
2014/11/25 职场文书
2014年妇委会工作总结
2014/12/10 职场文书
酒店总经理岗位职责
2015/04/01 职场文书
新员工辞职信范文
2015/05/12 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
2022/04/11 Vue.js