让javascript中的vs var

时间:2017-12-28 06:19:10

标签: javascript closures var 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

3 个答案:

答案 0 :(得分:3)

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

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();

答案 1 :(得分:1)

首先,输出将是四次而不是五次(如评论中所述)。 我将你的代码粘贴在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);
}

你看到现在内部如何运作? : - )

答案 2 :(得分:0)

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

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