摘要:構造函數繼承遍歷通過對象冒充實現繼承,實際上是在構造函數中,通過獲取父類中的所有屬性,并保存到自身對象中,這樣則可以調用父類的屬性和方法了。
JS從誕生之初本就不是面向對象的語言。
如何在JS中實現繼承,總結而言會有四種寫法。
構造函數繼承function Animal(name) { this.name = name this.sayName = function() { console.log(this.name) } } function Dog(name, hobby) { // 遍歷 let ani = new Animal(name) for(let p in ani) { if (ani.hasOwnProperty(p)) { this[p] = ani[p] } } this.hobby = hobby } let dog1 = new Dog("xiaohei", "bone") let dog2 = new Dog("fofo", "bone and fish") console.log(dog1.sayName()) // xiaohei console.log(dog2.sayName()) // fofo
通過對象冒充實現繼承,實際上是在構造函數中,通過獲取父類中的所有屬性,并保存到自身對象中,這樣則可以調用父類的屬性和方法了。這里forin的方式遍歷父類屬性,因為forin會遍歷公開的屬性和方法,所以通過hasOwnProperty控制寫入當前對象的范圍。否則則會將所有屬性全部變為私有屬性。
這樣做有一個缺點就是,無法訪問父類中的公開方法和屬性(prototype中的方法)
Animal.prototype.sayHobby = function() { console.log(this.hobby) } dog1.sayHobby() // VM2748:1 Uncaught TypeError: dog1.sayHobby is not a function at:1:6
代碼優化
在子類中,既然是需要獲取父類的私有屬性,則可以使用call和apply,當調用父類的方法的時候,改變當前上下文為子類對象,則子類對象就可以獲取到了父類的所有私有屬性。
function Animal(name) { this.name = name this.sayName = function() { console.log(this.name) } } function Dog(name, hobby) { // 更改構造函數的上下文 Animal.call(this, name) this.hobby = hobby } let dog1 = new Dog("xiaohei", "bone") let dog2 = new Dog("fofo", "bone and fish") console.log(dog1.sayName()) // xiaohei console.log(dog2.sayName()) // fofo類式繼承
function Animal(name) { this.name = name || "animal" this.types = ["cat", "dog"] this.sayTypes = function() { console.log(this.types.join("-")) } } Animal.prototype.sayName = function() { console.log(this.name) } function Dog(name) { this.name = name } Dog.prototype = new Animal("animal") let dog1 = new Dog("xiaohei") dog1.sayName() // xiaohei let dog2 = new Dog("feifei") dog2.sayName() // feifei
這種繼承方式是通過對子類的prototype.__proto__引用父類的prototype,從而可以讓子類訪問父類中的私有方法和公有方法。詳情可以查看關鍵字new的實現。
類式繼承會有兩方面的缺點
引用陷阱-子類對象可以隨意修改父類中的方法和變量,并影響其他子類對象
dog1.types.push("fish")
console.log(dog1.types) // ["cat", "dog", "fish"]
console.log(dog2.types) // ["cat", "dog", "fish"]
無法初始化構造不同的實例屬性
這個主要是由于類式繼承,是通過Dog.prototype = new Animal("animal")實現的,我們只會調用一次父類的構造函數。所以只能在子類中從寫父類的屬性,如上的name屬性,在子類中需要重寫一次。
組合繼承組合繼承,即結合以上兩種繼承方式的優點,拋棄兩者的缺點,而實現的一種組合方式
function Animal(name) { this.name = name this.types = ["dog", "cat"] } Animal.prototype.sayName = function() { console.log(this.name) } function Dog(name, hobby) { // 獲取私有方法并調用父類的構造函數,并傳遞構造函數的參數,實現初始化不同的構造函數 Animal.call(this, name) this.hobby = hobby } // 子類實例可以訪問父類prototype的方法和屬性 Dog.prototype = new Animal() Dog.prototype.constructor = Dog Dog.prototype.sayHobby = function() { console.log(this.hobby) } // test instance of dog1 let dog1 = new Dog("xiaohei", "bone") dog1.sayName() // xiaohei dog1.sayHobby() // bone dog1.types.push("ant") // types: ["dog", "cat", "ant"] // test instance of dog2 let dog2 = new Dog("feifei", "fish") dog2.sayName() // feifei dog2.sayHobby() // fish dog2.types // ["dog", "cat"]
組合模式,解決了使用構造函數繼承和類式繼承帶來的問題,算是一種比較理想的解決繼承方式,但是這里還有一些瑕疵,調用了兩次父類(Animal)的構造函數。
所以為了解決這個問題,進行了優化,產生了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101071.html
摘要:可以通過構造函數和原型的方式模擬實現類的功能。原型式繼承與類式繼承類式繼承是在子類型構造函數的內部調用超類型的構造函數。寄生式繼承這種繼承方式是把原型式工廠模式結合起來,目的是為了封裝創建的過程。 js繼承的概念 js里常用的如下兩種繼承方式: 原型鏈繼承(對象間的繼承) 類式繼承(構造函數間的繼承) 由于js不像java那樣是真正面向對象的語言,js是基于對象的,它沒有類的概念。...
摘要:首先為了模擬類創建對象的功能搞出了構造函數。也就是名字膚色膚色這里是繼承里的自有屬性生命值這里繼承的共有屬性的方法攻擊力兵種美國大兵攻擊防御死亡膚色 JS面向對象之五 【繼承】 我們已經準備了很多前置知識,包括 原型鏈,對象和對象之間的關系 this,對象和函數之間的關系 new, 用函數批量創建特定的對象的語法糖 JS面向對象的前世今生 我們說,面向對象是一種寫代碼的套路。因為如...
摘要:實現思路使用原型鏈實現對原型方法和方法的繼承,而通過借用構造函數來實現對實例屬性的繼承。繼承屬性繼承方法以上代碼,構造函數定義了兩個屬性和。 JS面向對象的程序設計之繼承的實現-組合繼承 前言:最近在細讀Javascript高級程序設計,對于我而言,中文版,書中很多地方翻譯的差強人意,所以用自己所理解的,嘗試解讀下。如有紕漏或錯誤,會非常感謝您的指出。文中絕大部分內容引用自《Java...
摘要:寄生式繼承的思路與寄生構造函數和工廠模式類似,即創建一個僅用于封裝繼承過程的函數,該函數在內部已某種方式來增強對象,最后再像真的是它做了所有工作一樣返回對象。 這篇本來應該是作為寫JS 面向對象的前奏,只是作為《javascript高級程序設計》繼承一章的筆記 原型鏈 code 實現 function SuperType() { this.colors = [red,blu...
摘要:首先捋清楚類和對象的關系類比如人類,指的是一個范圍對象比如某個人,指的是這個范圍中具體的對象中的作為構造函數時,就是一個類,通過操作符,可以返回一個對象。 JS中的類與類的繼承 我們知道,JS中沒有類或接口的概念,即不能直接定義抽象的類,也不能直接實現繼承。不過,為了編程的方便,我們可以在 JS 中模擬類和繼承的行為。首先捋清楚類和對象的關系: 類:比如人類,指的是一個范圍; ...
閱讀 2889·2021-11-17 09:33
閱讀 3662·2021-11-16 11:42
閱讀 3488·2021-10-26 09:50
閱讀 1318·2021-09-22 15:49
閱讀 3046·2021-08-10 09:44
閱讀 3670·2019-08-29 18:36
閱讀 3925·2019-08-29 16:43
閱讀 2208·2019-08-29 14:10