继承

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不存在变量提升,所以在实例化对象前必须先进行类的声明