首頁 web前端 js教程 JS Pro-深入物件導向的程式設計之繼承的詳解_javascript技巧

JS Pro-深入物件導向的程式設計之繼承的詳解_javascript技巧

May 16, 2016 pm 05:34 PM
js 繼承 物件導向

原型鏈(prototype chaining):

利用原型來繼承屬性和方法。回顧一下建構子(constructor),原型物件(prototype)和實例(instance)的關係。每一個建構函數都有一個prototype屬性,該屬性指向一個prototype物件;prototype物件也有constructor屬性,指向該函數;而實例也有一個內部指標(__proto__)指向這個prototype物件。如果這個prototype物件是另一個物件的實例會是怎樣的呢?這樣該prototype物件就包含一個指向另一個類型的指針,相應地,另一個原型中也包含著一個指向另一個建構函數的指針。

JS的繼承很簡單,就是把子類別的prototype設為父類別的一個(實例化)物件

複製程式碼



複製程式碼


程式碼如下:


function SuperType(){
    this.property = true;
}

SuperType.prototype.get
}

SuperType.prototype.get. >    return this.property;
};

function SubType(){
    this.subproperty = false;
}
SubType.prototype.getSubValue = function (){

    return this.subproperty;

} Sub

alert(instance.getSuperValue());   //true

最終的結果:instance的__proto__指向SubType.prototype對象,而SubType.prototype對象的__proto__屬性又指向SuperType.prototype物件。 getSuperValue()是一個方法,所以仍然存在於原型中,而property是一個實例屬性,所以現在存在於SubType.prototype這個實例中。  instance.constructor現在指向的是SuperType,這是由於SubType.prototype指向SuperType.prototype,而SuperType.prototype的constructor屬性指向SuperType函數,所以instance.constructor指向SuperType。 預設情況下,所有參考類型都繼承Object。這是因為所有函數的原型對象,預設都是Object的一個實例,所以內部prototype(__proto__)指向Object.Prototype。 原型和實例的關係:可以使用2種方法來確定原型與實例之間的關係。
- instancef操作符:使用該操作符來測試實例與原型鏈中出現過的建構函數,都會傳回true




複製程式碼


程式碼如下:- isPrototypeOf()方法:只要是原型鏈中出現過的原型,都可以說是該原型鏈所衍生的實例的原型。




複製程式碼


程式碼如下:給子instance)); //true


給子instance)); //true


給子類別添加方法的注意點:我們有的時候會為子類別添加方法,或是重寫父類​​別的某些方法。這時候就要注意,這些方法必須在繼承後再定義。以下的範例裡,SubType在繼承SuperType後,我們為它增加了新的方法getSubValue(),而且重寫了getSuperValue()方法。對於後者,只有SubType的實例才會使用重寫的方法,SuperType的實例還是會使用原有的getSuperValue()方法。




複製程式碼


程式碼如下:


