11

instanceof“大图书馆”的公平表现如何?

它是否像这样一一地沿着原型链向上移动?:

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

与在instanceof每个对象的属性中存储唯一的接口 id 号相比,它的性能相对较差。

4

3 回答 3

12

是的,类似的东西。这是规范中的相关部分:

11.8.6 instanceof 运算符

产生式RelationalExpression : RelationalExpression instanceof ShiftExpression的评估如下:

  1. lref为评估RelationalExpression的结果。
  2. lval为 GetValue( lref )。
  3. rref为评估ShiftExpression的结果。
  4. rval为 GetValue( rref )。
  5. 如果 Type( rval ) 不是 Object,则抛出TypeError异常。
  6. 如果rval没有 [[HasInstance]] 内部方法,则抛出TypeError异常。
  7. 返回使用参数lval调用rval的 [[HasInstance]] 内部方法的结果。

其中调用 [[HasInstance]] 方法定义为

15.3.5.3 [[HasInstance]] (V)

假设F是一个 Function 对象。

F的 [[HasInstance]] 内部方法以值V被调用时,将采取以下步骤:

  1. 如果V不是对象,则返回false
  2. O为使用属性名称“原型”调用F的 [[Get]] 内部方法的结果。
  3. 如果 Type( O ) 不是 Object,则抛出TypeError异常。
  4. 重复
    一个。令V为V的 [[Prototype]] 内部属性的值。
    湾。如果Vnull,则返回false
    C。如果OV引用同一个对象,则返回true

关于性能:这可能取决于浏览器中的实际实现。它们之间可能存在巨大差异,因此最好的方法是进行一些基准测试,例如使用http://jsperf.com/


一个问题instanceof是,如果您在来自不同上下文的元素(例如框架或 iframe)上调用它,它可能无法正常工作。例如,让a您可以访问的对象,iframe.contentWindow.a并且您想测试它是否是一个数组,然后

iframe.contentWindow.a instanceof Array

将返回false

于 2011-05-08T01:35:03.440 回答
12

在 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

Firefox 显示相同的行为。

这里有点疯狂,但是:

> 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 毫秒的性能差异,则可以安全地假设没有性能损失:)

于 2011-05-08T01:36:38.597 回答
7

根据 Felix Kling 引用的内容,instanceof 所做的一切(不包括错误检查)是检查是否可以在原型链的某个位置找到 Function 的原型属性(必须是对象)

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;
    }
}
于 2012-10-13T15:09:38.817 回答