通過在私有作用域中定義私有變量或函數,同樣也可以創建特權方法:
(function() {
// 私有變量和私有函數
var privateVariable = 10;
function privateFunction() {
return false;
}
// 構造函數
MyObject = function() {}
// 公有/特權方法
MyObject.prototype.publicMethod = function() {
privateVariable++;
return privateFunction();
};
})()
這個模式創建了一個私有作用域,并在其中封裝了一個構造函數及相應的方法。在私有作用域中,首先定義了私有變量和私有函數,然后又定義了構造函數及其公有方法。
公有方法是在原型上定義的,這一點體現了典型的原型模式。
需要注意的是,這個模式在定義構造函數時并沒有使用函數聲明,而是使用了函數表達式。函數聲明只能穿件局部函數,但那并不是我們想要的。
出于同樣的原因,我們也沒有在聲明 MyObject 時使用 var 關鍵字。
記住:初始化未聲明變量,總是會創建一個全局變量。
因此, MyObject 就成了一個全局變量,能夠在私有作用域之外被訪問到。但也要知道,在嚴格模式下未經聲明的變量賦值會導致錯誤。
這個模式在與構造函數中定義特權方法的主要區別,就在于私有變量和函數式由實例共享的。
由于特權方法是在原型上定義的,因此所有實例都使用同一個函數。而這個特權方法,作為一個閉包,總是保存著對包含作用域的引用。
(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("Bert");
alert(person1.getName()); // "Bert"
person1.setName("Greg");
alert(person1.getName()); // "Greg"
var person2 = new Person("Michael");
alert(person2.getName()); // "Michael"
person1.setName("Greg");
alert(person2.getName()); // "Michael"
上例中的 Person 構造函數與 getName() 和 setName() 方法一樣,都有權訪問私有變量 name。在這種模式下,變量 name 就變成了一個靜態的、由所有實例共享的屬性。
也就是說,在一個實例上調用 setName() 會印象所有實例。而調用 setName() 或新建一個 Person 實例都會賦予 name 屬性一個新值。
結果就是所有實例都會返回相同的值。
以這種方法創建靜態私有變量會因為使用原型而增進代碼復用,但每個實例都會沒有自己的私有變量。
到底是使用實例變量,還是靜態私有變量,最終還是要是視具體需求而定。
多查找作用域中的一個層次,就會在一定程度上影響查找速度。而這正是使用閉包和私有變量的一個明顯的不足之處。