在 JavaScript 中,const 关键字用于声明一个常量。很多开发者会误以为使用 const 声明的变量“值不能变”,其实这种理解并不完全准确。
✅ 一、一句话总结
const保证的是变量指向的内存地址不变,而不是该地址所存储的数据不可变。
- 对于基本类型(如
number、string、boolean)来说,值就保存在内存地址中,因此一旦赋值就不能再改变;- 对于引用类型(如
object、array)来说,const只能保证变量不再指向新的对象,但对象内部的内容是可以修改的。
✅ 二、具体分析
示例 1:基本类型
const a = 10;
a = 20; // 报错:Assignment to constant variable.
✅ 因为 a 是基本类型,其值直接存储在变量指向的内存地址中,所以不能更改。
示例 2:引用类型(对象)
const obj = { name: 'Tom' };
obj.name = 'Jerry';
console.log(obj); // { name: 'Jerry' }
✅ 成功修改了对象的属性!
📌 原因:
const obj表示变量obj指向的内存地址是固定的;- 但该地址上存储的是一个对象,对象内部的内容是可以自由修改的;
示例 3:尝试重新赋值对象
const obj = { name: 'Tom' };
obj = { name: 'Jerry' }; // 报错:Assignment to constant variable.
❌ 不允许重新给 obj 赋值一个新的对象,因为这会改变指针地址。
示例 4:数组同理
const arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
arr = [4, 5, 6]; // 报错:Assignment to constant variable.
✅ 可以修改数组内容;
❌ 不能将 arr 指向新的数组。
✅ 三、如何真正“冻结”一个对象?
如果你希望一个对象完全不可变(包括属性值也不能改),可以使用:
方法一:Object.freeze()
const obj = { name: 'Tom' };
Object.freeze(obj);
obj.name = 'Jerry'; // 静默失败(严格模式下报错)
console.log(obj.name); // Tom
📌 注意:
Object.freeze()是浅冻结;- 如果对象嵌套了其他对象,子对象不会被自动冻结;
深冻结函数示例:
function deepFreeze(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
Object.keys(obj).forEach(key => {
const prop = obj[key];
if (typeof prop === 'object' && prop !== null) {
deepFreeze(prop);
}
});
return Object.freeze(obj);
}
const obj = { user: { name: 'Tom' } };
deepFreeze(obj);
obj.user.name = 'Jerry';
console.log(obj.user.name); // Tom ✅
✅ 四、一句话总结
const并不保证对象的内容不能被修改,它只是确保变量指向的内存地址不变。如果想让对象不可变,需要配合使用Object.freeze()或手动实现深冻结逻辑。
💡 进阶建议
- 在 React/Vue 状态管理中,尽量避免直接修改
const对象,而是返回新对象保持不可变性; - 使用 TypeScript 的
readonly属性提升开发时的类型安全性; - 使用 ESLint 规则防止对
const变量进行非法赋值; - 使用
immer.js实现更安全的不可变状态更新;