下面是它的工做原理。每當聲明一個新函數並將其賦值給變量時,其實是保存了函數定義和閉包。閉包包含了建立函數時聲明的全部變量,就像一個揹包同樣——函數定義附帶一個小揹包。這個揹包保存了建立函數時聲明的全部變量。php
因此咱們上面的解釋都是錯誤的,讓咱們再試一次,但此次是正確的:閉包
function createCounter() { let counter = 0 const myFunction = function() { counter = counter + 1 return counter } return myFunction } const increment = createCounter() const c1 = increment() const c2 = increment() const c3 = increment() console.log('example increment', c1, c2, c3)
第 1-8 行,咱們在全局執行上下文中建立了一個新變量 createCounter,它包含了一個函數定義,與上面相同。函數
第 9 行,咱們在全局執行上下文中聲明一個名爲 increment 的新變量,與上面相同。spa
第 9 行,咱們調用 createCounter 函數並將其返回值賦給 increment 變量,與上面相同。設計
第 1-8 行,調用函數,建立新的本地執行上下文,與上面相同。blog
第 2 行,在本地執行上下文中聲明一個名爲 counter 的新變量,並賦值爲 0,與上面相同。接口
第 3-6 行,在本地執行上下文中聲明名爲 myFunction 的新變量。變量的內容是另外一個函數的定義,即第 4 行和第 5 行所定義的內容。咱們還建立了一個閉包並將其做爲函數定義的一部分,閉包含包含函數做用域內的變量,在本例中爲變量 counter(值爲 0)。資源
第 7 行,返回 myFunction 變量的內容,刪除本地執行上下文。myFunction 和 counter 再也不存在,控制權返回到調用上下文。因此咱們返回函數定義及其閉包,閉包中包含建立函數時聲明的變量。作用域
第 9 行,在調用上下文(全局執行上下文)中,createCounter 返回的值被賦給 increment。變量 increment 如今包含一個函數定義(和閉包),其中函數定義由 createCounter 返回。它再也不被標記爲 myFunction,但定義是同樣的。在全局上下文中,它被稱爲 increment。rem
第 10 行,聲明一個新變量(c1)。
第 10 行,查找變量 increment,它是一個函數,調用它,它包含以前返回的函數定義,也就是第 4-5 行所定義的內容(還有一個帶變量的閉包)。
建立新的執行上下文,沒有參數,開始執行這個函數。
第 4 行,counter = counter + 1。咱們須要查找變量 counter。在查看本地或全局執行上下文以前,先讓咱們來看看閉包。請注意,閉包包含一個名爲 counter 的變量,其值爲 0。在第 4 行的表達式以後,它的值被設置爲 1,而後再次保存在閉包中。閉包如今包含了值爲 1 的變量 counter。
第 5 行,咱們返回 counter 的值或數值 1,銷燬本地執行上下文。
返回第 10 行,返回值(1)被分配給 c1。
第 11 行,咱們重複步驟 10-14。此次,咱們能夠看到變量 counter 的值爲 1,這個值是在第 4 行代碼中設置的。它的值加 1,並在 increment 函數的閉包中存爲 2。c2 被賦值爲 2。
第 12 行,咱們重複步驟 10-14,c3 被設爲 3。
第 13 行,咱們記錄變量 c一、c2 和 c3 的內容。
因此如今咱們瞭解閉包的工做原理。當聲明一個函數時,它包含一個函數定義和一個閉包。閉包是函數建立時聲明的變量的集合。
你可能會問,任何函數是否都有閉包,包括在全局範圍內建立的函數?答案是確定的。在全局範圍中建立的函數也會建立一個閉包。但因爲這些函數是在全局範圍內建立的,所以它們能夠訪問全局範圍內的全部變量,就無所謂閉包不閉包了。
當一個函數返回另外一個函數時,纔會真正涉及閉包。返回的函數能夠訪問僅存在於其閉包中的變量。
結 論
我經過揹包類比的方式記住了閉包。當建立和傳遞一個函數或將其從另外一個函數返回時,這個函數就帶有一個揹包,揹包中包含了全部在建立函數時聲明的變量。
存在的意義:
閉包就是一種語法糖,它以很天然的形式,把咱們的目的和咱們的目的所涉及的資源全給自動打包在一塊兒,以某種天然、儘可能不讓人誤解的方式讓人來使用。至於其具體實現,我我的意見,在不影響使用的狀況下,不求甚解便可。在不少狀況下,須要在一段代碼裏去訪問外部的局部變量,不提供這種語法糖,須要寫很是多的代碼,有了閉包這個語法糖,就不用寫這麼多代碼,天然而然的就用了。
閉包是從用戶角度考慮的一種設計概念,它基於對上下文的分析,把齷齪的事情、複雜的事情和外部環境交互的事情都本身作了,留給用戶一個很天然的接口。