以前寫過一篇關於javascript閉包的隨筆,javascript閉包,但是寫的不夠詳細,也沒有體現出閉包的強大之處。故作此篇。 眾所周知,javascript沒有塊級範圍,只有函數範圍。那就意味著定義在函數中的參數和變數在函數外部是不可見的,而在一個函數內部任何位置定義的變數,在該函數內部任何地方都可見。這帶來的好處是內建函式可以訪問定義它們的外部函數的參數和變數。 首先,我們來構造一個簡單的對象 複製代碼 1 var testObj = { 2 value: 10, 3 add: function(inc){ 4 this.value += (typeof inc === "number") ? inc : 1; 5 } 6 }; 7 8 testObj.add(); 9 testObj.value; // 1110 11 testObj.add(2); 12 testObj.value; // 13複製代碼這樣寫就有一個問題,value值不能保證不會被非法修改,可以按如下的方法進行修改。 複製代碼 1 var testObj = (function(){ 2 var value = 10; 3 return { 4 add: function(inc){ 5 value += (typeof inc === "number") ? inc : 1; 6 }, 7 getValue: function(){ 8 return value; 9 }10 };11 })();12 13 testObj.add();14 testObj.getValue(); // 1115 16 testObj.add(2);17 testObj.getValue(); // 13複製代碼 我們可以通用調用一個函數的形式去初始化testObj,該函數會返回一個對象字面量,函數裡定義了一個value變數,該變數對add和getValue方法總是可用的,但函數的範圍使得它對其他的程式來說是不可見的。同時,我們還可以得出一個結論,內建函式擁有比它的外部函數更長的生命週期。 我們再繼續看一個建構函式調用的例子。 複製代碼var MyObj = function(str){ this.status = str;}; MyObj.prototype.getStatus = function(){ return this.status;}; var obj = new MyObj("javascript");obj.getStatus(); // "javascript"複製代碼這樣寫並沒有錯,但是會有一點“多此一舉”,為什麼要用一個getStatus方法去訪問一個本可以直接存取到的屬性呢?如果status是私人屬性,那當然才有意義。 複製代碼var obj = function(status){ return { getStatus: function(){ return status; } };}; var myObj = obj("javascript");myObj.getStatus(); // "javascript"複製代碼 這裡當我們調用obj的時候,它返回包含getStatus方法的一個新對象,該對象的一個引用儲存在myObj中,即使obj已經返回了,但getStatus方法仍然享有訪問obj對象的status屬性的特權。getStatus方法並不是訪問該參數的一個副本,它訪問的就是該參數本身。這是可能的,因為該函數可以訪問它被建立時所處的上下文環境,這被稱為閉包。