面试官:const 不是不能变吗?你该不会还答错吧…

0 阅读4分钟

面试的时候,面试官突然来了一句:“const 定义的对象可以修改你知道吗?”
我当场懵住了,心里只想着:“不是说 const 不能变吗?你是不是在套我话?”

如果你也曾有过这样的疑问,或者曾在项目中因为 const 引发过诡异的 bug,那你绝对不能错过这篇文章。

本文将彻底讲清楚:

  • const 到底限制了什么?
  • 简单类型和复杂类型在内存中是怎么存的?
  • letvarconst 三者在作用域、变量提升、内存管理上到底有什么区别?

🔥 全面梳理 JS 变量声明机制,干掉一切面试套路与认知误区!

一、varletconst 的区别与使用

1. var 的特点

  • 函数作用域var 声明的变量只在当前函数内有效,若在函数外声明,会挂载到全局对象 window 上。

image.png

  • 变量提升:声明会被提升到作用域顶部,值不会被提升。
  • 可重复声明:允许重复声明变量,容易引发命名冲突。

示例:

for (var i = 0; i < 10; i++) {
  setTimeout(function () {
    console.log(i); // 输出 10 次 10
  }, 1000);
}

运行结果:

屏幕截图 2025-05-19 210345.png

解释:由于 var 没有块级作用域,循环中的 i 实际是全局变量。setTimeout 延迟执行时,i 已经变成 10。

2. let 的特点

  • 块级作用域let 在当前 {} 代码块内有效,不会污染全局作用域。
  • 不允许变量提升访问:虽然会“预解析”,但存在 TDZ(暂时性死区)。
  • 不可重复声明:声明同名变量会报错。

示例:

for (let i = 0; i < 10; i++) {
  setTimeout(function () {
    console.log(i); // 输出 0 ~ 9
  }, 1000);
}

运行结果:

屏幕截图 2025-05-19 210312.png

解释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]; // ❌ 修改引用,报错

三、数组方法:pushpopshiftunshift

以下代码用于操作好友列表:

const newFriends = [];
newFriends.push({ name: '皮皮' });      // 尾部添加
newFriends.unshift({ name: '薛之谦' }); // 头部添加

image.png

newFriends.pop();  // 删除末尾元素

image.png

newFriends.shift();  // 删除头部元素

image.png

操作对比表:

方法操作位置操作描述
push()尾部添加元素到数组末尾
pop()尾部移除并返回最后一个元素
unshift()头部添加元素到数组开头
shift()头部移除并返回第一个元素

总结:

  • 栈结构push + pop (后进先出 LIFO)
  • 队列结构unshift + shift (先进先出 FIFO)

四、varletconst 对比总结

特性varletconst
作用域函数作用域块级作用域块级作用域
变量提升是(声明提升)否(有 TDZ)否(有 TDZ)
重复声明
是否挂载到 window
是否可修改❌(引用可变)

五、总结

ES6 的 letconst 为 JavaScript 带来了更加健壮的作用域管理和语义化的变量控制:

  • 使用 let 替代 var,避免作用域混乱;
  • 使用 const 声明不变引用,增强代码可读性和安全性;
  • 合理使用数组方法管理数据结构,写出更简洁清晰的逻辑。

🚀 建议:默认使用 const,需要改变值时使用 let,避免使用 var


🧠 学习建议
理解作用域 + 内存机制 + 数据类型行为,是掌握 JavaScript 的基础。继续深入,你会发现更多优雅的代码写法。


✍️ 欢迎点赞 + 收藏 + 关注,一起交流前端技术!如有疑问或更深入的讨论,欢迎在评论区留言。