文章摘自:

http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof

概述

instanceof 运算符可以用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上。

语法

  1. object instanceof constructor
 

参数

object
要检测的对象.
constructor
某个构造函数

描述

instanceof运算符用来检测constructor.prototype是否存在于参数object的原型链上。

  1. function C(){} // 定义一个构造函数
  2. function D(){} // 定义另一个构造函数
  3. var o = new C();
  4. o instanceof C; // true,因为:Object.getPrototypeOf(o) === C.prototype
  5. o instanceof D; // false,因为D.prototype不在o的原型链上
  6. o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
  7. C.prototype instanceof Object // true,同上
  8. C.prototype = {};
  9. var o2 = new C();
  10. o2 instanceof C; // true
  11. o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
  12. D.prototype = new C();
  13. var o3 = new D();
  14. o3 instanceof D; // true
  15. o3 instanceof C; // true
 

需要注意的是,如果表达式 obj instanceof Foo 返回true,则并不意味着该表达式会永远返回ture,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false。另外一种情况下,原表达式的值也会改变,就是改变对象obj的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的__proto__魔法属性是可以实现的。比如执行obj.__proto__ = {}之后obj instanceof Foo就会返回false了。

instanceof和多全局对象(多个frame或多个window之间的交互)

在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回false,因为 Array.prototype !== window.frames[0].Array.prototype,因此你必须使用 Array.isArray(myObj) 或者Object.prototype.toString.call(myObj) === "[object Array]"来判断myObj是否是数组。

Mozilla开发者注意:
In code using XPCOM instanceof has special effect: obj instanceof xpcomInterface (e.g.Components.interfaces.nsIFile) calls obj.QueryInterface(xpcomInterface) and returns trueif QueryInterface succeeded. A side effect of such call is that you can use xpcomInterface's properties on obj after a successful instanceof test. Unlike standard JavaScript globals, the test obj instanceof xpcomInterface works as expected even if obj is from a different scope.

例子

例子: 表明String对象和Date对象都属于Object类型

下面的代码使用了instanceof来证明:String和Date对象同时也属于Object类型

  1. var myString = new String();
  2. var myDate = new Date();
  3. myString instanceof String; // 返回true
  4. myString instanceof Object; // 返回true
  5. myString instanceof Date; // 返回false
  6. myDate instanceof Date; // 返回true
  7. myDate instanceof Object; // 返回true
  8. myDate instanceof String; // 返回false
 

例子: 表明mycar属于Car类型,同时又属于Object类型

下面的代码创建了一个类型Car以及该类型的对象实例mycarinstanceof运算符表明了这个mycar对象既属于Car类型又属于Object类型

  1. function Car(make, model, year) {
  2. this.make = make;
  3. this.model = model;
  4. this.year = year;
  5. }
  6. var mycar = new Car("Honda", "Accord", 1998);
  7. var a = mycar instanceof Car; // 返回 true
  8. var b = mycar instanceof Object; // 返回 true

在 JavaScript 中,判断一个变量的类型尝尝会用 typeof 运算符,在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 "object"。ECMAScript 引入了另一个 Java 运算符 instanceof 来解决这个问题。instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:

清单 1. instanceof 示例
  1. var oStringObject = new String("hello world");
  2. console.log(oStringObject instanceof String); // 输出 "true"

这段代码问的是“变量 oStringObject 是否为 String 对象的实例?”oStringObject 的确是 String 对象的实例,因此结果是"true"。尽管不像 typeof 方法那样灵活,但是在 typeof 方法返回 "object" 的情况下,instanceof 方法还是很有用的。

instanceof 运算符的常规用法

通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型。例如:

清单 2. instanceof 常规用法
  1. // 判断 foo 是否是 Foo 类的实例
  2. function Foo(){}
  3. var foo = new Foo();
  4. console.log(foo instanceof Foo)//true

另外,更重的一点是 instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型。例如:

清单 3. instanceof 在继承中关系中的用法
  1. // 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例
  2. function Aoo(){}
  3. function Foo(){}
  4. Foo.prototype = new Aoo();//JavaScript 原型继承
  5.  
  6. var foo = new Foo();
  7. console.log(foo instanceof Foo)//true
  8. console.log(foo instanceof Aoo)//true

上面的代码中是判断了一层继承关系中的父类,在多层继承关系中,instanceof 运算符同样适用。

