1. 原型式繼承方法
常規的類繼承實現結果(也就是es6繼承後結果)是:
- 子類重寫屬性和方法不影響父類
- 父類重寫屬性和方法影響子類
- 子類可以自定義繼承父類構造方法
es5 的原型式繼承方式,有如下 3 條:
- 子類重寫基本型別的屬性不影響父類,如果是引用屬性,則會影響(這裡說的引用所在記憶體的位置沒有發生變化)
- 父類重寫屬性和方法影響子類
- 子類可以自定義繼承父類構造方法
es5 繼承最主要的原型式繼承方法,這個函式步驟分為 4 步驟:
- 建立一箇中間的建構函式Fn,
Fn.prototype = Super.prototype
。 - 例項化 Fn 為
var fn = new Fn()
,將Child.prototype = fn
。 - 將
Child.prototype.constructor = Child
。 - 在
Child
建構函式中封裝一個super
方法,來繼承父類裡的建構函式。
ps:當然步驟 1 和 2 可用 Object.create()
來替代。
程式碼如下:
function extends (Sup, Sub) {
// var Fn = function () {}
// Fn.prototype = Sup.prototype
// var fn = new Fn()
// Sub.prototype = fn
Sub.prototype = Object.cteate(Sup.prototpye)
Sub.prototype.constructor = Sub
}
function super (Sup) {
var args = []
if (arguments.length > 1) {
args = Array.protoype.slice.call(arguments, 1)
}
Sup.apply(this, args)
}
function Sup (name) {
this.name = name
}
function Sub (name) {
super(Sup, name)
}
extends(Sup, Sub)
複製程式碼
記憶體分析:
需要注意的是:包含引用型別值的屬性始終都會共享相應的值,就像使用原型模式一樣。 這一點和 es6的繼承不同,下列是兩種繼承做對比。
es5
var parent = new Sup('父親')
var child = new Sub('孩子')
console.log('parent.name', parent.name)
console.log('child.name', child.name)
child.name = '女兒'
console.log('修改 child.name = \'女兒\' parent', child.name) // 女兒
console.log('修改 child.name = \'女兒\' parent', parent.name) // 父親
console.log('child.pet.name = xm =============')
parent.pet.name = 'jack'
console.log(parent.pet.name) // jack
console.log(child.pet.name) // jack
複製程式碼
es6
class Sup {
pet = {
name: 'mack'
}
constructor (name) {
this.name = name
}
say () {
console.log(`my name is ${this.name} and my pet's name is ${this.pet.name}`)
}
changePetName (name) {
this.pet.name = name
}
}
class Sub extends Sup {
constructor (name) {
super(name)
}
}
const parent = new Sup('父親')
const son = new Sub('兒子')
// 修改父親寵物的名字
parent.changePetName('jack')
console.log('parent.pet.name', parent.pet.name)
parent.say() // jack
son.say() // mack
複製程式碼