js繼承的幾種方式

1 原型鏈繼承

function Person () { // 父級構(gòu)造函數(shù)
    this.name = 'zhangsan';
    this.age = 23
  }
  function Son () { // 子級構(gòu)造函數(shù)
    this.num = 50
  }
  Son.prototype = new Person()

  Son.constructor = Son

  Son.prototype.count = 50
  
  var son = new Son()
  console.log(son.name, son.age, son.num)

把子類的prototype指向父級的實例,也就是原型鏈繼承

此繼承方法優(yōu)

簡單明了,父級新增的屬性和方法子級都能夠訪問的到

此繼承方法缺點

就是多個子類共享一個原型的屬性和方法,無法實現(xiàn)多個繼承

2,構(gòu)造函數(shù)繼承

// 構(gòu)造函數(shù)繼承
  // 構(gòu)造函數(shù)繼承
  function Person () {
    this.name = 'zhangsan'
    this.age = 23
  }
  Person.prototype.count = 50 
  function Son () {
    Person.apply(this)
    this.num = 18
  }

  var son = new Son()

  console.log(son.name) // zhangsan
  console.log(son.age)  // 23
  console.log(son.count)// undefined

構(gòu)造函數(shù)繼承就是在子級構(gòu)造函數(shù)里面執(zhí)行父級的構(gòu)造函數(shù)并且改變this的指向

構(gòu)造函數(shù)繼承的優(yōu)點:

子級直接繼承父級構(gòu)造函數(shù)的屬性和方法

構(gòu)造函數(shù)繼承的缺點:

子類無法繼承父類原型鏈上的屬性和方法

3,混合繼承

// 混合繼承
  function Person () {
    this.name = 'zhangsan'
    this.age = 23
  }
  Person.prototype.count = 50 
  function Son () {
    Person.apply(this)
    this.num = 18
  }
  Son.prototype = new Person()
  var son = new Son()

  console.log(son.name) // zhangsan
  console.log(son.age)  // 23
  console.log(son.count)// 50

混合繼承就是集合原型鏈繼承和構(gòu)造函數(shù)繼承兩者的優(yōu)點集合在一起,集二者優(yōu)點與一身

優(yōu)點:

集合了原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點集合在一起

缺點:

子類會擁有兩個原型鏈屬性,不過可以忽略不計;

4,原型式繼承

臨時創(chuàng)建一個構(gòu)造函數(shù),利用臨時構(gòu)造函數(shù)的原型,在此基礎(chǔ)上實例化對象;

// 原型是繼承;
  function object(o){
    function F(){}
    F.prototype = o;
    return new F();
  } 

  var person = {
    name: 'zhangsan',
    friend: ['111', '222', '333']
  }
  var son = object(person)
  son.name = 'lisi'
  son.friend.push('444')

  console.log(son.name) // lisi
  console.log(son.friend) // '111', '222', '333', '444'

  var son2 = object(person)
  console.log(son2.name) // zhangsan
  console.log(son2.friend) // '111', '222', '333', '444'

缺點:

原型的引用類型會在各實例化對象中共享,一旦修改其中一個就會污染其他實例;

Object.create()方法

ES5通過Object.create()方法規(guī)范了原型式繼承,可以接受兩個參數(shù),一個是用作新對象原型的對象和一個可選的為新對象定義額外屬性的對象,行為相同,基本用法和上面的object一樣,除了object不能接受第二個參數(shù)以外

var person = {
    name: 'Jiang',
    friends: ['Shelby', 'Court']
  }
  var anotherPerson = Object.create(person)
  console.log(anotherPerson.friends) // "Shelby", "Court"

5,寄生式繼承;

寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,即創(chuàng)建一個僅用于封裝繼承過程的函數(shù)

function createSuper (o) {
    var clone = Object.create(o) // 創(chuàng)建一個新對象
    clone.fn = function () {
      console.log('hello')
    }
    return clone
  }

  var person = {
    name: 'Jiang'
  }

  var anotherPeson = createSuper (person)
  anotherPeson.fn() // hello

基于person返回了一個新對象anotherPeson,新對象不僅擁有了person的屬性和方法,還有自己的fn方法

6,寄生式組合函數(shù);

使用寄生式組合模式相當于規(guī)避了混合繼承里面重復(fù)父類實例的屬性和方法在子類實例和原型里面重復(fù)出現(xiàn);
基本思路是不必為了子類的原型而調(diào)用父類的構(gòu)造函數(shù),我們需要的只是父類原型的一個副本;
核心概念就是利用寄生式繼承父類的原型,再把結(jié)果指定給子類的原型;

// 寄生式繼承的方法;
  function createSuper(son, person) {
    var prototype = Object.create(Person.prototype);
    prototype.constructor = Son;
    Son.prototype = prototype;
  }
  function Person () {
    this.name = 'zhangsan'
    this.age = 23
  }
  Person.prototype.count = 50
  function Son () {
    // 繼承屬性
    Person.call(this, name)
    this.num = 18
  }
  createSuper(Son, Person)
  var son = new Son()

  console.log(son.name) // zhangsan
  console.log(son.age) // 23
  console.log(son.num) // 18
  console.log(son.count) // 50

  function Son2 () {

  }
  createSuper(Son2, Person)
  var son2 = new Son2()
  son2.count = 80

  console.log(son.count) // 50
  console.log(son2.count) // 80

在createSuper()函數(shù)中所做的事:

在createSuper函數(shù)中用到了ES5的object.create()方法,將超類型的原型指定為一個臨時的空構(gòu)造函數(shù)的原型,并返回構(gòu)造函數(shù)的實例。
此時由于構(gòu)造函數(shù)內(nèi)部為空(不像Person里面有實例屬性),所以返回的實例也不會自帶實例屬性,這很重要!因為后面用它作為Son 的原型時,就不會產(chǎn)生無用的原型屬性了,借調(diào)構(gòu)造函數(shù)也就不用進行所謂的“重寫”了。
然后為這個對象重新指定constructor為Son ,并將其賦值給Son 的原型。這樣,就達到了將超類型構(gòu)造函數(shù)的實例作為子類型原型的目的,同時沒有一些從Person繼承過來的無用原型屬性。

優(yōu)點:

繼承了混合繼承的優(yōu)點,避免了出現(xiàn)重復(fù)多個原型鏈屬性

缺點:

感覺沒什么缺點,如果非說有缺點,個人感覺就是不好理解

7,Es6的class繼承

// Es6 class類的繼承
  class Person {
    constructor (name, age) {
      this.name = name
      this.age = age
    }
    fn () {
      console.log(this.name)
    }
  }
  // let person = new Person('zhangsan', 23)
  // person.fn()
  class Son extends Person {
    constructor (name, age, count) {
      super(name, age)
      this.count = count
    }
    fn1 () {
      console.log(this.name, this.count)
    }
  }
  var son = new Son('小花', 18, 50)
  var son2 = new Son('小紅', 20)
  son.fn() // 小花
  son.fn1() // 小花 50
  son2.fn() // 小紅
  son2.fn1() // 小紅 undefined

缺點:

就是兼容性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容