Что происходит в технике создания объектов Крокфорда? - PullRequest
24 голосов
/ 04 мая 2010

Есть только 3 строки кода, и все же у меня возникают проблемы с полным пониманием этого:

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};
newObject = Object.create(oldObject);

(из наследование прототипа )

  1. Object.create() начинается с создания пустой функции с именем F. Я думаю, что функция - это своего рода объект. Где хранится этот F объект? Во всем мире, я думаю.

  2. Затем наш oldObject, переданный как o, становится прототипом функции F. Функция (то есть объект) F теперь «наследует» от нашего oldObject, в том смысле, что разрешение имен будет проходить через нее. Хорошо, но мне интересно, какой прототип по умолчанию для объекта, Object? Это также верно для объекта-функции?

  3. Наконец, F создается и возвращается, становясь нашим newObject. Операция new здесь строго необходима? Разве F уже не обеспечивает то, что нам нужно, или есть критическое различие между объектами-функциями и объектами-не-функциями? Очевидно, что будет невозможно иметь функцию конструктора, использующую эту технику.

Что произойдет при следующем вызове Object.create()? Глобальная функция F перезаписана? Конечно, он не используется повторно, потому что это изменило бы ранее настроенные объекты. И что произойдет, если несколько потоков вызовут Object.create(), существует ли какая-либо синхронизация для предотвращения условий гонки на F?

Ответы [ 4 ]

29 голосов
/ 04 мая 2010

1) Object.create () начинается с создавая пустую функцию с именем F. Я думаю, что функция является своего рода объекта. Где этот объект F хранится? Во всем мире, я думаю.

Нет, он хранится в локальной области действия функции Object.create, каждый раз, когда вы вызываете Object.create, эта функция F будет воссоздана.

Вы могли бы даже создать более эффективную реализацию памяти, сохранив F в замыкании, и повторно использовать его:

if (typeof Object.create !== "function") {
  Object.create = (function () {
    function F() {} // created only once
    return function (o) {
      F.prototype = o; // reused on each invocation
      return new F();
    };
  })();
}

2) Далее наш старый объект, переданный как o, становится прототипом функции F. Функция (т.е. объект) F сейчас «наследует» от нашего старого объекта, в чувствую, что разрешение имен будет направлено через это. Хорошо, но мне интересно, что прототип по умолчанию для Объект Object? Это также верно для функция-объект?

Все объекты имеют внутреннее свойство, которое создает цепочку прототипов, это свойство известно как [[Prototype]], это внутреннее свойство, хотя некоторые реализации позволяют вам получить к нему доступ, например, mozilla, со свойством obj.__proto__.

Значение по умолчанию [[Prototype]] при создании нового объекта, т.е. var obj = {}; равно Object.prototype.

Все функции имеют свойство prototype, это свойство используется, когда функция используется в качестве Конструктора , вызываемого оператором new.

Новый экземпляр объекта создается за сценой, и этому объекту [[Prototype]] присваивается свойство конструктора prototype.

3) Наконец, создается экземпляр F и вернулся, став нашим новым объектом. Является «новая» операция строго необходима Вот? F уже не предоставляет то, что нам нужно, или есть критическое разница между функциями-объектами и нефункциональные объекты? Ясно это не будет возможности иметь функция конструктора, использующая это техника.

Да, оператор new необходим в этом методе.

Оператор new является единственным стандартным способом установить внутреннее свойство [[Prototype]] объекта. Если вам интересно, как он работает, вы можете посмотреть на [[Construct]] внутренняя операция.

Что произойдет в следующий раз Object.create () вызывается? Является глобальным функция F перезаписана? Конечно, это не используется повторно, потому что это изменило бы предварительно настроенные объекты. А также что произойдет, если вызов нескольких потоков Object.create (), есть ли синхронизация для предотвращения гонки условия по F?

В следующий раз, когда вызывается Object.create, новая локальная F функция создается только в рамках вызова метода, вам не стоит беспокоиться о условиях гонки .

Обратите внимание, что эта реализация едва ли соответствует Object.create, описанному в ECMAScript 5-е издание Спецификация , в этом методе вы можете передать дескриптор свойства для инициализации объекта.

Все поставщики браузеров реализуют его (уже доступно в Firefox 3.7 alphas, последних версиях Wekit Nightly Build и Chrome 5 Beta), поэтому я рекомендую вам хотя бы проверить, существует ли собственная реализация, прежде чем переопределять ее.

7 голосов
/ 04 мая 2010

1) Функция действительно является своего рода объектом. Функциональный объект с идентификатором F создается каждый раз, когда вызывается Object.create, и доступен только с этим идентификатором в рамках этого выполнения Object.create. Поэтому каждый раз, когда вызывается Object.create, вы получаете другой объект функции F. Этот функциональный объект живет как свойство constructor объекта, возвращаемого Object.create.

2)

F теперь «наследует» от нашего старого объекта, в том смысле, что разрешение имени будет маршрут через него

Это не совсем правильно. Присвоение объекта someObject свойству prototype функции просто означает, что прототип любого будущего объекта, созданного путем вызова этой функции в качестве конструктора, будет someObject.

3) new абсолютно необходим для этой техники. Только вызывая функцию в качестве конструктора, он создает новый объект, и прототип этого объекта (который обычно недоступен) устанавливается в свойство prototype функции конструктора. Нет другого (стандартизированного) способа установить прототип объекта.

Наконец, JavaScript в браузерах является однопоточным, поэтому условия гонки, которые вы описываете, невозможны.

2 голосов
/ 04 июля 2011

> Очевидно, что будет невозможно иметь функцию конструктора, использующую эту технику.

Техника уже является конструктором объекта, поскольку она возвращает новый F (), но значения свойств не могут быть установлены, как, скажем, new man ('John', 'Smith'). Однако, если код Object.create изменен, создание экземпляров возможно. Например, приведенный ниже объект sarah может быть создан и создан с использованием Object.creator и будет наследовать метод getName.

var girl = {
   name: '',
   traits: {},
   getName: function(){return this.name}
}

var sarah = Object.creator(girl, 'Sarah', {age:29,weight:90})

Объект sarah будет состоять из собственных свойств {name: 'Sarah', признаков: {age: 9, weight: 49}}, а унаследованный прототипом sarah.getName () будет создан 'Sarah'.

Следующий метод основывается на собственных свойствах, перечисляемых с помощью for для prop в ore. Хотя это не гарантировано спецификациями ECMA, этот пример (и несколько более сложный) работал для всех основных протестированных браузеров (4), при условии использования hasOwnProperty (), в противном случае - нет.

Object.creator = function(o) {
   var makeArgs = arguments 
   function F() {
      var prop, i=1, arg, val
      for(prop in o) {
         if(!o.hasOwnProperty(prop)) continue
         val = o[prop]
         arg = makeArgs[i++]
         if(typeof arg === 'undefined') break
         this[prop] = arg
      }
   }
   F.prototype = o
   return new F()
}

Официальный ECMA Object.create имеет необязательный второй параметр, propertiesObject, который может создавать экземпляры значений свойств, но это объект, а не обычный список, и его использование неудобно. Например. Я верю: -

o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });

эквивалентен гораздо более простому старому способу: -

o2 = new function(p) { this.p=p }(42)

и

o2 = Object.creator({p:''}, 42)
2 голосов
/ 04 мая 2010

Ваше главное недоразумение в том, что F имеет глобальный охват. Он объявляется в теле Object.create и, следовательно, находится только в области видимости этого блока метода.

...