亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript常見繼承模式實(shí)例小結(jié)

 更新時(shí)間:2019年01月11日 10:52:02   作者:jlu16  
這篇文章主要介紹了JavaScript常見繼承模式,結(jié)合實(shí)例形式總結(jié)分析了javascript原型鏈繼承、構(gòu)造函數(shù)繼承、組合繼承、原型式繼承、寄生式繼承等相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下

本文實(shí)例總結(jié)了JavaScript常見繼承模式。分享給大家供大家參考,具體如下:

JavaScript中并沒(méi)有傳統(tǒng)的面向?qū)ο笳Z(yǔ)言中的類的概念,但是卻實(shí)現(xiàn)了特殊的繼承機(jī)制。

(閱讀此文您首先需要知道原型的知識(shí))

先來(lái)說(shuō)說(shuō)第一種繼承方式,原型鏈繼承。

一. 原型鏈繼承

所謂原型鏈繼承,就是讓父類的一個(gè)實(shí)例作為子類的原型。

即 :

parentInstance = new Parent();
child.prototype = parentInstance;

這樣,在創(chuàng)建子類的實(shí)例時(shí),子類實(shí)例的__proto__指向父類的實(shí)例(即此時(shí)子類構(gòu)造函數(shù)的prototype屬性),而父類實(shí)例的__proto__又指向父類構(gòu)造函數(shù)的prototype屬性。借用這種方式形成了一條原型鏈。

由于JavaScript中搜索實(shí)例中調(diào)用的變量有如下方式:

  1. 在當(dāng)前實(shí)例中尋找變量名
  2. 在當(dāng)前實(shí)例所指向的原型中尋找

假設(shè)原型鏈中有如下繼承關(guān)系:

grandparent(有方法 grandparent.prototype.sayHello) -> parent -> child

當(dāng)在child的實(shí)例child_ming調(diào)用方法 sayHello 時(shí),首先在child_ming中(即只定義在child_ming這一個(gè)實(shí)例中,而非所有實(shí)例中)搜索sayHello,并未找到,然后開始搜索它所指向的原型,即parent的實(shí)例。在parent的實(shí)例中也沒(méi)有此方法,開始搜索parent的原型,即grandparent的實(shí)例。在grandparent的實(shí)例中依然沒(méi)有找到,又搜索grandparent的原型并找到該方法。

可以看出,這樣便實(shí)現(xiàn)了繼承。

如同在使用prototype創(chuàng)建對(duì)象時(shí)遇到的問(wèn)題,倘若完全使用原型鏈進(jìn)行繼承,會(huì)使得一些需要繼承但不需要在不同實(shí)例間進(jìn)行共享的屬性變得不方便實(shí)現(xiàn)。

下面就要說(shuō)一說(shuō)借用構(gòu)造函數(shù)實(shí)現(xiàn)的繼承。

二. 借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承

所謂借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承,即在子類的構(gòu)造函數(shù)中把父類的構(gòu)造函數(shù)借來(lái)使用,以求在子類中生成父類的屬性。

看如下代碼:

function Parent(color){
  this.color = color;
  this.getColor = function(){ alert(this.color); };
}
function Child(color,size){
  Parent.call(this,color);
  this.size = size;
}

這就是一個(gè)簡(jiǎn)單的借用構(gòu)造函數(shù)的繼承。

通過(guò)使用父類的構(gòu)造函數(shù),可以使得同一構(gòu)造函數(shù)的不同的實(shí)例的同一屬性擁有不同的值。解決了原型鏈繼承中的屬性共享的弊端。

然而,如同使用構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí)遇到的問(wèn)題,通過(guò)構(gòu)造函數(shù)生成的方法面臨著重復(fù)定義的問(wèn)題,同一類下的不同實(shí)例擁有各自的方法,而一般來(lái)講方法是需要實(shí)現(xiàn)復(fù)用的,沒(méi)有必要讓它們擁有各自的方法。

使用組合繼承可以解決這個(gè)問(wèn)題。

三. 組合繼承(原型鏈與借用構(gòu)造函數(shù))

既然原型鏈可以實(shí)現(xiàn)屬性共享,借用構(gòu)造函數(shù)可以實(shí)現(xiàn)屬性值的私有,不妨將它們結(jié)合起來(lái),這就形成了組合繼承。

所謂組合繼承,實(shí)際上就是用一次原型鏈繼承,用一次借用構(gòu)造函數(shù)繼承。

看如下代碼:

function Parent(color){
  this.color = color;
}
Parent.prototype.getColor = function(){ alert(this.color); };
function Child(color,size){
  Parent.call(this,color); //借用構(gòu)造函數(shù)繼承屬性
  this.size = size;
}
//下面的屬性'green'并沒(méi)有影響,這里要使用原型繼承方法
Child.prototype = new Parent('green');
var child_demo = new Child('red',200);

首先思考這樣兩個(gè)問(wèn)題,創(chuàng)建一個(gè)child 實(shí)例到底生成了幾份color 屬性?在代碼中既定義了'red' 又定義了 ‘green',當(dāng)調(diào)用 child_demo.getColor() 時(shí),到底會(huì)alert 哪一個(gè)?

