對象
Javascript 根本上是和對象相關的。數組是對象。函數是對象。對象是對象。那什麼是對象呢?對象是名-值對的集合。名是字符串,值可以是字符串,數字,布爾值或者對象(包括數組和函數)。通常對象是像哈希表一樣執行地,這樣便於值地快速檢索。
如果值是函數,我們可以認為這是一個方法。當一個對象地方法被調用的時候,this 變量就設置為這個對象。方法就可以通過 this 變量來訪問實例變量。
對象可以由用來初始化對象的構造函數生成。構造函數提供了其他語言中類所提供的特性,包括靜態變量和方法。
公共
對象的成員全部是公共成員。任何函數都可以訪問、修改或者刪除這些成員,或者增加新成員。有兩種向新對象中添加成員的方法:
在構造函數中添加
這個技術通常用於初始化公共實例變量。使用構造函數的 this 變量向對象中添加成員。
function Container(param){
this.member = param;
}
這樣,如果我們創建一個新對象:
var myContainer = new Container('abc');
這樣 myContainer.member 就包含 ‘abc’ 了。
在原型中添加
這個技術通常用於添加公共方法。當一個成員被檢索並且沒能在對象本身裡面找到時,就要從對象的構造函數的原型成員裡面尋找。原型機制是用於繼承的。也用於節省內存。向一個構造函數生成的所有對象中添加一個方法,只需要向構造函數原型中添加一個函數:
Container.prototype.stamp = function(string){
return this.member + string;
}
因此,我們可以調用這個方法:
myContainer.stamp('def')
結果為 ‘abcdef’。
私有
私有成員是由構造函數生成的。一般構造函數的變量和參數都是私有成員。
function Container(param){
this.member = param;
var secret = 3;
var that = this;
}
這個構造函數生成了3個私有實例變量:param,secret 和 that。它們和對象相關聯,但是它們不僅在函數外邊不可訪問,而且對對象自身的公共方法來說也是不可訪問的。它們只可以被私有方法訪問。私有方法是構造函數的內部函數。
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
}
私有方法 dec 檢查 secret 實例變量。如果它大於零,將其減一並返回 true。否則返回 false。它可以用作限定對象使用3次。
按照習慣,我們設置了一個私有的 that 參數。它使得這個對象對於私有方法使可見的。在 ECMAScript 語言規范中,這是一個可行的錯誤,它使得 this 對於內部函數被不正確地設置。(This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions.)
私有方法不能被公共方法調用。要想使得私有方法有用,需要介紹一下特權方法。
特權
特權方法可以訪問私有變量和方法,並且其自身對於公共方法和對象外部都是可訪問地。可以刪除或者替換一個特權方法,但是不能改變它,或者強迫它洩密。
特權方法是在構造函數內使用 this 指定地。
function Container(param) {
function dec() {
if (secret > 0) {
secret -= 1;
return true;
} else {
return false;
}
}
this.member = param;
var secret = 3;
var that = this;
this.service = function () {
if (dec()) {
return that.member;
} else {
return null;
}
};
}
service 就是特權方法。前三次調用 myContainer.service() 時會返回 ‘abc’。之後返回空(null)。service 調用了可訪問私有變量 secret 的私有方法 dec。service 對其他對象和方法都是可見的,但是不能直接訪問私有成員。
閉包
由於 Javascript 有閉包,因此這種公共,私有和特權成員模型時可以的。這意味著內部函數總是可以訪問它外部函數的變量和參數,甚至在外部函數返回後也可以。這是這個語言一個非常有用的特性。目前沒有任何關於 Javascript 編程的書描述了如何利用它。大部分甚至都不提及它。(糖伴西紅柿說,這是2001年的文章,當時估計還沒有這方面的研究文章。現在來說,犀牛書等都有涉及,javascript 的難點之一啊。)
私有和特權成員只在對象被創建時生成。公共成員可以隨時添加。
模式
公共
function Constructor(...) {
this.membername = value;
}
Constructor.prototype.membername = value;
私有
function Constructor(...) {
var that = this;
var membername = value;
function membername(...) {...}
}
注意:函數語句
function membername(...) {...}
是
var membername = function membername(...) {...};
的縮寫。
特權
function Constructor(...) {
this.membername = function (...) {...};
}
糖伴西紅柿說:
好久沒露面,本來就沒人記得我,這次更無名了。最近從高麗遷移回了天朝,嗯。而且正在為了工作進行最後的充電活動。生活中同時也遭遇到電視劇情節,還是高麗電視劇。這兩天在主攻 Javascript 中幾個比較難的知識點,閉包算是其中之一。兩天看了好多關於閉包的文章,才有點開竅,這篇文章屬於其中之一。算是個額外的參考資料,主要的是另一篇英文文章,有打算全篇翻譯。