面试题深度解析:let、const 与 var 的区别

在 JavaScript 面试中,"letconstvar 有什么区别?" 是一个高频基础题。看似简单,实则考察候选人对 变量声明机制、作用域、提升(hoisting)、暂时性死区(TDZ) 以及 ES6 新特性的理解深度。本文将从底层原理出发,全面剖析三者的异同,并结合实际代码示例,帮助你彻底掌握这一核心知识点。


一、作用域(Scope):最根本的区别

作用域决定了变量的可访问范围。这是三者最核心的差异。

声明方式 作用域类型 特点
var 函数作用域(Function Scope) 在函数内部声明的 var 变量,只在该函数内可见;在全局声明则为全局变量。
let 块级作用域(Block Scope) {} 内声明的 let 变量,只在该代码块内可见(如 ifforwhile 等)。
const 块级作用域(Block Scope) let 相同,具有块级作用域。

示例对比

javascript 复制代码
// var - 函数作用域
function exampleVar() {
    if (true) {
        var x = 10;
    }
    console.log(x); // 输出 10,x 在整个函数内都可访问
}
exampleVar();

// let - 块级作用域
function exampleLet() {
    if (true) {
        let y = 20;
    }
    console.log(y); // 报错:y is not defined
}
exampleLet();

// const - 块级作用域
function exampleConst() {
    if (true) {
        const z = 30;
    }
    console.log(z); // 报错:z is not defined
}
exampleConst();

关键点letconst 的块级作用域解决了 var 在循环中常见的闭包问题。

javascript 复制代码
// 使用 var 的经典陷阱
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100); // 输出 3, 3, 3
}

// 使用 let 的正确方式
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100); // 输出 0, 1, 2
}

二、变量提升(Hoisting):声明被"提升",但初始化不会

JavaScript 引擎在执行代码前会进行"编译"阶段,将变量和函数声明提升到作用域顶部。

声明方式 是否提升 提升后状态 访问未声明前的变量
var ✅ 是 提升声明,初始化为 undefined 可访问,值为 undefined
let ✅ 是 提升声明,但不初始化 报错:Cannot access before initialization
const ✅ 是 提升声明,但不初始化 报错:Cannot access before initialization

示例说明

javascript 复制代码
console.log(a); // undefined(var 被提升并初始化为 undefined)
var a = 1;

console.log(b); // 报错:Cannot access 'b' before initialization
let b = 2;

console.log(c); // 报错:Cannot access 'c' before initialization
const c = 3;

关键点letconst 虽然也被提升,但由于"暂时性死区(Temporal Dead Zone, TDZ)"的存在,无法在声明前访问,这比 var 更安全。


三、暂时性死区(Temporal Dead Zone, TDZ)

TDZ 是 letconst 特有的概念。从进入作用域到变量被声明并初始化之前,该变量处于"暂时性死区"------任何访问都会抛出错误

javascript 复制代码
{
    // TDZ 开始
    console.log(d); // ReferenceError
    let d; // TDZ 结束
    console.log(d); // undefined
    d = 4;
}

设计目的:避免因变量提升导致的"先使用后声明"的混乱,提高代码的可预测性和安全性。


四、重复声明(Redeclaration)

声明方式 同一作用域内是否允许重复声明
var ✅ 允许(后声明覆盖前声明)
let ❌ 不允许(报错)
const ❌ 不允许(报错)
javascript 复制代码
var x = 1;
var x = 2; // 合法

let y = 1;
let y = 2; // 报错:Identifier 'y' has already been declared

const z = 1;
const z = 2; // 报错:Identifier 'z' has already been declared

五、const 的"不可变性"真相

const 声明的变量不能重新赋值 ,但不等于其值不可变 。对于对象和数组,其引用不可变,但内容可变

javascript 复制代码
const obj = { name: 'Alice' };
obj.name = 'Bob'; // ✅ 合法,修改对象属性
obj.age = 25;      // ✅ 合法,添加新属性

obj = { name: 'Charlie' }; // ❌ 报错:Assignment to constant variable

const arr = [1, 2];
arr.push(3); // ✅ 合法
arr[0] = 10; // ✅ 合法

arr = [4, 5]; // ❌ 报错

关键点const 保证的是绑定(binding)的不可变性 ,而非值的不可变性。若需深度冻结对象,应使用 Object.freeze()


六、全局对象属性绑定

在全局作用域中:

声明方式 是否成为全局对象(如 window)的属性
var ✅ 是
let ❌ 否
const ❌ 否
javascript 复制代码
var a = 1;
let b = 2;
const c = 3;

console.log(window.a); // 1
console.log(window.b); // undefined
console.log(window.c); // undefined

意义letconst 避免了意外污染全局命名空间,更安全。


七、实际开发建议

  1. 优先使用 const :如果你不打算重新赋值变量,就用 const。这是最安全的选择。
  2. 其次使用 let :仅在需要重新赋值时使用 let
  3. 避免使用 var :除非兼容旧环境,否则应完全弃用 var
javascript 复制代码
// ✅ 推荐写法
const PI = 3.14159;
const user = { name: 'John' };

let count = 0;
for (let i = 0; i < 10; i++) {
    count += i;
}

总结:一张表看懂所有区别

特性 var let const
作用域 函数作用域 块级作用域 块级作用域
变量提升 是(初始化为 undefined 是(不初始化,TDZ) 是(不初始化,TDZ)
暂时性死区 ❌ 无 ✅ 有 ✅ 有
重复声明 ✅ 允许 ❌ 不允许 ❌ 不允许
重新赋值 ✅ 允许 ✅ 允许 ❌ 不允许
全局属性绑定 ✅ 是 ❌ 否 ❌ 否

面试加分回答

"letconst 是 ES6 引入的块级作用域变量声明方式,它们解决了 var 存在的变量提升副作用、作用域不清晰和全局污染等问题。const 提供了不可变绑定,鼓励函数式编程风格。在现代 JavaScript 开发中,应优先使用 constlet,避免使用 var,以写出更安全、可维护的代码。"

掌握这些细节,你不仅能回答面试题,更能理解 JavaScript 的演进逻辑和最佳实践。

相关推荐
Dr.kangder7 分钟前
嵌入式面试总结(十六)——AMBA总线
面试·职场和发展·架构·嵌入式·虚拟化·总线
Dr.kangder30 分钟前
嵌入式面试总结(十九)——内存泄露
单片机·算法·面试·职场和发展·架构·硬件架构
Dr.kangder42 分钟前
嵌入式面试总结(十七)——DMA总线
面试·职场和发展·架构·嵌入式·总线
无糖可可果1 小时前
从零读懂一个 Next.js 全栈笔记应用
前端
Maxkim1 小时前
DeepSeek Harness 源码深度分析:像 VS Code 一样插件化的 Agent 框架
前端·架构
xiaominlaopodaren1 小时前
three.js地图数学基础(八):浮点精度
javascript·gis·three.js
喜欢睡觉1 小时前
从零看懂一个 Next.js 笔记应用
前端
SendTomo1 小时前
跨设备文件互传新方案
javascript·网络·webrtc·html5·p2p
cindershade1 小时前
从零实现画布「双击创建节点」:一个 VueFlow 项目的交互全记录
前端
YHL1 小时前
🚀 SSE 服务器发送事件与 BFF 层实战
前端·后端