JavaScript - Object.create объяснение

У меня есть вопрос о следующем каноническом методе object.create:

Object.create = function(o, props) {
    function F() {}
    F.prototype = o;

    if (typeof(props) === "object") {
     for (prop in props) {
      if (props.hasOwnProperty((prop))) {
       F[prop] = props[prop];
      }
     }
    }
    return new F();
   };

В строке 3 приведенного выше кода мы устанавливаем свойство prototype объекта F в прототип аргумента o.

Я бы подумал, что это означает, что и o, и F указывают на один и тот же прототип и, следовательно, указывают на один и тот же набор членов.

Но код затем копирует все элементы в цикле prop in props.

Какой смысл устанавливать прототип в строке 3, если мы затем копируем все элементы вручную?

3 ответа

Решение

Там есть ошибка в версии Object.create на ваш вопрос: цикл присоединяет свойства к функции конструктора F (не для возвращаемого объекта или его прототипа), что означает, что они не доступны в созданном объекте.

Свойства второго параметра Object.create должны быть скопированы во вновь созданный объект. Документация Mozilla дляObject.create выражает это так:

Если указан и не определен, объект, чьи перечисляемые собственные свойства (то есть те свойства, которые определены для него самих, а не перечисляемые свойства в его цепочке прототипов) задают дескрипторы свойств, которые должны быть добавлены во вновь создаваемый объект, с соответствующими именами свойств.

Попробуйте запустить следующий код с версией Object.create в вопросе:

o = Object.create(
        {a: "prototype's a", b: "prototype's b"},
        {a: "object's a"}
    );

Вы найдете это o.a == "prototype's a" а также o.b == "prototype's b", "object's a" потерян.

Следующая версия функции, вероятно, будет более полезной:

Object.create = function(o, props) {
    var newObj;

    // Create a constructor function, using o as the prototype
    function F() {}
    F.prototype = o;

    // Create a new object using F as the constructor function
    newObj = new F();

    // Attach the properties of props to the new object
    if (typeof(props) === "object") {
        for (prop in props) {
            if (props.hasOwnProperty((prop))) {
                newObj[prop] = props[prop];
            }
        }
    }

    return newObj;
};

Давайте попробуем это на том же примере:

o = Object.create(
        {a: "prototype's a", b: "prototype's b"},
        {a: "object's a"}
    );

Новый объект o создается с прототипом, который имеет свойства a а также b и это собственная собственность a,

Давайте посмотрим на o.b первый: o.hasOwnProperty("b") вернусь false, так как o не имеет свойства под названием b, Вот где появляется прототип; потому что нет собственности b это рассматривается на прототип, и, следовательно, o.b === "prototype's b",

С другой стороны, o.hasOwnProperty("a") вернусь true, так как o действительно есть a имущество. o.a == "object's a" и ничего не оторвано от прототипа.

Как указано в ответе @chuckj, правильная реализация Object.create сложнее, чем это. Для получения дополнительной информации см. Статью Джона Резига об объектах и ​​свойствах ECMAScript 5.

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

Object.create = function(o, props) { 
    function F() {} 
    F.prototype = o; 
    var result = new F();
    if (typeof(props) === "object") 
       for (prop in props)
          if (props.hasOwnProperty(prop) && typeof(props[prop].value) != "undefined")
             result[prop] = props[prop].value; 
    return result;
}; 

props параметр содержит дескрипторы свойств для членов нового объекта, который вы хотите отличать от указанного в прототипе, o, Значения не должны копироваться буквально в объект, а должны обрабатываться так, как если бы вы вызывали Object.defineProperties()выше моделируется назначением value часть дескриптора нового объекта. Object.create() не может быть точно заполнен до ECMA 3, так как он может использоваться для указания свойств с помощью функций доступа, хотя вышеописанное будет работать для props которые используют value вместо get или же set,

Если вас не интересует версия для заполнения, ниже приведено точное описание того, что Object.create() делает, предполагая существование обоих __proto__ а также Object.defineProperties(),

Object.create = function (o, props) {
    if (typeof(o) !== "object" && o != null) throw new TypeError();
    var result = new Object();
    if (o != null)
        result.__proto__ = o;
    if (typeof(props) !== "undefined")
        Object.defineProperties(result, props);
    return result;
};

Думать о F как функция, которая возвращает новый экземпляр объекта и F.prototype ссылка на объект, от которого новый экземпляр заимствует свойства.

Экземпляры, созданные с F иметь свой собственный набор свойств независимо от F.prototype,

Когда собственность не может быть найдена в случае F тогда среда выполнения активизирует цепочку прототипов и заглянет, чтобы увидеть, существует ли свойство в F.prototype,

Вот почему вы хотите скопировать некоторые и наследовать другие.

Задача Prototype заключается в обеспечении повторного использования кода / хранения свойств класса.

Думать о F.prototype как экземпляры класса F как объект.

Другие вопросы по тегам