簡體   English   中英

JavaScript Object.create - 繼承嵌套屬性

[英]JavaScript Object.create — inheriting nested properties

我遇到過道格拉斯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'關鍵字的經典繼承風格時,似乎不會出現此嵌套問題。

如果有人能夠解釋為什么會發生這種情況,我會非常感激!?

發生這種情況是因為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中的對象文字總是引用,因此引用被復制(而不是它的內容)......所以它不是因為它在原型鏈中更深或者因為它是淺的復制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM