解析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 06 Javascript
filemanage功能中用到的common.js
Apr 08 Javascript
jquery入门—编写一个导航条(可伸缩)
Jan 07 Javascript
JS获取单击按钮单元格所在行的信息
Jun 17 Javascript
神奇!js+CSS+DIV实现文字颜色渐变效果
Mar 16 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
Mar 24 Javascript
js验证框架之RealyEasy验证详解
Jun 08 Javascript
jQuery ajax 当async为false时解决同步操作失败的问题
Nov 18 Javascript
AngularJS自定义指令详解(有分页插件代码)
Jun 12 Javascript
一些你可能不熟悉的JS知识点总结
Mar 15 Javascript
基于JS实现父组件的请求服务过程解析
Oct 14 Javascript
Vue-cli3项目引入Typescript的实现方法
Oct 18 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
最贵的咖啡是怎么产生的,它的风味怎么样?
2021/03/04 新手入门
无法载入 mcrypt 扩展,请检查 PHP 配置终极解决方案
2011/07/18 PHP
非常好用的两个PHP函数 serialize()和unserialize()
2012/02/04 PHP
使用CodeIgniter的类库做图片上传
2014/06/12 PHP
PHP图像裁剪缩略裁切类源码及使用方法
2016/01/07 PHP
PDO::exec讲解
2019/01/28 PHP
php反射学习之依赖注入示例
2019/06/14 PHP
php给数组赋值的实例方法
2019/09/26 PHP
javascript日期格式化示例分享
2014/03/05 Javascript
jQuery实现文本框邮箱输入自动补全效果
2015/11/17 Javascript
微信和qq时间格式模板实例详解
2016/10/21 Javascript
Bootstrap源码解读模态弹出框(11)
2016/12/28 Javascript
用node-webkit把web应用打包成桌面应用(windows环境)
2018/02/01 Javascript
jQuery创建及操作xml格式数据示例
2018/05/26 jQuery
JavaScript中的惰性载入函数及优势
2020/02/18 Javascript
Python使用win32com实现的模拟浏览器功能示例
2017/07/13 Python
浅谈python for循环的巧妙运用(迭代、列表生成式)
2017/09/26 Python
python3+django2开发一个简单的人员管理系统过程详解
2019/07/23 Python
Python使用scrapy爬取阳光热线问政平台过程解析
2019/08/14 Python
分享一个页面平滑滚动小技巧(推荐)
2019/10/23 HTML / CSS
美国美妆网站:B-Glowing
2016/10/12 全球购物
AE美国鹰日本官方网站: American Eagle Outfitters
2016/12/10 全球购物
国培教师自我鉴定
2014/02/12 职场文书
公司股权转让协议书
2014/04/12 职场文书
加入学生会演讲稿
2014/04/24 职场文书
《水乡歌》教学反思
2014/04/24 职场文书
计算机系本科生求职信
2014/05/31 职场文书
纪委书记群众路线整改措施思想汇报
2014/10/09 职场文书
青年文明号汇报材料
2014/12/23 职场文书
幼儿园教研工作总结2015
2015/05/12 职场文书
运动会开幕式致辞
2015/07/29 职场文书
2016消防宣传标语口号
2015/12/26 职场文书
2016年“我们的节日·端午节”活动总结
2016/04/01 职场文书
如何计划开一家便利店?
2019/07/31 职场文书
2019年恭贺升学祝福语集锦
2019/08/15 职场文书
导游词之镇江西津古渡
2019/11/06 职场文书