2014-11-16 20 views
1

我是新來的Javascript和有一個關於使用繼承它這是我應該期待看到使用Javascript原型繼承的行爲嗎?

本文的問題是有幫助的,到目前爲止(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#More_flexible_constructors),但我在Chrome的調試器中觀察的行爲似乎並沒有被匹配什麼,我想期待看到。

我有兩種情況:

Base = function() { 
    this.value = 0; 
}; 

Base.prototype.constructor = Base; 

Derived = function() { 
    Base.call(this); 
}; 

Derived.prototype = new Base(); 
Derived.prototype.constructor = Derived; 

在調試器中我看到這一點:

enter image description here

enter image description here

跨過任務後,我看到這個

enter image description here

實例中的值已更改,但原型中的值尚未更改。這是預期的嗎?

第二種方法我不太明白的是這(在這裏再次引用 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model#More_flexible_constructors(見節「的財產繼承權再訪」)

Base = function() { 
}; 

Base.prototype.constructor = Base; 
Base.prototype.value = 0; 

// Derived as before... 

enter image description here

和之後的底部剪斷代碼分配

enter image description here

值已被添加爲新屬性。這不應該改變原型的價值嗎?或者,我是否明確需要通過原型來訪問價值 - 例如derived.value.prototype.value = 5

任何有關這方面的信息將不勝感激!

謝謝!

UPDATE:

謝謝大家誰回答,原來它是與在適當的時候我不使用的Object.create做。我在我的代碼更新到這一點:

enter image description here

,並在調試器中我得到了我的預期:

enter image description here

這看起來沒錯! :)

enter image description here

謝謝@sixfingeredman和@Bergi對你有所幫助!

+0

是的,這是預期的。 – Bergi

+0

最好不要創建Parent的實例來設置Child的原型。反而使用Object.create繼承和混合插件在這裏詳細解釋:http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR

回答

2

首先,雖然不是話題,刪除此行:

Base.prototype.constructor = Base; 

它沒有做任何有用的事情。

現在你的問題,是的,行爲是預期的。想象一下,如果它更新了.prototype。由於所有實例之間共享.prototype,因此所有實例都會看到更新。這肯定不會是你想要的。

當你這樣做:

var derived = new Derived(); 

您創建了一個新的對象,從Derived.prototype繼承。

當你這樣做:

derived.value = 1; 

你直接分配一個值給新的對象。

所以在分配之前,繼承鏈是這樣的:

derived   Derived.prototype  Base.prototype  Object.prototype 
+-----------+   +-----------+   +-----------+   +-----------+ 
|   |   |   |   |   |   |   | 
|   |---------| value:0 |---------|   |---------|   | 
|   |   |   |   |   |   |   | 
+-----------+   +-----------+   +-----------+   +-----------+ 

而在轉讓之後,它看起來像這樣:

derived   Derived.prototype  Base.prototype  Object.prototype 
+-----------+   +-----------+   +-----------+   +-----------+ 
|   |   |   |   |   |   |   | 
| value:1 |---------| value:0 |---------|   |---------|   | 
|   |   |   |   |   |   |   | 
+-----------+   +-----------+   +-----------+   +-----------+ 

所以在分配之前,如果你擡頭value在您的derived對象上,它不會被發現,所以它會跳轉到Derived.prototype,它會在那裏找到它。

但是在分配之後,value會直接在derived對象上找到。


並與你的第二個辦法,原型鏈將開始尋找這樣的替代:上derived查找value當這樣

derived   Derived.prototype  Base.prototype  Object.prototype 
+-----------+   +-----------+   +-----------+   +-----------+ 
|   |   |   |   |   |   |   | 
|   |---------|   |---------| value:0 |---------|   | 
|   |   |   |   |   |   |   | 
+-----------+   +-----------+   +-----------+   +-----------+ 

,它會從derived遍歷Derived.prototypeBase.prototype前找到value屬性。


所以我們說,你從Derived構造函數創建一批對象。上面的草圖將會更改,以便您創建的每個對象都指向Derived.prototype

derived_1 
+-----------+   
|   | 
|   | 
|   | 
+-----------+ 
      \______ 
        \ 
        \ 
    derived_2   Derived.prototype  Base.prototype  Object.prototype 
+-----------+   +-----------+   +-----------+   +-----------+ 
|   |   |   |   |   |   |   | 
|   |---------|   |---------| value:0 |---------|   | 
|   |   |   |   |   |   |   | 
+-----------+   +-----------+   +-----------+   +-----------+ 
        /
       ______/ 
    derived_3 /
+-----------+   
|   | 
|   | 
|   | 
+-----------+   

現在你可以看到爲什麼你不想更新原型。

如果我們這樣做derived_1.value = 42,如果它更新了Derived.prototype對象,那麼當你去從derived_2derived_3查找value,你會得到你分配給derived_1值。

+0

嘿!非常感謝你的回覆。我認爲我現在對現實中正在發生的事情有了更好的理解,但是我不明白我將如何「正確」使用繼承。在這兩種情況下,儘管做了預期的事情,但他們並沒有按照我的實際需要去做。在第一種情況下,我將如何修改原型中的一個,而不是創建新的值屬性? – Tom

+0

@Tom:你可以像現在一樣修改原型...通過執行Derived.prototype.foo =「bar」;'。請記住,除非每個對象都有自己的'foo'屬性,否則它們都會看到相同的「bar」值。唯一一次你想更新'.prototype'就是在所有實例之間共享數據。最常見的例子是爲所有對象提供方法。 –

+0

另外,如果我理解正確,你會使用原型來存儲變量以類似的方式來使一個類的成員在C#或C++中靜態? – Tom

2

價值已被添加爲一個新的屬性。這不應該改變原型的價值嗎?

不,此行爲是預期的。屬性僅在「獲取」時繼承,而不是在設置上。一旦您將值分配給對象的屬性,該對象上的屬性就會更改(或創建)。

1:除了有一個accessor property (setter function) on the prototype

或者我明確需要通過原型即將接入的價值 - 例如, derived.value.prototype.value = 5

要更改原型上的值,您需要將其賦值給原型,是的。在你的情況,這將是

Derived.prototype.value = 5; 

Object.getPrototypeOf(derived).value = 5; 

順便說一句,請注意(這是由每個實例在Base構造函數創建)的屬性應該根本不存在的Derived.prototype - 見What is the reason to use the 'new' keyword at Derived.prototype = new Base 。而不是Derived.prototype = new Base;你應該使用

Derived.prototype = Object.create(Base.prototype); 
+0

謝謝你提供了一個非常有用的答案,我將使用Object.create(..)重複我的測試用例,看看是否會產生我想要的行爲。 – Tom

+0

關於使用Object.create(..)的提示是關於金錢的,我已經更新了我的問題並解決了我的問題,謝謝! – Tom