欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

js實(shí)現(xiàn)繼承的方法及優(yōu)缺點(diǎn)總結(jié)

 更新時(shí)間:2019年05月08日 08:27:10   作者:夏天來(lái)嘍  
這篇文章主要給大家介紹了關(guān)于js實(shí)現(xiàn)繼承的方法及優(yōu)缺點(diǎn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

整理《javascript高級(jí)程序設(shè)計(jì)》中繼承的方法以及優(yōu)缺點(diǎn)。

1. 原型鏈

ECMAScript中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)繼承的主要方法。

原型鏈繼承的基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。

簡(jiǎn)單回顧一下構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針。

那么,假如我們讓原型對(duì)象等于另一個(gè)類型的實(shí)例,結(jié)果會(huì)怎么樣呢?顯然,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型的指針,相應(yīng)地,另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針。假如另一個(gè)原型又是另一個(gè)類型的實(shí)例,那么上述關(guān)系依然成立,如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條。這就是所謂原型鏈的基本概念。

function SuperType() {
 this.property = true;
}
SuperType.prototype.getSuperValue = function () {
 return this.property;
}
function SubType() {
 this.subProperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
 return this.subproperty;
};

var instance = new SubType();
console.log(instance.getSuperValue());  //true

以上代碼定義了兩個(gè)類型:SuperType和SubType。每個(gè)類型分別有一個(gè)屬性和一個(gè)方法。它們的主要區(qū)別是SubType繼承了SuperType,而繼承是通過(guò)創(chuàng)建SuperType的實(shí)例,并將該實(shí)例賦給SubType.prototype實(shí)現(xiàn)的。實(shí)現(xiàn)的本質(zhì)是重寫原型對(duì)象,代之以一個(gè)新類型的實(shí)例。換句話說(shuō),原來(lái)存在于SuperType的實(shí)例中的所有屬性和方法,現(xiàn)在也存在于SubType.prototype中了。在確立了繼承關(guān)系之后,我們給SubType.prototype添加了一個(gè)方法,這樣就在繼承了SuperType的屬性和方法的基礎(chǔ)上又添加了一個(gè)新方法

要注意instance.constructor現(xiàn)在指向的是SuperType,這是因?yàn)樵瓉?lái)SubType.prototype中的constructor被重寫了的緣故。實(shí)際上,不是SubType的原型的constructor屬性被重寫了,而是SubType的原型指向了另一個(gè)對(duì)象——SuperType的原型,而這個(gè)原型對(duì)象的constructor屬性指向的是SuperType

別忘記默認(rèn)的原型

事實(shí)上,前面例子中展示的原型鏈還少一環(huán)。我們知道,所有引用類型默認(rèn)都繼承了Object,而這個(gè)繼承也是通過(guò)原型鏈實(shí)現(xiàn)的。大家要記住,所有函數(shù)的默認(rèn)原型都是Object的實(shí)例,因此默認(rèn)原型都會(huì)包含一個(gè)內(nèi)部指針,指向Object.prototype。這也正是所有自定義類型都會(huì)繼承toString()、valueOf()等默認(rèn)方法的根本原因


原型鏈的問題

原型鏈雖然很強(qiáng)大,可以用它來(lái)實(shí)現(xiàn)繼承,但它也存在一些問題。其中,最主要的問題來(lái)自包含引用類型值的原型

function SuperType(){
 this.colors = ["red", "blue", "green"];
}

function SubType(){
}
//繼承了SuperType
SubType.prototype = new SuperType();

var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);  //"red,blue,green,black"

var instance2 = new SubType();
console.log(instance2.colors);  //"red,blue,green,black"

原型鏈的第二個(gè)問題是:在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。實(shí)際上,應(yīng)該說(shuō)是沒有辦法在不影響所有對(duì)象實(shí)例的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)。有鑒于此,再加上前面剛剛討論過(guò)的由于原型中包含引用類型值所帶來(lái)的問題,實(shí)踐中很少會(huì)單獨(dú)使用原型鏈

2. 借用構(gòu)造函數(shù)

在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)

function SuperType() {
 this.colors = ['red', 'blue', 'green'];
}
function SubType() {
 SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType();
console.log(instance2.colors); //"red,blue,green"

通過(guò)使用call()方法(或apply()方法也可以),我們實(shí)際上是在(未來(lái)將要)新創(chuàng)建的SubType實(shí)例的環(huán)境下調(diào)用了SuperType構(gòu)造函數(shù)。這樣一來(lái),就會(huì)在新SubType對(duì)象上執(zhí)行SuperType()函數(shù)中定義的所有對(duì)象初始化代碼。結(jié)果,SubType的每個(gè)實(shí)例就都會(huì)具有自己的colors屬性的副本了

對(duì)于原型鏈而言,借用構(gòu)造函數(shù)有一個(gè)很大的優(yōu)勢(shì),即可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)

function SuperType() {
 this.colors = ['red', 'blue', 'green'];
}
function SubType() {
 SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType();
console.log(instance2.colors); //"red,blue,green"

借用構(gòu)造函數(shù)問題:

方法都在構(gòu)造函數(shù)中定義,因此函數(shù)復(fù)用就無(wú)從談起了。而且,在超類型的原型中定義的方法,對(duì)子類型而言也是不可見的,結(jié)果所有類型都只能使用構(gòu)造函數(shù)模式

3. 組合繼承

組合繼承(combination inheritance),有時(shí)候也叫做偽經(jīng)典繼承,指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一塊,從而發(fā)揮二者之長(zhǎng)的一種繼承模式。其背后的思路是使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承,而通過(guò)借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承。這樣,既通過(guò)在原型上定義方法實(shí)現(xiàn)了函數(shù)復(fù)用,又能夠保證每個(gè)實(shí)例都有它自己的屬性

function SuperType(name){
 this.name = name;
 this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
 console.log(this.name);
};

function SubType(name, age){ 

 //繼承屬性
 SuperType.call(this, name);
 
 this.age = age;
}

//繼承方法
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
 console.log(this.age);
};

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
console.log(instance1.colors);  //"red,blue,green,black"
instance1.sayName();   //"Nicholas";
instance1.sayAge();   //29

var instance2 = new SubType("Greg", 27);
console.log(instance2.colors);  //"red,blue,green"
instance2.sayName();   //"Greg";
instance2.sayAge();   //27

組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,融合了它們的優(yōu)點(diǎn),成為JavaScript中最常用的繼承模式。而且,instanceof和isPrototypeOf也能夠用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象。

無(wú)論什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部

4. 原型式繼承

這種方法并沒有使用嚴(yán)格意義上的構(gòu)造函數(shù)。借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類型

function object(o){
 function F(){}
 F.prototype = o;
 return new F();
}
var person = {
 name: "Nicholas",
 friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

console.log(person.friends); //"Shelby,Court,Van,Rob,Barbie"

ECMAScript 5通過(guò)新增Object.create()方法規(guī)范化了原型式繼承。這個(gè)方法接收兩個(gè)參數(shù):一個(gè)用作新對(duì)象原型的對(duì)象和(可選的)一個(gè)為新對(duì)象定義額外屬性的對(duì)象。在傳入一個(gè)參數(shù)的情況下,Object.create()與object()方法的行為相同。
Object.create()方法的第二個(gè)參數(shù)與Object.defineProperties()方法的第二個(gè)參數(shù)格式相同:每個(gè)屬性都是通過(guò)自己的描述符定義的。以這種方式指定的任何屬性都會(huì)覆蓋原型對(duì)象上的同名屬性

var person = {
 name: "Nicholas",
 friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = Object.create(person, {
 name: {
  value: "Greg"
 }
});

console.log(anotherPerson.name); //"Greg"

在沒有必要興師動(dòng)眾地創(chuàng)建構(gòu)造函數(shù),而只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類似的情況下,原型式繼承是完全可以勝任的。不過(guò)別忘了,包含引用類型值的屬性始終都會(huì)共享相應(yīng)的值,就像使用原型模式一樣

5. 寄生式繼承

創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方式來(lái)增強(qiáng)對(duì)象,最后再像真的是它做了所有工作一樣返回對(duì)象

function createAnother(original){
 var clone = Object.create(original); //通過(guò)調(diào)用函數(shù)創(chuàng)建一個(gè)新對(duì)象
 clone.sayHi = function(){   //以某種方式來(lái)增強(qiáng)這個(gè)對(duì)象
  console.log("hi");
 };
 return clone;     //返回這個(gè)對(duì)象
}

在這個(gè)例子中,createAnother()函數(shù)接收了一個(gè)參數(shù),也就是將要作為新對(duì)象基礎(chǔ)的對(duì)象。然后,把這個(gè)對(duì)象(original)傳遞給object()函數(shù),將返回的結(jié)果賦值給clone。再為clone對(duì)象添加一個(gè)新方法sayHi(),最后返回clone對(duì)象。可以像下面這樣來(lái)使用createAnother()函數(shù):

var person = {
 name: "Nicholas",
 friends: ["Shelby", "Court", "Van"]
};

var anotherPerson = createAnother(person);
anotherPerson.sayHi(); //"hi"

這個(gè)例子中的代碼基于person返回了一個(gè)新對(duì)象——anotherPerson。新對(duì)象不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法

使用寄生式繼承來(lái)為對(duì)象添加函數(shù),會(huì)由于不能做到函數(shù)復(fù)用而降低效率;這一點(diǎn)與構(gòu)造函數(shù)模式類似

6. 寄生組合式繼承

前面說(shuō)過(guò),組合繼承是JavaScript最常用的繼承模式;不過(guò),它也有自己的不足。組合繼承最大的問題就是無(wú)論什么情況下,都會(huì)調(diào)用兩次超類型構(gòu)造函數(shù):一次是在創(chuàng)建子類型原型的時(shí)候,另一次是在子類型構(gòu)造函數(shù)內(nèi)部。沒錯(cuò),子類型最終會(huì)包含超類型對(duì)象的全部實(shí)例屬性,但我們不得不在調(diào)用子類型構(gòu)造函數(shù)時(shí)重寫這些屬性。再來(lái)看一看下面組合繼承的例子

function SuperType(name){
 this.name = name;
 this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
 console.log(this.name);
};

function SubType(name, age){ 
 SuperType.call(this, name);   //第二次調(diào)用SuperType()

 this.age = age;
}

SubType.prototype = new SuperType(); //第一次調(diào)用SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
 console.log(this.age);
};

在第一次調(diào)用SuperType構(gòu)造函數(shù)時(shí),SubType.prototype會(huì)得到兩個(gè)屬性:name和colors;它們都是SuperType的實(shí)例屬性,只不過(guò)現(xiàn)在位于SubType的原型中。當(dāng)調(diào)用SubType構(gòu)造函數(shù)時(shí),又會(huì)調(diào)用一次SuperType構(gòu)造函數(shù),這一次又在新對(duì)象上創(chuàng)建了實(shí)例屬性name和colors,于是,這兩個(gè)屬性就屏蔽了原型中的兩個(gè)同名屬性

如上圖所示,有兩組name和colors屬性:一組在實(shí)例上,一組在SubType原型中。這就是調(diào)用兩次SuperType構(gòu)造函數(shù)的結(jié)果。好在我們已經(jīng)找到了解決這個(gè)問題方法——寄生組合式繼承。

所謂寄生組合式繼承,即通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。

其背后的基本思路是:不必為了指定子類型的原型而調(diào)用超類型的構(gòu)造函數(shù),我們所需要的無(wú)非就是超類型原型的一個(gè)副本而已。本質(zhì)上,就是使用寄生式繼承來(lái)繼承超類型的原型,然后再將結(jié)果指定給子類型的原型。寄生組合式繼承的基本模式如下所示

function inheritPrototype(subType, superType){
 var prototype = Object.create(superType.prototype);  //創(chuàng)建對(duì)象
 prototype.constructor = subType;     //增強(qiáng)對(duì)象
 subType.prototype = prototype;      //指定對(duì)象
}

這個(gè)示例中的inheritPrototype()函數(shù)實(shí)現(xiàn)了寄生組合式繼承的最簡(jiǎn)單形式。這個(gè)函數(shù)接收兩個(gè)參數(shù):子類型構(gòu)造函數(shù)和超類型構(gòu)造函數(shù)。在函數(shù)內(nèi)部,第一步是創(chuàng)建超類型原型的一個(gè)副本。第二步是為創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)因重寫原型而失去的默認(rèn)的constructor屬性。最后一步,將新創(chuàng)建的對(duì)象(即副本)賦值給子類型的原型。這樣,我們就可以用調(diào)用inheritPrototype()函數(shù)的語(yǔ)句,去替換前面例子中為子類型原型賦值的語(yǔ)句了

function SuperType(name){
 this.name = name;
 this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
 console.log(this.name);
};

