學習JavaScript設計模式——面向對象(三)

面向對象(三)

繼承

3. 原型式繼承——潔凈的繼承者

  • 借助原型prototype可以根據已有的對象創(chuàng)建一個新的對象
  • 同事不必創(chuàng)建新的自定義對象類型
// 原型是繼承
function inheritObject(o){
    // 聲明一個過度函數(shù)對象
    function F(){}
    // 過度原型對象的原型繼承父對象
    F.prototype = o;
    // 返回過度對象的一個實例,該實例的原型繼承了父對象
    return new F()
}
  • 這個是對象類式繼承的一個封裝
  • 其中的過渡對象就相當于類式繼承中的子類
  • 為了創(chuàng)建要返回的新的實例化對象,所以子類在原型式中所謂一個過渡對象出現(xiàn)

但是他們引用的父對象是一樣的,所以如果有對屬性修改還是會影響到父對象

 let book = {
  name: 'js book',
  alikeBook: ['css book', 'html book']
 }
 
 let newBook = inheritObject(book)
 newBook.name = 'ajax book'
 newBook.alikeBook.push('xml book')
 
 let otherBook = inheritObject(book)
 otherBook.name = 'flash book'
 otherBook.alikeBook.push('as book')

 console.log(newBook.name)        // ajax book
 console.log(newBook.alikeBook)   // ['css book', 'html book', 'xml book', 'as book']
 
 console.log(other.name)          // flash book
 console.log(other.alikeBook)     // ['css book', 'html book', 'xml book', 'as book']
 
 console.log(book.name)           // js book
 console.log(book.alikeBook)      // ['css book', 'html book', 'xml book', 'as book']
  
  • 跟類式繼承一樣,父類對象book中的值類型屬性被復制,引用類型的屬性被共用

4. 寄生式繼承——如虎添翼

// 寄生式繼承
// 聲明基對象
let book = {
    name: 'js book',
    alikeBook: ['css book', 'html book']
}

function createBook(obj){
    // 通過原型繼承方式創(chuàng)建新對象
    let o = new inheritObject(obj)
    // 拓展新對象
    o.getName = function() {
        console.log(name)
    }
    // 返回拓展新對象
    return o
}
  • 寄生式繼承是對原型式繼承的第二次封裝
  • 并且在第二次封裝過程中對繼承的對象進行了擴展
  • 這樣新創(chuàng)建的對象不僅僅有父類中的屬性和方法而且還添加新的屬性和方法
  • o.getName 那里,屬性名沒有聲明過,可能是作者忘了聲明還是什么,應該是對象o獨有的屬性

5. 寄生組合式繼承——終極繼承者 寄生模式繼承 和 構造函數(shù)式繼承

 /**
  * 寄生式繼承 繼承原型
  * 傳遞參數(shù) subClass 子類
  * 傳遞參數(shù) superClass 父類
  **/
  
  function inheritPrototype(subClass, superClass){
   // 復制一份父類的原型副本保存在變量中
   var p = inheritObject(superClass.prototype)
   // 修正因為重寫子類原型導致子類的constructor屬性被修改
   p.constructor = subClass
   // 設置子類的原型
   subClass.prototype = p
  }
  
  • 通過寄生式繼承重新繼承父類的原型,但是不需要父類的構造函數(shù)
  • 因為在構造函數(shù)繼承中我們已經調用了父類的構造函數(shù),我們繼承來的是父類原型的一個副本,通過原型繼承得來
  • 但是對父類原型對象復制得到的復制對象p 的constructor 指向的不是子類的subClass子類對象
  • 所以需要在寄生式繼承中對復制對象p修改,對p的constructor的指向修改
  • 最后將得到的復制對象p賦值給子類的原型
  • 這樣子類的原型就繼承了父類的原型并且沒有執(zhí)行父類的構造函數(shù)

P.S 確實有點繞,需要多仔細看看理解

測試代碼

 // 定義父類
 function SuperClass(name){
   this.name = name
   this.colors = ['red', 'blue', 'green']
 }
 // 定義父類原型方法
 SuperClass.prototype.getName = function() {
    console.log(this.name)
 }
 
 // 定義子類
 function SubClass(name, time) {
    // 構造函數(shù)式繼承
    SuperClass.call(this, name)
    // 子類新增屬性
    this.time = time
 }
 
 // 寄生式繼承父類原型
 inheritPrototype(subClass, superClass);
 // 子類新增原型方法
 subClass.prototype.getTime = function(){
    console.log(this.time)
 }
 
 // 創(chuàng)建兩個測試方法
 let instance1 = new SubClass('js book', 2014)
 let instance2 = new SubClass('css book', 2013)
 
 instance1.colors.push('black')
 console.log(instance1.colors) // 
 console.log(instance2.colors) //
 instance2.getName()           // css book
 instance2.getTime()           // 2013

周末愉快,明天寫多繼承和多態(tài),如果在家想寫的話=-=

補一張繼承原理圖


繼承原理.jpeg
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容