javascript
JavaScript面向对象——深入理解寄生组合继承
JavaScript面向?qū)ο蟆钊肜斫饧纳M合繼承
之前談到過組合繼承,會有初始化兩次實例方法/屬性的缺點,接下來我們談談為了避免這種缺點的寄生組合繼承
寄生組合繼承:
思路:組合繼承中,構造函數(shù)繼承時已經(jīng)繼承了父類中除了通過prototype定義的公有屬性和方法,也就是說我們需要在原型繼承時繼承父類的原型而不執(zhí)行父類的構造函數(shù),這樣就避免了組合繼承中的缺點。
思路有了,如何實現(xiàn)?
讓我們從名字入手,寄生組合繼承,組合繼承我們談過了,寄生是什么東西?《JavaScript設計模式》這本書中說得比較模糊,因此本人閱讀了另一本更專于介紹JavaScript面向?qū)ο蟮臅禞avaScript面向?qū)ο缶幊讨改系?版》,感覺這本書挺好的,推薦一下:
插播:寄生式繼承
思路:在創(chuàng)建對象的函數(shù)中直接吸收其他對象的功能,然后對其進行擴展并返回。
步驟:
1:設計inheritObject()函數(shù),名稱自定,只是舉例
設計理念:函數(shù)可以用來接收新對象,并返回一個以該對象為原型的新對象
function inheritObject(o) {function F() {}F.prototype = oreturn new F()}2:使用對象標識法定義一個普通對象
var twoD = {name: '2D shape',dimensions: 2}3:使用inheritObject()函數(shù)對twoD進行操作
function triangle(s, h) {var that = inheritObject(twoD)that.name = 'Triangle'that.side = sthat.height = hthat.getArea = function () {return that.side * that.height / 2}return that}說明:triangle()中使用inheritObject()將twoD克隆進that對象,并對that對象進行了擴展然后返回。(寄生式繼承的思路:在創(chuàng)建對象的函數(shù)中直接吸收其他對象的功能,然后對其進行擴展并返回,在此函數(shù)中實現(xiàn)。)注意:這個that只是個名稱,可以隨便換另一個,沒有跟保留字this那樣的含義。
這種繼承方式下創(chuàng)建對象,使不使用new都可以,因為返回的就是一個對象。
// testvar t = triangle(5, 10)console.log(t.dimensions)var t2 = new triangle(5, 5)console.log(t2.getArea())結果:
插播了一下寄生式繼承的實現(xiàn),現(xiàn)在我們重新談談寄生組合繼承....
寄生組合繼承思路回憶:組合繼承中,構造函數(shù)繼承時已經(jīng)繼承了父類中除了通過prototype定義的公有屬性和方法,也就是說我們需要在原型繼承時繼承父類的原型而不執(zhí)行父類的構造函數(shù),這樣就避免了組合繼承中的缺點。
實現(xiàn)方案:寄生式繼承+組合繼承,代碼中使用到上邊提到的inheritObject()函數(shù)。
function inheritPrototype(subClass, superClass) {// 復制一份父類的原型副本保存在變量中var p = inheritObject(superClass.prototype)// 修正因為重寫子類原型導致子類的constructor屬性被修改p.constructor = subClass// 設置子類的原型subClass.prototype = p}解釋:因為我們只需要父類原型對象的一個副本,這個副本通過原型繼承便可以得到,但是直接賦值給子類是會有問題的,因為對父類對象復制得到的對象p中的constructor指向的不是SubClass子類對象,因此寄生式繼承中要修復復制對象p的constructor屬性指向不正確的問題,最后得到的復制對象p賦值給子類的原型,這樣子類的原型就繼承了父類的原型并且沒有執(zhí)行父類的構造函數(shù)。
測試例子:
// 定義父類function SuperClass(name) {this.name = namethis.colors = ['red', 'orange', 'yellow']}// 定義父類原型方法SuperClass.prototype.getName = function () {console.log(this.name)}// 定義子類function SubClass(name, time) {// 構造函數(shù)式繼承SuperClass.call(this, name)// 子類新增屬性this.time = time}// 寄生式繼承父類原型inheritPrototype(SubClass, SuperClass)// 子類新增原型方法, 不可以寫在寄生式繼承父類原型函數(shù)前SubClass.prototype.getTime = function () {console.log(this.time)}// 創(chuàng)建測試實例var instance1 = new SubClass('JavaScript', '2018-03-18')var instance2 = new SubClass('NodeJs', '2018-03-19')instance1.colors.push('green')console.log(instance1.colors)console.log(instance2.colors)instance1.getName()instance1.getTime()instance2.getName()instance2.getTime()解釋:多數(shù)跟組合繼承的一樣,除了這點:子類原型被賦予了父類原型的一個引用,這是個對象,也就是引用類型,所以給子類添加原型方法時只可以通過prototype.語法,不可以使用subClass.prototype={xxx:function(){}}這種對象賦值式的寫法,否則父類的原型會被覆蓋。
運行結果終于來了.....
最后來一張寄生組合繼承的原理圖,理解了的伙伴請忽略,周日愉快,晚安~(2018.03.18)
總結
以上是生活随笔為你收集整理的JavaScript面向对象——深入理解寄生组合继承的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript面向对象——理解构造
- 下一篇: iOS 12.4漏洞可远程破解iPhon