JavaScript學習總結(十二)——JavaScript編寫類


  在工作中經常用到JavaScript,今天總結一下JavaScript編寫類的幾種寫法以及這幾種寫法的優缺點,關於JavaScript編寫類的方式,在網上看到很多,而且每個人的寫法都不太一樣,經常看到的就是以下幾種方式。

1、構造函數方式

  用構造函數模擬"類",在其內部用this關鍵字指代實例對象。

基本語法:

function 類名(){
     this.屬性名;//公共屬性
     var 屬性名;//私有屬性
    /*凡是定義類的公共屬性和公共方法都要使用this*/
    //定義類的公共函數
    this.函數名=function(){
            .....
    }
    //定義類的私有函數
    function 函數名(){
    ......
    }
}

范例:

 1 /*定義一個Person類*/
 2     function Person(_name,_age,_salary){
 3         //Person類的公開屬性,類的公開屬性的定義方式是:”this.屬性名“
 4         this.name=_name;
 5         //Person類的私有屬性,類的私有屬性的定義方式是:”var 屬性名“
 6         var age=_age;//私有屬性
 7         var salary=_salary;//私有屬性
 8 
 9         /*定義私有屬性Age的對外公開訪問方法*/
10         this.setAge = function(intAge) {
11             age = intAge;
12         }
13         /*定義私有屬性Age的對外公開訪問方法*/
14         this.getAge = function() {
15             return age;
16         }
17 
18         //定義Person類的公開方法(特權方法),類的公開方法的定義方式是:”this.functionName=function(){.....}“
19         this.Show=function(){
20             document.writeln("在公開方法里面訪問類的私有屬性是允許的,age="+age+"\t"+"salary="+salary);//在公開方法里面訪問類的私有屬性是允許的
21         }
22         //公共方法
23         this.publicMethod = function(){
24             document.writeln("在公開方法里面訪問類的私有方法是允許的");
25             privateFn();//在公開方法里面調用類的私有方法
26             privateFn2();//在公開方法里面調用類的私有方法
27         }
28         /*
29         定義Person類的私有方法(內部方法),
30         類的私有方法的定義方式是:”function functionName(){.....}“,
31         或者 var functionName=function(){....}
32         */
33         function privateFn(){
34             document.writeln("我是Person類的私有函數privateFn");
35         }
36 
37         var privateFn2=function(){
38             document.writeln("我是Person類的私有函數privateFn2");
39         }
40     }

測試Person類

 1     var p1 = new Person("孤傲蒼狼",24,2300);
 2     var p2 = new Person("白虎神皇",24,2300);
 3     document.write("<pre>");
 4     document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的實例,結果是true
 5     document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的實例,結果是true
 6     //當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等
 7     document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等");
 8     document.writeln("比較p1和p2這兩個對象的show方法的內存地址是否一樣:p1.show== p2.show的結果是:"+(p1.show == p2.show));//false
 9     document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象不是共享一個show方法,在內存中show方法的代碼有2份,存放在兩塊內存區域");
10     document.writeln("name是Person類定義的public屬性,可以使用類的對象去直接訪問類的public屬性");
11     document.writeln("p1.name="+p1.name);//訪問公有屬性,這是可以正常訪問的
12     document.writeln("age和salary是Person類定義的private屬性,不能使用類的對象去直接訪問類私有屬性,這是訪問不了的,結果都是undefined");
13     document.writeln("p1.age="+p1.age+","+"p1.salary="+p1.salary)//不能使用類的對象去直接訪問類私有屬性,這是訪問不了的,結果都是undefined
14     p1.show();//調用類的公共函數,這次允許的
15     p1.publicMethod();//調用類的公共函數,這次允許的
16     p1.setAge(24);//使用public方法setAge方法為私有屬性age賦值
17     document.writeln("使用public方法getAge方法獲取私有屬性age的值,p1.getAge()="+p1.getAge());//使用getAge方法獲取私有屬性age的值
18     //document.writeln("p1.privateFn():"+p1.privateFn()+"&nbsp;p1.privateFn2():"+p1.privateFn2());//不能使用類的對象去調用類的私有方法,這里會報錯”對象不支持此屬性或者方法
19     document.write("</pre>");

測試結果:

  

  這種方式的優點是:可以根據參數來構造不同的對象實例 ,每個對象的屬性一般是不相同的,缺點是構造每個實例對象時,方法不能共享,Person類里面定義的那些方法,p1對象有一份,p2也有一份,那么在內存中就得開辟兩塊內存空間來分別存儲p1的方法和p2的方法,這樣就造成了內存的浪費。對於一個類的不同實例對象,這些對象的屬性一般是不相同的,但是方法是相同的,所以節約內存的做法就是把方法放到內存的一塊區域中存放,然后每個實例對象都從這塊內存中取出方法。

2、原型方式

 需要說明的是,使用原型方式編寫JavaScript類是無法給類添加私有屬性和私有方法的,使用原型方式添加的屬性和方法都是public的。

