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

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

WBOY
WBOY原創
2016-05-16 17:34:341008瀏覽

原型鏈(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