这段代码,你觉得会输出什么?

for (
  let i = 0, getI = () => i, incrementI = () => i++;
  getI() < 3;
  incrementI()
) {
  console.log(i);
}

别偷看答案,先想一下,是 0 1 2,还是 3 3 3,还是 0 0 0
.
.
.
.
.
. 密
. 封
. 线
.
.
.
.
.

答案是 0 0 0。为什么?这就要明白 for 循环的初始化块中的词法声明中,变量的作用域是什么。

for 循环的结构是这样的:

for (initialization; condition; afterthought)
  statement

其中的 initialization 叫做初始化块,通常用于声明计数器变量。condition 是每次循环之前要判定的条件的表达式。afterthought 是每次循环结束时执行的表达式。前面这些都是可选的。statement 是每次 condition 判断为真时要执行的语句。

对于初始化块的作用域,MDN 上这样解释:

初始化块的作用域范围可以理解为声明发生在循环体内部,但实际上只能在 condition 和 afterthought 部分中访问。更准确地说,let 声明是 for 循环特有的——如果 initialization 是 let 声明,那么每次循环体执行完毕后,都会发生以下事情:

使用 let 声明新的变量会创建一个新的词法作用域。
上次迭代的绑定值用于重新初始化新变量。
afterthought 在新的作用域中执行。

新的词法作用域会在 initialization 之后、condition 第一次被判定之前创建。initialization 内部的变量与每次迭代中的变量是不同的,包括第一次

根据这个解释,文章开头的代码的执行流程是这样的:

  1. 在初始化块中声明了一个变量 i,它的值是 1;声明了一个函数 getI,它读取并返回 i;声明了一个函数 incrementI,它首先读取并返回 i,之后将 i 增加 1。注意!这两个函数和变量 i 处于同一个作用域下,并且它们都引用了 i,在后续步骤中,这两个函数处于不同的作用域下,依然能够读取这里的 i,这就是闭包
  2. 在第一次循环时,创建了一个新的作用域,这个时候的变量 i,并不是步骤 1 中的变量 i!它们不在同一个作用域中。根据文档描述,它的值应该使用上次循环的值(文档中对此值的称呼为“上次迭代的绑定值”,你可以理解为 i 自增后的那个值),但现在是第一次循环,它的值应该取的是初始值,因此是 0(这在文档中没有描述,如果你知道哪里有确切的描述,欢迎在评论区指出)。在第一次的条件判断中,函数 getI 实际上读取的是步骤 1 中的 i,返回 0。在 statement 中,打印了当前的变量 i 的值,输出 0。最后,在 afterthought 部分,调用了函数 incrementI,而函数 incrementI 也是闭包,它读取的依然是步骤 1 中的变量 i 的值,因此,步骤 1 中的变量 i 此时是 1,而当前作用域中的变量 i 的值依然为 0,因为并没有什么地方改变它的值。
  3. 第二次循环,又创建了一个新的作用域,在此作用域中创建了新的变量 i,它的值是上次循环的值 0。其他流程和步骤 2 相同。此时步骤 1 中的 i 的值为 2,而本次循环中的 i 依然是 0。继续输出一个 0
  4. 重复步骤 3,步骤 1 中的 i 的值增加为 3,依然输出一个 0
  5. 不符合判断条件,循环退出。

从这段代码可以看出 for 循环的初始化块是如何创建作用域并进行词法声明的。通过闭包绑定初始的 i,可以做到不影响 statement 部分的 i 的值。

标签: JavaScript, 闭包, for

已有 2 条评论

  1. 2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
    新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
    新车首发,新的一年,只带想赚米的人coinsrore.com
    新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
    做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
    新车上路,只带前10个人coinsrore.com
    新盘首开 新盘首开 征召客户!!!coinsrore.com
    新项目准备上线,寻找志同道合的合作伙伴coinsrore.com
    新车即将上线 真正的项目,期待你的参与coinsrore.com
    新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
    新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com

  2. 新盘 上车集合 留下 我要发发 立马进裙coinsrore.com

添加新评论