寫法一:

 1 /*定義一個Person類*/
 2     function Person(_name,_age,_weight,_height){
 3        this.init(_name,_age,_weight,_height);
 4     }
 5 
 6     /*使用原型的方式定義Person類的public屬性:name,age,weight,height,使用原型的方式添加的屬性都是public的*/
 7     Person.prototype.name;
 8     Person.prototype.age;
 9     Person.prototype.weight;
10     Person.prototype.height;
11     /*使用原型的方式給Person類添加public方法,使用原型的方式添加的方法都是public的*/
12     /*使用原型的方式給Person類添加init方法*/
13     Person.prototype.init = function(_name,_age,_weight,_height) {
14         if(_name != undefined && _age!=undefined && _weight!=undefined && _height!=undefined){
15             this.name = _name;
16             this.age = _age;
17             this.weight=_weight;
18             this.height=_height;
19             document.writeln("this.name="+this.name+",this.age="+this.age+",this.weight="+this.weight+",this.height="+this.height);
20         }
21          
22     }
23     /*使用原型的方式給Person類添加show方法*/
24     Person.prototype.show = function(){
25         document.writeln("show method");
26     }

測試Person類

 1     document.write("<pre>");
 2     var p1 = new Person("孤傲蒼狼",24,115,160);
 3     var p2 = new Person("白虎神皇",25,120,170);
 4     var p3 = new Person();
 5     p3.init("玄天邪帝",26,130,180);//調用public方法init初始化p3對象
 6     document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的實例,結果是true
 7     document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的實例,結果是true
 8     document.writeln("p3 instanceof Person的結果是:"+(p3 instanceof Person));//p3是Person類的實例,結果是true
 9     //當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等
10     document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等");
11     document.writeln("比較p1和p2這兩個對象的show方法的內存地址是否一樣:p1.show == p2.show的結果是:"+(p1.show == p2.show));//true
12     document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象共享一個show方法,在內存中show方法的代碼只有一份,存放在內存的一塊區域");//true
13     document.writeln("p1.name="+p1.name+",p1.age="+p1.age+",p1.weight="+p1.weight+",p1.height="+p1.height);//訪問公有屬性,這是可以正常訪問的
14     document.writeln("p2.name="+p2.name+",p2.age="+p2.age+",p2.weight="+p2.weight+",p2.height="+p2.height);//訪問公有屬性,這是可以正常訪問的
15     p3.name="滅世魔尊";//為公共屬性重新賦值
16     document.writeln("p3.name="+p3.name);//訪問公有屬性,這是可以正常訪問的
17     p1.show();//調用類的公共函數,這次允許的
18     document.write("</pre>");

測試結果:

  

寫法二:

使用原型方式給類定義public屬性和public方法更加優雅的寫法,我個人推薦使用這種方式,這種方式看起來比較舒服
 1     /*定義類Person2*/
 2     function Person2(){
 3         
 4     }
 5 
 6     /*使用原型方式給類定義public屬性和public方法更加優雅的寫法*/
 7     Person2.prototype = {
 8         name:"",//public屬性
 9         age:0,//public屬性
10         weight:0,//public屬性
11         height:0,//public屬性
12         /*public方法*/
13         init:function(_name,_age,_weight,_height) {
14             this.name = _name;
15             this.age = _age;
16             this.weight=_weight;
17             this.height=_height;
18             document.writeln("this.name="+this.name+",this.age="+this.age+",this.weight="+this.weight+",this.height="+this.height);
19         },
20         /*public方法*/
21         show:function(){
22             document.writeln("show method");
23         }
24     };

測試代碼:

 1     document.write("<pre>");
 2     var p2_1 = new Person2();
 3     var p2_2 = new Person2();
 4     p2_1.init("孤傲蒼狼",24,115,160);
 5     p2_2.init("白虎神皇",25,120,170);
 6     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);//訪問公有屬性,這是可以正常訪問的
 7     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);//訪問公有屬性,這是可以正常訪問的
 8     document.writeln("p2_1 instanceof Person2的結果是:"+(p2_1 instanceof Person2));//p2_1是Person2類的實例,結果是true
 9     document.writeln("p2_2 instanceof Person2的結果是:"+(p2_2 instanceof Person2));//p2_2是Person2類的實例,結果是true
10     //當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等
11     document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等");
12     document.writeln("比較p2_1和p2_2這兩個對象的init方法的內存地址是否一樣:p2_1.init == p2_2.init的結果是:"+(p2_1.init == p2_2.init));//true
13     p2_1.name="滅世魔尊";//為公共屬性重新賦值
14     document.writeln("p2_1.name="+p2_1.name);//訪問公有屬性,這是可以正常訪問的
15     p2_1.show();//調用類的公共函數,這次允許的
16     document.write("</pre>");

