2008-12-31 103 views
7

我看到了很多這樣的代碼:公約原型繼承在JavaScript

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 

但是,如果你這樣做:

s = new Sub(); 
print(s.constructor == Sub); 

這是錯誤的。這似乎讓我感到困惑,因爲s的構造函數實際上是Sub。這是常規/更好的做法嗎?

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 
Sub.prototype.constructor = Sub; 

還是沒有關係?

+0

我剛剛通過一個HTML頁面作爲警報(s.constructor == Sub)運行比較,並且它返回了真實的結果 – 2008-12-31 18:13:38

+0

許多框架調整`constructor`屬性爲正確地指向子類的構造函數,我的帖子在上面顯示的代碼中處理了這個問題和其他問題。http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html – 2012-05-15 00:49:13

回答

9

「構造」沒有做什麼,它看起來像它。除了非標準性之外,這是避免使用它的一個很好的理由 - 堅持使用instanceof和prototype。

從技術上講:'構造函數'不是's'實例的屬性,它是'Sub'原型對象的屬性。當你在Mozilla中創建'Sub'函數時,你會得到一個新創建的默認Sub.prototype對象,它具有一個'構造函數'作爲禮節指向Sub函數。

然而,你然後用一個新的Base()替換原型。鏈接回Sub的原始默認原型會丟失;相反,Sub.prototype是沒有任何重寫'構造函數'屬性的Base實例。所以:

new Sub().constructor=== 
Sub.prototype.constructor=== 
new Base().constructor=== 
Base.prototype.constructor=== 
Base 

...一直到最原始的你沒有改變的基本對象。

這是常規/更好嗎?

當處理JavaScript對象/類時,沒有一個約定;每個圖書館的元類系統的行爲略有不同。我還沒有看到一個手動爲每個派生類寫入「構造函數」,但如果你真的想要真正的構造函數,它似乎是一個很好的解決方案;它也將使代碼與不給你'構造函數'的瀏覽器/引擎兼容。

雖然我會考慮給它一個不同的名稱,以避免與現有和不同行爲的「構造函數」屬性混淆。

3

如果你想測試對象是否爲子使用instanceof運營商完全是一個實例: - 如果你想知道一個對象是否爲子的一個實例

print(s instanceof Sub); 

或子的一個實例子使用isPrototypeOf方法-class: -

print(Sub.prototype.isPrototypeOf(s)); 
1

呀,

Sub.prototype.constructor = Sub; 

讓我們使用的instanceof但有一個更好的解決方案。看這裏:,TDD JS Inheritance on GitHub,並找到寄生組合繼承模式。該代碼是TDD'd,因此您應該能夠非常快速地進行搜索,然後只需更改名稱即可開始。這基本上是YAHOO.lang.extend使用的內容(來源:雅虎員工和作者Nicholas Zakas的專業JavaScript for Web開發人員,第2期ED,第181頁)。順便說一下好書(不以任何方式附屬於!)

爲什麼?因爲你正在使用的經典模式具有靜態參考變量(如果在基礎對象中創建var arr = [1,2],所有實例都將具有讀/寫並且將「共享」arr'的狀態!使用構造函數竊取你可以解決這個問題。看看我的例子。