閉包,又見閉包。。。。?

1.閉包是指有權訪問另外一個函數做用域中的變量的函數。

上面這段話來自 javascript 高級程序設計 第三版 P178 。做者說閉包是一個函數,它有訪問另外一個函數做用域中的變量的能力。javascript

2.函數訪問它被建立時所處的上下文環境。這被稱爲閉包。

這段話來自 javascript 語言精粹 修訂版 P38 。做者沒有定義閉包爲什麼物,只是說函數訪問它被建立時的上下文環境,這種xxx(行爲?過程?能力?) 被稱爲閉包。前端

3.1閉包是依賴於詞法做用域編寫代碼而產生的結果

3.2閉包就是函數可以記住並訪問它的詞法做用域,即便當這個函數在它的詞法做用域以外執行時java

這兩段話來自 You-Dont-Know-JS 做用域閉包 這一章,做者說閉包是一種結果。git


閉包的通常定義

閉包是一種抽象概念,每一個人對其理解不一樣,因此有了上面的幾種解釋。但你們討論的確是同一個問題。github

//step 1
function outer() {
  var a = 'hello world';
  function inner() {
    return a ;
  }
  return inner();
}
// hello world
outer();

咱們發現位於 outer 函數內的 inner 函數能夠訪問到另外一個函數 outer 的做用域中的變量 a 。完美的閉包,對,閉包就這麼簡單。哈哈哈哈哈,本文結束!!!後端


閉包的由來

其實上面那段代碼並非你們真正所說的閉包,它實際上是利用了函數做用域的特色 -- 內層函數能夠訪問外層變量。這僅僅是閉包的一部分,閉包利用函數做用域達到了訪問外層變量 a 的目的。閉包

依據定義 1,閉包能夠說在代碼 step1 中已經產生了。
咱們接下來看 step2:函數

//step 2
function outer() {
  a = 'hello world';
  function inner() {
      return a;
    }
  return inner();
}

var c = outer();
// hello world
c;

此次咱們執行 outer 函數, outer() 是一個函數對象,在內部只會返回 inner 函數的結果 a ,由於 inner 函數的存在,每次執行 inner 便會對變量 a 進行引用,這會致使變量 a 的引用計數爲 1 ,從而垃圾回收機制沒法銷燬變量 a。咱們便在函數執行完畢後依然訪問到了變量 a。正規的寫法如 step3:設計

//step3
var c = (function() {
  var a = 'hello world';
  return {
    inner : function() {
      return a;
    }
  }
})();

// hello world
c.inner();

咱們利用自執行匿名函數把 inner 函數保存到對象 c 上,這時 c.inner 就是 inner 函數,它能夠訪問到 inner 函數以外的變量 a 。變量 c.inner 引用了變量 a 的值,致使變量 a 在函數執行後依然沒法被銷燬 。此時一個完整的閉包實現了, js 的垃圾回收機制因爲閉包的存在沒法銷燬變量 a。咱們利用閉包,在函數外層仍是訪問到了 a ,保存了函數內部的細節。這就是閉包的所有。由此得來下面定義:code

4.閉包是阻止垃圾回收機制在內存中銷燬變量的方法,使得在建立變量的執行環境外能夠訪問到該變量

上面這段話來自 單頁Web應用 JavaScript 從前端到後端 P49,我的認爲這本書也是對閉包解釋最爲詳盡生動的一本書。由於此書中大量使用了模塊模式因此對閉包的解釋十分詳盡。

總結一下:閉包是由函數產生的「函數能夠建立新的做用域」,當咱們把它賦值給一個變量後,一個完整的閉包出現了。它阻止了 js 的垃圾回收機制對函數內部變量的回收,致使函數內部變量的引用計數一直不爲 0,沒法被垃圾收集器回收。因此咱們常聽亂用閉包可能致使內存泄漏,就是由於閉包的這個特色。

函數做用域的特性讓咱們能夠從函數內部取得函數外部的變量,而閉包提供了一種反向的操做可能 -- 咱們在函數的外部也能夠取得函數內部的變量

閉包是函數外能夠訪問函數內變量的實現

其它:
StackOverflow 閉包是什麼
閉包的用處:You-Dont-Know-JS

相關文章
相關標籤/搜索