让 vs var in javascript

let vs var in javascript

我知道 let 有块作用域而 var 有函数作用域。但是我不明白在这种情况下,使用 let 将如何解决问题

const arr = [1,2,3,4];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
   console.log(arr[i]) 
}, 1000);
} // Prints undefined 5 times

const arr = [1,2,3,4];
for (let i = 0; i < arr.length; i++) {
setTimeout(function() {
   console.log(arr[i]) 
}, 1000);
} // Prints all the values correctly

您仍然可以将 var 用于 setTimeout。您可以使用立即调用的函数表达式 (IIFE) 在 setTimeout 周围创建一个闭包,以便 setTimeout 函数识别 i 的值。

const arr = [1,2,3,4];
for (var i = 0; i < arr.length; i++) {
(function(i){
setTimeout(function() {
   console.log(arr[i]) 
}, 1000)})(i);
}

这都跟变量的作用域有关。让我们尝试将这两个部分包装成函数,并观察输出:

function test() {
  // `i` will be declared here, making it a non-for-loop scoped variable
  const arr = [1, 2, 3, 4];
  for (var i = 0; i < arr.length; i++) {
    setTimeout(function() {
      console.log(arr[i])
    }, 1000);
  } // Prints undefined 5 times
}

test();

所以在第一种情况下,i会被提升,并且由于setTimeout的异步特性,i会随着循环结束而立即变为4,无需等待。这将使 arr[i] 指向数组中的 undefined 元素。

在第二种情况下,i 未提升,并且对循环的每次迭代进行范围访问,从而使 i 可准确地用于 console.log 语句。因此结果符合预期:

function test() {
  const arr = [1, 2, 3, 4];
  for (let i = 0; i < arr.length; i++) {
    setTimeout(function() {
      console.log(arr[i])
    }, 1000);
  } // Prints all the values correctly

}

test();

首先,输出将是四次而不是五次(如您的评论中所述)。 我将你的代码粘贴到 Babel REPL 中,这就是我得到的,

"use strict";

var arr = [1, 2, 3, 4];

var _loop = function _loop(i) {
setTimeout(function () {
   console.log(arr[i]);
}, 1000);
};

for (var i = 0; i < arr.length; i++) {
_loop(i);
}

你看到 let 现在在内部是如何工作的了吗? :-)