根本区别在于作用域:var 具有函数作用域并变量提升,let 具有块级作用域且不提升;for 循环中 var 声明的 i 循环外仍可访问,let 声明则报 ReferenceError。

JavaScript 中 let 和 var 的作用域差异最要命
根本区别不在“能不能重复声明”,而在变量在代码块内的可见范围。用 var 声明的变量会提升到函数顶部(函数作用域),而 let 只在它所在的块级作用域(比如 {}、if、for)内有效。
常见错误现象:
在 for 循环里用 var 声明计数器,循环结束后仍能访问;但用 let 声明,循环体外访问直接报 ReferenceError。
-
var i = 0在for (var i = 0; i 后,i值为3,且可访问 -
let j = 0在for (let j = 0; j 后,j在循环外不可访问 - 在
if (true) { var x = 1; }之后,x仍存在;换成let x = 1,则报错
let 有暂时性死区(TDZ),var 没有
这是最容易踩坑的地方:只要块级作用域中存在 let 声明,从块开始到声明语句之前,该变量都处于“暂时性死区”。此时访问会抛出 ReferenceError,而不是返回 undefined。
而 var 声明会被提升,即使写在后面,也能在前面读取(值为 undefined)。
立即学习“Java免费学习笔记(深入)”;
-
console.log(a); let a = 1;→ 报ReferenceError: Cannot access 'a' before initialization -
console.log(b); var b = 2;→ 输出undefined,不报错 - TZD 不是语法错误,是运行时错误,ESLint 等工具也检测不到
重复声明行为不同,但别依赖这个来判断用哪个
很多人以为“let 不让重复声明所以更安全”,其实这只是表象。真正影响开发的是作用域和 TDZ 行为,重复声明只是副作用。
-
var a = 1; var a = 2;合法,第二次声明被忽略,a最终是2 -
let b = 1; let b = 2;直接语法错误:Identifier 'b' has already been declared - 但在不同作用域里,
let和var都允许同名变量(比如函数内再let a) - 不要靠“是否报错”来选关键字,而要看你需要块级绑定还是函数级绑定
实际项目中该用哪个?优先 let,仅在需要函数作用域或兼容老环境时考虑 var
现代 JavaScript 开发默认应使用 let(或 const),除非你明确需要 var 的函数提升特性(极少见)或要支持 IE 等不支持 let 的环境(需 Babel 转译)。
- 循环变量、条件分支内的变量、临时计算结果,一律用
let - 如果变量值不会重新赋值,优先用
const,比let更语义清晰 -
var在严格模式下也不阻止重复声明,但很多构建工具(如 TypeScript、ESLint)会主动报错 - 注意:箭头函数没有自己的
this,但var/let的作用域规则与this无关,别混为一谈
真正复杂的是嵌套作用域 + 异步回调 + 变量复用的组合场景,比如在 setTimeout 里引用循环变量——这时 let 自动按每次迭代创建绑定,var 就会出人意料地全部输出最后一个值。这种细节,光记“区别”没用,得动手试几次闭包和作用域链才真正明白。











