2011-05-08 41 views
9

instanceof對於「龐大的圖書館」的性能如何?Javascript instanceof的工作原理是什麼?它是緩慢的風格?

它是否沿着原型鏈逐個上架,與此類似? :

//.. 
var _ = john.constructor; 
while (true) { 
    if (_ === Human) { 
     return true; 
    } 
    _ = _.prototype.constructor 
} 
return false; 
//.. 

instanceof相對unperfomant那麼,相比於在每一個對象的屬性存儲唯一的接口ID號。

+0

相關:https://stackoverflow.com/a/45656957/632951 – Pacerier 2017-08-13 04:19:19

回答

11

是的,就像那樣。下面是相關的部分從specification

11.8.6 The instanceof operator

生產RelationalExpressionRelationalExpression的instanceofShiftExpression如下評價:

  1. lref是評估結果關係表達式
  2. lval成爲GetValue(lref)。
  3. rref是評估結果ShiftExpression
  4. rval成爲GetValue(rref)。
  5. 如果類型(rval)不是Object,則拋出一個TypeError異常。
  6. 如果rval沒有[[HasInstance]]內部方法,則拋出TypeError異常。
  7. 返回調用[[HasInstance]]內部方法rval與參數lval的結果。

其中調用[[HasInstance]]方法被定義爲

15.3.5.3 [[HasInstance]] (V)

假設˚F是一個功能對象。

˚F的[[HasInstance]]內部方法被調用值V,採取以下步驟:

  1. 如果V不是一個對象,返回
  2. Ø是調用的的[[Get]]內部方法F與屬性名稱 「原型」 的結果。
  3. 如果類型(O)不是Object,則拋出TypeError異常。
  4. 重複
    a。假設VV [[Prototype]]內部屬性的值。 b。如果Vnull,返回
    c。如果OV指的是同一個對象,返回true

關於性能:這可能取決於瀏覽器中的實際實現。它們之間可能有很大的差異,所以最好的做法是做出一些基準,例如與http://jsperf.com/


instanceof的一個問題是,如果你調用它從不同的情境,如框架或iframe元素可能無法正常工作。例如,讓a是一個對象,你可以通過iframe.contentWindow.a訪問並要測試它是否是一個數組,然後

iframe.contentWindow.a instanceof Array 

將返回false

+0

這不是一個問題,這是一個巨大的優勢! :)你可以混淆'iframe.contentwindow.Array.prototype',然後有「特殊」數組!或'.Object.prototype' :) – 2011-05-08 01:53:47

+0

@cwolves:在iframe中可能有意外的行爲。這是一個問題,如果一個人不知道。 – 2011-05-08 01:59:38

11

在V8(Chrome的JS引擎),似乎有小到無的性能損失:

> function A(){} 
> function B(){} 
> function C(){} 
> function D(){} 
> B.prototype = new A(); 
> C.prototype = new B(); 
> D.prototype = new C(); 
> 
> var objA = new A(); 
> var objD = new D(); 
> 
> var start = (+new Date()); for(var i=0; i<10000000; i++){ objA instanceof A } console.log((+new Date()) - start); 
138 
> var start = (+new Date()); for(var i=0; i<10000000; i++){ objD instanceof A } console.log((+new Date()) - start); 
138 

火狐顯示相同的行爲。

去了一下這裏瘋狂,但:

> var classes = []; 
> for(var i=0; i<10000; i++){ 
> classes[i] = function(){}; 
> i && (classes[i].prototype = new (classes[i-1])()); 
> } 
> 
> var obj0 = new classes[0], 
> obj9999 = new classes[9999]; 
> 
> var start = (+new Date()); for(var i=0; i<10000000; i++){ obj0 instanceof classes[0] } console.log((+new Date()) - start); 
138 
> var start = (+new Date()); for(var i=0; i<10000000; i++){ obj999 instanceof classes[0] } console.log((+new Date()) - start); 
138 

我認爲它是安全的假設沒有性能損失,如果它可以到10,000類鑽,而不是看1毫秒的性能差異:)

+1

有點瘋狂是有時需要的 – Flion 2014-05-09 18:00:25

7

根據Felix Kling所引用的內容,所有這些instanceof(不包括錯誤檢查)都是檢查函數的原型屬性(它必須是對象)是否可以在原型鏈的某處找到

person instanceof Object 
// ROUGHTLY does 
return (
    person.__proto__==Object.prototype 
    || person.__proto__.__proto__==Object.prototype 
    || ...); 

下面是一些僞代碼:

person instanceof Person 
//ROUGHTLY equals 
person.instanceOf(Person) 

person.instanceOf = function(Person) { 
    if(typeof Person!='object') throw new TypeError; 
    if(!([[HasInstance]] in Person)) throw new TypeError; 
    return Person.[[HasInstance]](this /* person */) 
} 


Person.[[HasInstance]] = function(V) { 
    if(typeof V!='object') return false; 
    var O = this.prototype; 
    if(typeof O!='object') throw new TypeError; 
    while(true) { 
     V = V.__proto__; // [[prototype]] (hidden) property 
     if(V==null) return false; 
     if(V==O) return true; 
    } 
} 
相關問題