function SubType(name, age){ 
 SuperType.call(this, name);

 this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function(){
 console.log(this.age);
};

這個(gè)例子的高效率體現(xiàn)在它只調(diào)用了一次SuperType構(gòu)造函數(shù),并且因此避免了在SubType.prototype上面創(chuàng)建不必要的、多余的屬性。與此同時(shí),原型鏈還能保持不變;因此,還能夠正常使用instanceof和isPrototypeOf()。開發(fā)人員普遍認(rèn)為寄生組合式繼承是引用類型最理想的繼承范式。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Laydate時(shí)間組件在火狐瀏覽器下有多時(shí)間輸入框時(shí)只能給第一個(gè)輸入框賦值的解決方法

    Laydate時(shí)間組件在火狐瀏覽器下有多時(shí)間輸入框時(shí)只能給第一個(gè)輸入框賦值的解決方法

    這篇文章主要介紹了Laydate時(shí)間組件在火狐瀏覽器下有多時(shí)間輸入框時(shí)只能給第一個(gè)輸入框賦值的解決方法,需要的朋友可以參考下
    2016-08-08
  • 微信小程序?qū)崿F(xiàn)滑動(dòng)/點(diǎn)擊切換Tab及scroll-left的使用

    微信小程序?qū)崿F(xiàn)滑動(dòng)/點(diǎn)擊切換Tab及scroll-left的使用

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)滑動(dòng)/點(diǎn)擊切換Tab,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • js字符串替換所有的指定字符或文字(推薦replaceAll方法)

    js字符串替換所有的指定字符或文字(推薦replaceAll方法)

    要實(shí)現(xiàn)js字符串替換所有的某個(gè)字符,推薦大家使用replaceAll方法,默認(rèn)不是所有瀏覽器都兼容,所以這里給出一個(gè)解決方案,需要的朋友可以參考下
    2014-07-07
  • 詳解基于Bootstrap扁平化的后臺(tái)框架Ace

    詳解基于Bootstrap扁平化的后臺(tái)框架Ace

    Bootstrap是Twitter 于2010年開發(fā)出來(lái)的前端框架,用過(guò)的同學(xué)應(yīng)該知道,這款前端框架不僅界面很美觀,而且兼容了很多的瀏覽器,大大加速了我們開發(fā)網(wǎng)站的速度,本文給大家介紹基于Bootstrap扁平化的后臺(tái)框架Ace,需要的朋友參考下
    2015-11-11
  • 微信小程序?qū)D片進(jìn)行canvas壓縮的方法示例詳解

    微信小程序?qū)D片進(jìn)行canvas壓縮的方法示例詳解

    這篇文章主要給大家介紹了關(guān)于微信小程序?qū)D片進(jìn)行canvas壓縮的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • js實(shí)現(xiàn)3D旋轉(zhuǎn)相冊(cè)

    js實(shí)現(xiàn)3D旋轉(zhuǎn)相冊(cè)

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)3D旋轉(zhuǎn)相冊(cè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • JavaScript 實(shí)現(xiàn)HTML DOM增刪改查操作的常見方法詳解

    JavaScript 實(shí)現(xiàn)HTML DOM增刪改查操作的常見方法詳解

    這篇文章主要介紹了JavaScript 實(shí)現(xiàn)HTML DOM增刪改查操作,結(jié)合實(shí)例形式分析了JavaScript針對(duì)HTML DOM元素增刪改查常見操作技巧與使用注意事項(xiàng),需要的朋友可以參考下
    2020-01-01
  • 利用Bootstrap實(shí)現(xiàn)表格復(fù)選框checkbox全選

    利用Bootstrap實(shí)現(xiàn)表格復(fù)選框checkbox全選

    Bootstrap相信應(yīng)該不用多介紹,來(lái)自 Twitter,是目前最受歡迎的前端框架。這篇文章主要給大家介紹了如何利用Bootstrap實(shí)現(xiàn)表格中的checkbox復(fù)選框全選效果,文中給出詳細(xì)的介紹及完整的實(shí)例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,下面來(lái)一起看看吧。
    2016-12-12
  • JavaScript 動(dòng)態(tài)三角函數(shù)實(shí)例詳解

    JavaScript 動(dòng)態(tài)三角函數(shù)實(shí)例詳解

    本文通過(guò)實(shí)例代碼給大家實(shí)例講解了javascript動(dòng)態(tài)三角函數(shù)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下
    2017-01-01
  • Javascript日期時(shí)間函數(shù)的使用方法舉例

    Javascript日期時(shí)間函數(shù)的使用方法舉例

    在JavaScript中日期時(shí)間函數(shù)是一組用于操作和處理日期和時(shí)間的函數(shù),這些函數(shù)可以用于獲取當(dāng)前日期和時(shí)間、格式化日期和時(shí)間、計(jì)算日期和時(shí)間的差異、轉(zhuǎn)換日期和時(shí)間的格式等,這篇文章主要給大家介紹了關(guān)于Javascript日期時(shí)間函數(shù)的使用方法,需要的朋友可以參考下
    2024-02-02

最新評(píng)論