文章出處

一、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/

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()