簡單通俗的方式認識js繼承

前戲:

js 繼承是在前端面試及js庫開發中常常遇到的問題。在面向對象開發時繼承知識也是很是重要,本人閱讀了一些文章總結了js繼承的要點,但願能對你們有所幫助。前端

什麼是繼承?

通俗的說:某一個工程須要藍圖實現來工程,藍圖就是。但在一個新工程的藍圖設計時須要複製一些老藍圖上的工程經驗來提高效率,這個過程就至關於繼承。面試

js繼承有哪些? 一塊兒來看看

1.類式繼承

//父類
function SuperClass() {
  this.superValue = true;
}
SuperClass.prototype.getSuperValue = function() {
  return this.superValue;
}
//子類
function SubClass() {
  this.subValue = false;
}
SubClass.prototype = new SuperClass();

SubClass.prototype.getSubValue = function() {
  return this.subValue;
}

var instance = new SubClass();

console.log(instance instanceof SuperClass)//true
console.log(instance instanceof SubClass)//true
console.log(SubClass instanceof SuperClass)//false

這種方式是最原始的方式,使用父類的一個實例重寫到子類原型對象上,從而實現父類成員的繼承,有點繼承的樣子,可是總以爲怪怪的,你肯定把一個實例賦值到原型上真的沒有問題嗎?數組

缺點:瀏覽器

  • 引用類型問題,若是父類有個數組成員,只實例化一次賦值到原型上,那就是每次new出來的子實例都是在使用同一個數組,後果可想而知。
  • 不能傳參
  • 重寫了prototype,若是要額外給子類原型加東西就要加在SubClass.prototype = new SuperClass();重寫語句以後,很不方便
  • instance.constructor 構造器指向父類。子類的實例構造器是父類?那不胡扯嗎?

2.構造函數繼承

function SuperClass(id) {
  this.books = ['a','b'];
  this.id = id;
}
SuperClass.prototype.showBooks = function() {
  console.log(this.books);
}
function SubClass(id) {
  //繼承父類
  SuperClass.call(this,id);
}

var instance1 = new SubClass(10);

var instance2 = new SubClass(11);

instance1.books.push('c');
console.log(instance1)
console.log(instance2)
instance1.showBooks();

比上面一個稍微好了一點,也能傳參了,每次出來的數組也是惟一的了。原理是在子類構造的時候使用call的特性借用一下父類的構造函數,把父類的成員都設置在子類中來實現繼承。額。。那原型呢?
缺點:函數

  • 繼承不了父類原型上的成員
  • 每次實例化子類就會call一下父類,多執行了一遍

3.組合式繼承

function SuperClass(name) {
  this.name = name; 
  this.books = ['A','B'];
}
SuperClass.prototype.getBooks = function() {
    console.log(this.books);
}
function SubClass(name,time) {
  SuperClass.call(this,name);
  this.time = time;
}
SubClass.prototype = new SuperClass();

SubClass.prototype.getTime = function() {
  console.log(this.time);
}

還能夠,能用,原理也就是結合了以上兩種(構造函數、類式繼承)的繼承方式,並修復了嚴重的缺點。之前應該用這種方法的人也比較多吧
缺點:this

  • call一遍就算了又new了一遍 不以爲怪怪的麼?call已經設置了一遍成員,prototype只要父的prototype啊,不要把其餘無關的東西搞進來。
  • prototype仍是被重寫了

4.原型式繼承

function inheritObject(o) {
    //聲明一個過渡對象
  function F() { }
  //過渡對象的原型繼承父對象
  F.prototype = o;
  //返回過渡對象的實例,該對象的原型繼承了父對象
  return new F();
}
var book = {
    name:'A book',
    likeBook:['B Book','C book']
}
var newBook = inheritObject(book);
newBook.name = 'AA1 book';
newBook.likeBook.push('CC book');
var otherBook = inheritObject(book);
otherBook.name = 'EE book';
otherBook.likeBook.push('FF book');
console.log(newBook,otherBook);

這就像類式繼承同樣,直接把父的成員放到子類的原型上,經過原型鏈來實現繼承。inheritObject就像是object.create()和new的模擬實現,產出很是純淨的對象。
黑人問號.jpg。使用這種方法意思是放棄了構造函數來實現繼承?
缺點:prototype

  • 子類設置成員寫在外面,設置成員的代碼一堆一堆的,代碼組織差。
  • 每次繼承都用同一個likeBook ,並無新建立一個,後果可想而知,那還不是和第一種方法差很少,用不了
  • 這算的上是一種繼承麼,先拿到父類的東西而後再去想子類?

5.寄生式繼承

var book = {
    name:'A book',
    likeBook:['B book','C book']
}
function createBook(obj) {
    //經過原型方式建立新的對象
  var o = new inheritObject(obj);
  // 拓展新對象
  o.getName = function(name) {
    console.log(name)
  }
  // 返回拓展後的新對象
  return o;
}

依然保留了inheritObject函數來實現父成員的繼承,相比上面的原型繼承代碼更有組織性了,單獨封裝了一個函數來實現繼承,而後使用原型繼承來繼承對應的父類
缺點:
已經差很少作到了繼承,可是原型繼承問題依然沒有解決設計

6.寄生組合式繼承

function inheritObject(o) {

  function F() { }
  F.prototype = o;
  return new F();
}

function inheritPrototype(subClass,superClass) {
    // 複製一份父類的原型副本到變量中
  var p = inheritObject(superClass.prototype);
  // 修正由於重寫子類的原型致使子類的constructor屬性被修改
  p.constructor = subClass;
  // 設置子類原型
  subClass.prototype = p;
}

//繼承
function SuperClass(name) {
  this.name = name;
  this.books=['a book','b book'];
}
SuperClass.prototype.getName = function() {
  console.log(this.name);
}
function SubClass(name,time) {
  SuperClass.call(this,name);
  this.time = time;
}
inheritPrototype(SubClass,SuperClass);
SubClass.prototype.getTime = function() {
  console.log(this.time);
}
var instance1 = new SubClass('f1','2017')
var instance2 = new SubClass('r2','2018');

instance1.books.push('new book');

console.log(instance1,instance2);

繼承終極版。這個繼承方式是在解決組合繼承遇到的問題,先給子類鏈接上純淨的父原型成員,而後再借用父類構造函數獲取到父構造函數裏的成員,基本解決上面出現的問題。code

總結

剩下沒說的就是ES6的繼承,也是至關於一個ES6的語法糖,源碼也是基於寄生組合式繼承。缺點就是對低版本的瀏覽器不友好, 以上總結了6種js繼承方式,每個繼承方式都是修復以前繼承的不足,重點是理解它們的特色和之間的差別,弄明白爲何要這樣作,這樣才能完全理解js繼承的內容。最後,但願能對你有幫助~對象

相關文章
相關標籤/搜索