例1 在sayHello()函數中定義並調用了sayAlert()函數;sayAlert()作為內層函數,可以訪問外層函數sayHello()中的text變數。 例2 例3 得到的結果:連續輸出3個"item3 undefined"解析:通過執行buildList函數,返回了一個result,那麼這 ...
例1
function sayHello(name) { var text = 'Hello ' + name; var sayAlert = function() { console.log(text); } sayAlert(); } sayHello("Bob") // 輸出"Hello Bob"
在sayHello()函數中定義並調用了sayAlert()函數;sayAlert()作為內層函數,可以訪問外層函數sayHello()中的text變數。
例2
function sayHello2(name) { var text = 'Hello ' + name; // 局部變數 var sayAlert = function() { console.log(text); } return sayAlert; } var say2 = sayHello2("Jane"); say2(); // 輸出"Hello Jane"
例3
function buildList(list) { var result = []; for(var i = 0; i < list.length; i++) { var item = 'item' + list[i]; result.push( function() { console.log(item + ' ' + list[i]); } ); } return result; } var fnlist = buildList([1,2,3]); for (var j = 0; j < fnlist.length; j++) { fnlist[j](); }
得到的結果:連續輸出3個"item3 undefined"
解析:通過執行buildList函數,返回了一個result,那麼這個result存放的是3個匿名函數。然而這三個匿名函數其實就是三個閉包,因為它可以訪問到父函數的局部變數。所以閉包內的保留的i是最終的值為3.所以list[3]肯定是undefined.
item變數值為item3.
改成如下代碼:
function buildList(list) { var result = []; for(var i = 0; i < list.length; i++) { var item = 'item' + list[i]; result.push( (function(i) { console.log(item + ' ' + list[i]); })(i) ); } return result; } var fnlist = buildList([1,2,3]);
得到的結果:
item1 1 item2 2 item3 3
解釋:這兒雖然傳遞了一個數組進去,但是返回的是三個自執行的函數。
例4
function newClosure(someNum, someRef) { var anArray = [1,2,3]; var num = someNum; var ref = someRef; return function(x) { num += x; anArray.push(num); console.log('num: ' + num + "; " + 'anArray ' + anArray.toString() + "; " + 'ref.someVar ' + ref.someVar); } } closure1 = newClosure(40, {someVar: "closure 1"}); closure2 = newClosure(1000, {someVar: "closure 2"}); closure1(5); // 列印"num: 45; anArray 1,2,3,45; ref.someVar closure 1" closure2(-10); // 列印"num: 990; anArray 1,2,3,990; ref.someVar closure 2"
每次調用newClosure()都會創建獨立的閉包,它們的局部變數num與ref的值並不相同。
例5
function sayAlice() { var sayAlert = function() { console.log(alice); } var alice = 'Hello Alice'; return sayAlert; } var sayAlice2 = sayAlice(); sayAlice2(); // 輸出"Hello Alice"
alice變數在sayAlert函數之後定義,這並未影響代碼執行。因為返回函數sayAlice2所指向的閉包會包含sayAlice()函數中的所有局部變數,這自然包括了alice變數,因此可以正常列印”Hello Alice”。
例6
function setupSomeGlobals() { var num = 666; gAlertNumber = function() { console.log(num); } gIncreaseNumber = function() { num++; } gSetNumber = function(x) { num = x; } } setupSomeGlobals(); gAlertNumber(); // 輸出666 gIncreaseNumber(); gAlertNumber(); // 輸出667 gSetNumber(5); gAlertNumber(); // 輸出5
解釋:首先gAlertNumber,gIncreaseNumber,gSetNumber是三個全局變數,並且其三個值都是匿名函數,然而這三個匿名函數本身都是閉包。他們操作的num都是保存在記憶體中的同一個num,所有會得出上面的結果。