摘要:前言作為中最重要的內容之一,繼承問題一直是我們關注的重點。如果一個類別繼承自另一個類別,就把這個稱為的子類,而把稱為的父類別也可以稱是的超類。
前言
作為 JavaScript 中最重要的內容之一,繼承問題一直是我們關注的重點。那么你是否清晰地知道它的原理以及各種實現方式呢
閱讀這篇文章,你將知道:
什么是繼承
實現繼承有哪幾種方式
它們各有什么特點
這里默認你已經清楚的知道構造函數、實例和原型對象之間的關系,如果并不是那么清晰,那么推薦你先閱讀這篇文章 -- JavaScript 中的原型與原型鏈
如果文章中有出現紕漏、錯誤之處,還請看到的小伙伴多多指教,先行謝過
以下↓
概念繼承(inheritance)是面向對象軟件技術當中的一個概念。如果一個類別 B 繼承自 另一個類別 A ,就把這個 B 稱為 A的子類 ,而把 A 稱為 B的父類別 也可以稱 A是B的超類 。繼承可以使得子類具有父類別的各種屬性和方法,而不需要再次編寫相同的代碼 ...更多)
通過這些概念和圖示我們不難知道繼承可以在我們的開發中帶來的便捷,那么在 JavaScript 中如何去實現繼承呢?
繼承實現方式 原型鏈繼承利用原型讓一個引用類型繼承另一個引用類型的屬性和方法
function SuperType() { this.name = "tt"; } SuperType.prototype.sayName = function() { return this.name } function SubType() { this.name = "oo"; } SubType.prototype = new SuperType() var instance = new SubType() instance.sayName() // oo instance instanceof SubType // true instance instanceof SuperType // ture
以上的試驗中,我們創建了兩個構造函數 SuperType 和 SubType ,并且讓 SubType 的原型指向 SuperType ,SubType 也就繼承了 SuperType 原型對象中的方法。所以在創建 instance 實例的時候,實例本身也就具有了 SuperType 中的方法,并且都處在它們的原型鏈中
SubType.prototype.constructor == SubType // false SubType.prototype.constructor == SuperType // true
需要注意的是:這個時候 SubType.prototype.constructor 是指向 SuperType 的,相當于重寫了 SubType 的原型對象。
用一張圖表示:
SubType.prototype 相當于 SuperType 的實例存在的,所以 SubType.prototype.constructor 就指向 SuperType
原型繼承的特點優點:
簡單、易于實現
父類新增原型方法/原型屬性,子類都能訪問到
非常純粹的繼承關系,實例是子類的實例,也是父類的實例
缺點:
無法實現多繼承
想要為子類 SubType 添加原型方法,就必須在 new SuperType 之后添加(會覆蓋)
來自原型對象的所有屬性被所有實例共享(引用類型的值修改會反映在所有實例上面)
創建子類實例時,無法向父類構造函數傳參
借用構造函數在子類構造函數的內部調用超類型構造函數,通過 apply 和 call 實現
function SuperType(name) { this.name = name; this.colors = ["red", "orange", "black"]; } function SubType() { SuperType.call(this, "tt"); } var instance = new SubType() var instance1 = new SubType() instance.colors // ["red", "orange", "black"] instance.name // tt instance.colors.push("green"); instance.colors // ["red", "orange", "black", "green"] instance1.colors // ["red", "orange", "black"]借用構造函數的特點
優點:
解決了原型鏈繼承不能傳參的問題
子類實例共享父類引用屬性的問題
可以實現多繼承(call可以指定不同的超類)
缺點:
實例并不是父類的實例,只是子類的實例
只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
無法實現函數復用
組合繼承偽經典繼承(最常用的繼承模式):將原型鏈和借用構造函數的技術組合到一起。使用原型鏈實現對原型屬性和方法的繼承,通過構造函數來實現對實例屬性的繼承
function SuperType(name) { this.name = name; this.colors = ["red", "orange", "black"]; } SuperType.prototype.sayName = function() { return this.name } function SubType() { SuperType.call(this, "tt"); this.name = "oo"; } // 這里的 SubType.prototype.constructor 還是指向 SuperType SubType.prototype = new SuperType(); var instance = new SubType(); var instance1 = new SubType(); instance.name // oo instance.sayName() // oo instance.colors.push("green"); instance.colors // ["red", "orange", "black", "green"] instance1.colors // ["red", "orange", "black"]組合繼承的特點
優點:
可以繼承實例屬性/方法,也可以繼承原型屬性/方法
不存在引用屬性共享問題
可傳參
函數可復用
缺點:
調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)
原型式繼承借助原型鏈可以基于已有的對象創建新對象,同時還不必因此創建自定義類型
function obj(o) { function F(){} F.prototype = o; return new F(); } var person = { name: "tt", age: 18, colors: ["red", "green"] } var instance = obj(person); var instance1 = obj(person); instance.colors.push("black"); instance.name // tt instance.colors // ["red", "green", "black"] instance1.colors // ["red", "green", "black"]
創建一個臨時的構造函數,然后將傳入的對象當做這個構造函數的原型對象,最后返回這個臨時構造函數的新實例。實際上,就是對傳入的對象進行了一次淺復制
ES5 通過新增 Object.create() 規范化了原型式繼承
更多 Object.create()語法請點擊 這里
原型式繼承特點優點:
支持多繼承(傳入的對象不同)
不需要興師動眾的創建很多構造函數
缺點: 和原型鏈繼承基本一致,效率較低,內存占用高(因為要拷貝父類的屬性)
寄生式繼承創建一個僅用于封裝繼承過程的函數,在函數內部對這個對象進行改變,最后返回這個對象
function createAnother(obj) { var clone = Object(obj); clone.sayHi = function() { alert("Hi"); } return clone } var person = { name: "tt", age: 18, friends: ["oo", "aa", "cc"], sayName() { return this.name } } var instance = createAnother(person) var instance1 = createAnother(person) instance.friends.push("yy") instance.name // "tt" instance.sayHi() // Hi instance.friends // ["oo", "aa", "cc", "yy"] instance1.friends // ["oo", "aa", "cc", "yy"]寄生式繼承的特點
優點:
支持多繼承
缺點:
實例并不是父類的實例,只是子類的實例
不能實現復用(與構造函數相似)
實例之間會互相影響
寄生組合繼承借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。通過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點
function inherit(subType, superType) { var obj = Object(superType.prototype); // 創建對象 obj.constructor = subType; // 指定constructor subType.prototype = obj; // 指定對象 } function SuperType(name) { this.name = name; this.colors = ["red", "orange", "black"]; } SuperType.prototype.sayName = function() { return this.name } function SubType() { SuperType.call(this, "tt"); this.name = "oo"; } inherit(SubType, SuperType) var instance = new SubType() instance.name // oo instance.sayName // oo instance instanceof SubType // true instance instanceof SuperType // true SubType.prototype.constructor == SubType // true寄生組合繼承的特點
堪稱完美,只是實現稍微復雜一點
后記作為 JavaScript 最重要的概念之一,對于繼承實現的方式方法以及它們之間的差異我們還是很有必要了解的。
在實現繼承的時候,拷貝 也是一種很有效的方式,由于 JavaScript 簡單數據類型與引用類型的存在,衍生出了 淺拷貝 與 深拷貝 的概念,那么它們又是什么,怎么去實現呢
且聽下回分解,哈哈
周末愉快
最后,推薦一波前端學習歷程,不定期分享一些前端問題和有意思的東西歡迎 star 關注 傳送門
參考文檔JavaScript 高級程序設計
JavaScript實現繼承的幾種方式
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103697.html
摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構造函數繼承,在中是一種關鍵的實現的繼承方法,相信你已經很好的掌握了。 你應該知道,JavaScript是一門基于原型鏈的語言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關。甚至可以說,所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構造函數,原型屬性與實例對象 要搞清楚如何在JavaScript中實現繼承,...
摘要:的繼承方式屬于原型式繼承,非常靈活。當使用關鍵字執行類的構造函數時,系統首先創建一個新對象,這個對象會繼承自構造函數的原型對象新對象的原型就是構造函數的屬性。也就是說,構造函數用來對生成的新對象進行一些處理,使這個新對象具有某些特定的屬性。 繼承這個東西在Javascript中尤其復雜,我掌握得也不好,找工作面試的時候在這個問題上栽過跟頭。Javascript的繼承方式屬于原型式繼承,...
摘要:和構造函數前面提到,是個內置隱藏屬性,雖然在可以通過訪問,但是其設計本意是不可被讀取和修改的,那么我們如何利用原型鏈來建立繼承關系提供了關鍵字。到這兒,思路就清晰了,怎么讓對象和對象的相連實現繼承只需把的構造函數的連接到就行了。 什么是繼承? 大多數人使用繼承不外乎是為了獲得這兩點好處,代碼的抽象和代碼的復用。代碼的抽象就不用說了,交通工具和汽車這類的例子數不勝數,在傳統的OO語言中(...
摘要:我們有了構造函數之后,第二步開始使用它構造一個函數。來個例子這種方式很簡單也很直接,你在構造函數的原型上定義方法,那么用該構造函數實例化出來的對象都可以通過原型繼承鏈訪問到定義在構造函數原型上的方法。 來源: 個人博客 白話解釋 Javascript 原型繼承(prototype inheritance) 什么是繼承? 學過面向對象的同學們是否還記得,老師整天掛在嘴邊的面向對象三大特...
摘要:使用構造函數的原型繼承相比使用原型的原型繼承更加復雜,我們先看看使用原型的原型繼承上面的代碼很容易理解。相反的,使用構造函數的原型繼承像下面這樣當然,構造函數的方式更簡單。 五天之前我寫了一個關于ES6標準中Class的文章。在里面我介紹了如何用現有的Javascript來模擬類并且介紹了ES6中類的用法,其實它只是一個語法糖。感謝Om Shakar以及Javascript Room中...
閱讀 797·2021-09-06 15:02
閱讀 2439·2019-08-30 15:43
閱讀 2163·2019-08-30 11:26
閱讀 2372·2019-08-26 12:12
閱讀 3537·2019-08-23 18:24
閱讀 3253·2019-08-23 18:16
閱讀 695·2019-08-23 17:02
閱讀 2241·2019-08-23 15:34