1. 原型链继承
- 核心:将父类实例作为子类原型
- 优点:父类方法复用
- 缺点:创建子类实例的时候,不能传参
function Animal(name, age) {
this.name = name // 实例基本属性(强调私有,不共享)
this.age = age
}
Animal.prototype.say = function() { // 将需要复用、共享的属性或方法定义在父类原型上
console.log('hello')
}
function Dog() {
}
Dog.prototype = new Animal() // 核心
let dog1 = new Dog() // 该实例共享了父类的say方法
2. 借用构造函数
- 核心:借用父类的构造函数来增强子类实例
- 优点:实例之间独立。可以向父类构造函数传参数
- 缺点:父类原型上的属性和方法不能复用
function Animal(name, age) {
this.name = name // 实例基本属性(强调私有,不共享)
this.age = age
}
Animal.prototype.say = function() { // 将需要复用、共享的属性或方法定义在父类原型上
console.log('hello')
}
function Dog(name, age) {
Animal.call(this, name, age) // 核心
}
let dog1 = new Dog() // 该实例不能继承父类原型上的方法
3. 组合继承
-
核心:通过调用父类构造函数,继承父类的属性并保留传参的优点;然后通过将父类实例作为子类原型,实现父类方法复用
-
优点:创建子类实例的时候,可以传参。可以实现父类方法复用
-
缺点:由于调用了2次父类的构造方法,会存在一份多余的父类实例属性
注意:'组合继承'这种方式,要记得修复子类constructor指向
function Animal(name, age) {
this.name = name // 实例基本属性(强调私有,不共享)
this.age = age
}
Animal.prototype.say = function() { // 将需要复用、共享的属性或方法定义在父类原型上
console.log('hello')
}
function Dog(name, age) {
Animal.call(this, name, age) // 核心
}
Dog.prototype = new Animal() // 核心
let dog1 = new Dog() // 该实例共享了父类的say方法
注意:为啥要修复构造函数的指向?
console.log(dog1.constructor); // Animal 你会发现实例的构造函数居然是Animal。
而实际上,我们希望子类实例的构造函数是Dog,所以要记得修复构造函数指向。修复如下
Dog.prototype.constructor = Dog;