你真的了解 instanceof 操作符吗?

看了上面的代码示例,是不是觉得 instanceof 操作符很简单,下面来看点复杂的用法。

清单 4. instanceof 复杂用法
  1. console.log(Object instanceof Object);//true
  2. console.log(Function instanceof Function);//true
  3. console.log(Number instanceof Number);//false
  4. console.log(String instanceof String);//false
  5.  
  6. console.log(Function instanceof Object);//true
  7.  
  8. console.log(Foo instanceof Function);//true
  9. console.log(Foo instanceof Foo);//false

看了上面的代码是不是又晕头转向了?为什么 Object 和 Function instanceof 自己等于 true,而其他类 instanceof 自己却又不等于 true 呢?如何解释?要想从根本上了解 instanceof 的奥秘,需要从两个方面着手:1,语言规范中是如何定义这个运算符的。2,JavaScript 原型继承机制。

 

回页首

详细剖析 ECMAScript-262 edition 3 中 instanceof 运算符的定义

语言规范对中 instanceof 运算符的定义如下:

清单 5. 规范中 instanceof 运算符定义
  1. 11.8.6 The instanceof operator
  2. The production RelationalExpression:
  3. RelationalExpression instanceof ShiftExpression is evaluated as follows:
  4.  
  5. 1. Evaluate RelationalExpression.
  6. 2. Call GetValue(Result(1)).// 调用 GetValue 方法得到 Result(1) 的值,设为 Result(2)
  7. 3. Evaluate ShiftExpression.
  8. 4. Call GetValue(Result(3)).// 同理,这里设为 Result(4)
  9. 5. If Result(4) is not an object, throw a TypeError exception.// 如果 Result(4) 不是 object,
  10. //抛出异常
  11. /* 如果 Result(4) 没有 [[HasInstance]] 方法,抛出异常。规范中的所有 [[...]] 方法或者属性都是内部的,
  12. 在 JavaScript 中不能直接使用。并且规范中说明,只有 Function 对象实现了 [[HasInstance]] 方法。
  13. 所以这里可以简单的理解为:如果 Result(4) 不是 Function 对象,抛出异常 */
  14. 6. If Result(4) does not have a [[HasInstance]] method,
  15. throw a TypeError exception.
  16. // 相当于这样调用:Result(4).[[HasInstance]](Result(2))
  17. 7. Call the [[HasInstance]] method of Result(4) with parameter Result(2).
  18. 8. Return Result(7).
  19.  
  20. // 相关的 HasInstance 方法定义
  21. 15.3.5.3 [[HasInstance]] (V)
  22. Assume F is a Function object.// 这里 F 就是上面的 Result(4),V 是 Result(2)
  23. When the [[HasInstance]] method of F is called with value V,
  24. the following steps are taken:
  25. 1. If V is not an object, return false.// 如果 V 不是 object,直接返回 false
  26. 2. Call the [[Get]] method of F with property name "prototype".// 用 [[Get]] 方法取
  27. // F 的 prototype 属性
  28. 3. Let O be Result(2).//O = F.[[Get]]("prototype")
  29. 4. If O is not an object, throw a TypeError exception.
  30. 5. Let V be the value of the [[Prototype]] property of V.//V = V.[[Prototype]]
  31. 6. If V is null, return false.
  32. // 这里是关键,如果 O 和 V 引用的是同一个对象,则返回 true;否则,到 Step 8 返回 Step 5 继续循环
  33. 7. If O and V refer to the same object or if they refer to objects
  34. joined to each other (section 13.1.2), return true.
  35. 8. Go to step 5.

上面的规范定义很晦涩,而且看起来比较复杂,涉及到很多概念,但把这段规范翻译成 JavaScript 代码却很简单,如下:

清单 6. JavaScript instanceof 运算符代码
  1. function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
  2. var O = R.prototype;// 取 R 的显示原型
  3. L = L.__proto__;// 取 L 的隐式原型
  4. while (true) {
  5. if (L === null)
  6. return false;
  7. if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true
  8. return true;
  9. L = L.__proto__;
  10. }
  11. }
 

回页首

JavaScript 原型继承机制

由于本文主要集中在剖析 JavaScript instanceof 运算符,所以对于 JavaScript 的原型继承机制不再做详细的讲解,下面参考来自 http://www.mollypages.org/misc/js.mp 的一张图片,此图片详细的描述了 JavaScript 各种对象的显示和隐式原型链结构。

