1、建構函式方式
用建構函式類比”類”,在其內部用this關鍵字指代執行個體對象。
基本文法:
function 類名(){
this.屬性名稱;//公用屬性
var 屬性名稱;//私人屬性
/凡是定義類的公用屬性和公用方法都要使用this/
//定義類的公用函數
this.函數名=function(){
…..
}
//定義類的私人函數
function 函數名(){
……
}
}
範例:
/*定義一個Person類*/ function Person(_name,_age,_salary){ //Person類的公開屬性,類的公開屬性的定義方式是:”this.屬性名稱“ this.name=_name; //Person類的私人屬性,類的私人屬性的定義方式是:”var 屬性名稱“ var age=_age;//私人屬性 var salary=_salary;//私人屬性 /*定義私人屬性Age的對外公開存取方法*/ this.setAge = function(intAge) { age = intAge; } /*定義私人屬性Age的對外公開存取方法*/ this.getAge = function() { return age; } //定義Person類的公開方法(特權方法),類的公開方法的定義方式是:”this.functionName=function(){.....}“ this.Show=function(){ document.writeln("在公開方法裡面訪問類的私人屬性是允許的,age="+age+"\t"+"salary="+salary);//在公開方法裡面訪問類的私人屬性是允許的 } //公用方法 this.publicMethod = function(){ document.writeln("在公開方法裡面訪問類的私人方法是允許的"); privateFn();//在公開方法裡面調用類的私人方法 privateFn2();//在公開方法裡面調用類的私人方法 } /* 定義Person類的私人方法(內部方法), 類的私人方法的定義方式是:”function functionName(){.....}“, 或者 var functionName=function(){....} */ function privateFn(){ document.writeln("我是Person類的私人函數privateFn"); } var privateFn2=function(){ document.writeln("我是Person類的私人函數privateFn2"); } }
測試Person類
var p1 = new Person("孤傲蒼狼",24,2300); var p2 = new Person("白虎神皇",24,2300); document.write("<pre>"); document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的執行個體,結果是true document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的執行個體,結果是true //當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等 document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等"); document.writeln("比較p1和p2這兩個對象的show方法的記憶體位址是否一樣:p1.show== p2.show的結果是:"+(p1.show == p2.show));//false document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象不是共用一個show方法,在記憶體中show方法的代碼有2份,存放在兩塊記憶體地區"); document.writeln("name是Person類定義的public屬性,可以使用類的對象去直接存取類的public屬性"); document.writeln("p1.name="+p1.name);//訪問公有屬性,這是可以正常訪問的 document.writeln("age和salary是Person類定義的private屬性,不能使用類的對象去直接存取類私人屬性,這是訪問不了的,結果都是undefined"); document.writeln("p1.age="+p1.age+","+"p1.salary="+p1.salary)//不能使用類的對象去直接存取類私人屬性,這是訪問不了的,結果都是undefined p1.show();//調用類的公用函數,這次允許的 p1.publicMethod();//調用類的公用函數,這次允許的 p1.setAge(24);//使用public方法setAge方法為私人屬性age賦值 document.writeln("使用public方法getAge方法擷取私人屬性age的值,p1.getAge()="+p1.getAge());//使用getAge方法擷取私人屬性age的值 //document.writeln("p1.privateFn():"+p1.privateFn()+" p1.privateFn2():"+p1.privateFn2());//不能使用類的對象去調用類的私人方法,這裡會報錯”對象不支援此屬性或者方法 document.write("</pre>");
測試結果:
這種方式的優點是:可以根據參數來構造不同的對象執行個體 ,每個對象的屬性一般是不相同的,缺點是構造每個執行個體對象時,方法不能共用,Person類裡面定義的那些方法,p1對象有一份,p2也有一份,那麼在記憶體中就得開闢兩塊記憶體空間來分別儲存p1的方法和p2的方法,這樣就造成了記憶體的浪費。對於一個類的不同執行個體對象,這些對象的屬性一般是不相同的,但是方法是相同的,所以節約記憶體的做法就是把方法放到記憶體的一塊地區中存放,然後每個執行個體對象都從這塊記憶體中取出方法。
2、原型方式
需要說明的是,使用原型方式編寫JavaScript類是無法給類添加私人屬性和私人方法的,使用原型方式添加的屬性和方法都是public的。
寫法一:
/*定義一個Person類*/ function Person(_name,_age,_weight,_height){ this.init(_name,_age,_weight,_height); } /*使用原型的方式定義Person類的public屬性:name,age,weight,height,使用原型的方式添加的屬性都是public的*/ Person.prototype.name; Person.prototype.age; Person.prototype.weight; Person.prototype.height; /*使用原型的方式給Person類添加public方法,使用原型的方式添加的方法都是public的*/ /*使用原型的方式給Person類添加init方法*/ Person.prototype.init = function(_name,_age,_weight,_height) { if(_name != undefined && _age!=undefined && _weight!=undefined && _height!=undefined){ this.name = _name; this.age = _age; this.weight=_weight; this.height=_height; document.writeln("this.name="+this.name+",this.age="+this.age+",this.weight="+this.weight+",this.height="+this.height); } } /*使用原型的方式給Person類添加show方法*/ Person.prototype.show = function(){ document.writeln("show method"); }
測試Person類
document.write("<pre>"); var p1 = new Person("孤傲蒼狼",24,115,160); var p2 = new Person("白虎神皇",25,120,170); var p3 = new Person(); p3.init("玄天邪帝",26,130,180);//調用public方法init初始化p3對象 document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的執行個體,結果是true document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的執行個體,結果是true document.writeln("p3 instanceof Person的結果是:"+(p3 instanceof Person));//p3是Person類的執行個體,結果是true //當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等 document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等"); document.writeln("比較p1和p2這兩個對象的show方法的記憶體位址是否一樣:p1.show == p2.show的結果是:"+(p1.show == p2.show));//true document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象共用一個show方法,在記憶體中show方法的代碼只有一份,存放在記憶體的一塊地區");//true document.writeln("p1.name="+p1.name+",p1.age="+p1.age+",p1.weight="+p1.weight+",p1.height="+p1.height);//訪問公有屬性,這是可以正常訪問的 document.writeln("p2.name="+p2.name+",p2.age="+p2.age+",p2.weight="+p2.weight+",p2.height="+p2.height);//訪問公有屬性,這是可以正常訪問的 p3.name="滅世魔尊";//為公用屬性重新賦值 document.writeln("p3.name="+p3.name);//訪問公有屬性,這是可以正常訪問的 p1.show();//調用類的公用函數,這次允許的 document.write("</pre>");
測試結果:
寫法二:
使用原型方式給類定義public屬性和public方法更加優雅的寫法,我個人推薦使用這種方式,這種方式看起來比較舒服
/*定義類Person2*/ function Person2(){ } /*使用原型方式給類定義public屬性和public方法更加優雅的寫法*/ Person2.prototype = { name:"",//public屬性 age:0,//public屬性 weight:0,//public屬性 height:0,//public屬性 /*public方法*/ init:function(_name,_age,_weight,_height) { this.name = _name; this.age = _age; this.weight=_weight; this.height=_height; document.writeln("this.name="+this.name+",this.age="+this.age+",this.weight="+this.weight+",this.height="+this.height); }, /*public方法*/ show:function(){ document.writeln("show method"); } };
測試代碼:
document.write("<pre>"); var p2_1 = new Person2(); var p2_2 = new Person2(); p2_1.init("孤傲蒼狼",24,115,160); p2_2.init("白虎神皇",25,120,170); document.writeln("p2_1.name="+p2_1.name+",p2_1.age="+p2_1.age+",p2_1.weight="+p2_1.weight+",p2_1.height="+p2_1.height);//訪問公有屬性,這是可以正常訪問的 document.writeln("p2_2.name="+p2_2.name+",p2_2.age="+p2_2.age+",p2_2.weight="+p2_2.weight+",p2_2.height="+p2_2.height);//訪問公有屬性,這是可以正常訪問的 document.writeln("p2_1 instanceof Person2的結果是:"+(p2_1 instanceof Person2));//p2_1是Person2類的執行個體,結果是true document.writeln("p2_2 instanceof Person2的結果是:"+(p2_2 instanceof Person2));//p2_2是Person2類的執行個體,結果是true //當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等 document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等"); document.writeln("比較p2_1和p2_2這兩個對象的init方法的記憶體位址是否一樣:p2_1.init == p2_2.init的結果是:"+(p2_1.init == p2_2.init));//true p2_1.name="滅世魔尊";//為公用屬性重新賦值 document.writeln("p2_1.name="+p2_1.name);//訪問公有屬性,這是可以正常訪問的 p2_1.show();//調用類的公用函數,這次允許的 document.write("</pre>");
測試結果:
原型方式的優點:所有對象執行個體都共用類中定義的方法,這樣就沒有造成記憶體浪費。缺點,第一,不能定義類的私人屬性和私人方法,第二,給在建立對象,給對象的屬性初始化時,需要額外寫一個初始化對象的方法。
3、建構函式+原型
建構函式方式和原型方式都有各自的優缺點,因此可以把這兩種方式合并起來,用建構函式方式來定義類的屬性(public屬性,private屬性),用原型方式來定義類的方法(public方法)。互補不足,這就有了第三種寫法。
/*定義一個Person類*/ function Person(_name,_age,_salary){ //在Person類內部定義類的public屬性和private屬性以及private方法 //Person類的公開屬性,類的公開屬性的定義方式是:”this.屬性名稱“ this.name=_name; //Person類的私人屬性,類的私人屬性的定義方式是:”var 屬性名稱“ var age=_age;//私人屬性,只能在類內部使用 var salary=_salary;//私人屬性,只能在類內部使用 /* 定義Person類的私人方法(內部方法),只能在類內部使用 類的私人方法的定義方式是:”function functionName(){.....}“, 或者 var functionName=function(){....} */ function privateFn(){ document.write("<pre>"); document.writeln("我是Person類的私人屬性age,只能在Person類內部使用,初始化後age="+age); document.writeln("我是Person類的私人函數privateFn,只能在Person類內部使用"); document.write("</pre>"); } var privateFn2=function(){ document.write("<pre>"); document.writeln("我是Person類的私人屬性salary,只能在Person類內部使用,初始化後salary="+salary); document.writeln("我是Person類的私人函數privateFn2,只能在Person類內部使用"); document.write("</pre>"); } privateFn();//在Person類內部調用私人方法 privateFn2();//在Person類內部調用私人方法 } //使用prototype原型方式定義的方法(public方法)是無法訪問類的私人屬性和私人方法的 //使用prototype原型方式定義Person類的方public方法 Person.prototype={ setName:function(_name){ this.name = _name; //privateFn();//不能調用Person類定義的私人方法privateFn(),會報錯:缺少對象 }, getName:function(){ return this.name; }, show:function(){ document.writeln("公開方法show"); }, //公用方法 publicMethod:function(){ document.writeln("公開方法publicMethod"); } };
測試代碼:
var p1 = new Person("孤傲蒼狼",24,2300); var p2 = new Person("白虎神皇",25,3000); document.write("<pre>"); document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的執行個體,結果是true document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的執行個體,結果是true //當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等 document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較記憶體位址是否相等"); document.writeln("比較p1和p2這兩個對象的show方法的記憶體位址是否一樣:p1.show== p2.show的結果是:"+(p1.show == p2.show));//true document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象共用一個show方法,在記憶體中show方法的代碼有1份,存放在1塊記憶體地區"); document.writeln("name是Person類定義的public屬性,可以使用類的對象去直接存取類的public屬性"); document.writeln("p1.name="+p1.name);//訪問公有屬性,這是可以正常訪問的 document.writeln("age和salary是Person類定義的private屬性,不能使用類的對象去直接存取類私人屬性,這是訪問不了的,結果都是undefined"); document.writeln("p1.age="+p1.age+","+"p1.salary="+p1.salary)//不能使用類的對象去直接存取類私人屬性,這是訪問不了的,結果都是undefined p1.show();//調用類的公用函數,這次允許的 p1.publicMethod();//調用類的公用函數,這次允許的 p1.setName("玄天邪帝");//調用類的公用函數設定為name屬性重新賦值 document.writeln("p1.getName="+p1.getName()); //document.writeln("p1.privateFn():"+p1.privateFn()+" p1.privateFn2():"+p1.privateFn2());//不能使用類的對象去調用類的私人方法,這裡會報錯”對象不支援此屬性或者方法 document.write("</pre>");
運行結果:
第三種方式通過前兩種方式的結合,算是達到了一個比較理想的寫法了,可以通過傳參構造對象執行個體,對象執行個體都共用同一份方法不造成記憶體浪費。第三種方式在開發中用得最多,我本人也是採用這種方式來編寫JavaScript類。