閉包,英文叫做closure,借用MDN中的解釋,一個函數(shù)和對其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起(或者說函數(shù)被引用包圍),這樣的組合就是閉包(closure)。js中的閉包有以下幾個特性:
? ? 1.存在函數(shù)的嵌套
? ? 2.內(nèi)部函數(shù)可以引用外部的變量以及參數(shù)
? ? 3.變量以及參數(shù) 不會被垃圾回收機制回收
例子如下:
function?outFn(){
???var?name?=?'wolfBite'; // 外部函數(shù)變量
???function?innerFn(){ //內(nèi)部函數(shù)
??????console.log( 'hi '+name +'!') //引用外部的變量 name
???}
???innerFn();
}
outFn(); // hi?wolfBite!
????函數(shù)outFn定義了局部變量 name 和函數(shù) innerFn,函數(shù)innerFn中的console語句 引用name,注意函數(shù)innerFn內(nèi)部沒有定義局部變量name,? ?最后函數(shù)outFn執(zhí)行了函數(shù)innerFn。調(diào)用ouFn(),打印出問候語‘hi wolfBite!’。
第二個例子如下:
function?outFn(){
???var?name?=?'wolfBite';?//?外部函數(shù)變量
???function?innerFn(){?//內(nèi)部函數(shù)
??????console.log(?'hi?'+name?+'!')?//引用外部的變量?name
???}
???return?innerFn; //直接返回
}
var?myFn?=?outFn(); // 接收返回值(此時outFn執(zhí)行完了,但變量name并沒有被回收機制回收)
myFn();// hi?wolfBite!
????會發(fā)現(xiàn)例子二和例子一的區(qū)別,函數(shù)outFn最后沒有直接執(zhí)行innerFn,而是將函數(shù)innerFn返回,代碼最后沒有直接執(zhí)行函數(shù)outFn,而是將outFn的執(zhí)行結果(函數(shù)innerFn)返回給變量myFn ,最后再執(zhí)行myFn();
????你可能會覺得執(zhí)行完 ‘var?myFn?=?outFn();’這語句之后,outFn內(nèi)部定義的變量name已經(jīng)被回收機制回收了,innerFn無法訪問這個變量,然而代碼仍按預期運行。原因是函數(shù)innerFn形成了閉包,這個閉包是由這個函數(shù)和創(chuàng)建該函數(shù)時的詞法環(huán)境組合而成,這個環(huán)境包含了這個閉包創(chuàng)建時所有的局部變量。例子二中myFn 是 執(zhí)行outFn時返回的innerFn實例的引用,innerFn的實例維持了一個對它的詞法環(huán)境(變量?name?存在于其中)的引用,因此當myFn調(diào)用時,變量name仍可訪問。