简体   繁体   English

JavaScript Object.create - 继承嵌套属性

[英]JavaScript Object.create — inheriting nested properties

I've come across a peculiarity with Douglas Crockfords Object.create method which I'm hoping someone might be able to explain: 我遇到过道格拉斯Crockfords Object.create方法的特殊性,我希望有人可以解释一下:

If I create an object - say 'person' - using object literal notation then use Object.create to create a new object - say 'anotherPerson' - which inherits the methods and properties from the initial 'person' object. 如果我创建一个对象 - 比如'person' - 使用对象文字符号,那么使用Object.create创建一个新对象 - 比如'anotherPerson' - 它继承了最初'person'对象的方法和属性。

If I then change the name values of the second object - 'anotherPerson' - it also changes the name value of the initial 'person' object. 如果我然后更改第二个对象的名称值 - 'anotherPerson' - 它还会更改初始'person'对象的名称值。

This only happens when the properties are nested, this code should give you an idea of what I mean: 这只发生在嵌套属性时,这段代码应该让你知道我的意思:

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'

If I were to store the name values without nesting then this odd behaviour does not occur -- eg 如果我在没有嵌套的情况下存储名称值,则不会发生这种奇怪的行为 - 例如

// 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'

This nesting issue doesn't seem to occur when using a classical style of inheritance with a constructor function and the 'new' keyword. 当使用带有构造函数和'new'关键字的经典继承风格时,似乎不会出现此嵌套问题。

I'd be much appreciative if anyone's able to explain why this occurs!? 如果有人能够解释为什么会发生这种情况,我会非常感激!?

That happens because anotherPerson.name is an object and it is stored upper in the prototype chain, on the original person object: 发生这种情况是因为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

You can avoid this by assigning a new object to the name property of the newly created object: 您可以通过将新对象分配给新创建的对象的name属性来避免这种情况:

// create anotherPerson from person
var anotherPerson = Object.create(person);

anotherPerson.name = {
  first: 'Stephen',
  last: 'Merchant'
};

The problem is that Object.create only does a shallow copy, not a deep copy, so person.name and anotherPerson.name both point to the same Object instance. 问题是Object.create只执行浅拷贝而不是深拷贝,因此person.name和anotherPerson.name都指向同一个Object实例。

Edited 编辑

While it's true that person.name === anotherPerson.name , my explanation for why this is true is incorrect. 虽然person.name === anotherPerson.name是真的,但为什么这是真的我的解释是不正确的。 See @CMS's answer for the correct explanation. 有关正确的解释,请参阅@ CMS的答案。

不复制name属性的原因是因为JavaScript中的对象文字总是引用,因此引用被复制(而不是它的内容)......所以它不是因为它在原型链中更深或者因为它是浅的复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM