Javascript之繼承(原型鏈方式)


1.原型鏈
原型鏈是JavaScript中繼承的主要方法。
每個構造函數都擁有一個原型對象,原型對象都包含一個指向構造函數的指針(constructor),實例都包含一個指向原型對象的內部指針(__proto__)。
假如,原型對象(Son.prototype)等於另一個類型(Pserson)的實例(person1),那么此時的原型對象(Son.prototype)將包含一個指向另一個原型(Person.prototype)的指針,相應的,另有一個原型(Person.prototype)中也包含着一個指向另一個構造函數(Person())的指針。
再如,另一個原型(Person.prototype)又是另一個類型(Person)的實例(person1),那么上述關系依舊成立,如此層層遞進,就構成了實例與原型的鏈條,這就是所謂的原型鏈。
 ​
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function SuperType(){ 
     this .property= 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 Son(); 
alert(instance.getSuperValue());       //true 
    
alert(instance instanceof Object);     //true 
alert(instance instanceof SuperType);  //true 
alert(instance instanceof SubType);    //true

以上代碼定義了兩個類型:SuperType和SubType。每個類型分別有一個屬性和方法。它們主要區別就是SubType繼承了SuperType,而這繼承是通過創建SuperType新實例,並將這個新實例賦給SubType.prototype實現的。實現的本質就是重寫原型對象,代之以新類型的實例。

 

instance指向Subtyoe.prototype,SubType.prototype又指向了SuperType.prototype。getSuperValue()方法仍然還在SuperType。prototype中,但property則位於SubType.prototype中。這是因為property是一個實例屬性,而getSyoerValue()則是一個原型方法。既然SubType.prototype現在是SuperType的實例,那么property當然位於該實例中。此外,要注意instance.constrcutor現在指向的是SuperType,這是因為原來SubType.propertype中的constructor被重寫了的緣故。

注:SubType.propertype中的constructor不被重寫了的緣故,而是SubType的原型指向了另一個對象——SuperType的原型,而這個原型對象的constructor是指向SuperType的。

通過實現原型鏈,本質上就是擴展了原型搜索機制。

2.別忘了默認的原型

事實上,我們的原型鏈還少了一環,所有引用類型默認繼承了Object類型,而這個繼承也是通過原型鏈實現的。我們要記住,所有函數的默認原型都是Object的實例,因此默認原型都會包含一個內部指針,指向Object.prototype。這也正式自定義類型能使用toString()等默認方法的原因。

 

一句話,SubType集成了SuperType,而SuperType繼承了Object。當調用instance.toSring()時,實際調用的是保存在Object.prototype中的那個方法。

3.確定原型和實例的關系

可以使用instanceof操作符來測試實例與原型鏈中出點過的構造函數。 

1
2
3
alert(instance instanceof Object);     //true
alert(instance instanceof SuperType);  //true
alert(instance instanceof SubType);    //true

4.謹慎的定義方法

子類型有時需要重寫父類型中的某個方法,或者需要添加父類型中不穿在的某個方法,但不管怎么,給原型添加的代碼一定要放在替換原型的語句之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function SuperType(){
     this .property= 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;
     }
  
//重寫父類型中的方法
SubType.prototype.getSuperValue= function (){
     return this .subproperty;
     }
  
var instance= new SubType();
alert(instance.getSuperValue());         //false

注意,在通過原型鏈實現繼承時,不能使用對象字面量創建原型對象,這樣會重寫原型鏈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function SuperType(){
     this .property= 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;
         },
     someOtherMethod: function (){
         return false ;
         }
          
     }
var instance= new SubType();
alert(instance.getSuperValue());         //error

由於現在的原型包含的是一個Object的實例,而非SuperType的實例,因此我們設想中的原型鏈已經別切斷——SubType和SuperType已經沒關系了。

5.原型鏈的問題

​原型鏈最主要的問題還是來支援引用類型的原型,我們以前說過包含引用類型值的原型屬性會被所有實例共享,這也是為什么要在構造函數中定義屬性,而不是在原型中定義屬性的原因了。在通過原型來實現繼承時,原型實際上會被變成另一個類型的實例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function SuperType(){
     this .colors=[ "red" , "blue" , "green" ];
     }
      
function SubType(){
}
  
//繼承了SuperType
SubType.prototype= new SuperType();
  
var instance= new SubType();
instance.colors.push( "black" );   //"red","blue","green","black"
alert(instance.colors);
  
var instance2= new SubType();
alert(instance2.colors);          //"red","blue","green","black"

原型的第二個問題:在創建子類的實例時,不能向父類型的構造函數草地參數,所以實踐中很少單獨用到原型鏈。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM