JavaScript循环初始化变量的作用域?为何两段代码输出不同?
问题解答:循环变量作用域与闭包的影响
好问题!这其实涉及到JavaScript中let的块级作用域特性,以及闭包对变量绑定的捕获逻辑,咱们一步步拆解来看:
1. 循环初始化语句中let定义变量的作用域
当你在for循环的初始化部分(也就是for(...)的第一个括号里)用let定义变量时,这个变量的作用域是每一次单独的循环迭代块。而且JavaScript引擎会在每次循环迭代时,自动创建一个新的变量绑定——换句话说,每次循环里的i都是一个全新的变量,只是名字相同罢了,它们各自独立,不会互相干扰。
2. 两段代码输出差异的原因
咱们分别看两段代码的逻辑:
第一段代码:输出 0 1 2 3 4
let nodes = []; for (let i = 0; i < 5; ++i) { nodes[i] = () => i; } for (let node of nodes) { console.log(node()); }
这里的let i是在循环初始化里定义的,每次迭代都会生成一个新的i变量。你添加到nodes数组里的每个箭头函数,都会捕获当前这次迭代对应的那个i的绑定。当后续调用这些箭头函数时,每个函数都能找到自己对应的i的值(也就是迭代时的0、1、2、3、4),所以输出就是依次递增的数字。
第二段代码:输出 5 5 5 5 5
let nodes = []; let i; for (i = 0; i < 5; ++i) { nodes[i] = () => i; } for (let node of nodes) { console.log(node()); }
这段代码里的i是在循环外部定义的,整个循环过程中只有同一个i变量在被反复更新。箭头函数不会捕获当时的i值,而是捕获i的变量绑定——也就是说,所有箭头函数都指向同一个i。当循环结束时,i已经完成了最后一次递增,值变成了5,所以不管调用哪个箭头函数,它们返回的都是这个已经变成5的i,最终输出全是5。
简单总结一下:核心差异在于变量的作用域和绑定方式——循环内的let会为每个迭代创建独立变量,而外部定义的变量是全局共享的,箭头函数捕获的是变量的绑定而非临时值。
内容的提问来源于stack exchange,提问作者Bimo Adityarahman
相关产品推荐
相关产品推荐

