只读属性在浅拷贝中不会被保留其只读性;object.assign和展开运算符仅复制值,不复制writable等描述符,需用object.getownpropertydescriptor配合object.defineproperty手动复制完整属性特性才能确保只读性。

JavaScript 中对象浅拷贝默认不处理只读属性(writable: false)的“保护逻辑”,但能否成功复制,取决于目标对象是否允许重定义该属性——关键不在“拷贝动作本身”,而在 Object.defineProperty 的执行结果。
只读属性在浅拷贝中会怎样?
标准浅拷贝方法(如 Object.assign()、展开运算符 {...obj})底层依赖属性枚举和赋值操作。对于 writable: false 的自有属性:
- 如果该属性是 可配置(
configurable: true),Object.assign仍能将值写入目标对象(因为赋值操作不检查writable,只看能否设置); - 但如果该属性是 不可配置且只读(
configurable: false, writable: false),Object.assign仍会尝试赋值,且通常成功(目标对象是普通空对象,没有同名属性,所以属于首次定义,不受只读限制); - 真正的问题出现在:你想把只读属性复制到一个已有同名属性的目标对象上,且那个属性本身也是
writable: false——这时会静默失败(非严格模式)或抛错(严格模式)。
如何确保只读属性被完整保留?
想让拷贝后的新对象也拥有完全一致的只读性(包括 writable、configurable、enumerable 等元信息),必须用 Object.getOwnPropertyDescriptor + Object.defineProperty 手动复制描述符:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 获取原属性的完整描述符:
Object.getOwnPropertyDescriptor(obj, key); - 用该描述符在新对象上定义同名属性:
Object.defineProperty(target, key, descriptor); - 这样,
writable: false会被原样保留,后续对新对象该属性的赋值会失败(符合预期)。
常见误区提醒
别以为 Object.assign 复制了值,就等于保留了“只读”语义——它只复制值,不复制属性特性。例如:
const src = {};
Object.defineProperty(src, 'id', {
value: 100,
writable: false,
enumerable: true,
configurable: false
});
const copy1 = Object.assign({}, src);
copy1.id = 200; // ✅ 成功!因为 copy1.id 是可写的(assign 没保留 writable: false)
const copy2 = {};
Object.defineProperty(copy2, 'id', Object.getOwnPropertyDescriptor(src, 'id'));
copy2.id = 200; // ❌ 失败!TypeError: Cannot assign to read only property 'id'
顺便提一句:getter/setter 和只读的关系
如果只读是通过 getter 实现(get 描述符存在,无 set,且 writable: false 未显式设为 true),那么用 defineProperty 复制描述符后,getter 也会被保留,此时属性天然不可赋值——这种“只读”比单纯 writable: false 更可靠,也更容易被完整拷贝。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










