let声明的变量存在暂时性死区(TDZ),未声明前访问抛出ReferenceError;var会被提升并初始化为undefined,访问不报错。for循环中var共享绑定,let每次迭代新建绑定。let禁止重复声明,var允许。

let 声明的变量不会被提升,且有块级作用域;var 声明的变量会被提升到函数或全局顶部,只有函数作用域。
为什么 let 在声明前访问会报错,而 var 是 undefined
这是“暂时性死区”(TDZ)导致的。JS 引擎在进入作用域时,会先登记所有 let 变量名,但直到执行到声明语句前都不允许访问——此时读取会抛出 ReferenceError。而 var 会在作用域顶部被初始化为 undefined,所以访问不会报错,只是值是 undefined。
常见错误现象:
-
console.log(a); let a = 1;→ 报ReferenceError: Cannot access 'a' before initialization -
console.log(b); var b = 2;→ 输出undefined,不报错
for 循环中用 var 和 let 声明计数器的区别
这直接暴露了作用域差异。用 var 声明的循环变量属于函数作用域,所有迭代共享同一个绑定;let 每次迭代都会创建一个新绑定。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 写定时器或异步回调时,别用
var i:for (var i = 0; i console.log(i), 0);会输出三个3 - 换成
let i就能按预期输出0、1、2 - 如果必须用
var,需通过闭包或立即执行函数捕获当前值,但更啰嗦且易错
重复声明时 let 和 var 的行为差异
var 允许在同一作用域内重复声明(无提示),let 则直接报语法错误。
使用场景提醒:
-
var x = 1; var x = 2;合法,x最终是2 -
let y = 1; let y = 2;报SyntaxError: Identifier 'y' has already been declared - 这种限制让
let更适合现代开发——避免无意覆盖,IDE 和 ESLint 也能更好检测问题
块级作用域不是靠大括号“看起来像”就生效的,而是由 if、for、{} 等语法结构实际创建的词法作用域。很多人以为 var 在 if 块里声明就只在块内有效,其实它仍会泄漏到外层函数中——这点最容易被忽略,也最常引发 bug。











