【js篇】const 声明的对象,属性可以修改吗?

210 阅读2分钟

在 JavaScript 中,const 关键字用于声明一个常量。很多开发者会误以为使用 const 声明的变量“值不能变”,其实这种理解并不完全准确。


✅ 一、一句话总结

const 保证的是变量指向的内存地址不变,而不是该地址所存储的数据不可变。

  • 对于基本类型(如 numberstringboolean)来说,值就保存在内存地址中,因此一旦赋值就不能再改变;
  • 对于引用类型(如 objectarray)来说,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 实现更安全的不可变状态更新;