理解 const 的真正含义:它锁不住对象内容 《如何用 const 锁定变量引用并减少程序中的意外状态修改》——仅看标题,可能会让人误以为 const 能彻底“锁死”数据。但实际并非如此:const 并不能锁定一个值,它锁定的是变量名与内存地址之间的绑定关系。要真正防止意外修改,需要搭配不可变数据
用const锁定变量引用,减少意外状态修改
作者:技术拾光
时间:2026-06-29
浏览:114
文章目录
理解 const 的真正含义:它锁不住对象内容
《如何用 const 锁定变量引用并减少程序中的意外状态修改》——仅看标题,可能会让人误以为 const 能彻底“锁死”数据。但实际并非如此:const 并不能锁定一个值,它锁定的是变量名与内存地址之间的绑定关系。要真正防止意外修改,需要搭配不可变数据结构或深度冻结手段。

结论是:const 只能锁定引用,无法改变值本身;要防止意外修改,需配合不可变数据结构或深度冻结。
为什么 const 声明的对象/数组仍可被修改
这是一个常见的认知误区。const 的约束仅停留在变量引用这一层,不触及引用背后的值。例如:
const user = { name: 'Alice' };
user.name = 'Bob'; // 合法 —— 引用未变,只是对象内部改变
user = {}; // 报错 —— 尝试重新赋值引用
许多开发者初学时容易踩坑——函数接收一个 const 参数,内部无意间修改了传入对象的属性,导致上游状态混乱。
- 适用场景:声明配置对象、模块常量、DOM 元素引用等“不换引用但可能修改内容”的情况
- 性能影响:零开销,纯语法约束,运行时无介入——可放心使用
- 常见陷阱:误以为
const能防止深层修改,尤其在多人协作或封装函数时遗漏防御性拷贝
真正冻结对象:用 Object.freeze() 或 structuredClone()
Object.freeze() 是轻量级的运行时防护工具,但它有一个明显短板——只做浅冻结。嵌套对象的属性不受影响:
const config = Object.freeze({ api: { url: '/v1' } });
config.api.url = '/v2'; // 依然可以修改
深度冻结需要额外处理。JavaScript 标准库没有提供开箱即用的深度冻结 API,但有几种替代方案:
- 简单场景:使用
structuredClone()克隆后,再通过Object.freeze()实现深度冻结——需注意兼容性(Node.js ≥17.4,Chrome ≥98) - 复杂嵌套:可借助
immer等库的produce函数,或自行编写递归冻结——但递归冻结有一定性能代价,需谨慎使用 - 构建时防护:TypeScript 的
readonly修饰符能在编译期发现问题,但无法阻止运行时操作
数组和函数也需按需处理
用 const 声明数组后,push、splice 等方法依然生效,原理与对象相同:
const list = [1, 2]; list.push(3); // 合法 list = [4, 5]; // 报错
实现数组“只读”的方法:
- 使用
Object.freeze(list)冻结数组本身——但数组元素若为对象,其属性仍可变 - 通过
Array.from(list)或展开运算符创建新数组后再冻结,避免意外共享引用 - 函数本身是引用类型,
const fn = () => {}不影响其内部逻辑,也不阻止重新绑定fn.prototype
最令人头疼的情况是跨作用域的引用共享。例如一个 const 对象被多个函数闭包持有,任一函数修改它,所有地方的感知都会同步更新——此时仅靠 const 完全不够,需从数据流设计上切断可变链。这是日常开发中最值得深入思考的问题。
实用工具推荐
电子包浆
使用 ›绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
图片压缩
使用 ›选择画质和输出格式,预览压缩前后的大小。
相关文章