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
复制代码