几种继承打包带走 | 刷题打卡

206 阅读2分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、原型链继承

1. 核心原理:构造函数的实例指向继承对象的原型链。

  • 核心代码
function Animal() {}

function Dog() {}

Dog.prototype = new Animal()

2. 完整继承示例

function Animal() {
    this.colors = ['black', 'white']
}
Animal.prototype.getColor = function() {
    return this.colors
}
function Dog() {}
Dog.prototype =  new Animal()

let dog1 = new Dog()
dog1.colors.push('brown')
let dog2 = new Dog()
console.log(dog2.colors)  // ['black', 'white', 'brown']

3. 缺点

  • 原型中包含的引用类型属性将被所有实例共享
  • 子类在实例化的时候不能给父类构造函数传参

二、构造函数继承

1. 核心代码及实现原理

子类初始化时调用父类的构造函数。

function Animal2(name) {}

function Dog2(name) {
  Animal2.call(this, name)
}

Dog2.prototype = new Animal2()

2. 完整继承示例

function Anima3(name) {
    this.name = name
    this.getName = function() {
        return this.name
    }
}
function Dog3(name) {
    Animal3.call(this, name)
}
Dog3.prototype =  new Animal3()

3. 缺点

方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法

三、组合继承

  • 原型链实现对原属性的属性和方法的继承
  • 通过构造函数实现其对实例的继承
  • 这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。

1.核心代码

function Animal4(name) {}

function Dog4(name) {
  Animal4.call(this, name)
}

Dog4.prototype = new Animal4()
Dog4.prototype.constructor = Dog4

2. 完整示例

function Animal(name) {
    this.name = name
    this.colors = ['black', 'white']
}
Animal.prototype.getName = function() {
    return this.name
}
function Dog(name, age) {
    Animal.call(this, name)
    this.age = age
}
Dog.prototype =  new Animal()
Dog.prototype.constructor = Dog

let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2) 
// { name: "哈赤", colors: ["black", "white"], age: 1 }

3. 缺点

调用了两次父类构造函数。

四、 寄生式组合继承

function Animal2(name) {}

function Dog2(name) {
  Animal2.call(this, name)
}


Dog.prototype =  Object.create(Animal.prototype)
Dog.prototype.constructor = Dog

观察以上代码,再对比下组合继承,代码修改如下:

- Dog.prototype =  new Animal()
- Dog.prototype.constructor = Dog

+ Dog.prototype =  Object.create(Animal.prototype)
+ Dog.prototype.constructor = Dog

简单的说,继承对象的原型链指向从父对象的实例变成了父对象的原型链对象。

五、 class继承

使用es6的class关键字继承,这个语法糖用起来应该是很香的,唯一需要注意的就是子类必须在constructor方法中调用super方法,否则新建实例时会报错。因为子类自己的this对象必须先通过父类的构造函数构造。

class Point {
}


class ColorPoint extends Point {
}
// 等同于
class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}

更多class用法请参考阮一峰老师的ECMAScript 6 入门