一、Breif                               

大家都知道instanceof一般就是用来检查A对象是否为B类或子类的实例。那问题是JS中没有类的概念更没有类继承的概念(虽然有构造函数),那么instanceof到底是怎样判断A对象是B构造函数的实例呢?本文将对此作分析记录,以便日后查阅。

二、Reference 2 ECMA-262-3 Spec                

http://bclary.com/2004/11/07/#a-11.8.6

The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:

1. Evaluate RelationalExpression.

2.Call GetValue(Result(1)).

3.Evaluate ShiftExpression.

4.Call GetValue(Result(3)).

5.If Result(4) is not an object, throw a TypeError exception.

6.If Result(4) does not have a [[HasInstance]] method, throw a TypeError exception.

7.Call the [[HasInstance]] method of Result(4) with parameter Result(2).

8.Return Result(7).

从上述的定义我们可以得出以下内容:

1. ShiftExpression的实际值(GetValue(Evaluate(ShiftExpression)))必须为[object Function],否则就抛TypeError异常;

2. instanceof的实际判断则是调用RelationalExpression的Internal Method [[HasInstance]]来处理。

下面我们深入一下[[HasInstance]]的定义

http://bclary.com/2004/11/07/#a-15.3.5.3

Assume F is a Function object.

When the [[HasInstance]] method of F is called with value V, the following steps are taken:

1. If V is not an object, return false.

2. Call the [[Get]] method of F with property name "prototype".

3. Let O be Result(2).

4. If O is not an object, throw a TypeError exception.

5. Let V be the value of the [[Prototype]] property of V.

6. If V is null, return false.

7. If O and V refer to the same object or if they refer to objects joined to each other (13.1.2), return true.

8. Go to step 5.

上面的定义看得不太明白,我们把它翻译成JS的实现吧

// IE5.5~9下,由于无法通过__proto__访问对象的Internal Property [[Prototype]],因此该方法无效
;(function(rNotObj){
Function.prototype['[[HasInstance]]'] = function(value){
// 1. If V is not an object, return false
if (rNotObj.test(typeof value)) return false
// 2. Call the [[Get]] method of F with property name "prototype"
// 4. If O is not an object, throw a TypeError exception
var O = this.prototype
if (rNotObj.test(typeof O)) throw TypeError() // 5. Let V be the value of the [[Prototype]] prototype of V
// 6. If V is null, return false
if (null === (value = value.__proto__)) return false // 7. If O and V refer to the same object
// 8. Go to step 5
return O === value || this['[[HasInstance]]'](value)
}
}(/$[^of]/ /*not begin with o(bject) neither f(unction)*/))

现在稍微总结一下,a instanceof b底层的运算机制关键点如下:

1. b的数据类型必须为[object Function],否则就抛TypeError;

2. 若a为Primitive Value则直接返回false, 若a的数据类型为Object则执行后续运算;

3. 当且仅当b.prototype位于a的prototype chain中时,才返回true(由于Object.prototype.__proto__为null,因此prototype chain是有限链表);

也许大家会对 Function.prototype['[[HasInstance]]'] 的实现为什么能成功感到疑问,我们先看看以下图片

可以知道所有函数的 __proto__ 默认情况下均指向 Function.prototype ,而 Function.__proto__ 则与 Function.prototype 指向同一个对象。

Chrome中两者均指向 function Empty(){} ,因此添加到Function.protoype的属性,也会出现在Function的prototype chain中。

四、About if they refer to objects joined to each other 

Objects Joined其实是Spec建议实现者(如V8、SpiderMonkey)采用的底层优化手段。

function a(){
function b(){}
return b
}
var c = a()
var d = a()
// 假如JavaScript Engine实现了Objects Joined,那么
c === d 返回值为true。因为a中定义b函数啥都一样,所以底层实现可以不再生成一个新的Function object,从而从空间和时间上降低消耗。

五 、Conclusion                        

之前看了很多讲述instanceof的文章但始终对它理解得不透彻,看来还是看Spec比较实在。

尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4231454.html 肥仔John^_^

六、Thanks                          

http://www.w3cfuns.com/article-5597466-1-1.html

http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/

