Как именно работает экземпляр Javascript? Это медленный стиль? - PullRequest
9 голосов
/ 08 мая 2011

Как производительность instanceof справедлива для "огромных библиотек"?

Продвигается ли она вверх по цепочке прототипов одна за другой , как это? :

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

Является ли instanceof относительно неперфорированным по сравнению с сохранением уникального идентификатора интерфейса в свойстве каждого объекта.

Ответы [ 3 ]

11 голосов
/ 08 мая 2011

в V8 (JS-движок Chrome), кажется, что производительность почти отсутствует:

> 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

Я думаю, можно с уверенностью предположить, что не будет никакого снижения производительности, если он может просверлить 10000 классов и не увидеть разницу в производительности за 1 мс:)

11 голосов
/ 08 мая 2011

Да, что-то в этом роде. Вот соответствующая часть из спецификации :

11.8.6 Оператор instanceof

Производство RelationalExpression : RelationalExpression instanceof ShiftExpression оценивается следующим образом:

  1. Пусть lref будет результатом вычисления RelationalExpression .
  2. Пусть lval будет GetValue ( lref ).
  3. Пусть rref будет результатом вычисления ShiftExpression .
  4. Пусть rval будет GetValue ( rref ).
  5. Если тип ( rval ) не является объектом, выдается исключение TypeError .
  6. Если rval не имеет внутреннего метода [[HasInstance]], выбросить исключение TypeError .
  7. Возвращает результат вызова внутреннего метода [[HasInstance]] для rval с аргументом lval .

где вызов метода [[HasInstance]] определяется как

15.3.5.3 [[HasInstance]] (V)

Предположим, F является объектом Function.

Когда внутренний метод [[HasInstance]] для F вызывается со значением V , предпринимаются следующие шаги:

  1. Если V не является объектом, вернуть false .
  2. Пусть O будет результатом вызова внутреннего метода [[Get]] для F с именем свойства " prototype ".
  3. Если тип ( O ) не является объектом, выведите исключение TypeError .
  4. Повторите
    а. Пусть V будет значением внутреннего свойства [[Prototype]] V .
    б. Если V равно null , верните false .
    с. Если O и V относятся к одному и тому же объекту, верните true .

Относительно производительности: это, вероятно, зависит от реальных реализаций в браузерах. Между ними могут быть огромные различия, поэтому лучше всего сделать несколько тестов, например, с http://jsperf.com/.


Проблема с instanceof в том, что он может не работать, если вы вызываете его для элементов из разных контекстов, таких как фрейм или фрейм. Например, пусть a будет объектом, к которому вы можете получить доступ через iframe.contentWindow.a, и вы хотите проверить, является ли он массивом, тогда

iframe.contentWindow.a instanceof Array

вернет false.

7 голосов
/ 13 октября 2012

В соответствии с тем, что цитировал Феликс Клинг, все, что 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;
    }
}
...