继承
bridge 2022/8/21
es5继承类型:
- 原型链继承:让构造函数的原型指向父类的实例,缺点是子类没有办法构建私有属性,对一个子类实例的属性进行更改,会改变所有子类的实例
function Parent(){
this.name = ['张三']
}
Parent.prototype.getName = function(){
return this.name
}
function Child(){}
Child.prototype = new Parent()
Child.prototype.constructor = Child
let c1 = new Child()
let c2 = new Child()
console.log(c1.getName()) // ['张三']
console.log(c2.getName()) // ['张三']
c1.name.push('李四')
console.log(c2.getName()) // ['张三', '李四']
- 借用构造函数继承:利用call或apply,将父类的构造函数的this变为子类,缺点是无法获取到父类原型对象上的方法或属性
function Parent(name){
this.name = [name]
}
Parent.prototype.getName = function(){
return this.name
}
function Child(name){
Parent.call(this, name)
}
Child.prototype.constructor = Child
let c1 = new Child('张三')
let c2 = new Child('李四')
console.log(c1) // ['张三']
console.log(c2) // ['李四']
c1.name.push('李四')
console.log(c1) // ['张三', '李四']
console.log(c2) // ['李四']
console.log(c1.getName) // undefined
- 组合继承(原型链 + 构造函数继承)
function Parent(name){
this.name = [name]
}
Parent.prototype.getName = function(){
return this.name
}
function Child(name){
// 借助构造函数继承
Parent.call(this, name)
}
// 原型链继承
Child.prototype = new Parent('张三')
Child.prototype.constructor = Child
let c1 = new Child('李四')
let c2 = new Child('王五')
console.log(c1.name) // ['李四']
console.log(c2.name) // ['王五']
- 寄生继承
function Parent(name){
this.name = [name]
}
Parent.prototype.getName = function(){
return this.name
}
function Child(name){
// 借助构造函数继承
Parent.call(this, name)
}
// 指向所要继承的类的原型
Child.prototype = Parent.prototype
let c1 = new Child('李四')
let c2 = new Child('王五')
console.log(c1.name) // ['李四']
console.log(c2.name) // ['王五']
- 寄生组合式继承
function Parent(name){
this.name = name
}
Parent.prototype.getName = function(){
return this.name
}
function Child(name){
Parent.call(this, name)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
let c1 = new Child('zs')
let c2 = new Child('lisi')
console.log(c1,c2)
ES6 类的继承
Class之间可以通过extends关键字实现继承
子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
// this.color = color // 报错
super(x, y)
this.color = color
}
}
let p = new ColorPoint(1,1,'红色')
console.log(p)
不同之处
1)ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。
2)class不存在变量提升,所以在实例化对象前必须先进行类的声明