亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript面向?qū)ο?--原型鏈繼承

vspiders / 3008人閱讀

摘要:因?yàn)檫@造成了繼承鏈的紊亂,因?yàn)榈膶?shí)例是由構(gòu)造函數(shù)創(chuàng)建的,現(xiàn)在其屬性卻指向了為了避免這一現(xiàn)象,就必須在替換對(duì)象之后,為新的對(duì)象加上屬性,使其指向原來(lái)的構(gòu)造函數(shù)。這個(gè)函數(shù)接收兩個(gè)參數(shù)子類(lèi)型構(gòu)造函數(shù)和超類(lèi)型構(gòu)造函數(shù)。

最近一直在研究js面向?qū)ο?,原型鏈繼承是一個(gè)難點(diǎn),下面是我對(duì)繼承的理解
以下文章借鑒自CSDN季詩(shī)筱的博客

原型鏈繼承的基本概念:

ES中描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)繼承的主要方法;
基本思想:利用一個(gè)引用類(lèi)型繼承另一個(gè)引用類(lèi)型的屬性和方法:
簡(jiǎn)單回顧下: 構(gòu)造函數(shù) -- 原型 -- 實(shí)例 三者之間的關(guān)系
構(gòu)造函數(shù):function Person(){}
每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象(Person.prototype),
原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針(constructor),
(其實(shí)原型對(duì)象也是一個(gè)對(duì)象,也有一個(gè) __proto__ 指針,指向他所繼承的對(duì)象)
而實(shí)例都包含著一個(gè)指向圓形對(duì)象的內(nèi)部指針([[prototye]] 又稱(chēng)__proto__);
每個(gè)實(shí)例也有一個(gè)constructor屬性默認(rèn)調(diào)用原型對(duì)象的constructor屬性(!?。。?/p>

原型鏈繼承的核心

讓原型對(duì)象等于另一個(gè)構(gòu)造函數(shù)的實(shí)例, 顯然,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)原型對(duì)象的指針([[prototype]]),從而擁有該原型對(duì)象的屬性和方法

另一個(gè)原型對(duì)象中也包含著指向另一個(gè)構(gòu)造函數(shù)的指針。那么上述關(guān)系依然成立,如此層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條。這就是所謂原型鏈的基本概念!

如上如所示,這種關(guān)系直到 當(dāng)某個(gè)原型對(duì)象的 contructor屬性指向 Object 為止

1.原型鏈繼承基本模式:
function SuperType(){
    this.prototype = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
}

function SubType(){
    this.subproperty = false;
}
//繼承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
    return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());  //true

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

在上面的代碼中,我們沒(méi)有使用SubType默認(rèn)提供的原型,而是給他換了一個(gè)新原型;
這個(gè)原型就是SuperType的實(shí)例。
于是,新原型不僅有作為一個(gè)SuperType的實(shí)例所擁有的全部屬性和方法,而且內(nèi)部還有一個(gè)指針,指向了SuperType的原型。
最終結(jié)果是這樣的:instace指向SubType的原型,SubType的原型又指向SuperType的原型。

在通過(guò)原型鏈繼承的情況下,搜索過(guò)程就得以沿著原型鏈繼續(xù)向上。就拿上面的例子來(lái)說(shuō),調(diào)用instance.getSuperValue()會(huì)經(jīng)歷三個(gè)步驟:
1.搜索實(shí)例
2.搜索SubType.prototype
3.搜索SuperType.prototype
最后一步才會(huì)找到該方法,再找不到該屬性或方法的情況下,搜索過(guò)程總是要一環(huán)一環(huán)地前行到原型鏈末端才會(huì)停下來(lái).
別忘記默認(rèn)原型Object
事實(shí)上前面例子中展示的原型鏈還少一環(huán),我們知道,所有引用類(lèi)型都默認(rèn)繼承了Object,而這個(gè)繼承也是通過(guò)原型鏈實(shí)現(xiàn)的。
大家記住,所有函數(shù)的默認(rèn)原型都是Object的實(shí)例,因此默認(rèn)原型內(nèi)部都會(huì)包含一個(gè)指針,指向Object.prototype。這也正是所有自定義類(lèi)型都會(huì)繼承toString()等默認(rèn)方法的根本原因.

原型鏈存在的問(wèn)題

原型鏈雖然很強(qiáng)大,可以用它實(shí)現(xiàn)繼承,但也存在一些問(wèn)題。

其中,最主要的問(wèn)題來(lái)自包含引用類(lèi)型值的原型。
想必大家還記得,我們前面介紹過(guò)包含引用類(lèi)型值的屬性會(huì)被所有實(shí)例共享;而這也正是為什么要在構(gòu)造函數(shù)中,而不是在原型對(duì)象中定義屬性的原因。

在通過(guò)原型來(lái)實(shí)現(xiàn)繼承時(shí),原型實(shí)際上會(huì)變成另一個(gè)類(lèi)型的實(shí)例。于是原先的實(shí)例屬性也就順理成章地變成了現(xiàn)在的原型屬性了.
例子說(shuō)明問(wèn)題:

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

}
SubType.prototype = new SuperType();    // 繼承了SuperType
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors);    //  red,blue,green,black
var instance2 = new SubType();
alert(instance2.colors);    //  red,blue,green,black

這個(gè)例子中的SuperType構(gòu)造函數(shù)定義了一個(gè)colors屬性,該屬性包括一個(gè)數(shù)組(引用類(lèi)型值)。SuperType的每個(gè)實(shí)例都會(huì)有各自包含自己數(shù)組的colors屬性。當(dāng)SubType通過(guò)原型鏈繼承了SuperType之后,SubType.prototype就變成了SuperType的一個(gè)實(shí)例,因此他也擁有了一個(gè)他自己的colors屬性-----就跟專(zhuān)門(mén)創(chuàng)建了一個(gè)SubType.prototype.colors屬性一樣。
但結(jié)果是什么呢? 所有實(shí)例都會(huì)共享這個(gè)colors屬性?。。?/p>

問(wèn)題1:結(jié)果是SubType的所有實(shí)例都會(huì)共享這一個(gè)colors屬性。而我們對(duì)instance1.colors的修改能夠通過(guò)instance2.colors反映出來(lái),就已經(jīng)充分證明這一點(diǎn)了

問(wèn)題2:在創(chuàng)建自定義類(lèi)型的時(shí)候,不能向超類(lèi)型的構(gòu)造函數(shù)中傳遞參數(shù)。
實(shí)際上,應(yīng)該說(shuō)是沒(méi)有辦法在不影響所有實(shí)例的情況下,給超類(lèi)型構(gòu)造函數(shù)傳遞參數(shù)。
有鑒于此,在加上前面剛剛討論的由于原型中所包含引用類(lèi)型值所帶來(lái)的問(wèn)題,實(shí)踐中中很少多帶帶使用原型鏈

2.原型鏈繼承缺陷的解決方法(紅寶書(shū))

1.借用構(gòu)造函數(shù)
2.組合式繼承
3.原型式繼承
4.寄生式繼承
5.寄生組合式繼承

這里來(lái)談一下最常用的組合式繼承和寄生組合式繼承

組合式繼承:

組合繼承,有時(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í)例的屬性的繼承
請(qǐng)看例子:

