用戶JonathanLonowski已經回答了您關於如何避免在設置inheritanc時調用構造的問題。但我也讀過你的問題是關於inhertance如何在JavaScript中工作的一般問題。所以這裏是我試圖解釋這個話題:
當談到繼承,你基本上想要做的是增強原型鏈。
那麼,它的原型鏈是什麼?
當您請求一個對象的屬性,即obj.prop
時,JavaScript首先檢查對象obj
是否具有這樣的屬性。如果不是,它會檢查該對象的原型是否具有這樣的屬性。如果不是,它會檢查原型的原型是否具有這樣的屬性,等等。
當你寫obj = new B()
創建一個構造函數一個新的對象,然後原型鏈如下所示:
obj -> B.prototype -> Object -> null
繼承如何與原型鏈
如果你希望你的B
對象從類型A
的對象繼承,你想你原型鏈看起來像這樣:
obj -> B.prototype -> A.prototype -> Object -> null
爲了達到這個目的,您需要在B.prototype
之後「打破」原型鏈,然後插入A
的完整原型鏈。換句話說,你想設置B.prototype
指向A.prototype
。
你可以做到這一點,因爲你以前那樣:
B.prototype = new A();
現在爲什麼做這項工作?通過new A()
創建的對象具有以下原型鏈:
objA -> B.prototype -> Object -> null
如果覆蓋B.prototype
與該對象,B
類型的對象的原型鏈是這樣的:
objB -> objA -> A.prototype -> Object -> null
正如你看到的, 有用。通過簡單地覆蓋B.prototype
,您只會失去一些屬性,如constructor
屬性。因此,如果您嘗試獲取B
類型的constructor
與objB.constructor
的對象,它首先在對象本身中查找並找不到它,然後查找objA
並且找不到它,然後查找A.prototype
並查找A
,這是錯誤的。雖然你不需要constructor
財產往往也算是很好的做法,覆蓋B.prototype
之後再進行設置:
B.prototype = new A();
B.prototype.constructor = B;
現在,你的方式只是一種實現原型鏈的鏈接。喬納森·洛諾夫斯基的解決方案是另一個,也是更好的解決方案,因爲它不稱爲函數A
。它創建具有相同的原型鏈一個空對象作爲A
類型的對象:
(empty object) -> A.prototype -> Object -> null
另一種解決方案將是不越權B.prototype
但修改它以簡單地指向A.prototype
代替Object
。並非所有的瀏覽器都支持這一點,但在一些你可以通過設置__proto__
屬性實現這一點:
B.prototype.__proto__ = A.prototype;
這將導致以下原型鏈:
obj -> B.prototype -> A.prototype -> Object -> null
請注意,我simplyfied在這裏在那裏,但我認爲這應該讓你知道它是如何工作的。要了解的基本原理是原型。從技術上講,現在只有一個真實的原型屬性,即每個對象都具有屬性[[prototype]]
。您無法直接通過JavaScript訪問它,但您有.prototype
和.__proto__
可以在特定條件下對其進行設置和操作。
在這個答案有另一種解決方案來設置繼承而不調用不使用Object.create的構造函數:http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR
@HMR我認爲我在寫這篇文章之前偶然發現了這個問題,但你說得對,它和凱文斯的回答很相似,我猜測並且會起作用。謝謝你的幫助! – Josh