Javascript之匿名函數(私有變量)


嚴格來講,JavaScript中沒有私有成員的概念;所喲對象屬性都是公開的。不過,有一個私有變量的概念。任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數的外部訪問這些變量。私有變量包括函數的參數、局部變量和函數內定義的其他函數。如:
 
1
2
3
4
function add(num1,num2){
    var sum=num1+num2;
    return sum; 
}

在這個函數內部,有3個私有變量:num1、num2和sum。如果在這個函數內部創建一個閉包,那么閉包通過自己的作用域鏈也可以訪問這些變量,利用這一點,就可以創建用於訪問私有變量的公用方法。

我們把有權訪問私有變量和私有函數的公有方法叫做特權方法

1.構造函數定義法

有兩種在對象上創建特權方法的方式。第一種是在構造函數中定義特權方法,基本模式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function myobject (){
  
      //私有屬性和私有函數
      var privateVariable=10;
      
     function privatevateFunction(){
         return false ;
     }
      
     //特權方法
      this .publicMethod= function (){
         privateVariable++;
         return privatevateFunction();
     };
}

這個模式在函數內部定義了所有私有變量和函數。然后,又繼續創建了能夠訪問這些私有成員的特權方法。能夠在構造函數中定義特權方法,是因為特權方法作為閉包有權訪問在構造函數中的所有變量和函數。

利用私有和特權方法,可以隱藏那些不該被直接修改的數據,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Persom(name){
      
     this .getName= function (){
        return name;
     };
  
     this .setName= function (value){
        name=value;
     };
}
  
var person= new Person( "zxj" );
alert(person.getName());    //zxj
person.setName( "Greg" );
alert(person.getName());    //Greg

在以上構造函數中定義了兩個特權方法:getName()和setName()。這兩個方法都可以在函數外部使用,而且都有權訪問私有變量name。

構造函數定義法,也是構造函數,構造函數有的缺點,它同樣也存在。

2.靜態私有變量

通過在私有作用域中定義私有變量或函數,同樣也可以創建特權方法,基本模式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
( function (){
     
       //私有變量和私有函數
       var privateVariable=10;
       function privareFunction(){
          return false ;
       };
         
       //構造函數
        MyObject= function (){
       };
  
       //公有/特權方法
        MyObject.prototype.publicMethod= function (){
           privateVariable++;
           privareFunction();
       };
   }
)()

這個模式創建了一個私有作用域,並在其中封裝了一個構造函數級相應的方法。在私有作用域中,首先定義了私有變量和私有函數,然后定義了一個構造函數及其公有方法。公有方法是在原型上定義的,這一點體現了典型的原型模式。需要注意的是,這個模式在定義構造函數是並沒有使用函數聲明,而是使用的函數表達式。函數聲明只能創建局部函數,出於相同原因,在聲明MyObject時也沒使用var.記住:初始化未經聲明的變量,總會創建一個全局變量。因此,MyObject就成了全局變量,能夠在私有作用域之外被訪問。

與構造函數定義特權的區別在於:私有變量和函數是由實例共享的。由於特權方法是在原型上定義的,因此所有實例都使用同一個函數。而這個特權方法,作為閉包,總是保存着對包含作用域的引用。 

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
( function (){
              
         var name = "" ;
          
         Person = function (value){                
             name = value;                
         };
          
         Person.prototype.getName = function (){
             return name;
         };
          
         Person.prototype.setName = function (value){
             name = value;
         };
})();
              
var person1 = new Person( "zxj" );
alert(person1.getName());   //"zxj"
person1.setName( "Greg" );
alert(person1.getName());   //"Greg"
                     
var person2 = new Person( "Michael" );
alert(person1.getName());   //"Michael"
alert(person2.getName());   //"Michael"

一這種方式創建靜態私有變量會因為使用原型而增進代碼的復用,但每個實例都沒有自己的私有變量。到底使用實例變量還是靜態私有變量,最終還是有具體業務決定。

3.模塊模式

前面模式用於自定義類型創建私有變量和特權方法。

模塊模式是為單例創建私有變量和特權方法,單例就是指,只有一個實例的對象。

JavaScript是以對象字面量的方式創建單例對象的。

1
2
3
4
5
6
var singlton={
     name:value,
     method: function {
        //這是方法的代碼
    }
}

模塊模式通過單例添加私有變量和特權放哪廣發能夠使其得到增強,基本形式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var singlton= function {  
      
      //私有變量和私有函數  
      var privateVaiable= 10 ;  
     function privateMethod(){  
         return false ;  
     };  
     //公有/特權方法  
     return {  
       publicProperty: true ,  
       piblicMethod: function (){  
          privateVaiable++;  
          return privateMethod();  
         }  
     }  
}();

這個模塊使用了一個返回對象的匿名函數。在這個匿名函數內部,首先定義了私有變量和函數。然后,將一個對象字面量作為函數的值返回。返回的對象字面量中只包含可以公開的屬性和方法。由於這個對象是在匿名函數內部定義的,因此它的公有方法有權訪問私有變量和函數。從本質上講,這個對象字面量定義的是單例的公共接口。這種模式在需要對單例進行某些初始化,同時有需要維持其私有變量時是非常有用的,如

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
28
29
30
function BaseComponent(){
}
  
function OtherComponent(){
}
  
var application = function (){
  
     //私有變量和函數
     var components = new Array();
  
     //初始化
     components.push( new BaseComponent());
  
     //公有
     return {
         getComponentCount : function (){
             return components.length;
         },
  
         registerComponent : function (component){
             if ( typeof component == "object" ){
                 components.push(component);
             }
         }
     };
}();
  
application.registerComponent( new OtherComponent());
alert(application.getComponentCount());  //2

這個簡單的例子創建了一個用於管理組件的application對象。在創建這個對象的過程中,首先聲明了一個私有的components數組,並向數組中添加一個BaseComponent的新實例(這里不需要關心BaseComponent的代碼,我們只是用他來展示初始化操作)。而返回對象的getComponentCount()和registerComponent ()方法,都有權訪問數組components的特權方法。前者只是發那個會已注冊的組件數目,后則用於注冊新組件。

一這種模式創建的每一個單例都是Object的實例,因為最終要通過一個對象字面量來表示它。單例通常都是作為全局對象存在的。

4.增強的模塊模式

增強的模塊模式適合那些單例必須是某種類型的實例,同時還必須添加某些屬性或(和)方法對齊加以增強的情況。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var singlton= function {  
      
      //私有變量和私有函數  
      var privateVaiable=10;  
     function privateMethod(){  
         return false ;  
     };  
     //創建對象
     var object= new CustomType();    
  
     //公有/特權方法  
     object.publicProperty= true ;
  
     object.piblicMethod= function (){
          privateVaiable++;  
          return privateMethod();  
     };
     //返回這個對象
     return object;
}();

如果前面演示模塊模式的例子中的application對象必須是BaseComponent的實例,我們可以使用一下代碼:

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
28
29
30
31
32
33
34
35
36
function BaseComponent(){
}
  
function OtherComponent(){
}
  
var application = function (){
  
     //私有變量和私有函數   
     var components = new Array();
  
     //創建對象 
     components.push( new BaseComponent());
  
     //創建application的一個局部副本
     var app = new BaseComponent();
  
     //公共
     app.getComponentCount = function (){
         return components.length;
     };
  
     app.registerComponent = function (component){
         if ( typeof component == "object" ){
             components.push(component);
         }
     };
  
     //返回這個副本
     return app;
}();
  
alert(application instanceof BaseComponent);
application.registerComponent( new OtherComponent());
alert(application.getComponentCount());  //2

 






免責聲明!

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



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