[英]Why is result different (using var vs. let)?
這使用var
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 10
這使用let
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 6
我不明白為什么結果不同。 有人可以指導我嗎?
結果數組由函數組成,每個函數體如下所示:
console.log(i);
i
的值取決於我們是使用var
還是let
來聲明變量。
var
(ECMAScript 5和6) 這里i
是一個全局變量,在退出循環后其值為10
。 這是記錄的值。
let
(ECMAScript 6) 這里i
是一個局部變量,其范圍僅限於for
語句。 此外,此變量在每次迭代時都會獲得新的綁定。 最好的解釋是您的代碼轉換為ECMAScript 5 :
"use strict";
var a = [];
var _loop = function(i) {
a[i] = function() {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); // 6
因此,例如,在第七次迭代中, i
的值將為6
(從零開始計數)。 在迭代內創建的函數將引用此值。
我認為不在循環中定義函數會好得多,您可以使用一個返回閉包的函數定義輕松完成此操作:
function logNumber(num) {
return function() {
console.log(num);
}
}
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = logNumber(i);
}
a[6]();
關於兩個示例之間的區別,一個是使用let
進行塊作用域。 一個顯示差異的更好的例子是:
ECMA5:
for (var i = 0; i < 10; i++) { }
console.log(i); // 10
ECMA6:
for (let i = 0; i < 10; i++) { }
console.log(i); // i is not defined
編輯 :正如我在您對您的問題的評論中所述,這更可能是您正在使用的轉換器的副作用。 Firefox支持塊作用域,你的循環的兩個版本都產生10
作為輸出(他們應該)。
根據規范,這是正確的行為。 var
和let
的行為定義為不同。
請參閱規范, 網址為https://people.mozilla.org/~jorendorff/es6-draft.html#sec-forbodyevaluation 。 根據這一點,使得在循環內聲明的函數接近塊作用域循環索引的當前值的相關概念稱為“每次迭代綁定”和“每次迭代環境”。
Babel正確處理它,產生以下代碼:
var a = [];
var _loop = function (i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
這實現的語義for (let
通過分離的內容for
循環到由索引參數化的單獨的功能。借助於這樣做的,該函數不再關閉在for循環索引,並且i
在每個功能單獨處理因此答案是6。
Traceur無法產生正確的結果。 它產生10。
因此,在SO上被問過100次的着名問題,關於我的函數在循環中聲明並關閉索引索引的原因是使用循環索引的“錯誤”值,不應再被問到了嗎?
這個問題稍微有些細微之處,只是宣稱“當然, let
是塊范圍的”。 我們知道。 例如,我們了解它在if
塊中的工作原理。 但是在這里發生的事情有點像在包括我在內的很多人都不知道的for
的背景下的塊區域划分。 它是在“塊” 之外實際聲明的變量(如果您將塊視為for
語句的主體),但在循環的每次迭代中都有一個單獨的存在 。
有關更多信息,請參閱https://github.com/babel/babel/issues/1078 。
為什么ES6和ES5的結果不同?
因為let
和var
是不同的。 let
是塊作用域,而var
是函數作用域 。
在您的第一個示例中,只有一個變量i
。 您創建的每個函數都引用了相同的變量i
。 在你調用a[6]()
, i
的值為10
,因為這是循環的終止條件。
在第二個例子中,循環的每次迭代都有它自己的變量i
。 它與塊范圍的其他語言完全一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.