搞一搞JavaScript閉包

定義

下面是來自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在哪裏調用,都是打印全局的aspa

這就是閉包!閉包是實現詞法做用域的一種手段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優化掉了或被垃圾回收了。

總結:也就是說,咱們定義的函數,無論返不返回、無論有沒有引用自由變量、無論自由變量是全局的仍是局部的,都是閉包。

最後

歡迎關注咱的微博,一塊兒嗨:@狂刀二

相關文章
相關標籤/搜索