面向對象-類的繼承

一、實例化一個類的方式

   分爲兩種

1.使用傳統的方式
function foo(){
   this.name = 'wangwei'
}
new foo();
2.使用ES6中class的方式
class foo2{
   constructor(){
     this.name = 'libai';
  }
}
new foo2();

二、類的繼承

  類的繼承又分爲了幾種不同的方式,每個方式又各有其缺點。

  首先,第一種方式是藉助構造函數來實現繼承

比如先聲明一個父類
function parent1(){
  this.name = 'parent1';
}
再聲明一個子類,並在其內部去執行parent1
function child1(){
  parent1.call(this);
  this.type= 'child1';
}
這樣子child1就實現了對parent1的繼承。

但是這種寫法有很多缺點,不推薦這樣寫。

1.實例化後的子類child1只是繼承了parent1的屬性和方法,而parent1原型鏈沒有繼承。

第二種方式是,藉助原型鏈實現繼承

先聲明一個父類
function parent2(){
   this.name = 'parent2';
}
再聲明一個子類
function child2(){
   this.type = 'child2';
}
然後將child2的prototype屬性指向parent2的實例,意思是將child2的實例的原型對象指向了parent2的實例。
child2.prototype = new parent2();
這種寫法同樣有缺點
比如,將child2實例出兩個對象
var a1 = new child2();
var a2 = new child2();

這個時候訪問
a1.name  //parent2
a2.name  //parent2
但是一旦其中一個實例去修改了原型鏈上的任意一個屬性,另一個實例的對應屬性也會跟着改變(注意,如果修改的是實例本身的屬性,那麼就不會相互影響)
a1.name = 'notParent2';
a2.name   //notParent2;
這是爲什麼呢?
因爲實例化後的這兩個類的原型鏈引用的是同一個實例對象new parent2.注意是同一個。
另外還有一點需要注意
子類child實例化後的對象的constructor(構造器)並不是child2構造函數,而是parent2構造函數
這是因爲child2.prototype是由parent2的實例賦值的。

第三種方式,是這兩種方式的組合方式來實現繼承

function parent3(){
  this.name = 'parent3';
}

function child3(){
  parent3.call(this);
  this.type = 'child3';
}
child3.prototype = new parent3;
var a3 = new child3();
var b3 = new child3();
這種方式就可以避免多個構造函數實例化後的對象都指向同一個原型對象,但是第二種方式中的實例化的對象的constructor指向仍然沒有解決
而且,parent3這個函數被執行了兩次。
其實沒有必要,優化後只要執行一次就可以了

第三種方式的優化1

function parent3(){
  this.name = 'parent3';
}

function child3(){
  parent3.call(this);
  this.type = 'child3';
}
child3.prototype = parent3.prototype;
var a3 = new child3();
var b3 = new child3();
console.log(a3,b3)

因爲按方法一的寫法,已經將父類的屬性和方法都複製到了子類上,所以第8行中如果按方式3寫的,就只是在原型鏈上增加了一個原型對象,其實這一個是可以省去的。

但是方式三優化1仍然沒有解決子類實例化對象的constructor的問題。

因此,引出方式三優化2方案。

function parent5(){
  this.name = 'parent5';
}

function child5(){
  parent5.call(this);
  this.type = 'child5';
}
child5.prototype= Object.create(parent5.prototype);
child5.prototype.constructor = child5;
var a5 = new child5();
var b5 = new child5();
console.log(a5,b5)
使用Object.create方法,使child5.prototype與patent5.prototype隔離開來,而不是直接的賦值關係,然後在child5.prototype上指定其構造器constructor爲child5,就實現了完美的繼承。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章