函數(shù)內(nèi)部又定義了一個(gè)函數(shù),這個(gè)子函數(shù)就可以稱為閉包。
創(chuàng)新互聯(lián)主營蘇州網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,app軟件定制開發(fā),蘇州h5成都微信小程序搭建,蘇州網(wǎng)站營銷推廣歡迎蘇州等地區(qū)企業(yè)咨詢
閉包的一個(gè)特點(diǎn)就是閉包內(nèi)部可以引用外部函數(shù)的變量。
要理解閉包的原理,最重要的是要理解JavaScript的作用域鏈機(jī)制。
作用域
js中作用域分為兩種,全局作用域和函數(shù)作用域(局部作用域),此外js遵循的是靜態(tài)作用域規(guī)則。
作用域鏈
由作用域形成的鏈條就稱為作用域鏈,但這個(gè)作用域鏈存儲(chǔ)的是指向各個(gè)活動(dòng)對(duì)象的指針。下面我們看下作用域鏈的具體形成過程:全局作用域是一直存在的,函數(shù)作用域只有在執(zhí)行到它的時(shí)候才會(huì)生成,當(dāng)函數(shù)被定義時(shí),函數(shù)的`scope`屬性會(huì)存儲(chǔ)該函數(shù)外部的作用域下的活動(dòng)對(duì)象(指針),包括全局變量對(duì)象,所以可能是個(gè)指針列表。然后我們?cè)谡{(diào)用函數(shù)時(shí),首先會(huì)為它創(chuàng)建一個(gè)執(zhí)行環(huán)境,然后創(chuàng)建作用域鏈,這個(gè)作用域鏈先是復(fù)制`scope`屬性的值,新航道雅思培訓(xùn)然后把自己的活動(dòng)對(duì)象推入作用域鏈的前端,這個(gè)活動(dòng)對(duì)象由該函數(shù)作用域下的變量構(gòu)成,這樣函數(shù)的作用域鏈就形成了。
舉個(gè)栗子:
var g = 1;function out(){var out = "out";return function(){ var inner = "inner"; return out; } }
示例圖
當(dāng)函數(shù)執(zhí)行完畢,作用域鏈就會(huì)被銷毀,之前占用的內(nèi)存也會(huì)被釋放,但如果函數(shù)內(nèi)部定義了一個(gè)子函數(shù),這個(gè)時(shí)候子函數(shù)的`scope`屬性就會(huì)存儲(chǔ)著指向父函數(shù)活動(dòng)對(duì)象的指針,活動(dòng)對(duì)象由于仍被子函數(shù)引用,所以不會(huì)被銷毀,父函數(shù)的變量仍舊沒有被消除。變量out的值仍舊是“out”。
// 可通過如下代碼驗(yàn)證var abc = out(); alert(abc());
結(jié)果:
閉包最常用的一個(gè)地方就是保留父函數(shù)的變量,這個(gè)在上面的例子中已經(jīng)說明
閉包的另一個(gè)應(yīng)用是模擬塊級(jí)作用域和私有變量,這是應(yīng)用函數(shù)擁有自己的作用域的特點(diǎn),在不想成為公有變量的變量外報(bào)上一層匿名函數(shù)并且立即執(zhí)行
(function(){ // 這里是塊級(jí)作用域 })();
閉包雖然看似簡單,但它揭示了js作用域鏈的機(jī)制,而且閉包有很多應(yīng)用場景,如果不看懂它只會(huì)越來越懵逼。