JavaScript Object.create — inheriting nested properties

我的未来我决定 提交于 2019-11-27 12:41:35

问题


I've come across a peculiarity with Douglas Crockfords Object.create method which I'm hoping someone might be able to explain:

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.

If I then change the name values of the second object - 'anotherPerson' - it also changes the name value of the initial 'person' object.

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 -- e.g.

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

I'd be much appreciative if anyone's able to explain why this occurs!?


回答1:


That happens because anotherPerson.name is an object and it is stored upper in the prototype chain, on the original person object:

//...
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:

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

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



回答2:


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.

Edited

While it's true that person.name === anotherPerson.name, my explanation for why this is true is incorrect. See @CMS's answer for the correct explanation.




回答3:


The reason the name attribute isn't copied is because object literals in JavaScript are always references, therefore the reference is copied (not its content) ... so it is not because it is deeper in the prototype chain or because it's doing a shallow copy.



来源:https://stackoverflow.com/questions/3191103/javascript-object-create-inheriting-nested-properties

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!