浅拷贝配合object.freeze仅实现“半防御”:顶层属性被冻结不可增删改,但嵌套对象(如headers)仍可修改,因二者均为浅操作,未递归处理内部引用。

浅拷贝本身不提供防御能力,它只是复制对象第一层属性的引用。配合 Object.freeze() 后,确实能形成你描述的“半防御”状态:顶层结构被锁死,但嵌套对象仍可修改。
为什么是“半防御”?
因为 Object.freeze() 本身就是浅冻结,它只冻结目标对象自身的属性(键值对),而不会深入到值为对象或数组的内部。浅拷贝(如 Object.assign({}, obj) 或展开运算符 {...obj})只是把原始对象第一层的属性“搬”到新对象上,这些属性若指向另一个对象,那新对象里存的仍是同一个引用——冻结这个新对象,只锁住了“引用本身”,没锁住“被引用的对象”。
典型操作流程
- 先用浅拷贝创建一个新对象(避免污染原对象)
- 再对这个新对象调用
Object.freeze() - 结果:新对象无法增删改属性,但其内部嵌套的对象/数组仍可自由修改
一个直观例子
假设原始配置:
const original = {host: 'api.example.com',
timeout: 5000,
headers: { auth: 'Bearer xyz' }
};
执行浅拷贝 + 冻结:
此时:
-
safeCopy.host = 'new.com'→ ❌ 失败(顶层属性被冻结) -
safeCopy.headers.auth = 'Bearer abc'→ ✅ 成功(headers是另一个未冻结对象) -
safeCopy.newField = true→ ❌ 失败(禁止新增)
这种模式适合什么场景?
它不是为了彻底防篡改,而是做一层轻量级契约约束:
- 对外暴露配置时,防止调用方误删/重写关键字段名(如把
timeout改成timeOut) - 在 Redux 初始 state 中锁定结构,但允许 reducer 深层更新(比如
state.user.profile.name) - 构建“只读接口”——使用者知道不能动顶层字段,但业务逻辑仍需灵活处理子结构
注意边界和风险
这种组合容易给人“已保护”的错觉。要清楚:
- 它不防深层修改,也不防原型链污染(需额外冻结
Object.prototype等) - 如果嵌套对象是共享的(比如多个 freeze 对象共用同一个
headers),一处修改会影响所有 - 调试时看到属性变灰带锁图标,不代表整个数据树安全