測試結果:

  

   原型方式的優點:所有對象實例都共享類中定義的方法,這樣就沒有造成內存浪費。缺點,第一,不能定義類的私有屬性和私有方法,第二,給在創建對象,給對象的屬性初始化時,需要額外寫一個初始化對象的方法。

3、構造函數+原型

  構造函數方式和原型方式都有各自的優缺點,因此可以把這兩種方式合並起來,用構造函數方式來定義類的屬性(public屬性,private屬性),用原型方式來定義類的方法(public方法)。互補不足,這就有了第三種寫法。

 1     /*定義一個Person類*/
 2     function Person(_name,_age,_salary){
 3         //在Person類內部定義類的public屬性和private屬性以及private方法
 4         //Person類的公開屬性,類的公開屬性的定義方式是:”this.屬性名“
 5         this.name=_name;
 6         //Person類的私有屬性,類的私有屬性的定義方式是:”var 屬性名“
 7         var age=_age;//私有屬性,只能在類內部使用
 8         var salary=_salary;//私有屬性,只能在類內部使用
 9         /*
10         定義Person類的私有方法(內部方法),只能在類內部使用
11         類的私有方法的定義方式是:”function functionName(){.....}“,
12         或者 var functionName=function(){....}
13         */
14         function privateFn(){
15             document.write("<pre>");
16             document.writeln("我是Person類的私有屬性age,只能在Person類內部使用,初始化后age="+age);
17             document.writeln("我是Person類的私有函數privateFn,只能在Person類內部使用");
18             document.write("</pre>");
19         }
20 
21         var privateFn2=function(){
22             document.write("<pre>");
23             document.writeln("我是Person類的私有屬性salary,只能在Person類內部使用,初始化后salary="+salary);
24             document.writeln("我是Person類的私有函數privateFn2,只能在Person類內部使用");
25             document.write("</pre>");
26         }
27 
28         privateFn();//在Person類內部調用私有方法
29         privateFn2();//在Person類內部調用私有方法
30     }
31 
32     //使用prototype原型方式定義的方法(public方法)是無法訪問類的私有屬性和私有方法的
33     //使用prototype原型方式定義Person類的方public方法
34     Person.prototype={
35         setName:function(_name){
36             this.name = _name;
37             //privateFn();//不能調用Person類定義的私有方法privateFn(),會報錯:缺少對象
38         },
39         getName:function(){
40             return this.name;
41         },
42         show:function(){
43             document.writeln("公開方法show");
44         },
45         //公共方法
46         publicMethod:function(){
47             document.writeln("公開方法publicMethod");
48         }
49     };

測試代碼:

 1     var p1 = new Person("孤傲蒼狼",24,2300);
 2     var p2 = new Person("白虎神皇",25,3000);
 3     document.write("<pre>");
 4     document.writeln("p1 instanceof Person的結果是:"+(p1 instanceof Person));//p1是Person類的實例,結果是true
 5     document.writeln("p2 instanceof Person的結果是:"+(p2 instanceof Person));//p2是Person類的實例,結果是true
 6     //當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等
 7     document.writeln("當==兩邊的內容是對象或者是對象的函數屬性時,則比較內存地址是否相等");
 8     document.writeln("比較p1和p2這兩個對象的show方法的內存地址是否一樣:p1.show== p2.show的結果是:"+(p1.show == p2.show));//true
 9     document.writeln("p1.show == p2.show的結果是:"+(p1.show == p2.show)+",這證明p1對象和p2對象共享一個show方法,在內存中show方法的代碼有1份,存放在1塊內存區域");
10     document.writeln("name是Person類定義的public屬性,可以使用類的對象去直接訪問類的public屬性");
11     document.writeln("p1.name="+p1.name);//訪問公有屬性,這是可以正常訪問的
12     document.writeln("age和salary是Person類定義的private屬性,不能使用類的對象去直接訪問類私有屬性,這是訪問不了的,結果都是undefined");
13     document.writeln("p1.age="+p1.age+","+"p1.salary="+p1.salary)//不能使用類的對象去直接訪問類私有屬性,這是訪問不了的,結果都是undefined
14     p1.show();//調用類的公共函數,這次允許的
15     p1.publicMethod();//調用類的公共函數,這次允許的
16     p1.setName("玄天邪帝");//調用類的公共函數設置為name屬性重新賦值
17     document.writeln("p1.getName="+p1.getName());
18     //document.writeln("p1.privateFn():"+p1.privateFn()+"&nbsp;p1.privateFn2():"+p1.privateFn2());//不能使用類的對象去調用類的私有方法,這里會報錯”對象不支持此屬性或者方法
19     document.write("</pre>");

運行結果:

  

  第三種方式通過前兩種方式的結合,算是達到了一個比較理想的寫法了,可以通過傳參構造對象實例,對象實例都共享同一份方法不造成內存浪費。第三種方式在開發中用得最多,我本人也是采用這種方式來編寫JavaScript類。


免責聲明!

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



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