let声明变量的箭头函数闭包捕获策略差异原因探究
为什么两段闭包代码输出结果不同?
这问题真的戳中了 JavaScript 闭包和let作用域的关键细节,很多开发者第一次碰到都会困惑,我来给你拆解清楚:
首先明确核心前提:JavaScript 的闭包确实是捕获变量的引用,但两段代码的差异,本质是被捕获的变量本身的绑定方式完全不一样。
第一段代码:for 循环内用let声明变量
arr = []; for(let i = 0; i < 3; i++) { arr.push(() => console.log(i)); } arr.forEach(ele => ele());
这里的let i写在 for 循环的初始化语句里,这是 ECMAScript 标准专门做的特殊处理:每次循环迭代时,都会创建一个全新的i变量实例。也就是说:
- 第一次循环(i=0):创建一个值为0的
i变量,闭包捕获这个变量的引用 - 第二次循环(i=1):再创建一个全新的
i变量(和上一个完全独立),值为1,闭包捕获这个新变量的引用 - 第三次循环(i=2):又创建一个全新的
i变量,值为2,闭包捕获这个变量的引用
当你后续调用数组里的三个函数时,每个函数对应的都是各自迭代时的那个i变量,所以会依次输出0,1,2。
第二段代码:循环外声明let j
arr = []; let j; for(j = 0; j < 3; j++) { arr.push(() => console.log(j)); } arr.forEach(ele => ele());
这里的j是在循环外部声明的,整个循环过程中只有一个j变量存在,每次循环只是更新这个变量的值:
- 循环开始时 j=0,闭包捕获这个 j 的引用
- 循环到 j=1,还是同一个 j 变量,值被更新,闭包依然指向这个变量
- 循环到 j=2,同样是同一个 j,值更新为2
- 循环结束后,j 的值会变成3(最后一次 j=2 时,j++后等于3,不满足 j<3 的条件,循环终止)
当你调用数组里的函数时,三个闭包捕获的都是同一个 j 变量的引用,而此时 j 的值已经是3了,所以三个函数都会输出3。
额外补充:换成var会怎样?
如果把第一段代码的let i换成var i,输出结果会和第二段一样都是3,3,3。因为var没有块级作用域,整个循环里只有一个i变量,闭包捕获的都是这个变量的引用,循环结束后 i 的值是3,所以调用函数时都会打印3。
内容的提问来源于stack exchange,提问作者wlnirvana
相关产品推荐
相关产品推荐

