標籤:
學習地址 :http://stackoverflow.com/questions/111102/how-do-javascript-closures-work
1,關於閉包的簡單實現
//example 1
function sayHello(name) {
var words = "hello," + name;
var sayForAlert = function () {
alert(words);
}
sayForAlert();
}
//sayHello("jack");
/*
An Example of a Closure
Two one sentence summaries:
a closure is the local variables for a function — kept alive after the function has returned, or
a closure is a stack-frame which is not deallocated when the function returns (as if a ‘stack-frame‘ were malloc‘ed instead of being on the stack!).
*/
function sayHello2(name){
var words = "hello, "+name; //local variables;
var sayForAlert = function (){
alert(words);
}
return sayForAlert;
}
var say2 = sayHello2("lucy");
say2();
/*
一個函數的引用,作為一個參數返回回來。在這裡相當於返回一個函數的
指標。sayForAlert 和 say2指向的是同一函數。
javascrip與c的一個重要區別在於c指標指向一個函數,而javascript是一個引用指向一個函數。(相當於是隱藏性指標)。
在許多的語言中和c一樣,當函數執行完成後,本地的變數就不能再訪問。
因為其函數的堆棧被銷毀。
在javascript中函數的裡面可以在聲明函數。並且本地的變數可以訪問,並
可心在聲明的函數中返回。
*/
function saynumadd(){
var num = 666;
var showAlert = function(){
alert(num);
//num++;//place 2;
}
num++;//place 1;
return showAlert;
}
var sayNumber = saynumadd();
sayNumber();//alert 667;
/*
note: 根據上面的執行結果來看num做為一個變數被儲存起來在後面
函數的調用可以再擷取到。 如果我們把num++;放到place2的位置
看到的結果就是666.說明函數的執行順序執行 saynumadd() 執行過程
中 1,聲明變數num,2,聲明函數 showAlert,3,把變數num自增加1;
當我們執行 sayNumber()的時候看到的就是667 增加後被儲存的結果。
*/
function setupSomeGlobals(){
var num = 666;
//store some references to function as global variables
getAlertNumber = function (){
alert(num);
}
getIncreaseNumber = function(){
num ++;
}
getSetNumber = function(x){
num = x;
}
}
setupSomeGlobals();
getIncreaseNumber();
getAlertNumber();
getSetNumber(10);
getAlertNumber();//10
setupSomeGlobals();
getAlertNumber();//666
/*
onte:
從上面的例子可以看出,
setupSomeGlobals 裡面的三個函數被聲明都有許可權去訪問裡面的變數。
如果我們重新調用 setupSomeGlobals() 新的函數堆棧會被建立. 之前建立的getAlertNumber, getIncreaseNumber, getSetNumber 會被重寫並有一個新的閉包. (在 JavaScript中, 無論任何候都可以在function的內部聲明另外一個function,外面的function被調用的時候,裡面的function都會被重新建立.)
*/
function buildList( list ){
var result = [];
for (var i = 0 ; i<list.length; i ++){
var item = ‘item‘ + list[i];
result.push(function(){alert(item +‘ ‘+list[i])});
}
return result;
}
function testList(){
var fnList = buildList([1,2,3,4]);
for(var j=0; j < fnList.length; j ++){
fnList[j]();
}
}
testList();//alert item1 undefined;
/*
運行結果,可以說明function裡面的function只可以儲存本地變數,不能儲存參數變數。所以我們在使用封包函數要注意其中變數的範圍。
*/
function callLocalVar(){
var sayAlertName = function(){alert(name)};
var name = "jacy";
return sayAlertName;
}
callLocalVar()();//這種寫首先會執行callLocalVar再執行返回的sayAlertName;
/*
note:
總結閉包函數可以訪問到同一個域時定義的變數,無論是在這個閉包函數的前面還是後面。 只要是同一個域就可以被訪問到。
*/
function checkClosure(someNum, someRef){
var num = someNum;
var arr = [1,2,3];
var ref = someRef;
return function(x){
num += x;
arr.push(num);
alert(‘num :‘+num + ‘ \n arr :‘+arr.toString()
+‘\n ref.someVar‘+ref.someVar);
}
}
var obj = {someVar:4};
var fn1 = checkClosure(4,obj);
var fn2 = checkClosure(5,obj);
fn1(1);// num: 5; arr: 1,2,3,5; ref.someVar: 4;
fn2(1);// num: 6; arr: 1,2,3,6; ref.someVar: 4;
obj.someVar ++;
fn1(2);// num: 7; arr: 1,2,3,5,7; ref.someVar: 5;
fn2(2);//num: 8; arr: 1,2,3,6,8; ref.someVar: 5;
/*
note:
這裡的寫法解決了參數變數不能被儲存的問題,只要建立一個本地範圍一個變數來接收這個參數變數的值就可以了。
可以說明不同的範圍,互相不影響。
*/
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
學習總結 javascript 閉包