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