【JS系列】继承的这6种方式!(下)

本篇博客接着继承的这6种方式!(上),继续介绍你想知道的后三种继承方式,尤为是最理想的寄生组合式继承。函数

4. 原型式继承

4.1 介绍

  原型式继承的基本思想:post

  • 1个基础对象
  • 1个新对象,把基础对象做为原型对象
  • 新对象建立实例
//基础对象
var person = {
  name: "一灯",
  arr: [1,2,3]
}

//Object.create()建立新对象,传入基础对象
var son1 = Object.create(person)
son1.name = "AAA"
son1.arr.push(4)
console.log(son1.name)    //AAA

var son2 = Object.create(person)
son2.name = "BBB"
console.log(son2.name)    //BBB
console.log(son2.arr)     //1,2,3,4,引用类型问题依然存在
复制代码

  固然你也能够使用Object.create()的第二个参数传添加对象属性ui

var person = {
  name: "一灯",
  arr: [1,2,3]
}

var son1 = Object.create(person, {
  name: {
    value: "AAA"
  }
})
son1.arr.push(4)
console.log(son1.name)    //AAA

var son2 = Object.create(person, {
  name: {
    value: "BBB"
  }
})
console.log(son2.name)    //BBB
console.log(son2.arr)     //1,2,3,4
复制代码

4.2 优劣分析

  • 原型式继承解决了原型链没法传参的问题,而且无需使用构造函数(避免了构造函数的问题)。所以在不必使用构造函数时能够采用这种方法。this

  • 引用类型问题依旧存在spa

5. 寄生式继承

5.1 介绍

  寄生式继承能够理解为是原型式继承的加强。在原型式继承中咱们建立了一个新对象,寄生式继承即是在新对象中添加方法,以加强对象。prototype

var person = {
  name: "一灯",
  arr: [1,2,3]
}

//加强对象
function increase(obj, prop) {
  var object = Object.create(obj,prop)
  object.getName =  function() {
    console.log(this.name)
  }
  return object
}

var son1 = increase(person, {
  name: {
    value: "AAA"
  }
})
son1.arr.push(4)
console.log(son1.name)    //AAA
son1.getName()            //AAA

var son2 = increase(person, {
  name: {
    value: "BBB"
  }
})
console.log(son2.name)    //BBB
console.log(son2.arr)     //1,2,3,4
son2.getName()            //BBB
复制代码

5.2 缺陷

  寄生式继承相似于构造函数,每一个实例对象都有一个副本——破坏了复用性code

6. 寄生组合式继承——大招来了

6.1 介绍

  在继承的这6种方式!(上)中讲到的组合式继承比较经常使用的一种方式,然而这种方式仍是存在一个问题——父级构造函数调用了两次(能够到上篇博文查看代码)。一次在建立子级原型对象,另外一次在子级构造函数内部。对象

  对于精益求精的码农,固然不能容忍,所以诞生了寄生组合式继承,其核心思想是:继承

  • 组合式:子级的prototype继承父级的prototype——经过new Father()
  • 寄生组合式:子级的prototype继承父级的prototype——经过赋值
function inheritPrototype(Son, Father) {
  //建立一个Father.prototype的副本
  var prototype = Object.create(Father.prototype)
  /*下面这句代码的不少资料的描述感受不太清晰,个人理解: *一、Father.prototype的做用是赋值给Son.prototype *二、若是没有下面这条语句:Son.prototype.constructor == Father构造函数 *三、所以须要更改Son.prototype.constructor,模拟new Father()的过程 */
  prototype.constructor = Son
  //把Father.prototype赋值给 Son.prototype
  Son.prototype = prototype
}

function Father(name) {
  this.name = name
  this.arr = [1,2,3]
}

Father.prototype.getName = function() {
  console.log(this.name)
}

function Son(name, age) {
  Father.call(this, name)
  this.age = age
}

inheritPrototype(Son, Father)

Son.prototype.getAge = function() {
  console.log(this.age)
}

var son1 = new Son("AAA", 23)
son1.getName()            //AAA
son1.getAge()             //23
son1.arr.push(4)          
console.log(son1.arr)     //1,2,3,4

var son2 = new Son("BBB", 24)
son2.getName()            //BBB
son2.getAge()             //24
console.log(son2.arr)     //1,2,3
复制代码

6.2 优劣分析

  • 寄生组合式继承对于引用类型的继承来讲是最理想的继承方式:避免了应用类型问题,而且只调用一次父级构造函数。原型链

  • 要说其缺点就是比其余方式更为复杂一些

总结

  1. JS共有6种方式实现继承:
  • 原型链:最原始的继承方式(引用类型值相互影响、没法向父级构造函数传参)
  • 借用构造函数:解决原型链的问题,但破坏了复用性
  • 组合式:原型链+借用构造函数(取长避短),但调用了两次父级构造函数
  • 原生式:解决原型链传参问题,而且无需使用构造函数,但也存在引用类型问题
  • 寄生式:原生式的加强
  • 寄生组合式:寄生式+组合式,解决了各类问题,只是代码稍微复杂
  1. 理解原型/原型链对理解继承帮助甚大,强烈建议先弄得JS原型——一张图完全KO原型链(prototype,__proto__)

更多优质文章将持续更新,来关注一波……

相关文章
相关标签/搜索