Javascript instanceof究竟是如何工作的?是慢节奏吗?

Pac*_*ier 9 javascript inheritance instanceof

instanceof"巨型图书馆" 的公平表现如何?

它是否一个接一个地沿原型链传播,类似于此?:

//..
var _ = john.constructor;
while (true) {
    if (_ === Human) {
        return true;
    }
    _ = _.prototype.constructor
}
return false;
//..
Run Code Online (Sandbox Code Playgroud)

instanceof与在每个对象的属性中存储唯一的接口ID号相比,相对来说是不相容的.

Fel*_*ing 11

是的,那样的.以下是规范中的相关部分:

11.8.6 instanceof运算符

ShiftExpression的生产RelationalExpression:RelationalExpression 实例 的计算方法如下:

  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对象.

当使用值V调用F的[[HasInstance]]内部方法时,将执行以下步骤:

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

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


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

iframe.contentWindow.a instanceof Array
Run Code Online (Sandbox Code Playgroud)

会回来的false.


Mar*_*ahn 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我认为可以安全地假设没有性能损失,如果它可以钻取10,000个类而不会看到1毫秒的性能差异:)

  • 有点疯狂正是有时所需要的 (2认同)

小智 7

根据Felix Kling所引用的,所有instanceof做的(不包括错误检查)是检查函数的原型属性(必须是对象)是否可以在原型链的某处找到

person instanceof Object
// ROUGHTLY does
return (
     person.__proto__==Object.prototype
  || person.__proto__.__proto__==Object.prototype
  || ... );
Run Code Online (Sandbox Code Playgroud)

这是一些伪代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)