How exactly does Javascript instanceof work? Is it slow style?

一世执手 提交于 2019-11-30 03:06:54

问题


How does the performance of instanceof fair for "huge libraries"?

Does it travel up the prototype chain one by one, similar to this? :

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

Is instanceof relatively unperfomant then, compared to storing a unique interface id number in the property of every object.


回答1:


Yeah something like that. Here is the relevant part from the specification:

11.8.6 The instanceof operator

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

  1. Let lref be the result of evaluating RelationalExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating ShiftExpression.
  4. Let rval be GetValue(rref).
  5. If Type(rval) is not Object, throw a TypeError exception.
  6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
  7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

where calling the [[HasInstance]] method is defined as

15.3.5.3 [[HasInstance]] (V)

Assume F is a Function object.

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

  1. If V is not an object, return false.
  2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
  3. If Type(O) is not Object, throw a TypeError exception.
  4. Repeat
    a. Let V be the value of the [[Prototype]] internal property of V.
    b. If V is null, return false.
    c. If O and V refer to the same object, return true.

Regarding performance: This probably depends on the actual implementations in the browsers. There can be huge differences between them so the best thing would be to make some benchmarks, e.g. with http://jsperf.com/.


A problem with instanceof is that it might not work if you invoke it on elements from different contexts, such as a frame or iframe. For example, let a be an object you can access via iframe.contentWindow.a and you want to test whether it is an array, then

iframe.contentWindow.a instanceof Array

will return false.




回答2:


in V8 (Chrome's JS engine), there seems to be little-to-no performance hit:

> 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 shows identical behavior.

Going a bit crazy here, but:

> 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

I think it's safe to assume there is no performance hit if it can drill through 10,000 classes and not see 1 ms performance difference :)




回答3:


According to what Felix Kling quoted, all that instanceof does (excluding the error checks) is to check whether the prototype property(which has to be an object) of the Function can be found somewhere down the prototype chain

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

Here's some pseudocode:

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;
    }
}


来源:https://stackoverflow.com/questions/5925063/how-exactly-does-javascript-instanceof-work-is-it-slow-style

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!