是否抛出错误取决于浅拷贝方式:Object.assign({}, obj)和扩展运算符正常,而Object.assign(objPrevented, source)会因向不可扩展对象添加新属性报TypeError。

在 Object.preventExtensions() 的对象上执行浅拷贝操作时,**是否抛出错误取决于你使用的浅拷贝方式**——有些会立即报错(如 `Object.assign`、扩展运算符),有些则不会(如 `Object.keys().forEach` 手动赋值)。
为什么某些浅拷贝会抛错?
因为 Object.preventExtensions() 禁止向对象添加新属性,但不禁止修改已有属性。而很多“浅拷贝”方法(尤其是目标对象为空对象 `{}` 时)本质是「往目标对象上设置新属性」:
-
Object.assign({}, obj):把obj的自有可枚举属性逐个复制到 `{}` 上 → 对 `{}` 赋值新属性 → ✅ 正常 -
Object.assign(objPrevented, source):把source的属性复制到已被preventExtensions的objPrevented上 → 尝试给它添加新属性 → ❌ 报错:TypeError: Cannot add property xxx, object is not extensible -
{...objPrevented}(扩展运算符):等价于Object.assign({}, objPrevented)→ ✅ 正常(目标是新对象) -
{...objPrevented, newProp: 1}:尝试往已不可扩展的对象展开后「再加属性」→ 实际是往新对象加,✅ 不报错;但如果写成Object.assign(objPrevented, {newProp: 1})→ ❌ 报错
哪些操作一定会触发错误?
以下操作会在目标对象被 preventExtensions 后,且该目标**原本不含对应属性**时抛错:
-
Object.assign(targetPrevented, source)(当source有targetPrevented不存在的属性) -
Reflect.set(targetPrevented, key, value)(当key不存在) -
targetPrevented[key] = value(严格模式下,且key不存在)
如何安全地对不可扩展对象做浅拷贝?
关键是:**确保目标对象是新的、可扩展的,而不是复用被保护的对象本身**:
- ✅ 推荐:用空对象作目标 ——
Object.assign({}, objPrevented)或{...objPrevented} - ✅ 手动遍历已有属性(不新增)——
const copy = {}; Object.getOwnPropertyNames(objPrevented).forEach(k => copy[k] = objPrevented[k]); - ⚠️ 注意:`Object.create(null)` 创建的对象默认不可扩展,但它是空的,不影响拷贝逻辑;而 `preventExtensions` 是对已有对象「关上扩展门」,不影响读和改旧属性
小实验验证
你可以直接运行这段代码观察行为:
const src = { a: 1, b: 2 };
Object.preventExtensions(src);
// ✅ 安全:拷贝到新对象
console.log(Object.assign({}, src)); // { a: 1, b: 2 }
// ❌ 报错:往被锁定的对象上写新属性
try {
Object.assign(src, { c: 3 });
} catch (e) {
console.error(e.message); // "Cannot add property c, object is not extensible"
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











