解析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 相关文章推荐
Extjs Ajax 乱码问题解决方案
Apr 15 Javascript
JQuery扩展插件Validate—4设置错误提示的样式
Sep 05 Javascript
JavaScript获取和设置CheckBox状态的简单方法
Jul 05 Javascript
Javascript实现动态菜单添加的实例代码
Jul 05 Javascript
JS逆序遍历实现代码
Dec 02 Javascript
怎么引入(调用)一个JS文件
May 26 Javascript
js简单实现调整网页字体大小的方法
Jul 23 Javascript
基于jQuery代码实现圆形菜单展开收缩效果
Feb 13 Javascript
vue 多入口文件搭建 vue多页面搭建的实例讲解
Mar 12 Javascript
JavaScript实现文件下载并重命名代码实例
Dec 12 Javascript
jQuery实现轮播图效果demo
Jan 11 jQuery
javascript canvas API内容整理
Feb 16 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中curl_multi的应用
2013/07/17 PHP
php网页标题中文乱码的有效解决方法
2014/03/05 PHP
php读取文件内容的方法汇总
2015/01/24 PHP
PHP设计模式之装饰器模式实例详解
2018/02/07 PHP
javascript下过滤数组重复值的代码
2007/09/10 Javascript
jquery的Theme和Theme Switcher使用小结
2010/09/08 Javascript
IE6下出现JavaScript未结束的字符串常量错误的解决方法
2010/11/21 Javascript
Jquery判断IE6等浏览器的代码
2011/04/05 Javascript
jQuery图片的展开和收缩实现代码
2013/04/16 Javascript
node.js中的events.EventEmitter.listenerCount方法使用说明
2014/12/08 Javascript
javascript和jquery实现设置和移除文本框默认值效果代码
2015/01/13 Javascript
JS弹出可拖拽可关闭的div层完整实例
2015/02/13 Javascript
JavaScript中的toLocaleDateString()方法使用简介
2015/06/12 Javascript
js判断文本框输入的内容是否为数字
2015/12/23 Javascript
再次谈论Javascript中的this
2016/06/23 Javascript
jquery遍历标签中自定义的属性方法
2016/09/17 Javascript
详解ES6中的let命令
2020/04/05 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
2016/12/18 Javascript
vue实现表格增删改查效果的实例代码
2017/07/18 Javascript
vue + vuex todolist的实现示例代码
2018/03/09 Javascript
vue 使某个组件不被 keep-alive 缓存的方法
2018/09/21 Javascript
Python函数中定义参数的四种方式
2014/11/30 Python
python如何为创建大量实例节省内存
2018/03/20 Python
python自动发送邮件脚本
2018/06/20 Python
django项目登录中使用图片验证码的实现方法
2019/08/15 Python
Pytorch之Variable的用法
2019/12/31 Python
Pytorch使用PIL和Numpy将单张图片转为Pytorch张量方式
2020/05/25 Python
Python Switch Case三种实现方法代码实例
2020/06/18 Python
html5画布旋转效果示例
2014/01/27 HTML / CSS
心得体会开头
2014/01/01 职场文书
服务员岗位责任制
2014/02/11 职场文书
求职个人评价范文
2014/04/09 职场文书
项目经理助理岗位职责
2015/04/13 职场文书
2015年仓库管理员工作总结
2015/04/21 职场文书
2015年勤工助学工作总结
2015/04/29 职场文书
mysql insert 存在即不插入语法说明
2022/03/25 MySQL