閉包並不是 JavaScript 特有的,大部分高階語言都具有這項能力。
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).##這段是MDN 上對閉包的定義,理解為:一個函數及其周圍封閉詞法環境中的引用構成閉包。可能這句話還是不好理解,看看範例:
function createAction() { var message = "封闭环境内的变量"; return function() { console.log(message); } } const showMessage = createAction(); showMessage(); // output: 封闭环境内的变量這個範例是一個典型的閉包,有這麼幾點要注意:
是
createAction 執行後從中傳回出來的一個
函數。
內部是一個封閉的詞法環境,
message 作為該封裝環境內的變量,在外面是絕不可能直接存取。
在
createAction 外部執行,但執行時卻存取到其內部定義的局部變數
message(成功輸出)。這是因為
showMessage 引用的函數(
createAction 內部的匿名函數),在定義時,綁定了其所處詞法環境(
createAction 內部)中的引用(
message 等)。
帶到了
createAction 封閉環境之外使用,這才能形成閉包。如果是在
createAction 內部調用,不算是閉包。
不要認為是「你」創建了閉包,因為閉包是語言特性,你只是利用了這個特性。
如果語言不支援閉包,類似上面的程式碼,執行showMessage 時,就會找不到
message 變數。我特別想去找一個例子,但是很不幸,我所知道的高階語言,只要能在函數/方法內定義函數的,似乎都支援閉包。
return 把局部定義的函數帶出去,除此之外有沒有別的辦法?
function encase(aCase) { const dog = "狗狗"; const cat = "猫猫"; aCase.show = function () { console.log(dog, cat); }; } const myCase = {}; encase(myCase); myCase.show(); // output: 猫猫 狗狗是不是受到了啟發,有沒有聯想到什麼? 模組和閉包對了,就是 exports 和 module.exports。在CJS (CommonJS) 定義的模組中,就可以透過
exports.something 逐一帶貨,也可以透過
module.exports = ... 打包帶貨,但不管怎麼樣,
exports 就是帶貨的那一個,只是它有可能是原來安排的
exports 也可能是被換成了自己人的
exports。
import 和
export 語法,也只不過是換種方法帶貨出去而已,和
return 帶貨差不多,差別只在於
return 只能帶一個(除非打包),
export 可以帶一堆。
const var1 = "我是一个顶层变量吧"; function maybeATopFunction() { }結果在運行環境中,它其實是這樣的(注意:僅示意):
// module factory function createModule_18abk2(exports, module) { const var1 = "我是一个顶层变量吧"; function maybeATopFunction() { } } // ... 遥远的生产线上,有这样的示意代码 const module = { exports: {} }; const m18abk2 = createModule_18abk2(module) ?? module; // 想明白 createModule_18abk2 为什么会有一个随机后缀没?還是那個函數嗎? 扯遠了,拉回來。思考一個問題:理論上,函數是靜態程式碼區塊,那麼多次呼叫外層函數回傳的閉包函數,是同一個嗎? 試試看:
function create() { function closure() { } return closure; } const a = create(); const b = create(); console.log(a === b); // false如果覺得意外,那把
closure() 換個方式定義看會不會好理解一點:
function create() { closure = function() { } return closure; }如果還不能理解,再看這個:
function create() { const a = function () { }; const b = function () { }; console.log(a === b); // false }能理解了不:每一次
function 都定義了一個新的函數。函數是新的,名字不重要 —— 你能叫小明,別人也能叫小明不是。
JS教學》
以上是js中閉包的概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!