下面是來自MDN對閉包的定義bash
閉包是函數和聲明該函數的詞法環境的組合。閉包
先擱這,看下面。函數
var a = 1;
function foo() {
console.log(a);
}
function bar() {
var a = 2;
foo(); // a是1仍是2?
}
bar();
複製代碼
foo
中的a
打印1仍是2?優化
JS是詞法做用域,詞法做用域就是定義在詞法階段的做用域,因此a
指的是全局中的a
,JS如何保持詞法做用域不變呢?ui
把函數foo
和全局變量a
捆綁在一塊兒,這樣無論foo
在哪裏調用,都是打印全局的a
。spa
這就是閉包!閉包是實現詞法做用域的一種手段。code
咱們在JS中定義的每一個函數,都是閉包。不過要觀察閉包,就須要繞點彎子了。cdn
這是最經典的例子了blog
var a = 1;
function foo() {
var a = 2;
function bar() {
console.log(a);
}
return bar;
}
var closure = foo();
closure(); // 2
複製代碼
解釋1、閉包就是函數返回函數ip
閉包又稱爲「詞法閉包」,和做用域同樣,閉包在詞法階段就肯定了,和返不返回沒有關係,如上面的代碼,不返回bar
不影響bar
是閉包。
解釋2、閉包是引用了自由變量的函數
先解釋下自由變量
自由變量:一個變量,既不是函數參數,也不是函數的本地變量,則稱爲自由變量。
不引用自由變量也是閉包,證據以下,來自《你不知道的JavaScript(上卷)》,click回調並無引用自由變量
解釋3、如何解釋Chrome控制檯console.dir對函數的打印結果
在Chrome控制檯中使用console.dir
打印函數,有一個[[Scopes]]
屬性,裏面可能會有Closure
類型的域,咱們會發現
函數引用了自由變量,且自由變量是局部變量,
console.dir
打印結果中就會有Closure
類型的域
是否是沒有Closure
類型的域就說明打印的函數不是閉包了呢?個人猜想是:沒有打印,是由於被V8優化掉了或被垃圾回收了。
總結:也就是說,咱們定義的函數,無論返不返回、無論有沒有引用自由變量、無論自由變量是全局的仍是局部的,都是閉包。
歡迎關注咱的微博,一塊兒嗨:@狂刀二