Javascript繼承小結

 對象                                                                                                                                                            

對象是已命名的數據的集合。這些已命名的屬性被作爲對象的屬性來引用。如:person.name

Javascript中的對象可以當作關聯數組來使用,如:person[“name”]=”jane”

對象的創建:var obj = new Object();

對象直接量:var obj = {}; var obj = {name:”joye”,age:11}

 

函數                                                                                                                                                            

函數是一個可執行的代碼段,只需定義一次,可以多次調用。

function area(x,y){

  return x*y;

}

上面是一個長方形計算面積的函數,通過area(2,3)可以調用它。

Javascript中,函數也是一種數據類型,這意味着:

1、              函數也可以成爲某個變量或者是某個對象的屬性值。如:var rect = new Object(), rect.area = function(x,y){return x*y;}

2、              函數也可以有屬性,如area.counter = 0; function area(x,y){area.counter++; return x*y;}area函數每被調用一次,counter加一

 

                                                                                                                                                               

Javascript中沒有類這個概念,但是對象可以擁有屬性,而屬性的值又可以是函數類型的數據,那麼我們可以模擬出類來。

 

Java代碼 
  1. var Person = function(){  
  2.   this.name = “jane”; //實例屬性  
  3.   this.sayHi = function(){alert(“HI,” +this.name)} //實例方法  
  4. }  
  5. Person.MIN_AGE = 1//類屬性  
  6. Person.run = function(){} //類方法  
 

上面定義的是一個Person類,其實是一個function對象。

實例屬性:是指每個對象都具有的屬性,它們各自維護了一份單獨的拷貝,比如一個Person類的對象p,name屬性就是p的實例屬性,可以通過p.name訪問,p.name=’kyle’修改。這些操作不會影響別的Person對象的屬性值。

實例方法:它與實例屬性很相似,只不過它是一個方法,而不是一個數據值。通過p.sayHi()可以調用。實例方法是每個對象都可以調用的方法,但是它並不需要每個對象都維護一份單獨的拷貝,方法可以定義在類的原型中,所有的對象共享一個方法。

這裏的sayHi()方法在每個實例中都會有一份拷貝,實例方法可以只維持一份拷貝在原型中,這樣可以節省空間,在下面介紹了原型之後,在對類進行改進。

類屬性:如上的Person.MIN_AGE = 1,它是Person類上的一個屬性,跟Person的對象不相關,這個屬性只能通過Person類自身來訪問

類方法:只能通過Person類自身調用,不能通過Person的實例調用

實例創建                                                                                                                                                    

var p = new Person();  //生成了一個Person類的實例

new Person()分成兩部分看,第一部分new創建了一個空的對象,第二部分Person()Person函數的調用,並且把第一部分創建出來的空對象當作是this關鍵字的值傳遞。那麼這個新生成的對象就會執行Person函數內的代碼,就有了屬性name,值爲”jane”,最後把這個對象設置爲p的值。

 

構造函數                                                                                                                                                   

很明顯Person函數在創建對象的時候起了初始化對象的作用。它就是創建Person類的構造函數。

構造函數的定義:是初始化一個對象的屬性並且專門和New運算符一起使用的一個函數。

 

Prototype                                                                                                                                              

構造過程明白了,在看看new的過程,new 在創建了空對象之後,會給這個對象設置原型,其值是構造函數的prototype屬性的值。

所有的函數都有一個prototype屬性,當這個函數被定義的時候,prototype屬性自動創建和初始化,初始化值是一個對象,這個對象只帶有一個屬性:constructor,它指回到和原型相關的那個構造函數,此處的Person()。這就是爲什麼每個對象都有一個constructor屬性。

對象沒有prototype屬性,但是具有對構造函數的prototype的內部引用,也就是說對象可以從構造函數的原型中繼承它屬性和方法。繼承的屬性就和對象的常規屬性一樣,可以使用for..in..來枚舉它們。

 

屬性讀寫                                                                                                                                                     

讀取屬性的值:

當要讀取一個對象o的屬性p,首先檢查o是否有一個名爲p的對象,如果沒有則查找oprototype中是否有一個名爲p的屬性。如果在prototype內定義的實例不能找到屬性或函數,它就會在 原型中查找,依此類推。原型繼承就是使用這個機制來實現。

設置屬性的值:

當要寫入一個屬性的值時,如果o中並不存在屬性p時,Js不會直接去修改prototype中的p屬性,因爲prototype是一個類所共享的,如果由於一個對象去修改prototype的值,那麼別的對象中的p屬性值也跟着變化。

修改屬性p的值:

Js所做的事情是在o中增加一個新的屬性p,並且設置好值,之後在訪問op屬性時,直接就能在o中訪問到p,而不用去訪問原型中的p屬性。這其實就是o中的p屬性隱藏了原型中的p屬性。

 

繼承                                                                                                                                                          

Javascript中查找屬性是通過:對象->原型1,如果原型1也是某個類的對象,則原型1也有一個原型2,那麼查找過程就是:對象->原型1->原型2…這樣形成一個原型鏈,Javascript中的繼承就是基於這種機制的。

所以要實現繼承,只要讓子類的原型指向父類的對象。看個例子:

 

Java代碼 
  1. Var Animal = function(){}  
  2. Animal.prototype.sleep = function(){  
  3.   If(this.type) alert(this.type +”ZZZZ”);  
  4.   else alert(“ZZZZ”);  
  5. }  
  6. Var Dog = function(){  
  7.   This.type = “Dog”;  
  8. }  
  9. Dog.prototype = new Animal();// 把Dog的原型設置爲Animal對象  
  10. d.sleep();// 提示:”DogZZZZ”<span style="white-space: normal;"> </span>  

這樣Dog類就繼承了 Animal類的sleep方法。在Animal原型中的方法和屬性都能夠被繼承。

 

改進繼承                                                                                                                                                      

通過下面代碼發現:

alert(d.constructor === Animal) // 值爲true

alert(d.constructor === Dog) // 值爲false

也就是說Dog對象的構造函數是Animal,而不是Dog,而實際上我們在new Dog()後執行的構造函數是Dog(),這樣造成了類關係上的混亂,在修改了子類的prototype時,應該同時修改prototype中的constructor,保證子類自身準確。

改進的繼承代碼如下:

Java代碼 
  1. Var Animal = function(){}  
  2. Animal.prototype.sleep = function(){  
  3.   If(this.type) alert(this.type +”ZZZZ”);  
  4.   else alert(“ZZZZ”);  
  5. }  
  6. Var Dog = function(){  
  7.   This.type = “Dog”;  
  8. }  
  9. Dog.prototype = new Animal();  
  10. Dog.prototype.constructor = Dog; //把Dog新的原型中的constructor指回爲原來的constructor.  
 

 

 

一個通用繼承方法                                                                                                                                      

以下是一個繼承的通用方法,摘自YUI源碼:

function extend(subc, superc, overrides) {

 

Java代碼 
  1. if (!superc||!subc) {  
  2.     throw new Error("extend failed, please check that " +  
  3.                     "all dependencies are included.");  
  4. }  
  5. var F = function() {};  
  6. F.prototype=superc.prototype;  
  7. subc.prototype=new F();// 修改子類的原型爲父類對象  
  8. subc.prototype.constructor=subc;//修改constructor  
  9. subc.superclass=superc.prototype;//當類繼承比較簡單時,可以設置一個superclass屬性,這樣需要執行父類的方法時,可以通過superclass來調用  
  10. if (superc.prototype.constructor == Object.prototype.constructor) {  
  11.     superc.prototype.constructor=superc;//如果父類的constructor沒有指定,則修改爲父類自身  
  12. }  
  13.   
  14. if (overrides) { //需要覆蓋的方法  
  15.     for (var i in overrides) {  
  16.         subc.prototype[i]=overrides[i];  
  17.     }  
  18. }  
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章