function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
    alert(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(); // 相當(dāng)重要,此處
SubType.prototype.sayAge = function(){
    alert(this.age);
}
var instance1 = new SubType("leo",29);
instance1.colors.push("black");
alert(instance1.colors);  // r,b,g,b
instance1.sayName();      // leo
instance1.sayAge();       // 29

var instance2 = new SubType("lck",34);
alert(instance2.colors);  // r,b,g
instance2.sayName();      // lck
instance2.sayAge();       // 34

在例子中,SuperType構(gòu)造函數(shù)定義了兩個(gè)屬性:name 和 colors。SuperType的原型定義了一個(gè)方法sayName()。
SubType構(gòu)造函數(shù)在調(diào)用SuperType構(gòu)造函數(shù)傳入了name參數(shù),緊接著又定義了他自己的屬性age,然后,將SuperType的實(shí)例賦值給SubType的原型,然后又在該新原型上定義了方法sayAge()方法,
這樣一來(lái),就可以讓兩個(gè)不同的SubType實(shí)例既分別擁有自己屬性和公共的colors屬性,又可以使用相同的方法
組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,融合了他們的優(yōu)點(diǎn),成為js中最常用的繼承模式。
而且 instanceof和isPrototypeOf()也能夠用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象
**另外說(shuō)一下:

1.任何一個(gè)Prototype對(duì)象都有一個(gè)constructor指針,指向它的構(gòu)造函數(shù);
2.每個(gè)實(shí)例中也會(huì)有一個(gè)constructor指針,這個(gè)指針默認(rèn)調(diào)用Prototype對(duì)象的constructor屬性。
結(jié)果:當(dāng)替換了子類(lèi)的原型之后,即 SubType.prototype = new SuperType()之后,
SubType.prototype.constructor 就指向了SuperType(),
SubType的實(shí)例的constructor也指向了SuperType(),這就出現(xiàn)問(wèn)題了。

因?yàn)檫@造成了繼承鏈的紊亂,因?yàn)镾ubType的實(shí)例是由SubType構(gòu)造函數(shù)創(chuàng)建的,現(xiàn)在其constructor屬性卻指向了SuperType,為了避免這一現(xiàn)象,就必須在替換prototype對(duì)象之后,為新的prototype對(duì)象加上constructor屬性,使其指向原來(lái)的構(gòu)造函數(shù)。

組合式繼承的缺點(diǎn)
組合繼承最大的問(wèn)題就是無(wú)論在什么情況下,都會(huì)兩次調(diào)用超類(lèi)型構(gòu)造函數(shù);
一次是在創(chuàng)建子類(lèi)型的原型的時(shí)候,
另一次是在子類(lèi)型構(gòu)造函數(shù)內(nèi)部。
沒(méi)錯(cuò)子類(lèi)型最終會(huì)包含超類(lèi)型對(duì)象的全部實(shí)例屬性,但我們不得不在調(diào)用子類(lèi)構(gòu)造函數(shù)時(shí)重寫(xiě)這些屬性

寄生組合式繼承

此種模式解決了組合式繼承的缺點(diǎn)
原理:通過(guò)借用構(gòu)造函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法。
思路:不必為了指定子類(lèi)的原型而調(diào)用超類(lèi)型的構(gòu)造函數(shù),我們所需要的無(wú)非就是超類(lèi)型原型的一個(gè)副本而已。

本質(zhì)上,就是使用寄生式繼承來(lái)繼承超類(lèi)型的原型,然后再將結(jié)果指定給子類(lèi)型的原型。

寄生式組合繼承的基本模式如下所示:

function inheritPrototype(subType,superType){
    var prototype = object(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ù):子類(lèi)型構(gòu)造函數(shù)和超類(lèi)型構(gòu)造函數(shù)。
在函數(shù)內(nèi)部:
第一步:是創(chuàng)建超類(lèi)型原型的一個(gè)副本
第二步:為創(chuàng)建的副本添加constructor屬性,從而彌補(bǔ)因失去原型而失去的默認(rèn)的constructor屬性
第三步:將創(chuàng)建的對(duì)象(即副本)賦值給子類(lèi)型的原型。
這樣,我們就可以調(diào)用inherit-Protoype()函數(shù)的語(yǔ)句,去替換前面例中為了子類(lèi)型原型賦值的語(yǔ)句了

實(shí)例如下:
//借助原型可以基于已有對(duì)象創(chuàng)建新對(duì)象
function object(o){
    var F = function(){};    // 創(chuàng)建一個(gè)空對(duì)象
    F.prototype = o;
    return new F();          //返回出一個(gè)實(shí)例對(duì)象
}
//寄生式組合繼承
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);  //創(chuàng)建父構(gòu)造函數(shù)實(shí)例對(duì)象副本
    prototype.constructor = subType;    // 重寫(xiě)將子類(lèi)原型對(duì)象的constructor屬性
    subType.prototype = prototype;     // 父類(lèi)實(shí)例賦值給子類(lèi)原型
};         

