子类的继承其实就是继承父类的属性和方法
原型链继承
function Father() {
this.colors = ['red', 'green', 'blue']
}
Father.prototype.getColors = function () {
return this.colors
}
function Child(value) {
this.value = value
}
Child.prototype = new Father() // 关键代码
Child.prototype.getValue = function () {
return this.value
}
let c1 = new Child('c1')
let c2 = new Child('c2')
c1.colors[0] = null
c2.colors[0] // ==> null
缺点:多个实例对引用类型的操作会被篡改。
构造函数继承
function Father() {
this.colors = ['red', 'green', 'blue']
}
Father.prototype.getColors = function () {
return this.colors
}
function Child(value) {
Father.call(this) // 关键代码
this.value = value
}
Child.prototype.getValue = function () {
return this.value
}
let c1 = new Child('c1')
let c2 = new Child('c2')
c1.colors[0] = null
c2.colors[0] // ==> "red"
c1.getColors() // ==> Uncaught TypeError: c1.getColors is not a function
缺点:
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现复用,每个子类都有父类实例函数的副本,影响性能
组合继承
function Father() {
this.colors = ['red', 'green', 'blue']
}
Father.prototype.getColors = function () {
return this.colors
}
function Child(value) {
Father.call(this) // 关键代码
this.value = value
}
Child.prototype = new Father() // 关键代码
Child.prototype.constructor = Child // 关键代码
Child.prototype.getValue = function () {
return this.value
}
let c1 = new Child('c1')
let c2 = new Child('c2')
c1.colors.push('black')
console.log(c1.getColors()) // ==> ["red", "green", "blue", "black"]
console.log(c2.getColors()) // ==> ["red", "green", "blue"]
console.log(c1.getValue()) // c1
console.log(c2.getValue()) // c2
注意:
组合模式的缺点就是在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法。
寄生组合式继承
function Father() {
this.colors = ['red', 'green', 'blue']
}
Father.prototype.getColors = function () {
return this.colors
}
function Child(value) {
Father.call(this) // 关键代码
this.value = value
}
// 下面的操作类似于
// Child.prototype.__proto__ = Father.prototype
Child.prototype = Object.create(Father.prototype) // 关键代码
Child.prototype.getValue = function () {
return this.value
}
let c1 = new Child('c1')
let c2 = new Child('c2')
c1.colors.push('black')
console.log(c1.getColors()) // ==> ["red", "green", "blue", "black"]
console.log(c2.getColors()) // ==> ["red", "green", "blue"]
console.log(c1.getValue()) // c1
console.log(c2.getValue()) // c2
ES6 extends
class Father {
colors = ['red', 'green', 'blue']
getColors() {
return this.colors
}
}
class Child extends Father {
constructor(value) {
super()
this.value = value
}
getValue() {
return this.value
}
}
let c1 = new Child('c1')
let c2 = new Child('c2')
c1.colors.push('black')
console.log(c1.getColors()) // ==> ["red", "green", "blue", "black"]
console.log(c2.getColors()) // ==> ["red", "green", "blue"]
console.log(c1.getValue()) // c1
console.log(c2.getValue()) // c2
class
实现继承的核心在于使用extends
表明继承自哪个父类,并且在子类构造函数中必须调用super
,因为这段代码可以看成Parent.call(this, value)
。当然了,之前也说了在
JS
中并不存在类,class
的本质就是函数。