Я столкнулся с особенностью с Douglas Crockfords метод Object.create, который я надеюсь, что кто-то смог объяснять:
Если я создаю объект - говорят, что 'человек' - использующий нотацию литерала объектов затем использует Object.create для создания нового объекта - скажем 'anotherPerson' - который наследовал методы и свойства от начального объекта 'человека'.
Если я затем изменяю значения имени второго объекта - 'anotherPerson' - он также изменяет значение имени начального объекта 'человека'.
Это только происходит, когда свойства вкладываются, этот код должен дать Вам общее представление о том, что я имею в виду:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
};
// initiate new 'person' object
var person = {
name: {
first: 'Ricky',
last: 'Gervais'
},
talk: function() {
console.log('my name is ' + this.name.first + ' ' + this.name.last);
}
}
// create anotherPerson from person.prototype
var anotherPerson = Object.create(person);
// change name of anotherPerson
anotherPerson.name.first = 'Stephen';
anotherPerson.name.last = 'Merchant';
// call talk method of both 'person' and 'anotherPerson' objects
person.talk(); // oddly enough, prints 'Stephen Merchant'
anotherPerson.talk(); // prints 'Stephen Merchant'
Если я должен был сохранить значения имени без вложения затем, это нечетное поведение не происходит - например.
// initiate new 'person' object
var person = {
firstName: 'Ricky',
lastName: 'Gervais',
talk: function() {
console.log('my name is ' + this.firstName + ' ' + this.lastName);
}
}
// create anotherPerson from person.prototype
var anotherPerson = Object.create(person);
// change name of anotherPerson
anotherPerson.firstName = 'Stephen';
anotherPerson.lastName = 'Merchant';
// call talk method of both 'person' and 'anotherPerson' objects
person.talk(); // prints 'Ricky Gervais'
anotherPerson.talk(); // prints 'Stephen Merchant'
Эта вложенная проблема, кажется, не происходит при использовании классического стиля наследования с функцией конструктора и 'новым' ключевым словом.
Я был бы очень благодарен, если чье-либо способное для объяснения, почему это происходит!?
Это происходит потому, что anotherPerson.name
является объектом и хранится вверху в цепочке прототипов, на исходном объекте person
:
//...
var anotherPerson = Object.create(person);
anotherPerson.hasOwnProperty('name'); // false, the name is inherited
person.name === anotherPerson.name; // true, the same object reference
Вы можете избежать этого, назначив новый объект свойству name
вновь созданного объекта:
// create anotherPerson from person
var anotherPerson = Object.create(person);
anotherPerson.name = {
first: 'Stephen',
last: 'Merchant'
};
Проблема в том, что Object.create выполняет только поверхностную копию, а не глубокую копию, поэтому person.name и anotherPerson.name указывают на один и тот же экземпляр Object.
Отредактировано
Хотя это правда, что person.name === anotherPerson.name
, мое объяснение того, почему это правда, неверно. См. Ответ @ CMS для правильного объяснения.
Причина, по которой атрибут name
не копируется, заключается в том, что литералы объектов в JavaScript всегда являются ссылками, поэтому ссылка копируется (а не ее содержимое) ... так что это не потому, что она глубже цепочка прототипов или потому, что она делает неглубокую копию.