JavaScript 闭包:通过示例理解 let 和 var 的区别

27 浏览
0 Comments

JavaScript 闭包:通过示例理解 let 和 var 的区别

这个问题已经有了答案:

\"let\"和\"var\"之间的区别是什么?

虽然我理解let允许您声明仅限于块级别的范围的变量,但在使用它与javascript闭包时,我遇到了一个奇怪的letvar之间的区别。下面是我的例子:

使用let

function buildFunction() {
  var arr = [];
  for(var i = 0; i < 3; i++) {
    let j = i;  //Using let to assign j
    arr.push(
      function(){
        console.log(j);
      }
    )
  }
   return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();

上面的代码片段输出:

0
1
2

使用var

function buildFunction() {
  var arr = [];
  for(var i = 0; i < 3; i++) {
    var j = i;  //Using var to assign j
    arr.push(
      function(){
        console.log(j);
      }
    )
  }
   return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();

上面的代码片段输出以下内容:

2
2
2

我的问题是:

  1. 如果我在块内部使用var并在执行期间为其赋值,那么它不应该像let一样正常工作并在内存中存储不同的j的副本吗?
  2. javascript是否在闭包中以不同的方式处理letvar

对此的任何澄清将不胜感激。

admin 更改状态以发布 2023年5月23日
0
0 Comments

var将作用域限制在函数内;let将作用域限制在代码块内。

在你的例子中,使用var时,j的作用域限制在函数buildFunction()内。这意味着你在每个函数中都在使用 '相同的' j。当你的for循环运行时,j被设置为0,然后是1,再然后是2。当你运行控制台日志时,引用的是被设置为2的j,因此你得到的是2 2 2

当你使用let时,你将j的作用域限制在for循环的每次迭代中。这意味着每次迭代都有一个 '不同的' j,而控制台日志打印的是你期望打印出的内容。

如果你使用ES5并且需要使用var,你可以通过将原始的匿名函数封装在一个自执行函数中并将j作为参数传入来复制let的效果(让它打印0 1 2)。 这将在自执行函数中为j创建一个新的作用域,其值为当前迭代中j的值。

function buildFunction() {
  var arr = [];
  for(var i = 0; i < 3; i++) {
    var j = i;  //Using var to assign j
    arr.push(
      //self executing function
      (function(j) { //j here is scoped to the self executing function and has the value of j when it was called in the loop. Any changes to j here will not affect the j scope outside this function, and any changes to j outside this function will not affect the j scoped inside this function.
        //original function
        return function() {
          console.log(j);
        }
      })(j) //call with the value of j in this iteration
    )
  }
  return arr;
}
var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();

0