首先來(lái)看第一個(gè)問(wèn)題。由于子類構(gòu)造函數(shù)中借用了父類的構(gòu)造函數(shù),在創(chuàng)建子類實(shí)例時(shí)必然會(huì)生成一次color 屬性。但是不要忘記,我們?cè)诶^承方法時(shí)是讓子類構(gòu)造函數(shù)的原型指向一個(gè)父類的實(shí)例,在創(chuàng)建這個(gè)父類實(shí)例時(shí)還要生成一次color 屬性(即上面'green'處),而這個(gè)屬性是完全沒(méi)有必要存在的。所以一共生成了兩份color 屬性,一個(gè)有用一個(gè)沒(méi)用。

再來(lái)看第二個(gè)問(wèn)題。只要能理解this 的含義就可以知道:

child_demo.getColor() // 'red'
Child.prototype.getColor() //'green'

組合繼承結(jié)合了前兩種繼承方式的優(yōu)點(diǎn),但它也有自己的缺點(diǎn)。從生成兩份color 屬性可以知道在繼承過(guò)程中調(diào)用了兩次Parent 的構(gòu)造函數(shù),這會(huì)造成執(zhí)行完成速度的問(wèn)題,影響了效率。但是瑕不掩瑜,這種繼承方式還是成為了JavaScript中最常用的繼承模式。

四. 原型式繼承

原型式繼承是從已有對(duì)象的基礎(chǔ)上繼承,基于已有對(duì)象創(chuàng)建新的對(duì)象。

看如下代碼:

var obj = {
  color: 'red',
  getColor: function(){ alert(this.color); },
};
//getChild(obj)返回的是一個(gè)__proto__指向obj的實(shí)例
function getChild(obj){
  function func(){}
  func.prototype = obj;
  return new func();
}
var child_demo = getChild(obj);

這種繼承方式與原型鏈?zhǔn)降睦^承方式有相同點(diǎn)和不同點(diǎn)。

相同點(diǎn):它們都是通過(guò)改變子類構(gòu)造函數(shù)的原型屬性來(lái)實(shí)現(xiàn)繼承,所繼承的屬性都具有不同實(shí)例共享的特點(diǎn)。

不同點(diǎn):原型鏈繼承中子類構(gòu)造函數(shù)的原型(prototype)是父類的一個(gè)實(shí)例(我們真正需要繼承的東西可能存在于父類構(gòu)造函數(shù)的原型中,也可能存在于直接指向的父類實(shí)例中),而原型式繼承中子類構(gòu)造函數(shù)的原型是一個(gè)已有的對(duì)象,可以說(shuō)直接就是父類。

五. 寄生式繼承

寄生式繼承可以說(shuō)是原型式繼承的變體,它對(duì)原型式繼承進(jìn)行了封裝,使得創(chuàng)建子類實(shí)例只依賴于一個(gè)函數(shù)。

看如下代碼:

var obj = {
  color: 'red',
  getColor: function(){ alert(this.color); },
};
function getChild(obj){
  function func(){}
  func.prototype = obj;
  return new func();
}
/*-------以上是原型式繼承的代碼----------*/
function betterGetChild(obj,size){
  var temp_obj = getChild(obj);
  temp_obj.size = size;
  temp_obj.getSize = function(){ return this.size; };
  return temp_obj;
}
var demo = betterGetChild(obj,200);

六. 寄生組合式繼承

寄生組合式是組合繼承加上原型式繼承的應(yīng)用。由于組合式繼承中子類構(gòu)造函數(shù)的原型指向父類的一個(gè)實(shí)例而非父類構(gòu)造函數(shù)的原型,會(huì)導(dǎo)致設(shè)置子類構(gòu)造函數(shù)的原型時(shí)對(duì)父類的構(gòu)造函數(shù)進(jìn)行一次額外的調(diào)用。所以在寄生式組合繼承中,借用原型式繼承的思想,將父類構(gòu)造函數(shù)的原型當(dāng)作一個(gè)已有對(duì)象,讓子類構(gòu)造函數(shù)的原型直接指向它。

看如下代碼:

function getChild(obj){
  function func(){}
  func.prototype = obj;
  return new func();  //調(diào)用構(gòu)造函數(shù)
}
/*-------以上是原型式繼承的代碼----------*/
function Parent(color){
  this.color = color;
}
Parent.prototype.getColor = function(){
  alert(this.color);
};
function Child(color,size){
  Parent.call(this,color); //調(diào)用構(gòu)造函數(shù)
  this.size = size;
}
//Child.prototype直接指向一個(gè)__proto__指向Parent.prototype的實(shí)例
Child.prototype = getChild(Parent.prototype);
Child.prototype.getSize = function(){ alert(this.size); };

其實(shí)嚴(yán)格來(lái)說(shuō),這種方式也調(diào)用了兩次構(gòu)造函數(shù),但是其中一次構(gòu)造函數(shù)的調(diào)用是對(duì)一個(gè)空函數(shù)的調(diào)用,而不是兩次都調(diào)用父類的構(gòu)造函數(shù)。

在組合繼承中,在子類的原型中其實(shí)還保存有父類的沒(méi)有定義在原型中的屬性(由于子類構(gòu)造函數(shù)的原型是父類的一個(gè)實(shí)例),只不過(guò)是子類構(gòu)造函數(shù)在借用父類構(gòu)造函數(shù)在當(dāng)前實(shí)例中生成了覆蓋原型中那些屬性的屬性。而寄生式組合繼承中,根本不會(huì)產(chǎn)生那些冗余數(shù)據(jù)。

人們普遍認(rèn)為寄生時(shí)組合繼承是最理想的繼承方式。

更多關(guān)于JavaScript相關(guān)內(nèi)容還可查看本站專題:《javascript面向?qū)ο笕腴T教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)

希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。

相關(guān)文章

最新評(píng)論