由其本文涉及显示原型和隐式原型,所以下面对这两个概念作一下简单说明。在 JavaScript 原型继承结构里面,规范中用 [[Prototype]] 表示对象隐式的原型,在 JavaScript 中用 __proto__ 表示,并且在 Firefox 和 Chrome 浏览器中是可以访问得到这个属性的,但是 IE 下不行。所有 JavaScript 对象都有 __proto__ 属性,但只有 Object.prototype.__proto__ 为 null,前提是没有在 Firefox 或者 Chrome 下修改过这个属性。这个属性指向它的原型对象。 至于显示的原型,在 JavaScript 里用 prototype 属性表示,这个是 JavaScript 原型继承的基础知识,在这里就不在叙述了。

图 1. JavaScript 原型链

 

回页首

讲解 instanceof 复杂用法

有了上面 instanceof 运算符的 JavaScript 代码和原型继承图,再来理解 instanceof 运算符将易如反掌。下面将详细讲解 Object instanceof Object,Function instanceof Function 和 Foo instanceof Foo 三个示例,其它示例读者可自行推演。

清单 7. Object instanceof Object
  1. // 为了方便表述,首先区分左侧表达式和右侧表达式
  2. ObjectL = Object, ObjectR = Object;
  3. // 下面根据规范逐步推演
  4. O = ObjectR.prototype = Object.prototype
  5. L = ObjectL.__proto__ = Function.prototype
  6. // 第一次判断
  7. O != L
  8. // 循环查找 L 是否还有 __proto__
  9. L = Function.prototype.__proto__ = Object.prototype
  10. // 第二次判断
  11. O == L
  12. // 返回 true
清单 8. Function instanceof Function
  1. // 为了方便表述,首先区分左侧表达式和右侧表达式
  2. FunctionL = Function, FunctionR = Function;
  3. // 下面根据规范逐步推演
  4. O = FunctionR.prototype = Function.prototype
  5. L = FunctionL.__proto__ = Function.prototype
  6. // 第一次判断
  7. O == L
  8. // 返回 true
清单 9. Foo instanceof Foo
  1. // 为了方便表述,首先区分左侧表达式和右侧表达式
  2. FooL = Foo, FooR = Foo;
  3. // 下面根据规范逐步推演
  4. O = FooR.prototype = Foo.prototype
  5. L = FooL.__proto__ = Function.prototype
  6. // 第一次判断
  7. O != L
  8. // 循环再次查找 L 是否还有 __proto__
  9. L = Function.prototype.__proto__ = Object.prototype
  10. // 第二次判断
  11. O != L
  12. // 再次循环查找 L 是否还有 __proto__
  13. L = Object.prototype.__proto__ = null
  14. // 第三次判断
  15. L == null
  16. // 返回 false
 

回页首

简析 instanceof 在 Dojo 继承机制中的应用

在 JavaScript 中,是没有多重继承这个概念的,就像 Java 一样。但在 Dojo 中使用 declare 声明类时,是允许继承自多个类的。下面以 Dojo 1.6.1 为例。

清单 10. Dojo 中多重继承
  1. dojo.declare("Aoo",null,{});
  2. dojo.declare("Boo",null,{});
  3. dojo.declare("Foo",[Aoo,Boo],{});
  4.  
  5. var foo = new Foo();
  6. console.log(foo instanceof Aoo);//true
  7. console.log(foo instanceof Boo);//false
  8.  
  9. console.log(foo.isInstanceOf(Aoo));//true
  10. console.log(foo.isInstanceOf(Boo));//true

上面的示例中,Foo 同时继承自 Aoo 和 Boo,但当使用 instanceof 运算符来检查 foo 是否是 Boo 的实例时,返回的是 false。实际上,在 Dojo 的内部,Foo 仍然只继承自 Aoo,而通过 mixin 机制把 Boo 类中的方法和属性拷贝到 Foo 中,所以当用 instanceof 运算符来检查是否是 Boo 的实例时,会返回 false。所以 Dojo 为每个类的实例添加了一个新的方法叫 isInstanceOf,用这个方法来检查多重继承。

