中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

javascript中的閉包

發布時間:2020-06-19 10:43:21 來源:億速云 閱讀:131 作者:Leah 欄目:web開發

這篇文章將為大家詳細講解有關javascript中的閉包,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

閉包并不是 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: 封閉環境內的變量

這個示例是一個典型的閉包,有這么幾點需要注意:

  1. showMessagecreateAction 執行后從中返回出來的一個函數
  2. createAction 內部是一個封閉的詞法環境,message 作為該封裝環境內的變量,在外面是絕不可能直接訪問。
  3. showMessagecreateAction 外部執行,但執行時卻訪問到其內部定義的局部變量 message(成功輸出)。這是因為 showMessage 引用的函數(createAction 內部的匿名函數),在定義時,綁定了其所處詞法環境(createAction 內部)中的引用(message 等)。
  4. 綁定了內部語法環境的匿名函數被 return 帶到了 createAction 封閉環境之外使用,這才能形成閉包。如果是在 createAction 內部調用,不算是閉包。

好了,我相信 1, 2, 4 都好理解,但是要理解最重要的第 3 點可能有點困難 —— 困難之處在于,這不是程序員能決定的,而是由語言特性決定的。所以不要認為是“你”創建了閉包,因為閉包是語言特性,你只是利用了這一特性

如果語言不支持閉包,類似上面的代碼,在執行 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

ESM (ECMAScript Module) 中使用了 importexport 語法,也只不過是換種方法帶貨出去而已,和 return 帶貨差不多,區別只在于 return 只能帶一個(除非打包),export 可以帶一堆。

還要補充的是,不管是 CJS 還是 ESM,模塊都是一個封裝環境,其中定義的東西只要不帶出去,外面是訪問不到的。這和網頁腳本默認的全局環境不同,要注意區別。

如果用代碼來表示,大概是定義模塊的時候以為是這樣:

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
}

閉包是由一個函數以及其定義時所在封閉環境內的各種資源(引用)構成,拿到的每一個閉包都是獨一無二的,因為構成閉包的環境資源不同(不同的局部環境,定義了不同的局部變量,傳入了不同的參數等)。

關于javascript中的閉包就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

始兴县| 纳雍县| 石城县| 临漳县| 滨海县| 林甸县| 镇巴县| 灵台县| 项城市| 合水县| 海伦市| 日喀则市| 河间市| 钦州市| 北票市| 枝江市| 舟曲县| 高尔夫| 建湖县| 嵊州市| 大冶市| 吉水县| 章丘市| 石门县| 泌阳县| 普兰店市| 霍州市| 台南县| 平昌县| 资溪县| 琼中| 个旧市| 舞阳县| 永年县| 盐源县| 庆安县| 靖边县| 濉溪县| 西昌市| 大埔区| 玉环县|