原鏈接:http://www.cnblogs.com/xiaohuochai/p/5728577.html
古老定義
閉包(closure),是指函數變量可以保存在函數作用域內,因此看起來是函數將變量“包裹”了起來
那這樣說來,包含變量的函數就是閉包
//按照古老定義,包含變量n的函數foo就是閉包
function foo() {
var n = 0;
}
console.log(n)//Uncaught ReferenceError: n is not defined
定義一
閉包是指可以訪問其所在作用域的函數
那這樣說來,需要通過作用域鏈查找變量的函數就是閉包
//按照定義一的說法,需要通過作用域鏈在全局環境中查找變量n的函數foo()就是閉包
var n = 0;
function foo() {
console.log(n)//0
}
foo();
定義二
閉包是指有權訪問另一個函數作用域中的變量的函數
那這樣說來,訪問上層函數的作用域的內層函數就是閉包
//按照定義二的說法,嵌套在foo函數裏的bar函數就是閉包
function foo(){
var a = 2;
function bar(){
console.log(a); // 2
}
bar();
}
foo();
定義三
閉包是指在函數聲明時的作用域以外的地方被調用的函數
在函數聲明時的作用域以外的地方調用函數,需要通過將該函數作爲返回值或者作爲參數被傳遞
//按照定義三的說法,在foo()函數的作用域中聲明,在全局環境的作用域中被調用的bar()函數是閉包
function foo(){
var a = 2;
function bar(){
console.log(a); //2
}
return bar;
}
foo()();
可以簡寫爲如下表示:
function foo(){
var a = 2;
return function(){
console.log(a);//2
}
}
foo()();
IIFE(立即執行函數)
IIFE是不是閉包呢?
foo()函數在全局作用域定義,也在全局作用域被立即調用,如果按照定義一的說法來說,它是閉包。如果按照定義二和定義三的說法,它又不是閉包
var a = 2;
(function foo(){
console.log(a);//2
})();
最後
閉包定義之所以混亂,我覺得與經典書籍的不同解讀有關。經典定義是犀牛書的原話,定義二是高程的原話
但,歸納起來就是關於一個函數要成爲一個閉包到底需要滿意幾個條件
嚴格來說,閉包需要滿足三個條件:【1】訪問所在作用域;【2】函數嵌套;【3】在所在作用域外被調用
有些人覺得只滿足條件1就可以,所以IIFE是閉包;有些人覺得滿足條件1和2纔可以,所以被嵌套的函數纔是閉包;有些人覺得3個條件都滿足纔可以,所以在作用域以外的地方被調用的函數纔是閉包
問題是,誰是權威呢?