什么是閉包
閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)鳞尔,創(chuàng)建閉包的常見的方式长酗,就是在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù),通過另一個函數(shù)訪問這個函數(shù)的局部變量蜘拉。
function f1(){
var n=999;
return function (){
console.log(n++);
}
}
var result=f1();
result(); // 999
result(); // 1000
當(dāng)匿名函數(shù)被返回時,我們會初始化其作用域鏈有鹿,包含了f1()的活動對象和全局變量對象旭旭,這樣匿名函數(shù)就可以訪問f1()的變量,而且f1()函數(shù)執(zhí)行完畢后葱跋,他的活動對象不會銷毀持寄,因為匿名函數(shù)的作用域鏈仍然保存著對他的引用源梭。
1. 從理論角度來說:
所有的函數(shù)都是閉包。因為所有的函數(shù)在創(chuàng)建的時候就將上層的上下文的作用域鏈保存起來稍味。即使在函數(shù)中訪問了全局變量相當(dāng)于訪問自由變量废麻。
2. 從實踐角度:需要滿足以下條件:
- 即使創(chuàng)建他的上下文已經(jīng)銷毀,他仍然存在
- 在代碼中引用了自由變量(跨了自己的作用域的變量)
循環(huán)中的閉包
看下面這個例子:
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = function(){
return i;
}
}
return arr;
}
console.log(box()[0]());
結(jié)果是5模庐,是數(shù)組中的第一個數(shù)返回的值烛愧,
為什么????
一個函數(shù)的創(chuàng)建伴隨著他的執(zhí)行環(huán)境和作用域鏈,我們需要在作用域中查找變量 i 掂碱,如果在當(dāng)前的匿名函數(shù)內(nèi)沒有找到怜姿,那就要到上一層的作用域去找,找到 i 的值 疼燥。
作用域鏈的本質(zhì)是指向變量對象的指針列表沧卢,不包含實際的變量對象。但是閉包中保存的的是整個變量對象悴了,而不是某一個具體的值搏恤。所以每個匿名函數(shù)的父作用域是同一個,他們的 i 都指向同一個變量對象湃交,最終的 i 是5熟空。
解決方法:
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(e){
return e;
})(i)
}
return arr;
}
console.log(box()); //輸出 [0, 1, 2, 3, 4]
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(e){
return function(){
return e;
}
})(i)
}
return arr;
}
console.log(box()[0]()); //輸出0,是數(shù)組中的第一個數(shù)