javascript建構函式的繼承簡單介紹

antzone發表於2017-04-07

實現繼承的方式有多種,下面介紹一下比較常見的幾種方式,需要的朋友可以做一下參考。

準備工作:

下面是一個父類,當前ES版本中還沒有類這個概念(ES6新增class),不過確實是類的作用:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
  this.target="使用者瀏覽";
}

下面是一個子類:

[JavaScript] 純文字檢視 複製程式碼
function Antzone(webName,url){
  this.webName=webName;
  this.url=url;
}

那面就介紹一下如何讓子類來繼承父類中的相關屬性。

一.建構函式繫結:

使用call()或者apply()方法可以實現此功能。

所謂的建構函式繫結,就是將父類建構函式繫結到子類物件上,程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
  this.target="使用者瀏覽";
}
 
function Antzone(webName,url){
  Web.apply(this,arguments);
  this.webName=webName;
  this.url=url
}
 
var oantzone=new Antzone("螞蟻部落","softwhy.com");
console.log(oantzone.target);

二.使用prototype原型實現繼承:

如果子類Antzone的原型指向父類的物件例項,那麼子類的物件例項將會繼承父類的所有屬性和方法。

程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
  this.target="使用者瀏覽";
}
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
Antzone.prototype=new Web();
var oantzone=new Antzone("螞蟻部落","softwhy.com");
console.log(oantzone.target);

上面的程式碼實現了繼承功能,但是這並不完美,甚至可以說是有問題的。

Antzone.prototype=new Web()是覆蓋了子類的原型物件,那麼這個時候Antzone.prototype.constructor指向就不是Antzone,而是Web,那麼物件例項antzone的constructor就不會指向Antzone了,這樣就會導致繼承鏈的紊亂,程式碼修改如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
  this.target="使用者瀏覽";
}
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=new Web();
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("螞蟻部落","softwhy.com");
console.log(oantzone.target);
console.log(oantzone.constructor==Antzone);

上面的程式碼重新修改了一下Antzone.prototype.constructor的指向即可。

三.直接繼承prototype:

上面程式碼是繼承的父類的物件例項,我們也可以直接繼承父類的原型物件,這樣的話能夠節省記憶體空間提高效率。

父類中不變的屬性可以寫在在prototype原型物件中,程式碼修改如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
}
Web.prototype.target="使用者瀏覽";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=Web.prototype
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("螞蟻部落","softwhy.com");
console.log(oantzone.target);

這種方式雖然效率比較高,但是也有一個比較嚴重的問題,那就是一旦修改子類原型物件,那麼父類的原型物件也會被修改,因為實質上它倆是指向的同一個原型物件,程式碼演示如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
}
Web.prototype.target="使用者瀏覽";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
 
Antzone.prototype=Web.prototype
Antzone.prototype.constructor=Antzone;
Antzone.prototype.target="div教程";
console.log(Antzone.prototype.target);
console.log(Web.prototype.target);

四.使用空物件進行過渡:

對於上面方式的缺點,下面就進行一下改進,使用一個空物件進行一下過渡。

程式碼例項如下:

[JavaScript] 純文字檢視 複製程式碼
function Web(){
}
Web.prototype.target="使用者瀏覽";
 
function Antzone(webName,url){
  this.webName=webName;
  this.url=url
}
var F=function(){};
F.prototype=Web.prototype;
Antzone.prototype=new F();
Antzone.prototype.constructor=Antzone;
var oantzone=new Antzone("螞蟻部落","softwhy.com");
console.log(oantzone.target);

宣告瞭一個空函式F(),是為了讓它足夠的"乾淨",也幾乎不佔任何記憶體空間。

修改Antzone的原型的時候也不會影響到父類Web的原型。

程式碼封裝如下:

[JavaScript] 純文字檢視 複製程式碼
function extend(Child, Parent) {
  var F = function(){};
  F.prototype = Parent.prototype;
 Child.prototype = new F();
 Child.prototype.constructor = Child;
 Child.uber = Parent.prototype;
}

extend函式,就是YUI庫如何實現繼承的方法。

可能其他程式碼大家都比較明白了,唯獨對最後一行程式碼可能還有點疑問:

[JavaScript] 純文字檢視 複製程式碼
Child.uber = Parent.prototype;

為子物件設一個uber屬性,這個屬性直接指向父物件的prototype屬性。

(uber是一個德語詞,意思是"向上"、"上一層"。)這等於在子物件上開啟一條通道,可以直接呼叫父物件的方法。這一行放在這裡,只是為了實現繼承的完備性,純屬備用性質。

相關文章