面试的时候,面试官突然来了一句:“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 的基础。继续深入,你会发现更多优雅的代码写法。
✍️ 欢迎点赞 + 收藏 + 关注,一起交流前端技术!如有疑问或更深入的讨论,欢迎在评论区留言。