实现继承的几种方式及优缺点

126 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情

原型继承

原型继承:让子类实例的原型等于父类的实例

优点:实例可继承:实例的构造函数的属性,父类构造函数属性,父类原型的属性

缺点:

  • 子类实例无法像父类构造函数传参
  • 子类实例共享属性,造成实例间的属性会相互影响
function Parent() {
  this.num = ['1']
  this.addNum = function () {
    this.num.push('2')
  }
}
function Child() {
}
Child.prototype = new Parent()
var child1 = new Child()
var child2 = new Child()
var parent = new Parent()
child1.addNum()
console.log(child1.num, child2.num) // [ '1', '2' ] [ '1', '2' ]
console.log(child1.addNum === child2.addNum) // true

构造函数

构造函数:继承用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制)

优点:子类实例可以向父实例传参,可以继承多个构造函数属性

缺点:

  • 父类的方法没有被共享,造成内存浪费
  • 只继承父类构造函数的属性,没有继承父类原型的属性
function Parent() {
  this.num = ['1']
  this.addNum = function () {
    this.num.push('2')
  }
}
function Child() {
  Parent.call(this)
}
var child1 = new Child()
var child2 = new Child()
child1.addNum()
console.log(child1.num, child2.num) // [ '1', '2' ] [ '1' ]
console.log(child1.addNum === child2.addNum) // false

组合继承

组合继承:组合原型链继承和借用构造函数继承

优点:可以继承父类原型上的属性,可以传参,可复用

缺点:父类构造函数被调用两次,子类实例的属性存在两份。造成内存浪费

function Parent() {
  this.num = ['1']
}
Parent.prototype.addNum = function() {
  this.num.push('2')
}
function Child() {
  Parent.call(this) 
}
Child.prototype = new Parent() 
var child1 = new Child()
var child2 = new Child()
child1.addNum()
console.log(child1.num, child2.num) // [ '1', '2' ] [ '1' ]
console.log(child1.addNum === child2.addNum) //true

寄生继承

完美:子类都有各自的实例不会相互影响,且共享了父类的方法

function Parent() {
  this.num = ['1']
}
Parent.prototype.addNum = function() {
  this.num.push('2')
}
function Child() {
  Parent.call(this) 
}
Child.prototype = Object.create(Parent.prototype) 
var child1 = new Child()
var child2 = new Child()
child.addNum()
console.log(child1.num, child2.num) //[ '1','2' ] [ '1' ]
console.log(child1.addNum === child2.addNum) //true

ES6 class

和寄生继承实现的效果一致

class Parent {
  constructor() {
    this.num = ['1']
  }
  addNum() {
    this.name.push('2')
  }
}
class Child extends Parent {
  constructor() {
    super()
  }
}
var child1 = new Child()
var child2 = new Child()
child1.addNum()
console.log(child1.num, child2.num) // [ '1', '2' ],['2'] 
console.log(child1.addNum === child2.addNum)

总结

对比以上几个demo,通过打印两个子类实例的num属性,判断子类实例是否相互影响,通过打印两个子实例的addNum方法是否相等,可以判断是否共享了父类方法,从而更好的体现以上几种继承方法的优缺点,让我们在开发中能更合理的选择哪种继承方法进行使用开发。