2017-02-26 25 views
1

我只是想了解Javascript中的閉包。我在三個例子中遇到了。
Expample 1:理解閉包,爲每個迭代創建不同的範圍

for (var i = 0; i <= 10; i++) { 
 
    setTimeout(function() { 
 
    console.log("i :" + i) 
 
    }, i * 1000); 
 
}

,並如預期的那樣輸出它打印的「i:11」到控制檯11倍,因爲對整個循環只創建一個範圍是全球範圍內要在每次迭代中使用不同的範圍,我使用了IIFE(立即調用函數表達式),請參閱下面的代碼片段。
例如:於:2-

for (var i = 0; i <= 10; i++) { 
 
    (function(i) { 
 
    setTimeout(function() { 
 
     console.log("i : " + i) 
 
    }, i * 1000) 
 
    })(i); 
 
}

它從 「0 I」 打印 「我:10」 作爲預期的,因爲是針對每次迭代創建不同範圍。
我無法理解下面的代碼段中究竟發生了什麼。
例如:3

for (let i = 0; i <= 10; i++) { 
 
    setTimeout(function() { 
 
    console.log("i :" + i) 
 
    }, i * 1000); 
 
}

它輸出從 「我:0」 到 「I:10」。
1.我不能理解爲什麼輸出不像第一個例子那樣相同,即打印「1:11」11次?
2。如果我使用塊範圍,是否爲每次迭代創建了不同的作用域?
3。如果創建的範圍不同,那麼它與示例1有什麼不同?

回答

1

這是因爲let與塊範圍(var沒有)操作。這意味着它就像在構成for語句的代碼塊中聲明局部變量。

例如,你可以這樣做:

if (blockCount === 3) { 
    let x = 1; 
    // do something with x 
} else { 
    let x = 2: 
    // do something with x 
} 

console.log(x); // undefined since no longer in scope 

書面這將工作。如果您嘗試在if語句之外訪問x,則它將不確定。

有關更多信息,請參閱this link

0

在第一個示例中,您調用setTimeout(),該值在特定時間後打印變量i。當setTimeout()回調觸發時,循環結束並且i擁有最後的迭代值(11)。所有回調都會打印該變量。

在第二個示例中,您使用立即調用的函數表達式(IIFE)。這是一個函數,定義爲立即調用,並將參數i傳遞給它。 當你傳遞一個參數給一個函數時,它就像是一個新的局部變量被聲明。例如:

var foo = 5; 
 

 
function myLog(foo) { 
 
    console.log(foo); 
 
} 
 

 
myLog("not 5"); // logs "not 5" instead of 5

這意味着論點立即調用函數的i是從循環使用的i不同,但具有相同的價值,因爲你在當前傳遞循環迭代。
通過這種方法,您可以創建12個不同的i變量。一爲循環,11人的IIFEs,其使用的內部setTimeout()回調。

在第三個例子中,會發生類似的事情。 let聲明一個塊作用域局部變量。循環運行時,就像創建了11個不同的變量,並且每個回調都引用了在其本地範圍內創建的變量。這更詳細地解釋here