浅拷贝后立即冻结新对象需先用展开运算符或object.assign()创建副本,再调用object.freeze();该组合仅冻结顶层属性,嵌套对象仍可修改。

浅拷贝后立即冻结新对象,是实现“只读副本”的常用组合操作,但必须明确:它只保护顶层结构,不递归锁定嵌套内容。
浅拷贝 + freeze 的标准流程
这一步不能跳过顺序——必须先生成副本,再冻结;直接冻结原对象会影响原始数据,且无法实现“副本只读”目标。
- 用展开运算符或 Object.assign() 创建新对象:
const copy = { ...original };或const copy = Object.assign({}, original); - 立刻调用 Object.freeze():
Object.freeze(copy); - 验证是否生效:
console.log(Object.isFrozen(copy)); // true
它能防什么?——顶层属性完全锁定
冻结后的副本在第一层具备强防护能力:
- 赋值修改(
copy.name = 'new')在严格模式下报错,非严格模式静默失败 - 新增属性(
copy.id = 123)无效,属性不会出现 - 删除属性(
delete copy.age)无效,原值保留 - 重定义描述符(如用
Object.defineProperty改writable)会抛出错误
它防不住什么?——嵌套对象仍可变
这是最容易误判的关键点。浅拷贝只复制引用,freeze 只冻结顶层,所以嵌套对象本身未被冻结:
- 若
original.data = { value: 1 },则copy.data.value = 999依然成功 - 数组同理:
copy.list.push('item')可执行,只要list是引用类型且未被单独冻结 - 验证方式:
Object.isFrozen(copy.data)返回false
需要真正不可变?得手动深冻结
若业务要求整棵树都只读,需额外递归处理:
- 基础递归函数示例(忽略循环引用):
function deepFreeze(obj) {<br> if (obj && typeof obj === 'object') {<br> Object.getOwnPropertyNames(obj).forEach(key => {<br> if (obj[key] && typeof obj[key] === 'object') deepFreeze(obj[key]);<br> });<br> }<br> return Object.freeze(obj);<br>} - 生产环境建议用成熟库(如
immer的freeze工具,或deep-freeze),它们已内置循环引用检测 - 注意:深冻结无法逆转,也不适用于含函数、Date、RegExp 等特殊值的复杂配置
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











