let 有什么用,有了 var 为什么还要用 let?
面试速答(30 秒版 TL;DR)
let提供块级作用域,解决var的函数作用域带来的变量泄漏、循环异步捕获等问题。let有暂时性死区(TDZ),能更早暴露“先用后声明”的错误。let不允许同一作用域重复声明,降低隐式覆盖风险。
核心差异对比(面试高频)
- 作用域:
var:函数作用域(或全局作用域),没有块级作用域。let:块级作用域({}、for、if、switch等)。
- 提升(hoist)与初始化:
var:声明提升并初始化为undefined,容易“看起来能用”但逻辑错误。let:声明也会被“登记”,但在声明语句执行前处于 TDZ,访问会抛错。
- 重复声明:
var:允许重复var x。let:同一作用域重复声明直接报错。
经典题:for 循环 + 异步输出
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 常见输出:3 3 3
改成 let:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 0 1 2
可讲清楚的点:let 在 for 中会为每次迭代创建新的绑定,因此闭包捕获到的是“每次迭代各自的 i”。
暂时性死区(TDZ)是为了什么?
console.log(x); // ReferenceError
let x = 1;
TDZ 的价值:让“先用后声明”更快失败,避免 var 那种默默得到 undefined 的隐性 bug。
常见追问
Q:那我用 const 不就好了?
const也有块级作用域和 TDZ,但它强调“绑定不可重新赋值”。- 需要重新赋值的场景用
let,不需要重新赋值用const(更利于阅读与约束)。
易错点/坑
- “
let没有提升”是口误:更准确说法是“有提升的登记,但在声明前不可访问(TDZ)”。 let的块级作用域会影响某些老代码的重构方式,尤其是依赖变量泄漏的写法。
速记要点(可背诵)
let:块级作用域 + TDZ + 禁止重复声明,主要用来修复var的坑。