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
как объект.