1、先來看一個(gè)閉包的代碼小例子:
var scope = "全局scope";
function checkScope() {
var scope = "內(nèi)部scope";
function f() {
return scope;
}
return f();
}
checkScope(); //=> "內(nèi)部scope"
閉包可以捕獲到局部變量和參數(shù)的外部函數(shù)綁定,即便外部函數(shù)的調(diào)用已經(jīng)結(jié)束。
詞法作用域的規(guī)則,即函數(shù)被執(zhí)行時(shí)(executed)使用的作用域鏈(scope chain)是被定義時(shí)的scope chain,而不是執(zhí)行時(shí)的scope chain,就可以很容易的理解閉包的行為了。
2、在javascript語言中,閉包就是函數(shù)和該函數(shù)作用域的組合。從這個(gè)概念上來講,在js中,所有函數(shù)都是閉包(函數(shù)都是對(duì)象并且函數(shù)都有和他們相關(guān)聯(lián)的作用域鏈scope chain)。簡(jiǎn)單說:閉包就是有權(quán)訪問另一個(gè)函數(shù)作用域中變量的函數(shù).
3、在ES6之前,函數(shù)只能在全局作用域和函數(shù)作用域中聲明,不能在塊級(jí)作用域中聲明。沒有塊級(jí)作用域?qū)е潞芏鄨?chǎng)景不合理,閉包在一些地方很好解決了這個(gè)不合理。
4.閉包的使用場(chǎng)景
場(chǎng)景描述:假如頁面上有5個(gè)button,要給button綁定onclick事件,點(diǎn)擊的時(shí)候,彈出對(duì)應(yīng)button的索引編號(hào)。
#html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<button>Button0</button>
<button>Button1</button>
<button>Button2</button>
<button>Button3</button>
<button>Button4</button>
</body>
</html>
#js
...
var btns = document.getElementsByTagName('button');
for(var i = 0, len = btns.length; i < len; i++) {
btns[i].onclick = function() {
console.log(i);
}
}
...
通過執(zhí)行該段代碼,發(fā)現(xiàn)不論點(diǎn)擊哪個(gè)button ,均輸入4;
這顯然不符合我們的需求,我們我們需要修改代碼:
1?? 將for循環(huán)中的var 變?yōu)閘et
2??Tip: 在ES6之前,沒有塊級(jí)作用域 ,只有函數(shù)作用域(即:通過var聲明的變量沒有塊級(jí)作用域)??梢圆捎谩傲⒓磮?zhí)行函數(shù)”的方式創(chuàng)建作用域。
for(var i = 0, len = btns.length; i < len; i++) {
(function(i) {
btns[i].onclick = function() {
console.log(i);
}
}(i))
}
5、閉包注意點(diǎn)
由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。