JavaScript 繼承

admin發表於2018-12-20

JavaScript是一門物件導向的語言,繼承方式與C#和Java等迥然不同。

儘管受到許多人的詬病,但不能否則JavaScript中的繼承更加強大與靈活。

ES2015對繼承方式做了一些表面的修改,實質依然是通過prototype原型實現。

具體參閱JavaScript class 繼承一章節,本文僅對ES5常見的繼承方式進行一下總結。

首先建立一個父類,後面會逐一演示對其各種不同的繼承方式:

[JavaScript] 純文字檢視 複製程式碼
function Web(webName){
  this.webName=webName;
  this.show=function(){
    console.log("網站名稱"+this.webName);
  }
}
Web.prototype.infor=function(url){
  console.log("網站地址是"+url);
}

上面建立一個簡單的父類,下面介紹一下子類對其繼承的各種方式。

一.原型繼承:

關於prototype原型參閱JavaScript prototype 原型一章節。

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function Web(webName){
  this.webName=webName;
  this.show=function(){
    console.log("網站名稱"+this.webName);
  }
}

Web.prototype.infor=function(url){
  console.log("網站地址是"+url);
}

function Antzone(){}
Antzone.prototype=new Web("螞蟻部落");
let ant=new Antzone();

console.log(ant.webName);
console.log(ant.show());
console.log(ant.infor());
console.log(ant instanceof Web);
console.log(ant instanceof Antzone);
console.log(ant.constructor === Antzone);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201812/20/222527ksisjkrygkkkyizx.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).通過prototype原型實現了對父類的繼承,只要將父類例項物件設定為子類的原型物件即可。

(2).原型繼承可以實現原型上的屬性和方法的共享,提高效能。

(3).建立的物件例項是子類的例項也是父類的例項。

最後一個行列印結果為false,ant例項的建構函式分明是Antzone。

constructor屬性繼承自原型物件,原本是指向建構函式的,然後我們用父類例項重置了子類的原型物件。

具體參閱JavaScript constructor一章節,程式碼修改如下:

[JavaScript] 純文字檢視 複製程式碼
function Antzone(){}
Antzone.prototype=new Web("螞蟻部落");
Antzone.prototype.constructor=Antzone;
let ant=new Antzone();

只要重置一下constructor的指向即可。

二.構造繼承:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function Web(webName){
  this.webName=webName;
  this.show=function(){
    return "網站名稱"+this.webName;
  }
}

Web.prototype.infor=function(){
  return "網站資訊";
}

function Antzone(webName){
  Web.call(this,webName);
}
let ant=new Antzone("螞蟻部落");

console.log(ant.webName);
console.log(ant.show());
console.log(ant instanceof Web);
console.log(ant instanceof Antzone);
console.log(ant.infor());

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201812/20/222633da980swxom0a4oxs.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).將父類至於子類之類,然後利用call修改父類的呼叫物件為子類例項物件。

(2).於是子類可以繼承父類的自有屬性和方法,但是無法繼承原型鏈上的例項與方法,所以最後一行報錯。

(3).例項是子類的例項,並非父類的例項(從instanceof返回值來論,後面程式碼也是如此)

(4).每一建立子類例項,都是拷貝一份父類自有屬性與方法,有點浪費資源。

三.例項繼承:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function Web(webName){
  this.webName=webName;
  this.show=function(){
    return "網站名稱"+this.webName;
  }
}

Web.prototype.infor=function(){
  return "網站資訊";
}

function Antzone(webName){
  let instance = new Web(webName);
  instance.address="青島市南區";
  return instance;
}
let ant=new Antzone("螞蟻部落");

console.log(ant.webName);
console.log(ant.show());
console.log(ant instanceof Web);
console.log(ant instanceof Antzone);
console.log(ant.infor());

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201812/20/222703q7fdvzd7e7nhmw2v.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).在子類內建立父類例項,這樣子類就可以繼承父類自有和原型鏈上的方法與屬性。

(2).是父類的例項,不是子類的例項。

(3).每一次建立物件例項也是對父類自有屬性和方法的一次拷貝,有點浪費效能。

四.寄生組合繼承:

[JavaScript] 純文字檢視 複製程式碼執行程式碼
function Web(webName){
  this.webName=webName;
  this.show=function(){
    return "網站名稱"+this.webName;
  }
}

Web.prototype.infor=function(){
  return "網站資訊";
}

function Antzone(webName){
  Web.call(this,webName);
}

(function(){
  let Super = function(){};
  Super.prototype = Web.prototype;
  Antzone.prototype = new Super();
})();

Antzone.prototype.constructor=Antzone;
let ant=new Antzone("螞蟻部落");

console.log(ant.webName);
console.log(ant.show());
console.log(ant instanceof Web);
console.log(ant instanceof Antzone);
console.log(ant.infor());
console.log(ant.constructor === Antzone);

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201812/20/222731c6m6f8gtmpotzm6t.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

程式碼分析如下:

(1).在子類中通過call呼叫父類建構函式,這樣就可以繼承父類的自有屬性與方法。

(2).通過自執行函式,將父類原型物件賦值給空建構函式的Super的原型物件,然後再將子類的原型物件重置為Super物件例項,子類例項也會繼承父類原型物件上的屬性和方法。

(3).由於是重置的子類原型物件,所以還需要重置一下constructor屬性值。

(4).這樣可以共享父類的原型物件,效能還不錯。

相關文章