function SuperType(){


function SuperType(){

function SuperType(){
this.So. true;
}SuperType.prototype.getSuperValue = function(){  return this.property;};function SubType(){『 }//inherit from SuperTypeSubType.prototype = new SuperType();//new methodSubType.prototype.getSubValue = function (){this. subproperty;};//override existing methodSubType.prototype.getSuperValue = function (){  return false;};  return false;};}; alert(instance.getSuperValue()); //false
另一個需要注意的是,透過原型鏈實現繼承時,不能使用物件字面量來建立原型方法,因為這樣會重寫原型鏈。如下面的程式碼,在SubType繼承SuperType以後,使用物件字面量為原型添加方法,但這樣做,會重寫SubType原型,重寫後的SubType.prototype包含的是一個Object的實例,從而也切斷了與SuperType的關係。
複製程式碼 程式碼如下:

function SuperType(){


function SuperType(){

function SuperType(){
this.So. true;
}
SuperType.prototype.getSuperValue = function(){
  return this.property;
};
function SubType(){
〟『. 🎜>}
//inherit from SuperType
SubType.prototype = new SuperType();
//try to add new methods - this nullifies the previous line
SubType.prototype> getSubValue : function (){
    return this.subproperty;
  },
  someOtherMethod : function (){
  some returnevar instance = new SubType();
alert(instance.getSuperValue()); //error!

原型鏈的問題:
和原型一樣,當使用引用類型值的時候,原型鏈就會出問題了。回顧之前的內容,包含一個引用類型值的原型屬性會被所有實例共享,這就是為什麼我們要把引用類型值在建構函數中定義,而不是在原型中定義。透過原型鏈實現繼承時,原型實際上會變成另一個類型的實例,於是,原先的實例屬性也順利成章的變成現在的原型屬性了。 程式碼如下:


function SuperType(){


function SuperType(){


function SuperType(){
this =d. [“red”, “blue”, “green”];
}
function SubType(){
}
//inherit from SuperType
SubType.prototype = new 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屬性。所以,當創建SubType實例的時候,所有實例都共享這項屬性了。如上面的程式碼所示。
第二個問題就是:在建立子類別的實例時,不能傳遞參數給超類別的建構子。實際上,應該說是沒有辦法在不影響所有物件實例的情況下,給超類別的建構函式傳遞參數。由於這些問題,我們不會單獨使用原型鏈。

----------------------------------------------- --------------------------------- 借用建構子(Contructor stealing):為了解決上述問題,開發人員發明了一種叫做借用建構函式的技術。這種技術的想法就是:在子類型建構函式的內部呼叫超類型建構函式。 (函數,只不過是在特定環境中執行程式碼的物件?)我們可以透過使用apply()或call()方法在新建立的物件上執行建構函數。


複製程式碼


程式碼如下:


function SuperType(){


function SuperType(){

function SuperType(){
this =d. [“red”, “blue”, “green”];}

function SubType(){
  //inherit from SuperType

  SuperType.call(this);}  SuperType.call(this);}}}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”我們在SubType裡使用call()方法呼叫SuperType的建構函數,實際上就是在新的SubType物件上執行SuperType()函數中定義的所有物件初始化程式碼。結果就是每個SubType實例都具有自己的colors屬性的副本。 傳遞參數:使用借用建構函式方法的一個很大的好處在於就是,我們可以從子類別的建構函式傳遞參數到父類別的建構函式中。 複製程式碼 程式碼如下:

function SuperType(name){
  this.name = name;
}
function SubType(){
  //〕 call(this, “Nicholas”);
  //instance property
  this.age = 29;
}
var instance = new SubType();
alert(instance.name); //”Nicholas”;
alert(instance.age); //29

新的SuperType建構子新增了一個參數name,我們在call SuperType的同時,往SuperType傳遞參數"Nicholas"。為了不讓超類型的建構子重寫子類型的屬性,可以在呼叫超類型建構函式後再定義子類別的屬性。

借用建構子的問題:方法都在建構子中定義,無法重複使用。而且在超類型的原型中定義的方法,對子類型而言是不可見的。結果所有型別都只能使用建構函數模式。

----------------------------------------------- ---------------------------------

組合繼承:
結合原型鍊及借用建構子各自的優點的一種繼承模式。使用原型鏈繼承原型屬性及方法,使用借用建構函式來繼承實例屬性。如下面例子,我們使用call()方法呼叫SuperType的建構子(每個SubType實例都擁有自己的name和colors屬性,以及SubType的age屬性);然後再把SuperType實例賦值給SubType的原型,使其繼承SuperType的sayName()方法(每個實例都共用這個方法)。

複製程式碼 程式碼如下:
f = name;
    this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){    alert(this.name);

};

function SubType(name, age){

    //inherit properties

    SuperType.call(this, name);
    this.age = age
;
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
    alert(this.age);
};
};
};
var instance1 = new SubType("Nicholas", 29);

instance1.colors.push("black");

alert(instance1.colors); //"red,blue,green,black "
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2 .colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27


原型式繼承(Prototypal Inheritance):

複製程式碼複製程式碼

複製程式碼

function object(o){
  function F(){}
  F.prototype = o;
  return new F();}

  return new F();

}
--------- -------------------------------------------------- ---------------------


寄生式繼承(Parasitic Inheritance):

缺點同建構子
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」? May 01, 2024 pm 10:27 PM

C++ 函式繼承詳解:如何在繼承中使用「基底類別指標」和「衍生類別指標」?

建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

建議:優秀JS開源人臉偵測辨識項目

C++ 中繼承和多態性如何影響類別的耦合度? C++ 中繼承和多態性如何影響類別的耦合度? Jun 05, 2024 pm 02:33 PM

C++ 中繼承和多態性如何影響類別的耦合度?

C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤? May 02, 2024 am 09:54 AM

C++ 函式繼承詳解:如何偵錯繼承中出現的錯誤?

探索Go語言中的物件導向編程 探索Go語言中的物件導向編程 Apr 04, 2024 am 10:39 AM

探索Go語言中的物件導向編程

PHP高階特性:物件導向程式設計的最佳實踐 PHP高階特性:物件導向程式設計的最佳實踐 Jun 05, 2024 pm 09:39 PM

PHP高階特性:物件導向程式設計的最佳實踐

js和vue的關係 js和vue的關係 Mar 11, 2024 pm 05:21 PM

js和vue的關係

Go語言的物件導向特性解析 Go語言的物件導向特性解析 Apr 04, 2024 am 11:18 AM

Go語言的物件導向特性解析

See all articles