JS魔法堂:再识instanceof的更多相关文章

  1. JS魔法堂:jsDeferred源码剖析

    一.前言 最近在研究Promises/A+规范及实现,而Promise/A+规范的制定则很大程度地参考了由日本geek cho45发起的jsDeferred项目(<JavaScript框架设计& ...

  2. JS魔法堂:那些困扰你的DOM集合类型

    一.前言 大家先看看下面的js,猜猜结果会怎样吧! 可选答案: ①. 获取id属性值为id的节点元素 ②. 抛namedItem is undefined的异常 var nodes = documen ...

  3. JS魔法堂:追忆那些原始的选择器

    一.前言                                                                                                 ...

  4. JS魔法堂:不完全国际化&本地化手册 之 实战篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  5. JS魔法堂:属性、特性,傻傻分不清楚

    一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...

  6. JS魔法堂:doctype我们应该了解的基础知识

    一.前言 什么是doctype?其实我们一直使用,却很少停下来看清楚它到底是什么,对网页有什么作用.本篇将和大家一起探讨那个默默无闻的doctype吧! 二.什么是doctype doctype或DT ...

  7. JS魔法堂:精确判断IE的文档模式by特征嗅探

    一.前言 苦逼的前端攻城狮都深受浏览器兼容之苦,再完成每一项功能前都要左顾右盼,生怕浏览器不支持某个API,生怕原生API内含臭虫因此判断浏览器类型和版本号成了不可绕过的一道关卡,而特征嗅探是继浏览器 ...

  8. JS魔法堂:不完全国际化&本地化手册 之 理論篇

    前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ...

  9. JS魔法堂:判断节点位置关系

    一.前言 在polyfill querySelectorAll 和写弹出窗时都需要判断两个节点间的位置关系,通过jQuery我们可以轻松搞定,但原生JS呢?下面我将整理各种判断方法,以供日后查阅. 二 ...

  10. JS魔法堂:LINK元素深入详解

    一.前言 我们一般使用方式为 <link type="text/css" rel="stylesheet" href="text.css&quo ...

随机推荐

  1. 微信网页开发之创建Controller(三)

    首先,我们需要在App区域下添加一个控制器,这里我们就以AppDemoController为例.如下图所示: 注意:你也可以自己创建其他区域,只是这里推荐使用App区域. 创建好之后,请添加自己的Ac ...

  2. 微软正式发布Visual Studio 2013 Update 3 (2013.3) RTM

    昨天微软的Visual Studio 2013 Update 3(Visual Studio 2013.3)正式发布(RTM)了,做为微软认证金牌合作的葡萄城控件,我们组织力量第一时间进行翻译.分享给 ...

  3. C#中的线程三 (结合ProgressBar学习Control.BeginInvoke)

    C#中的线程三(结合ProgressBar学习Control.BeginInvoke) 本篇继上篇转载的关于Control.BeginInvoke的论述之后,再结合一个实例来说明Cotrol.Begi ...

  4. 团队项目——站立会议DAY9

    第九次站立会议记录: 参会人员:张靖颜,钟灵毓秀,何玥,赵莹,王梓萱 项目进展: 1.张靖颜:部署总体战略,需求分析,反复运行程序并完善. 2.钟灵毓秀:近一步修改代码,并进行功能性的扩展,不断完善. ...

  5. 为 Exchange 服务器编写自定义的反垃圾插件

    Exchange 2010 的 Edge Transport 包含了一些 Anti-spam 的 Feature,如图: 都开启了,但是呢,还是会有漏网之鱼,而且把这些邮件自己列为 Junk 也起不了 ...

  6. Field 'id' doesn't have a default value

    首先原因在于没有设置主键自增长. mysql的自增长模式是IDENTITY. jpa标签: @Id @GeneratedValue(strategy=GenerationType.IDENTITY) ...

  7. 一则JVM memory leak解决的过程

    起因是我们的集群应用(3台机器)新版本测试过程中,一般的JVM内存占用 都在1G左右, 但在运行了一段时间后,慢慢升到了4G, 这是一个明显不正常的现象. 定位 过程: 1.先在该机器上按照步骤尝试重 ...

  8. Java基础之网络编程

    网络编程:1.网络编程概述 (1)网络模型 OSI参考模型 TCP/IP参考模型 (2)网络通讯要素 IP地址 端口号 传输协议 (3)网络通讯前提: **找到对方IP **数据要发送到指定端口.为了 ...

  9. DDD~领域服务的规约模式

    回到目录 规 约(Specification)模式:第一次看到这东西是在microsoft NLayer项目中,它是微软对DDD的解说,就像petshop告诉了我们MVC如何使用一样,这个规约模式最重 ...

  10. 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现

    返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...