javascript 继承可以理解为将一个对象所拥有的属性复制到另一个对象。这里记录几种实现的方式。
首先定义一个父级构造函数:
// 父级构造函数 A
function A () {
this.name = 'A'
this.age = 16
}
A.prototype.sayHi = function () {
console.log('Hi i am A')
}
一、原型继承
原型继承是通过将子类的原型
prototype
赋值为父类实例的方式来实现。
function B () {
this.name = 'B'
}
B.prototype = new A() // A 的实例赋值给 B 的prototype
const instance = new B() // B 的实例
console.log('name: ', instance.name) // name: B
console.log('age: ', instance.age) // age: 16
instance.sayHi() // Hi i am A
缺点:
- 实例无法向父类传递参数。
- 父类的属性被所有实例共享,多个子类实例引用属性后会造成污染。
二、构造函数继承
将父类上下文指定为子类,并执行父类。
function B () {
A.call(this, ...arguments)
}
B.prototype.status = function () {
console.log('B status: working')
}
B.prototype.constructor = B
const instance = new B()
// 父类的 prototype 没有被继承,访问 sayHi 会报错
// instance.sayHi()
console.log('name: ', instance.name) // name: A
console.log('age: ', instance.age) // age: 16
缺点:
- 无法继承父类的 prototype。
- 无法实现函数复用,每次生成子类实例都要执行父类函数。
- 实例不属于父类的实例,只属于子类的实例。
三、组合继承
原型继承喝构造函数继承组合在一起。
function B () {
A.call(this, ...arguments) // 调用父类函数继承
}
B.prototype = new A() // 通过原型继承
B.prototype.constructor = B
const instance = new B()
console.log('name: ', instance.name) // name: A
console.log('age: ', instance.age) // age: 16
缺点:
- 调用了两次父类,生成两份父类的实例。
四、寄生组合继承
function B () {
A.call(this, ...arguments)
}
B.prototype = Object.create(A.prototype)
B.prototype.constructor = B
const instance = new B()
console.log('name: ', instance.name) // name: A
console.log('age: ', instance.age) // age: 16
五、class 实现继承
class Aa {
constructor () {
this.name = 'Aa'
}
sayHi () {
console.log('Hi i am Aa')
}
}
class Bb extends Aa {
constructor() {
super()
this.age = 17
}
}
const instance = new Bb()
console.log('name:', instance.name) // name: Aa
console.log('age:', instance.age) // age: 17
instance.sayHi() // Hi i am Aa