国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript面向對象---原型鏈繼承

vspiders / 2950人閱讀

摘要:因為這造成了繼承鏈的紊亂,因為的實例是由構造函數創建的,現在其屬性卻指向了為了避免這一現象,就必須在替換對象之后,為新的對象加上屬性,使其指向原來的構造函數。這個函數接收兩個參數子類型構造函數和超類型構造函數。

最近一直在研究js面向對象,原型鏈繼承是一個難點,下面是我對繼承的理解
以下文章借鑒自CSDN季詩筱的博客

原型鏈繼承的基本概念:

ES中描述了原型鏈的概念,并將原型鏈作為實現繼承的主要方法;
基本思想:利用一個引用類型繼承另一個引用類型的屬性和方法:
簡單回顧下: 構造函數 -- 原型 -- 實例 三者之間的關系
構造函數:function Person(){}
每個構造函數都有一個原型對象(Person.prototype),
原型對象都包含一個指向構造函數的指針(constructor),
(其實原型對象也是一個對象,也有一個 __proto__ 指針,指向他所繼承的對象)
而實例都包含著一個指向圓形對象的內部指針([[prototye]] 又稱__proto__);
每個實例也有一個constructor屬性默認調用原型對象的constructor屬性(!!!)

原型鏈繼承的核心

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

另一個原型對象中也包含著指向另一個構造函數的指針。那么上述關系依然成立,如此層層遞進,就構成了實例與原型的鏈條。這就是所謂原型鏈的基本概念!

如上如所示,這種關系直到 當某個原型對象的 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

以上代碼定義了兩個類型:SuperType 和 SubType.
每個類型分別有一個屬性和方法
他們的主要區別是SubType繼承了SuperType,而繼承是通過創建SuperType的實例,并將該實例賦值給SubType.prototype實現的
實現的本質是重寫原型對象,代之以一個新類型的實例
換句話說,原來存在于SuberType的實例中的所有屬性和方法,現在存在于SubType.prototype中了。
在確立了繼承關系之后,我們給SubType.prototype添加了一個方法,,這樣就在繼承了SuperType的屬性和方法的基礎上又添加了一個新方法。
這個例子的實例以及構造函數和原型之間的關系如下圖所示
圖:

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

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

原型鏈存在的問題

原型鏈雖然很強大,可以用它實現繼承,但也存在一些問題。

其中,最主要的問題來自包含引用類型值的原型。
想必大家還記得,我們前面介紹過包含引用類型值的屬性會被所有實例共享;而這也正是為什么要在構造函數中,而不是在原型對象中定義屬性的原因。

在通過原型來實現繼承時,原型實際上會變成另一個類型的實例。于是原先的實例屬性也就順理成章地變成了現在的原型屬性了.
例子說明問題:

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

這個例子中的SuperType構造函數定義了一個colors屬性,該屬性包括一個數組(引用類型值)。SuperType的每個實例都會有各自包含自己數組的colors屬性。當SubType通過原型鏈繼承了SuperType之后,SubType.prototype就變成了SuperType的一個實例,因此他也擁有了一個他自己的colors屬性-----就跟專門創建了一個SubType.prototype.colors屬性一樣。
但結果是什么呢? 所有實例都會共享這個colors屬性!!!

問題1:結果是SubType的所有實例都會共享這一個colors屬性。而我們對instance1.colors的修改能夠通過instance2.colors反映出來,就已經充分證明這一點了

問題2:在創建自定義類型的時候,不能向超類型的構造函數中傳遞參數。
實際上,應該說是沒有辦法在不影響所有實例的情況下,給超類型構造函數傳遞參數。
有鑒于此,在加上前面剛剛討論的由于原型中所包含引用類型值所帶來的問題,實踐中中很少多帶帶使用原型鏈

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

1.借用構造函數
2.組合式繼承
3.原型式繼承
4.寄生式繼承
5.寄生組合式繼承

這里來談一下最常用的組合式繼承和寄生組合式繼承

組合式繼承:

組合繼承,有時候也叫做經典繼承,指的是將原型鏈和借用構造函數的技術組合到一起,從而發揮二者之長的一種繼承模式。
其背后的思路是使用原型鏈實現對原型屬性和方法的繼承,而通過借用構造函數來實現對實例的屬性的繼承
請看例子:

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);   //繼承屬性, 第二次調用SuperType
    this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();       //第一次調用SuperType
