我遇到过道格拉斯Crockfords Object.create方法的特殊性,我希望有人可以解释一下:
如果我创建一个对象 - 比如'person' - 使用对象文字符号,那么使用Object.create创建一个新对象 - 比如'anotherPerson' - 它继承了最初'person'对象的方法和属性。
如果我然后更改第二个对象的名称值 - 'anotherPerson' - 它还会更改初始'person'对象的名称值。
这只有在嵌套属性时才会发生,这段代码可以让你知道我的意思:
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'
当使用带有构造函数和'new'关键字的经典继承风格时,似乎不会发生这种嵌套问题。
如果有人能够解释为什么会发生这种情况,我会非常感激!?
答案 0 :(得分:19)
之所以发生这种情况,是因为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'
};
答案 1 :(得分:2)
问题是Object.create只执行浅拷贝而不是深拷贝,因此person.name和anotherPerson.name都指向同一个Object实例。
<强>被修改强>
虽然person.name === anotherPerson.name
确实如此,但我对此为何的解释是不正确的。有关正确的解释,请参阅@ CMS的答案。
答案 2 :(得分:1)
不复制name
属性的原因是因为JavaScript中的对象文字总是引用,因此复制了引用(而不是其内容)......所以它不是因为它在原型中更深链或因为它正在做一个浅的副本。