解析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 相关文章推荐
javascript 多级checkbox选择效果
Aug 20 Javascript
jQuery事件绑定.on()简要概述及应用
Feb 07 Javascript
JavaScript实现鼠标滑过图片变换效果的方法
Apr 16 Javascript
JavaScript实现带标题的图片轮播特效
May 20 Javascript
浅谈node.js中async异步编程
Oct 22 Javascript
Javascript基础知识盲点总结之函数
May 15 Javascript
ion content 滚动到底部会遮住一部分视图的快速解决方法
Sep 06 Javascript
jQuery监听文件上传实现进度条效果的方法
Oct 16 Javascript
微信小程序 scroll-view隐藏滚动条详解
Jan 16 Javascript
BootStrap select2 动态改变值的方法
Feb 10 Javascript
深入浅析Vue.js 中的 v-for 列表渲染指令
Nov 19 Javascript
Vue 数据绑定的原理分析
Nov 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如何将日志写进syslog
2013/06/28 PHP
PHP 安全检测代码片段(分享)
2013/07/05 PHP
CI框架开发新浪微博登录接口源码完整版
2014/05/28 PHP
PHP正则表达式笔记与实例详解
2019/05/09 PHP
jQuery验证插件 Validate详解
2014/11/20 Javascript
JavaScript对象数组的排序处理方法
2015/10/21 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
深入理解jquery中的事件与动画
2016/05/24 Javascript
jQuery插件实现文件上传功能(支持拖拽)
2020/08/27 Javascript
jQuery EasyUI API 中文帮助文档和扩展实例
2016/08/01 Javascript
深入理解选择框脚本[推荐]
2016/12/13 Javascript
ionic实现底部分享功能
2017/05/11 Javascript
JS去掉字符串前后空格、阻止表单提交的实现代码
2017/06/08 Javascript
js实现canvas图片与img图片的相互转换的示例
2017/08/31 Javascript
vue组件父子间通信详解(三)
2017/11/07 Javascript
JavaScript面试出现频繁的一些易错点整理
2018/03/29 Javascript
JS中appendChild追加子节点无效的解决方法
2018/10/14 Javascript
[49:27]2018DOTA2亚洲邀请赛 4.4 淘汰赛 TNC vs VG 第一场
2018/04/05 DOTA
python3访问sina首页中文的处理方法
2014/02/24 Python
Python实现通过文件路径获取文件hash值的方法
2017/04/29 Python
python实现八大排序算法(2)
2017/09/14 Python
Python定时任务sched模块用法示例
2018/07/16 Python
计算机二级python学习教程(2) python语言基本语法元素
2019/05/16 Python
Ubuntu18.04下python版本完美切换的解决方法
2019/06/14 Python
利用Python产生加密表和解密表的实现方法
2019/10/15 Python
TensorFlow保存TensorBoard图像操作
2020/06/23 Python
django和flask哪个值得研究学习
2020/07/31 Python
详解如何修改python中字典的键和值
2020/09/29 Python
Flask中jinja2的继承实现方法及实例
2021/03/03 Python
AmazeUI的下载配置与Helloworld的实现
2020/08/19 HTML / CSS
美国领先的户外服装与装备用品店:Moosejaw
2016/08/25 全球购物
南京某软件公司的.net面试题
2015/11/30 面试题
消防志愿者活动方案
2014/08/23 职场文书
单方离婚协议书范本2014
2014/10/28 职场文书
小学中等生评语
2014/12/29 职场文书
导游词之江苏溱潼古镇
2019/11/27 职场文书