面向對象(三)
繼承
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