let在循环内外声明是否存在差异?关于let作用域的疑问
两段代码的核心差异解析
这两段代码有非常明显的差异,核心就在于let的块级作用域特性,以及for循环中let声明的特殊行为——我给你拆解开讲清楚:
1. 变量i的作用域范围完全不同
示例1:
let i是在循环外声明的,它的作用域覆盖整个外层区域(比如包裹这段代码的函数、或是全局作用域)。循环结束后,i仍然存在,你可以在循环外访问到它最后一次更新的值:// Example 1 let i; var arr = [1,2,3]; for (i=0; i<arr.length; i++){ // do stuff } console.log(i); // 输出:3,循环结束后i依然可访问示例2:
let i是在for循环的初始化部分声明的,它的作用域被严格限制在循环体内部(包括循环的条件判断、更新表达式以及{}包裹的代码块)。循环结束后,i就会被销毁,外部无法访问:// Example 2 var arr = [1,2,3]; for (let i=0; i<arr.length; i++){ // do stuff } console.log(i); // 报错:ReferenceError: i is not defined
2. 循环迭代中的变量实例不同
这是for循环里let声明容易被忽略的关键点:
示例1的
i是同一个变量,循环过程中只是不断更新它的值。如果循环里有异步操作(比如setTimeout),所有异步回调都会引用最后一次更新的i:let i; var arr = [1,2,3]; for (i=0; i<arr.length; i++){ setTimeout(() => { console.log(i); // 输出3次:3 }, 100); }示例2的
let i会在每一次循环迭代时创建一个新的变量实例,每个迭代的i都是独立的。异步回调会绑定当前迭代的那个i值:var arr = [1,2,3]; for (let i=0; i<arr.length; i++){ setTimeout(() => { console.log(i); // 依次输出:0、1、2 }, 100); }
总结
简单说:
- 示例1的
i是「全局/外层作用域的变量,循环只是修改它的值」 - 示例2的
i是「循环专属的块级变量,每个迭代都有独立副本」
内容的提问来源于stack exchange,提问作者Henry Yang
相关产品推荐
相关产品推荐

