JavaScript Object.create——继承嵌套属性

发布于 2024-09-08 07:03:32 字数 1776 浏览 9 评论 0原文

我遇到了 Douglas Crockfords Object.create 方法的一个特点,我希望有人能够解释一下:

如果我创建一个对象 - 比如说“人” - 使用对象文字表示法,然后使用 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”关键字的经典继承风格时。

如果有人能够解释为什么会发生这种情况,我将不胜感激!

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!?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

街角卖回忆 2024-09-15 07:03:32

发生这种情况是因为 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'
};

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'
};
已下线请稍等 2024-09-15 07:03:32

问题是 Object.create 只进行浅复制,而不是深复制,因此 person.name 和 anotherPerson.name 都指向同一个 Object 实例。

已编辑

虽然person.name === anotherPerson.name确实如此,但我对为什么这是正确的解释是不正确的。正确的解释请参阅@CMS 的答案。

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.

我不吻晚风 2024-09-15 07:03:32

name 属性不被复制的原因是因为 JavaScript 中的对象字面量始终是引用,因此引用被复制(而不是其内容)......所以这不是因为它在原型中更深层次链或者因为它正在执行浅复制。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文