真实面经题目 · 原创解析
let、const 和 var 有什么区别?
这道题考察的不只是三种声明方式的表层语法,而是 JavaScript 变量绑定模型:作用域边界、提升行为、暂时性死区、重复声明、重新赋值、全局对象映射、循环闭包以及 const 对引用值的真实约束。面试中应从执行上下文和词法环境解释差异,再落到工程实践:默认使用 const,需要变更绑定时用 let,尽量避免 var。
真实面经题目 · 原创解析
这道题考察的不只是三种声明方式的表层语法,而是 JavaScript 变量绑定模型:作用域边界、提升行为、暂时性死区、重复声明、重新赋值、全局对象映射、循环闭包以及 const 对引用值的真实约束。面试中应从执行上下文和词法环境解释差异,再落到工程实践:默认使用 const,需要变更绑定时用 let,尽量避免 var。
let、const 和 var 的核心区别可以从作用域、提升、声明限制和赋值规则来回答。var 是函数作用域,声明会提升到当前函数或全局环境顶部,初始化为 undefined,因此可能在声明前访问到 undefined;let 和 const 是块级作用域,也会被提升到词法环境中,但在声明执行前处于暂时性死区,访问会报错。var 允许在同一作用域重复声明,let 和 const 不允许。let 可以重新赋值,const 声明后必须立即初始化,且不能重新绑定;但如果 const 绑定的是对象或数组,对象内部属性仍然可以修改,因为 const 限制的是绑定关系而不是深度不可变。全局作用域下,var 声明的变量会成为全局对象属性,而 let、const 不会。循环里使用 let 会为每次迭代创建独立绑定,更适合解决闭包捕获同一个变量的问题。实践上优先 const,其次 let,避免 var,可以减少作用域泄漏和意外覆盖。
var 使用函数作用域,只有函数边界能限制它的可见范围,if、for、while 等代码块不会形成独立的 var 作用域。这会导致变量在块外仍可访问,容易污染外层逻辑。let 和 const 使用块级作用域,声明只在最近的一对花括号内部有效,更符合开发者对局部变量的直觉,也更适合复杂组件、条件分支和循环逻辑。
三者都存在声明提升,但表现不同。var 的声明会被提升并初始化为 undefined,所以声明前读取不会报引用错误,而是得到 undefined,这常常掩盖代码顺序问题。let 和 const 的声明也会进入词法环境,但在真正执行到声明语句之前不能访问,这段区域称为暂时性死区,提前访问会抛出错误,目的是让变量使用顺序更清晰。
var 在同一作用域中允许重复声明,后续声明不会报错,容易在多人协作或长函数中造成变量覆盖和语义混乱。let 和 const 在同一块级作用域内不允许重复声明,同名变量会直接报语法错误。这个限制看似更严格,实际能提前暴露冲突,减少运行期才发现的隐藏缺陷。
let 声明的变量可以重新赋值,适合表示会随流程变化的绑定,例如计数器、状态过渡值或临时结果。const 声明后不能重新绑定,并且必须在声明时初始化。需要强调的是,const 固定的是变量名到值的绑定关系;当值是对象或数组时,内部属性和元素仍然可能变化,除非再配合冻结对象等额外机制。
在浏览器全局作用域中,var 声明的全局变量会成为全局对象的属性,这意味着它可能和已有全局属性产生耦合或冲突。let 和 const 声明的全局变量不会挂到全局对象上,而是存在于全局词法环境中。这个差异在调试老代码、封装脚本、避免全局污染时很重要,也是现代代码减少 var 的原因之一。
在 for 循环中使用 var 声明计数器时,所有闭包通常共享同一个函数作用域变量,异步回调执行时可能读到循环结束后的最终值。使用 let 声明循环变量时,每次迭代会创建一个新的词法绑定,回调能捕获对应轮次的值。这是前端面试中非常常见的追问点,也能体现对执行机制的理解。
实际开发中推荐默认使用 const,因为它表达了绑定不会变化的意图,方便阅读和重构;确实需要重新赋值时再改用 let;除非维护历史代码或需要特定兼容策略,否则不推荐使用 var。这样的规则能减少变量提升、作用域泄漏、重复声明和闭包捕获错误,让代码的生命周期和可变性更加明确。
有提升,但不能像 var 那样在声明前安全访问。let 和 const 会先进入词法环境,在执行到声明语句前处于暂时性死区,因此提前读取会抛出错误。
因为 const 限制的是变量名和内存中某个值之间的绑定不能改变,而不是限制对象内容本身。对象属性是否可变取决于对象自身的可变性控制。
var 声明的循环变量通常只有一个共享绑定,回调执行时读到的是同一个变量的最终状态。let 会为每次迭代创建独立绑定,回调能保留对应轮次的值。
var 的函数作用域、声明前可读、重复声明和全局对象挂载都容易制造隐式行为。let 和 const 的约束更明确,能提前暴露错误并提高代码可维护性。
如果变量绑定不会重新指向别的值,优先使用 const;如果后续流程确实需要重新赋值,例如累加、状态切换或分支赋值,再使用 let。