理解Javascript的閉包非常關鍵,本篇試圖用最簡單的例子理解此概念。
function greet(sth){ return function(name){ console.log(sth + ' ' + name); } } //hi darren greet('hi')('darren');
或者可以寫成這樣:
var sayHi = greet('hi'); sayHi('darren');
我們要提的問題是:為什么greet的內部函數能使用sth這個變量?
其內部大致運作如下:
→ 創建全局上下文
→ 執行var sayHi = greet('hi');語句,創建greet上下文,變量sth存儲在greet上下文中。
→ 繼續執行greet函數內的語句,返回一個匿名函數,雖然greet上下文從堆棧上消失,但sth變量依舊存在於內存的某個空間。
→ 繼續執行sayHi('darren');創建了sayHi上下文,並試圖搜尋sth變量,但在sayHi這個上下文中沒有sth變量。sayHi上下文會沿着一個作用域鏈找到sth變量對應的那個內存。 外層函數就像一個閉包,其內部函數可以使用外部函數的變量。
一個閉包的簡單例子
function buildFunctions(){ var funcArr = []; for(var i = 0; i < 3; i++){ funcArr.push(function(){console.log(i)}); } return funcArr; } var fs = buildFunctions(); fs[0](); //3 fs[1](); //3 fs[2](); //3
以上,為什么結果不是0, 1, 2呢?
--因為i作為一個閉包變量,當前值為3,被內部函數使用。要實現想要的效果,可以在遍歷的時候每一次遍歷創建一個獨立的上下文使其不受閉包影響。而自觸發函數可以實現獨立上下文。
function buildFunctions(){ var funcArr = []; for(var i = 0; i < 3; i++){ funcArr.push((function(j){ return function(){ console.log(j); }; }(i))); } return funcArr; } var fs = buildFunctions(); fs[0](); //0 fs[1](); //1 fs[2](); //2
本篇的兩個例子正好體現了閉包的2個方面:一個是內部函數使用閉包變量,另一個是把內部函數寫在自觸發函數中從而避免受閉包影響。
