Почему * не * «наследовать» / расширять от объекта в JavaScript?

#javascript

#javascript

Вопрос:

Хорошо известно, что объявление объектов с использованием нотации JSON делает их «наследуемыми» от (или, точнее, построенными как) базового объекта:

myobj={a:1, b:2};

что почти эквивалентно myobj = Object.create(Object); myobj.a=1; myobj.b=2;

и чем:

Object.getPrototypeOf(myobj)

выводит следующее:

 Object
    __defineGetter__: function __defineGetter__() { [native code] }
    __defineSetter__: function __defineSetter__() { [native code] }
    __lookupGetter__: function __lookupGetter__() { [native code] }
    __lookupSetter__: function __lookupSetter__() { [native code] }
    constructor: function Object() { [native code] }
    hasOwnProperty: function hasOwnProperty() { [native code] }
    isPrototypeOf: function isPrototypeOf() { [native code] }
    propertyIsEnumerable: function propertyIsEnumerable() { [native code] }
    toLocaleString: function toLocaleString() { [native code] }
    toString: function toString() { [native code] }
    valueOf: function valueOf() { [native code] }
  

Однако можно вызвать Object.create() , null указав в качестве аргумента:

 myobj2 = Object.create(null);
  

В этом случае будет возвращен пустой прототип:

 Object
    No Properties
  

И здесь возникает вопрос: в каких случаях и почему я должен заботиться о том, чтобы разбить цепочку прототипов на оригинал Object ? Где это может быть полезно?

Обновление: как уже исправлено ниже, я имею Object.create(Object.prototype) в виду, а не Object.create(Object) то, что вернет Function объект (действительно Object() , это функция конструктора для Object прототипов).

Комментарии:

1. Выбор Nit: это не нотация JSON (которая, кстати, была бы нотацией объекта JavaScript ), а просто объектный литерал . Но, кроме того, это интересный вопрос.

Ответ №1:

Вместо этого:

 myobj = Object.create(Object);
  

… Я думаю, вы имеете в виду, что это эквивалентно:

 myobj = Object.create(Object.prototype);
  

… потому что:

 Object.getPrototypeOf( {a:1, b:2} ) === Object.prototype;  // true
  

Что касается того, зачем использовать null early, если вашему объекту не нужны какие-либо свойства Object.prototype , досрочное завершение цепочки технически (хотя и незначительно) ускорит поиск свойств, когда свойство не существует для рассматриваемого объекта.

Обратите внимание, что я говорю «рано», потому что цепочка всегда заканчивается null .

 Object.getPrototypeOf( Object.prototype );  // null
  

 
             obj ----------> proto -------> Object.proto -----> null
          ---------        ---------        -------------      
         |         |      |         |      |             |
         |  foo:1  |      |  bar:1  |      | toString:fn |      null
         |         |      |         |      |             |
          ---------        ---------        -------------  
              ^                ^                  ^               X
              |                |                  |               |
obj.foo ------                 |                  |               |
              ^                |                  |               |
obj.bar------- ----------------                   |               |
              ^                ^                  |               |
obj.toString-- ---------------- ------------------                |
              ^                ^                  ^               |
obj.baz------- ---------------- ------------------ --------------- 

   ^---property lookups
  

Обратите внимание, что baz свойство не существует нигде в цепочке прототипов.

Из-за этого ему необходимо последовательно искать каждый объект, пока он, наконец, не достигнет null , прежде чем он поймет, что baz его нигде не существует.

Если вы удалите Object.prototype из цепочки, это будет null немного быстрее.

Комментарии:

1. Итак, ЕСЛИ я вас правильно понял, единственной «очевидной» причиной прототипа являются проблемы с производительностью / полнотой функций? null

2. @BreakPhreak: Да. Цепочка прототипов всегда заканчивается null . Чем раньше вы доберетесь null , тем скорее цепочка закончится, остановив поиск свойств. Все остальное (по моей оценке) было бы крайним случаем, например, если бы кто-то по какой-то причине захотел my_obj instanceof Object; // false

3. Это не только производительность. Иногда вы просто не хотите, чтобы эти свойства были там вообще (например, при реализации хэш-таблицы вам не нужны никакие посторонние ключи)

4. @missingno: не могли бы вы подробнее остановиться на этом?

5. Когда вы хотите использовать объект для хранения пар ключ-значение, имеющих поддельные ключи, такие как hasOwnProperty, и могут быть нежелательными. Хотя и теоретически, поскольку Object.create пока не так широко распространен.