Javascript instanceof 究竟是如何工作的?是慢风格吗?

发布于 2024-11-05 13:14:10 字数 342 浏览 1 评论 0原文

对于“巨大的库”来说,instanceof 的性能如何?

它是否沿着原型链一个接一个向上移动,与此类似? :

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

自此以后,行同陌路 2024-11-12 13:14:10

在 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 毫秒的性能差异,那么可以安全地假设不会影响性能:)

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 :)

野味少女 2024-11-12 13:14:10

是的,类似的事情。以下是规范中的相关部分:

11.8.6 instanceof 运算符

产生式RelationalExpressionRelationalExpression instanceof ShiftExpression评估如下:

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

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

15.3.5.3 [[HasInstance]] (V)< /p>

假设F是一个Function对象。

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

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

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


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

iframe.contentWindow.a instanceof Array

将返回false< /代码>。

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.

柳若烟 2024-11-12 13:14:10

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

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文