function SuperType(name){
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};
function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}
//調(diào)用此方法代替前面賦值語(yǔ)句,可解決兩次調(diào)用超類(lèi)型構(gòu)造函數(shù)的問(wèn)題
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
   alert(this.age);
}; 
var instance1 = new SubType("lck",29);  console.log(instance1.name,instance1.age,instance1.colors); // lck,29,r,b,g
instance1.sayName();  // lck
instance1.sayAge()   // 29

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

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/81113.html

相關(guān)文章

  • 面向對(duì)象JavaScript

    摘要:是完全的面向?qū)ο笳Z(yǔ)言,它們通過(guò)類(lèi)的形式組織函數(shù)和變量,使之不能脫離對(duì)象存在。而在基于原型的面向?qū)ο蠓绞街?,?duì)象則是依靠構(gòu)造器利用原型構(gòu)造出來(lái)的。 JavaScript 函數(shù)式腳本語(yǔ)言特性以及其看似隨意的編寫(xiě)風(fēng)格,導(dǎo)致長(zhǎng)期以來(lái)人們對(duì)這一門(mén)語(yǔ)言的誤解,即認(rèn)為 JavaScript 不是一門(mén)面向?qū)ο蟮恼Z(yǔ)言,或者只是部分具備一些面向?qū)ο蟮奶卣?。本文將回歸面向?qū)ο蟊疽?,從?duì)語(yǔ)言感悟的角度闡述為什...

    novo 評(píng)論0 收藏0
  • JS對(duì)象(1)重新認(rèn)識(shí)面向對(duì)象

    摘要:對(duì)象重新認(rèn)識(shí)面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對(duì)象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過(guò)構(gòu)造器創(chuàng)建對(duì)象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對(duì)象該函數(shù)對(duì)象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對(duì)象(1)重新認(rèn)識(shí)面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對(duì)象是...

    superw 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    李昌杰 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    Lyux 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.32 - 七夕將至,你的“對(duì)象”還好嗎?

    摘要:很多情況下,通常一個(gè)人類(lèi),即創(chuàng)建了一個(gè)具體的對(duì)象。對(duì)象就是數(shù)據(jù),對(duì)象本身不包含方法。類(lèi)是相似對(duì)象的描述,稱(chēng)為類(lèi)的定義,是該類(lèi)對(duì)象的藍(lán)圖或原型。在中,對(duì)象通過(guò)對(duì)類(lèi)的實(shí)體化形成的對(duì)象。一類(lèi)的對(duì)象抽取出來(lái)。注意中,對(duì)象一定是通過(guò)類(lèi)的實(shí)例化來(lái)的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...

    AaronYuan 評(píng)論0 收藏0
  • 前端進(jìn)擊的巨人(七):走進(jìn)面向對(duì)象,原型原型繼承方式

    摘要:除了以上介紹的幾種對(duì)象創(chuàng)建方式,此外還有寄生構(gòu)造函數(shù)模式穩(wěn)妥構(gòu)造函數(shù)模式。 showImg(https://segmentfault.com/img/remote/1460000018196128); 面向?qū)ο?是以 對(duì)象 為中心的編程思想,它的思維方式是構(gòu)造。 面向?qū)ο?編程的三大特點(diǎn):封裝、繼承、多態(tài): 封裝:屬性方法的抽象 繼承:一個(gè)類(lèi)繼承(復(fù)制)另一個(gè)類(lèi)的屬性/方法 多態(tài):方...

    wums 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<