SubType.prototype.constructor = SubType(); // 相當重要,此處
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構造函數定義了兩個屬性:name 和 colors。SuperType的原型定義了一個方法sayName()
SubType構造函數在調用SuperType構造函數傳入了name參數,緊接著又定義了他自己的屬性age,然后,將SuperType的實例賦值給SubType的原型,然后又在該新原型上定義了方法sayAge()方法
這樣一來,就可以讓兩個不同的SubType實例既分別擁有自己屬性和公共的colors屬性,又可以使用相同的方法
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,成為js中最常用的繼承模式。
而且 instanceof和isPrototypeOf()也能夠用于識別基于組合繼承創建的對象
**另外說一下:

1.任何一個Prototype對象都有一個constructor指針,指向它的構造函數
2.每個實例中也會有一個constructor指針,這個指針默認調用Prototype對象的constructor屬性。
結果:當替換了子類的原型之后,即 SubType.prototype = new SuperType()之后,
SubType.prototype.constructor 就指向了SuperType(),
SubType的實例的constructor也指向了SuperType(),這就出現問題了。

因為這造成了繼承鏈的紊亂,因為SubType的實例是由SubType構造函數創建的,現在其constructor屬性卻指向了SuperType,為了避免這一現象,就必須在替換prototype對象之后,為新的prototype對象加上constructor屬性,使其指向原來的構造函數。

組合式繼承的缺點
組合繼承最大的問題就是無論在什么情況下,都會兩次調用超類型構造函數;
一次是在創建子類型的原型的時候,
另一次是在子類型構造函數內部。
沒錯子類型最終會包含超類型對象的全部實例屬性,但我們不得不在調用子類構造函數時重寫這些屬性

寄生組合式繼承

此種模式解決了組合式繼承的缺點
原理:通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。
思路:不必為了指定子類的原型而調用超類型的構造函數,我們所需要的無非就是超類型原型的一個副本而已

本質上,就是使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。

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

function inheritPrototype(subType,superType){
    var prototype = object(superType.prototype);    // 創建對象
    prototype.constructor = subType;                // 增強對象
    subType.prototype = prototype;                  // 指定對象
}

這個示例中的inheritPrototype()函數實現了寄生式組合繼承的最簡單形式。
這個函數接收兩個參數:子類型構造函數和超類型構造函數。
在函數內部:
第一步:是創建超類型原型的一個副本
第二步:為創建的副本添加constructor屬性,從而彌補因失去原型而失去的默認的constructor屬性
第三步:將創建的對象(即副本)賦值給子類型的原型。
這樣,我們就可以調用inherit-Protoype()函數的語句,去替換前面例中為了子類型原型賦值的語句了

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

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;
}
//調用此方法代替前面賦值語句,可解決兩次調用超類型構造函數的問題
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

優點:
這個例子的高效率體現在他只調用了一次SuperType構造函數,
并且因此避免了在SubType.prototype上面創建不必要的,多余的屬性。
與此同時,原型鏈還能保持不變
因此,還能正常使用instanceof 和 isPrototypeOf()。
開發人員普遍認為寄生式組合式繼承是引用類型最理想的繼承范式

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81113.html

相關文章

  • 面向對象JavaScript

    摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...

    novo 評論0 收藏0
  • JS對象(1)重新認識面向對象

    摘要:對象重新認識面向對象面向對象從設計模式上看,對象是計算機抽象現實世界的一種方式。除了字面式聲明方式之外,允許通過構造器創建對象。每個構造器實際上是一個函數對象該函數對象含有一個屬性用于實現基于原型的繼承和共享屬性。 title: JS對象(1)重新認識面向對象 date: 2016-10-05 tags: JavaScript 0x00 面向對象 從設計模式上看,對象是...

    superw 評論0 收藏0
  • SegmentFault 技術周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

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

    李昌杰 評論0 收藏0
  • SegmentFault 技術周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

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

    Lyux 評論0 收藏0
  • SegmentFault 技術周刊 Vol.32 - 七夕將至,你的“對象”還好嗎?

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

    AaronYuan 評論0 收藏0
  • 前端進擊的巨人(七):走進面向對象原型原型繼承方式

    摘要:除了以上介紹的幾種對象創建方式,此外還有寄生構造函數模式穩妥構造函數模式。 showImg(https://segmentfault.com/img/remote/1460000018196128); 面向對象 是以 對象 為中心的編程思想,它的思維方式是構造。 面向對象 編程的三大特點:封裝、繼承、多態: 封裝:屬性方法的抽象 繼承:一個類繼承(復制)另一個類的屬性/方法 多態:方...

    wums 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<