1. 程式人生 > >設計模式什麼的根本記不住啊 , 直接看各類原生JS繼承吧!!!

設計模式什麼的根本記不住啊 , 直接看各類原生JS繼承吧!!!

原生JS繼承詳解

參考資料
不要講什麼設計模式 , 看得老子腦殼昏 , 智商欠費 , 還是簡單點 , 方案 , 繼承 , 就完事了

// 首先我們得有個父類
// 這個父類也很簡單
function Human(name) {
    this.name = name || '肥宅' // 有參就取參 , 沒參就叫肥宅
}
Human.prototype.drink = function(drinks) {
    console.log(this.name + '正在喝' + (drinks || '可樂'));
}
複製程式碼

OK, 我們現在有了一個父類, 先來看一個最簡單的繼承

最簡單的原型鏈繼承

直接把父類的例項作為子類的原型

// 先寫個空類
function Jianren(){}
Jianren.prototype = new Human()

// new個例項看看
var haidong = new Jianren();

console.log(haidong.name); //'肥宅'
console.log(haidong.drink()); //'haidong正在喝可樂'
複製程式碼

對於這個繼承, 概括為子類的原型鏈繫結父類的例項實現繼承

缺陷

  1. 不能實現多類繼承
  2. 為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行
  3. 無法控制子類能夠訪問父類屬性的許可權
  4. 建立子類的例項時也不能向父類建構函式傳參

構造繼承

複製父類屬性

function Jianren(){
  Human.call(this);// 把父類寫進子類建構函式內部, 呼叫call把子類的this傳進去改變this的指向做到複製父類屬性
  this.age = 22
}
複製程式碼
  1. 構造繼承其實就是複製了父類屬性, new Jianren()出來的例項的construct和prototype都與Human無關, 指向Jianren()
  2. 可以不管new 父類前後順序來新增子類的屬性
  3. 建立子類例項時, 也可以向父類傳遞引數,
  4. 可以call多個父類實現多類繼承
  5. 只能繼承父類的例項屬性和方法, 不能繼承/訪問到父類原型上的東西
  6. 難以複用, 影響效能

例項繼承

在子類內部新增一個屬性, 該屬性為父類的例項

function Jianren(name){
  var ren = new Human();// 注意這裡是不是this
  ren.name = name || 'haidong';
  return ren;
}
複製程式碼
  1. 不會限制呼叫的方式, new 子類() 或者 子類()執行, 都返回ren
  2. new Jianren()的例項實際上是new Human(), constructor也是指向Human()
  3. 不支援多類繼承

拷貝繼承

function Jianren(name){
  var ren = new Human()
  for(var r in ren) {
      Cat.prototype[r] = ren[r] // 該處r是key, 應該用Object[key]的形式賦值和訪問
  }
  Jianren.prototype.name = name || 'haidong'
}
複製程式碼
  1. 支援多繼承
  2. 效率低, 拷貝屬性會佔用記憶體
  3. 不可列舉父類

推薦的兩種繼承

組合繼承和寄生組合繼承

上面的繼承主要是幫助理解, 或有時暴力快速解決小問題時使用 .

推薦一, 組合繼承

子類的原型指向父類例項,該父類例項又可向上原型查詢訪問,修正後constructor指向子類自身

function Jianren(name) {
    Human.call(this) //第一步拷貝屬性
    this.name = name || 'haidong'
}
Jianren.prototype = new Human() //第二步, 原型指向父類例項
Jianren.prototype.constructor = Jianren //第三步, 修正constructor指向
複製程式碼
  1. 可以繼承例項的屬性/方法, 也可以繼承原型的屬性方法,
  2. 是子類的例項, 也相當於是父類的例項
  3. 子類的原型指向父類例項,該父類例項又可向上原型查詢訪問,修正後constructor指向子類自身
  4. 可傳參,//call()可以傳參,具體用法,自行百度谷歌
  5. 呼叫兩次父類建構函式, 佔記憶體, 第一步拷貝過一次, 第二步導致以後的Jianren的例項裡和Jianren原型上重複的屬性

推薦二, 寄生組合繼承

// 有點複雜
function Jianren(name) {
    Human.call(this) //第一步拷貝屬性
    this.name = name || 'haidong'
}
(function() { //來個匿名立即執行函式
    function J() {}// 建立一箇中間類, 空, 什麼都沒有
    J.prototype = Human.prototype //第二步中間類原型指向父類原型
    Jianren.prototype = new J() //子類原型賦值為中間類的例項,往上查詢,指向了父類的原型
})()
Jianren.prototype.constructor = Jianren //修正子類constructor指向
複製程式碼

與上面的組合繼承相比, 第一步拷貝 和 第二步中間類(空類)不會重複有Human的屬性, 略微複雜, 可以忽略不計, 完美方式