2010-07-07 65 views
11

我遇到道格拉斯康樂福的Object.create方法,我希望有人也許能夠解釋一個特點:如果我創建一個對象的JavaScript的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'關鍵字的古典風格的繼承時,似乎不會出現這種嵌套問題。

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

+2

可能的重複:[克羅克福德的原型繼承 - 嵌套對象的問題](http://stackoverflow.com/q/10131052/1048572) – Bergi 2014-06-08 12:59:55

回答

18

這是因爲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' 
}; 
+0

哇,堆棧溢出比論壇更像是即時通訊工具!感謝你的迴應,這是有道理的 - 所以第二個對象只有引用的名稱對象,它並沒有被實際複製。然後我假設原來的'person'對象會評估hasOwnProperty('name')=== true,因爲它是'anotherPerson'的原型。 – Richard 2010-07-07 00:41:34

+1

我是Javascript新手,但我猜你也可以使用:'anotherPerson.name = Object.create(person.name);'如果需要,可以使新的嵌套對象從舊的嵌套對象繼承。 – 2013-09-25 09:51:15

+0

這已經是一箇舊的答案,但我仍然有這個問題。我知道B.name不存在,它會查找A.name,從而替代A.name的值。但是,爲什麼在第二個例子中,「B.firstName/lastName」存在於B對象中,並且沒有覆蓋A的屬性? – user2734550 2016-05-06 23:11:25

2

問題是Object.create只做淺拷貝而不是深拷貝,所以person.name和anotherPerson.name都指向同一個Object實例。

編輯

雖然這是事實,person.name === anotherPerson.name,我爲什麼這是真實的解釋是不正確。請參閱@ CMS的正確解釋。

+2

真的,都指向同一個實例,但實際上,'Object.create' doesn根本不會生成對象副本,它只是創建一個新的*空對象*,它從原始對象中繼承*。 – CMS 2010-07-07 00:39:02

+0

感謝您的回覆。你知道淺拷貝和深拷貝的任何像樣的文章嗎? – Richard 2010-07-07 00:43:35

+0

@CMS,其實'F.prototype = o;'是一個副本。它將對象及其屬性複製到新對象的原型中......並且不復制'name'屬性的原因是因爲JavaScript中的對象文字始終是引用,因此引用被複制(而不是其內容)。 ..所以這不是因爲它在原型鏈中更深或者因爲它正在做一個淺拷貝。 – 2010-07-07 00:43:37

1

name的屬性不被複制的原因是因爲在JavaScript對象文字是總是引用,所以引用被複制(而不是它內容)......所以這不是因爲它在原型鏈中更深,或者因爲它在做一個淺拷貝。

+0

這對我來說非常有意義。它仍然是正確的嗎? – ryansstack 2015-04-01 20:53:23