面试的时候,面试官突然来了一句:“const 定义的对象可以修改你知道吗?”
我当场懵住了,心里只想着:“不是说 const 不能变吗?你是不是在套我话?”
如果你也曾有过这样的疑问,或者曾在项目中因为 const 引发过诡异的 bug,那你绝对不能错过这篇文章。
本文将彻底讲清楚:
const到底限制了什么?- 简单类型和复杂类型在内存中是怎么存的?
let、var、const三者在作用域、变量提升、内存管理上到底有什么区别?
🔥 全面梳理 JS 变量声明机制,干掉一切面试套路与认知误区!
一、var、let、const 的区别与使用
1. var 的特点
- 函数作用域:
var声明的变量只在当前函数内有效,若在函数外声明,会挂载到全局对象window上。
- 变量提升:声明会被提升到作用域顶部,值不会被提升。
- 可重复声明:允许重复声明变量,容易引发命名冲突。
示例:
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i); // 输出 10 次 10
}, 1000);
}
运行结果:
解释:由于 var 没有块级作用域,循环中的 i 实际是全局变量。setTimeout 延迟执行时,i 已经变成 10。
2. let 的特点
- 块级作用域:
let在当前{}代码块内有效,不会污染全局作用域。 - 不允许变量提升访问:虽然会“预解析”,但存在 TDZ(暂时性死区)。
- 不可重复声明:声明同名变量会报错。
示例:
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i); // 输出 0 ~ 9
}, 1000);
}
运行结果:
解释:
let每次循环都会创建一个新的i,所以输出的是 0 到 9。
3. const 的特点
- 块级作用域:和
let一样具有块级作用域。 - 必须初始化:声明时必须赋值。
- 不能修改绑定:简单数据类型不可更改,复杂数据类型地址不可变但内容可变。
const age = 18;
age = 20; // ❌ 报错
const friends = [
{ name: '红男', hometown: '抚州' },
];
friends.push({ name: '黑女', hometown: '抚州' }); // ✅ 允许
二、深入理解内存模型与 const
简单数据类型(Primitive)
- 类型:
number,string,boolean,undefined,null,symbol,bigint - 存储位置:栈内存
- 特性:直接存储值,值不可变
const约束:值本身不能修改
复杂数据类型(Object/Array/Function)
- 存储位置:栈存地址、堆存对象
- 特性:地址引用传递,内容可变
const约束:地址不能变,对象内容可变
示例:
const arr = [1, 2];
arr.push(3); // ✅ 修改内容
arr = [4, 5]; // ❌ 修改引用,报错
三、数组方法:push、pop、shift、unshift
以下代码用于操作好友列表:
const newFriends = [];
newFriends.push({ name: '皮皮' }); // 尾部添加
newFriends.unshift({ name: '薛之谦' }); // 头部添加
newFriends.pop(); // 删除末尾元素
newFriends.shift(); // 删除头部元素
操作对比表:
| 方法 | 操作位置 | 操作描述 |
|---|---|---|
push() | 尾部 | 添加元素到数组末尾 |
pop() | 尾部 | 移除并返回最后一个元素 |
unshift() | 头部 | 添加元素到数组开头 |
shift() | 头部 | 移除并返回第一个元素 |
总结:
- 栈结构:
push+pop(后进先出 LIFO) - 队列结构:
unshift+shift(先进先出 FIFO)
四、var、let、const 对比总结
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 是(声明提升) | 否(有 TDZ) | 否(有 TDZ) |
| 重复声明 | ✅ | ❌ | ❌ |
| 是否挂载到 window | ✅ | ❌ | ❌ |
| 是否可修改 | ✅ | ✅ | ❌(引用可变) |
五、总结
ES6 的 let 和 const 为 JavaScript 带来了更加健壮的作用域管理和语义化的变量控制:
- 使用
let替代var,避免作用域混乱; - 使用
const声明不变引用,增强代码可读性和安全性; - 合理使用数组方法管理数据结构,写出更简洁清晰的逻辑。
🚀 建议:默认使用 const,需要改变值时使用 let,避免使用 var。
🧠 学习建议:
理解作用域 + 内存机制 + 数据类型行为,是掌握 JavaScript 的基础。继续深入,你会发现更多优雅的代码写法。
✍️ 欢迎点赞 + 收藏 + 关注,一起交流前端技术!如有疑问或更深入的讨论,欢迎在评论区留言。