函數中的私有變量和特權方法
定義
【1】【私有變量】
任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數外部訪問這些變量。私有變量包括函數的參數、局部變量和在函數內部定義的其他函數
【2】【特權方法】
如果在函數內部創建一個閉包,那麽閉包通過自己的作用域鏈也可以訪問這些變量。而利用這一點,就可以創建用於訪問私有變量的公有方法。有權訪問私有變量和私有函數的公有方法稱為特權方法。
創建方式
【1】【構造函數】
在構造函數內部定義所有私有變量和函數。然後,創建能夠訪問這些私有成員的特權方法。能夠在構造函數中定義特權方法,是因為特權方法作為閉包有權訪問在構造函數中定義的所有變量和函數。
[缺點]必須使用構造函數模式來達到目的,且針對每個實例都會創建同樣一組方法
function MyObject(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ alert(1) return false; } //特權方法 this.publicMethod = function(){ privateVariable++; return privateFunction(); } } new MyObject().publicMethod();//彈出1
【2】【靜態私有變量】
通過在私有作用域中定義私有變量和方法來創建特權方法。
[優點]私有變量和函數由實例共享,增強代碼復用
[缺點]每個實例都沒有自己的私有變量
(function(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ alert(1) return false; } //在定義該構造函數時並沒有使用函數聲明,而是使用了函數表達式。且沒有使用var關鍵字,使其成為全局變量。 MyObject = function(){}; //在原型上定義特權方法 MyObject.prototype.publicMethod = function(){ privateVariable++; return privateFunction(); } })(); new MyObject().publicMethod();//彈出1
[另一個例子]
(function(){ var name = ""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; //name變成靜態的由所有實例共享的屬性 Person.prototype.setName = function(value){ name = value; } })(); var person1 = new Person("Nicholas"); console.log(person1.getName());//"Nicholas" person1.setName("Greg"); console.log(person1.getName());//"Greg" var person2 = new Person("Michael"); console.log(person1.getName());//"Michael" console.log(person2.getName());//"Michael"
作用
【隱藏數據】:利用私有和特權成員,隱藏不應該被直接修改的數據
function Person(name){ this.getName = function(){ return name; } this.setName = function(value){ name = value; }; } var person = new Person("Nicholas"); console.log(person.getName());//"Nicholas" person.setName(‘Greg‘); console.log(person.getName());//"Greg" /*以上代碼的構造函數定義了兩個特權方法:getnName()和setName()。這兩個方法都可以在構造函數外部使用,而且有權訪問私有變量name。但在Person構造函數外部,沒有任何辦法訪問name。由於這兩個方法都是在構造函數內部定義的,它們作為閉包能夠通過作用域訪問name。*/
單例
【單例定義】單例是指只有一個實例的對象
【單例創建方式】JavaScript是以對象字面量的方式來創建單例對象的
針對於單例的私有變量和特權方法的兩種模式
【1】【模塊模式】:使用一個返回對象的匿名函數。在這個匿名函數的內部,首先定義了私有變量和函數。然後,將一個對象字面量作為函數的值返回。返回的對象字面量中只包含可以公開的屬性和方法。由於這個對象是在匿名函數內部定義的。因此它的公有方法有權訪問私有變量和函數。從本質上講,這個對象字面量定義的是單例的公共接口。這種模式在需要對單例進行某些初始化,同時又需要維護其私有變量時非常有用。
var singleton = function(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ alert(1) return false; } //特權方法和屬性 return{ publicProperty: true, publicMethod : function(){ privateVariable++; return privateFunction(); } } }(); singleton.publicMethod();//彈出1
[應用場景]用於管理組件的application對象
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); } } } }();
【2】【增強模塊模式】適合於那些單例必須是某種類型的實例,同時還必須添加某些屬性和方法對其加以增強的情況。
var singleton = function(){ //私有變量和私有函數 var privateVariable = 10; function privateFunction(){ alert(1) return false; } //創建對象 var object = new CustomType(); //特權方法和屬性 object.publicProperty = true; object.publicMethod = function(){ privateVariable++; return privateFunction(); }; return object; }();
[應用場景]用於管理組件的application對象的增強模式
var application = function(){ //私有變量和函數 var components = new Array(); //初始化 components.push(new BaseComponent()); //創建application的一個局部副本,這個變量實際上是application對象的局部變量版 var app = new BaseComponent(); //公共接口 //返回已註冊的數目 app.getComponentCount = function(){ return components.length; }; //註冊新組件 app.registerComponent = function(component){ if(typeof component == "object"){ components.push(component); } } return app; }();
函數中的私有變量和特權方法