JavaScript的繼承方式
繼承是面向對象編程中又一非常重要的概念,JavaScript支持實現繼承,不支持接口繼承,實現繼承主要依靠原型鏈來實現的!下面就來介紹下javascript存在的繼承方式!
原型鏈:
原型鏈繼承基本思想就是讓一個原型對象指向另一個類型的實例。
代碼定義了兩個類型SuperType和SubType,每個類型分別有一個屬性和一個方法,SubType繼承了SuperType,而繼承是通過創建SuperType的實例,並將該實例賦給SubType.prototype實現的
實現的本質是重寫原型對象,代之以一個新類型的實例,那麼存在SuperType的實例中的所有屬性和方法,現在也存在於SubType.prototype中了
我們知道,在創建一個實例的時候,實例對象中會有一個內部指針指向創建它的原型,進行關聯起來,在這裡代碼 SubType.prototype = new SuperType() ,也會在SubType.prototype創建一個內部指針,將SubType.prototype與SuperType關聯起來
所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,繼而在instance在調用getSuperValue()方法的時候,會順著這條鏈一直往上找
添加方法:
在給SubType原型添加方法的時候,如果,父類上也有同樣的名字,SubType將會覆蓋這個方法,達到重新的目的。 但是這個方法依然存在於父類中
記住不能以字面量的形式添加,因為,上面說過通過實例繼承本質上就是重寫,再使用字面量形式,又是一次重寫了,但這次重寫沒有跟父類有任何關聯,所以就會導致原型鏈截斷
問題:
單純的使用原型鏈繼承,主要問題來自包含引用類型值的原型。
在SuperType構造函數定義了一個colors屬性,當SubType通過原型鏈繼承後,這個屬性就會出現SubType.prototype中,就跟專門創建了SubType.prototype.colors一樣,所以會導致SubType的所有實例都會共享這個屬性,所以instance1修改colors這個引用類型值,也會反映到instance2中
借用構造函數:
此方法為了解決原型中包含引用類型值所帶來的問題
這種方法的思想就是在子類構造函數的內部調用父類構造函數,可以藉助apply()和call()方法來改變對象的執行上下文
在新建SubType實例是調用了SuperType構造函數,這樣以來,就會在新SubType對象上執行SuperType函數中定義的所有對象初始化代碼
結果,SubType的每個實例就會具有自己的colors屬性的副本了
傳遞參數:
藉助構造函數還有一個優勢就是可以傳遞參數
組合繼承(原型鏈+構造函數)
組合繼承是將原型鏈繼承和構造函數結合起來,從而發揮二者之長的一種模式
思路就是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承
這樣,既通過在原型上定義方法實現了函數複用,又能夠保證每個實例都有它自己的屬性
這種模式避免了原型鏈和構造函數繼承的缺陷,融合了他們的優點,是最常用的一種繼承模式
原型式繼承:
藉助原型可以基於已有的對象創建新對象,同時還不必因此創建自定義類型
在object函數內部,先創建一個臨時性的構造函數,然後將傳入的對象作為這個構造函數的原型,最後返回這個臨時類型的一個新實例
本質上來說,object對傳入其中的對象執行了一次淺複製
這種模式要去你必須有一個對象作為另一個對象的基礎
在這個例子中,person作為另一個對象的基礎,把person傳入object中,該函數就會返回一個新的對象
這個新對象將person作為原型,所以它的原型中就包含一個基本類型和一個引用類型
所以意味著如果還有另外一個對象關聯了person,anotherPerson修改數組friends的時候,也會體現在這個對象中