instanceof 运算符简介的更多相关文章

  1. JavaScript instanceof 运算符深入剖析

    简介: 随着 web 的发展,越来越多的产品功能都放在前端进行实现,增强用户体验.而前端开发的主要语言则是 JavaScript.学好 JavaScript 对开发前端应用已经越来越重要.在开发复杂产 ...

  2. JavaScript instanceof 运算符深入剖析【转载】

    http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/   instanceof 运算符简介 在 JavaScript ...

  3. JavaScript instanceof 运算符

    instanceof运算符简介 在 JavaScript 中 判断一个变量的类型常常会用 typeof 运算符 判断一个实例是否属于某种类型会使用instanceof 与 typeof 方法不同的是, ...

  4. instanceof 运算符

    java中的instanceof=======>二元运算符 用法: result = object instanceof class 参数: result 是boolean类型 object 是 ...

  5. instanceof运算符

    instanceof运算符:判断该对象是否是某一个类的实例. 语法格式:boolean b = 对象A instanceof 类B://判断A对象是否是B类的实例,如果是返回true. 若对象是类的实 ...

  6. Object.prototype 与 Function.prototype 与 instanceof 运算符

    方法: hasOwnProperty isPrototypeOf propertyIsEnumerable hasOwnProperty 该方法用来判断一个对象中的某一个属性是否是自己提供的( 住要用 ...

  7. tips instanceof运算符和typeof运算符的区别

    tips instanceof运算符和typeof运算符的区别  一.instanceof运算符:       此运算符可以判断一个变量是否是某个对象(类)的实例,返回值是布尔类型的(true和fal ...

  8. JavaScript原型链和instanceof运算符的暧昧关系

    时间回到两个月前,简单地理了理原型链.prototype以及__proto__之间的乱七八糟的关系,同时也简单了解了下typeof和instanceof两个运算符,但是,anyway,试试以下两题: ...

  9. js的in运算符与instanceof运算符

    in运算符:希望他的左操作数是一个字符串或可以转换为字符串,希望他的右操作数是一个对象.如果右操作数的对象拥有一个名为左操作数值的属性名,那么表达式返回true. var point= {x:1,y: ...

随机推荐

  1. about route

    route add default dev  my_iface1 route del default route add default gw 192.168.120.1 route add -net ...

  2. [翻译]Hystrix wiki–How it Works

    注:本文并非是精确的文档翻译,而是根据自己理解的整理,有些内容可能由于理解偏差翻译有误,有些内容由于是显而易见的,并没有翻译,而是略去了.本文更多是学习过程的产出,请尽量参考原官方文档. 流程图 下图 ...

  3. spring-集成redis

    Redis是key-value存储的非关系型数据库.Spring Data Redis包含了多个模板实现,用来完成Redis数据库的数据存取功能 1.如何连接Redis? Spring Data Re ...

  4. window server IIS组建方法

    文章来自:二度云IIS(Internet Information Server,互联网信息服务)是一种Web(网页)服务组件,其中包括Web服务器.FTP服务器.NNTP服务器和SMTP服务器,分别用 ...

  5. [转]MySQL常用字符串函数

    本文转载自:http://www.cnblogs.com/geaozhang/ 是最常用的的一种函数,在一个具体应用中通常会综合几个甚至几类函数来实现相应的应用: 1.LOWER(column|str ...

  6. vmware 虚拟机设置 redhat 桥接模式

    1.设置 vmware 网络模式 2.设置 linux 网络模式

  7. 大数据技术原理与应用——分布式文件系统HDFS

    分布式文件系统概述 相对于传统的本地文件系统而言,分布式文件系统(Distribute File System)是一种通过网络实现文件在多台主机上进行分布式存储的文件系统.分布式文件系统的设计一般采用 ...

  8. Leecode刷题之旅-C语言/python-203移除链表元素

    /* * @lc app=leetcode.cn id=203 lang=c * * [203] 移除链表元素 * * https://leetcode-cn.com/problems/remove- ...

  9. C语言调整数组使奇数全部都位于偶数前面

    //输入一个整数数组,实现一个函数,//来调整该数组中数字的顺序使得数组中所有的奇数 位于数组的前半部分,//所有偶数 位于数组的后半部分. #include<stdio.h>#inclu ...

  10. [SGU223]Little Kings(状压DP)

    随便DP一下 Code #include <cstdio> int sta[150],cnt[150],tp,n,k; long long dp[12][144][150],Ans; in ...