国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

詞法作用域與閉包

張金寶 / 2177人閱讀

摘要:我們可以這么解決問題在上述代碼中,每次遍歷我們都使用生成一個新的作用域,使得延遲函數的回調可以將新的作用域封閉在每個迭代內部,每個迭代中都會含有一個具有正確值的變量供我們訪問。

首先需要明確的是,javascript 中沒有塊作用域,只有函數作用域
到底什么是閉包?
function foo() {
    var a = 2;

    function bar() {
        console.log(a); // 2
    }

    bar();
}

foo();

這是閉包嗎?
技術上來講也許是,但確切地說并不是。

我認為最準確地用來解釋 bar() 對 a 的引用的方法是詞法作用域的查找規則,而這些規則只是閉包的一部分。(但卻是非常重要的一部分!)
function foo() {
    var a = 2;

    function bar() {
        console.log(a); // 2
    }

    return bar;
}

var baz = foo();

baz(); // 2

這才是閉包的效果!
在上例中函數 bar 在定義自己的詞法作用域以外的地方執行,在 foo 執行后垃圾回收器不知道 bar 什么時候會被調用,這使得對 foo 內部作用域的回收工作被阻止,而 bar 依然持有對該作用域的引用,這個引用就叫做閉包

無論通過何種手段將內部函數傳遞到所在的詞法作用域以外,它都會持有對原始定義作用域的引用,無論在何處執行這個函數都會使用閉包。
循環與閉包

要說明閉包,for 循環是最常見的例子。

for (var i = 0; i < 10; i++) {
    console.log(i);
}

執行上述代碼我們可以打印出0到9十個數字,但是如果執行下面這段代碼呢?

for (var i = 1; i <= 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, i * 1000);
}

正常情況下,我們對這段代碼行為的預期是分別輸出數字 1~5,每秒一次,每次一個。
但實際上,這段代碼在運行時會以每秒一次的頻率輸出五次 6。

我們可以這么理解問題:眾所周知 javascript 是解釋型的單線程編程語言,上述代碼的執行過程實際是,執行 for 循環并把5個匿名函數的觸發分別間隔 1-5 秒放入異步隊列當中,而當異步隊列的頭節點開始執行時,for 循環早已經執行完畢,并且此時 i 作為全局作用域中的變量,其值為 6,這時無論異步隊列中的頭節點還是尾節點,在打印 i 變量的值并試圖向上層作用域查找 i 時,獲得的結果都是 6。

我們可以這么解決問題!

for (var i = 1; i <= 5; i++) {
    (function(j) {
        setTimeout(function timer() {
            console.log(j);
        }, j * 1000);
    })(i);
}
在上述代碼中,每次遍歷我們都使用 IIFE 生成一個新的作用域,使得延遲函數的回調可以將新的
作用域封閉在每個迭代內部,每個迭代中都會含有一個具有正確值的變量供我們訪問。

用容易理解的語言可以這么描述:IIFE 在執行完畢后,不知道延遲函數的回調什么時候執行,所以 IIFE 的作用域無法被銷毀,其 j 變量的值被鎖住。

塊作用域與閉包

熟悉 ES6 的同學們都知道,下述代碼也可以解決上面的 for 循環問題:

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}
for (let i = 1; i <= 5; i++) 這行代碼的圓括號之間存在一個隱藏的作用域,在每次執行循環體之前,javascript 引擎會把 i 在循環體的上下文中重新聲明及初始化一次。

看到這兒我想大家應該有一個比較清楚的認識:解決 for 循環問題的根本是 塊作用域!無論是 let/const 還是閉包,其本質都是在每次遍歷時構建一個塊作用域。

至少從 ES3 發布以來,javaScript 中就有了塊作用域,而 withcatch 分句就是塊作用域的兩個小例子。

附錄

Tip: let 存在提升,只不過由于暫時死區的限制,不能在 let x 之前使用 x。

let 的「創建」過程被提升,但是初始化沒有提升

var 的「創建」和「初始化」都被提升

function 的「創建」「初始化」和「賦值」都被提升

const 和 let 只有一個區別,那就是 const 只有「創建」和「初始化」,沒有「賦值」過程

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83211.html

相關文章

  • Js基礎知識(三) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...

    lemanli 評論0 收藏0
  • Js基礎知識(三) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...

    XFLY 評論0 收藏0
  • Js基礎知識(三) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...

    tanglijun 評論0 收藏0
  • Js基礎知識(三) - 作用域與閉包

    摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...

    lmxdawn 評論0 收藏0

發表評論

0條評論

張金寶

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<