真实面经题目 · 原创解析

let、const 和 var 有什么区别?

这道题考察的不只是三种声明方式的表层语法,而是 JavaScript 变量绑定模型:作用域边界、提升行为、暂时性死区、重复声明、重新赋值、全局对象映射、循环闭包以及 const 对引用值的真实约束。面试中应从执行上下文和词法环境解释差异,再落到工程实践:默认使用 const,需要变更绑定时用 let,尽量避免 var。

出现于:阿里巴巴 · 前端

60 秒回答模板

let、const 和 var 的核心区别可以从作用域、提升、声明限制和赋值规则来回答。var 是函数作用域,声明会提升到当前函数或全局环境顶部,初始化为 undefined,因此可能在声明前访问到 undefined;let 和 const 是块级作用域,也会被提升到词法环境中,但在声明执行前处于暂时性死区,访问会报错。var 允许在同一作用域重复声明,let 和 const 不允许。let 可以重新赋值,const 声明后必须立即初始化,且不能重新绑定;但如果 const 绑定的是对象或数组,对象内部属性仍然可以修改,因为 const 限制的是绑定关系而不是深度不可变。全局作用域下,var 声明的变量会成为全局对象属性,而 let、const 不会。循环里使用 let 会为每次迭代创建独立绑定,更适合解决闭包捕获同一个变量的问题。实践上优先 const,其次 let,避免 var,可以减少作用域泄漏和意外覆盖。

考点 作用域模型
主线 提升与暂时性死区
易错点 误以为 let 和 const 完全没有提升,忽略它们…

深入解析

01

作用域模型

var 使用函数作用域,只有函数边界能限制它的可见范围,if、for、while 等代码块不会形成独立的 var 作用域。这会导致变量在块外仍可访问,容易污染外层逻辑。let 和 const 使用块级作用域,声明只在最近的一对花括号内部有效,更符合开发者对局部变量的直觉,也更适合复杂组件、条件分支和循环逻辑。

02

提升与暂时性死区

三者都存在声明提升,但表现不同。var 的声明会被提升并初始化为 undefined,所以声明前读取不会报引用错误,而是得到 undefined,这常常掩盖代码顺序问题。let 和 const 的声明也会进入词法环境,但在真正执行到声明语句之前不能访问,这段区域称为暂时性死区,提前访问会抛出错误,目的是让变量使用顺序更清晰。

03

重复声明与命名冲突

var 在同一作用域中允许重复声明,后续声明不会报错,容易在多人协作或长函数中造成变量覆盖和语义混乱。let 和 const 在同一块级作用域内不允许重复声明,同名变量会直接报语法错误。这个限制看似更严格,实际能提前暴露冲突,减少运行期才发现的隐藏缺陷。

04

重新赋值与绑定关系

let 声明的变量可以重新赋值,适合表示会随流程变化的绑定,例如计数器、状态过渡值或临时结果。const 声明后不能重新绑定,并且必须在声明时初始化。需要强调的是,const 固定的是变量名到值的绑定关系;当值是对象或数组时,内部属性和元素仍然可能变化,除非再配合冻结对象等额外机制。

05

全局对象差异

在浏览器全局作用域中,var 声明的全局变量会成为全局对象的属性,这意味着它可能和已有全局属性产生耦合或冲突。let 和 const 声明的全局变量不会挂到全局对象上,而是存在于全局词法环境中。这个差异在调试老代码、封装脚本、避免全局污染时很重要,也是现代代码减少 var 的原因之一。

06

循环闭包行为

在 for 循环中使用 var 声明计数器时,所有闭包通常共享同一个函数作用域变量,异步回调执行时可能读到循环结束后的最终值。使用 let 声明循环变量时,每次迭代会创建一个新的词法绑定,回调能捕获对应轮次的值。这是前端面试中非常常见的追问点,也能体现对执行机制的理解。

07

工程实践

实际开发中推荐默认使用 const,因为它表达了绑定不会变化的意图,方便阅读和重构;确实需要重新赋值时再改用 let;除非维护历史代码或需要特定兼容策略,否则不推荐使用 var。这样的规则能减少变量提升、作用域泄漏、重复声明和闭包捕获错误,让代码的生命周期和可变性更加明确。

易错点

  • 误以为 let 和 const 完全没有提升,忽略它们只是处于暂时性死区。
  • 误以为 const 声明对象后对象内部也完全不能被修改。
  • 只回答能不能重复声明和赋值,不解释作用域与执行机制。
  • 把 var 的块外可访问理解成正常特性,忽略函数作用域导致的泄漏风险。
  • 没有提到全局 var 会挂到全局对象,而 let 和 const 不会。
  • 解释循环闭包时只背结论,不说明 var 共享绑定和 let 独立绑定的原因。

面试官追问

let 和 const 有没有变量提升?

有提升,但不能像 var 那样在声明前安全访问。let 和 const 会先进入词法环境,在执行到声明语句前处于暂时性死区,因此提前读取会抛出错误。

为什么 const 声明对象后还能改属性?

因为 const 限制的是变量名和内存中某个值之间的绑定不能改变,而不是限制对象内容本身。对象属性是否可变取决于对象自身的可变性控制。

for 循环里 var 和 let 的闭包差异是什么?

var 声明的循环变量通常只有一个共享绑定,回调执行时读到的是同一个变量的最终状态。let 会为每次迭代创建独立绑定,回调能保留对应轮次的值。

为什么现代项目中不推荐 var?

var 的函数作用域、声明前可读、重复声明和全局对象挂载都容易制造隐式行为。let 和 const 的约束更明确,能提前暴露错误并提高代码可维护性。

什么时候用 let,什么时候用 const?

如果变量绑定不会重新指向别的值,优先使用 const;如果后续流程确实需要重新赋值,例如累加、状态切换或分支赋值,再使用 let。