最近正在整理一些JS的基礎(chǔ)知識眯亦,看見閉包這個詞伤溉,突然覺得有必要記錄一下:
在ES6的塊級作用域出現(xiàn)之前,是沒有塊級作用域的概念的妻率,這就導(dǎo)致當想訪問一個函數(shù)內(nèi)部變量的時候乱顾,會出現(xiàn)一定的困難,這個時候閉包就出現(xiàn)了宫静。
我們最初接觸閉包的時候糯耍,很大概率是通過以下情況:
function fn(){
var li = document.getElementsByTagName("li");
for(var i = 0; i < li.length; i++){
li[i].onclick = function(){
console.log(i);
}
}
}
fn();
運行的結(jié)果是這樣的:每點擊一個li,打印出來的都是 li的長度囊嘉;為什么會出現(xiàn)這么個結(jié)果呢温技?這就從JS中的作用域鏈講起。
什么是JS的作用域鏈扭粱?
簡單來說就是在函數(shù)中所能訪問的變量按照層級關(guān)系所組成的一條有著先后順序的鏈子舵鳞。所以每個函數(shù)最先能訪問的變量(也就是在這條鏈子上最先能接觸到的)是當前函數(shù)的活動對象(就是在函數(shù)當中定義或重新賦值的變量),其次下一個能訪問的變量就是當前的函數(shù)所在的包含環(huán)境琢蛤。然后是下下個包含環(huán)境蜓堕。這樣一層層的找下去,直到找到全局執(zhí)行環(huán)境為止博其。
所以套才,以上題目的結(jié)果,可以解釋:每個li標簽的onclick事件執(zhí)行時慕淡,本身onclick綁定的function的作用域中沒有變量i背伴,i為undefined,則解析引擎會尋找父級作用域,發(fā)現(xiàn)父級作用域中有i峰髓,且for循環(huán)綁定事件結(jié)束后傻寂,i已經(jīng)賦值為4,所以每個li標簽的onclick事件執(zhí)行時携兵,打印的都是父作用域中的i疾掰,也就是4。這是作用域的問題徐紧。
所以根據(jù)以上解釋静檬,我們只能把i存放在一個變量之中,這時候閉包就出現(xiàn)了:
function fn(){
var li = document.getElementsByTagName("li");
for(var i = 0; i < li.length; i++){
li[i].onclick = function(n){
return function(){
console.log(n);
}
}(i)
}
}
fn();
所以閉包的含義就很明顯了:閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)并级。
那么閉包的作用:
1拂檩、可以在函數(shù)的外部訪問到函數(shù)內(nèi)部的局部變量。
2死遭、讓這些變量始終保存在內(nèi)存中广恢,不會隨著函數(shù)的結(jié)束而自動銷毀。