现在有两个构造函数 Super 和 Child
如何实现Child 继承 自Super
function Super() {
this.age = 12
}
Super.prototype.sayHello = () => { }
function Child() {
this.color = 'red'
}
Child.prototype.getColor = () => { }
首先分别 new 一下两个函数
控制台打印出两个实例,他们分别都有自己的实例属性
以及原型方法
先声明一下,下文中:
- Child 指的是Child
构造函数
- Child对象 指的是用Child构造函数生成的
实例
- Super 指的是Super
构造函数
- Super对象 指的是Super构造函数生成的
实例
观察Child对象,他的原型[[prototype]]
是一个Object对象,若Child继承了Super以后,Child对象的原型[[prototype]]
将换成Super对象
如何做到上面的效果?
要替换Child对象的原型[[prototype]]
,就需要替换Child构造函数的原型prototype
举个栗子:
Child.prototype = {
info:'我替换了Child的prototype'
}
上面一行代码就把Child的prototype
替换了,又叫原型重写,继续:
Child.prototype = new Super()
这一句代码的意思就是把Child的prototype
重写成Super对象,到这里,似乎实现了最简单的继承,运行试试
完整代码:
function Super() {
this.age = 12
}
Super.prototype.sayHello = () => { }
function Child() {
this.color = 'red'
}
Child.prototype.getColor = () => { }
Child.prototype = new Super()
console.log(new Child());
我们发现Child对象的原型确实变成Super,但是存在一个问题,Child原型上定义的getColor 方法丢失了,constructor好像也丢失了,而且Child原型上还多了age属性,这是我们不希望看到的,于是:
function Super() {
this.age = 12
}
Super.prototype.sayHello = () => { }
function Child() {
this.color = 'red'
}
Child.prototype.getColor = () => { }
const prototype = Object.create(Super.prototype)
prototype.constructor= Child
prototype.getColor = Child.prototype.getColor
Child.prototype = prototype
console.log(new Child());
这里我们创建了一个空对象prototype ,并且复制Child.prototype上的getColor到空对象身上,然后重写Child原型
打印的结果很接近完美了,这样做还有个问题,如果Child.prototype上面原本有多个方法呢?得想个办法完整复制原来的方法
function Super() {
this.age = 12
}
Super.prototype.sayHello = () => { }
function Child() {
this.color = 'red'
}
Child.prototype.getColor = () => { }
Child.prototype.getName = () => { }
const prototype = Object.create(Super.prototype)
prototype.constructor= Child
for (const [key, value] of Object.entries(Child.prototype)) {
prototype[key] = value // 复制Child原型原来的属性以及方法
}
Child.prototype = prototype
console.log(new Child());
到这里,就能完整复制Child原型原来的属性以及方法了
把这几个步骤封装成函数
/**
* 继承
* @param {Function} Child 子类
* @param {Function} Super 超类(父类)
*/
function extend(Child, Super) {
const sp = Super.prototype// 父类原型
const sub = Child.prototype // 子类原型
const prototype = Object.create(sp)// new出来一个纯净的对象,并且__proto__指向父类原型
for (const [key, value] of Object.entries(sub)) {
prototype[key] = value // 复制子类原型原来的属性以及方法
}
// 显式声明构造器(不可枚举)
Object.defineProperty(prototype, 'constructor', {
enumerable: false,
configurable: true,
value: Child
})
Child.prototype = prototype// 重写原型
}
Object.defineProperty() 表示:定义对象自身上的属性,具体用法可以自行百度
现在可以愉快的使用继承了,测试:
function Super() {
this.age = 12
}
Super.prototype.sayHello = () => { }
function Child() {
this.color = 'red'
}
Child.prototype.getColor = () => { }
extend(Child, Super)// 执行继承
console.log(new Child())