浅拷贝默认不保留属性描述符,需用Object.defineProperty逐个还原;应遍历自有属性(含Symbol),获取并定义完整描述符,避免使用展开运算符或Object.assign。

浅拷贝本身不保留属性描述符,比如 writable、enumerable、configurable,默认会变成普通可写、可枚举、可配置的属性。想在浅拷贝时“避免修改描述符”,本质是**不走默认赋值逻辑,改用定义式复制**。
用 Object.defineProperty 逐个还原描述符
这是最准确的方式:先读取原属性的完整描述符,再在新对象上用相同描述符定义同名属性。
-
获取描述符:用
Object.getOwnPropertyDescriptor(obj, key)拿到包括writable、enumerable、configurable和value或get/set的完整配置 -
定义到新对象:用
Object.defineProperty(target, key, descriptor)把整个描述符原样搬过去 -
注意遍历范围:只对自有属性(
Object.getOwnPropertyNames()或Object.getOwnPropertySymbols())操作,避免误拷原型链上的属性
不要依赖展开运算符或 Object.assign
这些方法本质是“赋值”,不是“定义”:
-
{...obj}和Object.assign({}, obj)只复制属性值,忽略所有描述符设置 - 原本
writable: false的属性,拷贝后变成可写;enumerable: false的属性,拷贝后出现在Object.keys()中 - 访问器属性(
get/set)会被降级为普通数据属性,只保留当前取值
封装一个保描述符的浅拷贝函数
适用于需要精确控制属性行为的场景,比如克隆配置对象、冻结前预处理、或构建不可变数据结构:
立即学习“Java免费学习笔记(深入)”;
- 遍历
Object.getOwnPropertyNames(obj)和Object.getOwnPropertySymbols(obj) - 对每个 key 调用
Object.getOwnPropertyDescriptor(obj, key) - 用
Object.defineProperty(newObj, key, descriptor)复制过去 - 若需保留原型,可用
Object.setPrototypeOf(newObj, Object.getPrototypeOf(obj))
什么情况下可以不用这么麻烦
如果对象只是普通数据容器,没有自定义描述符,也不含访问器、不可枚举属性,那用展开运算符或 Object.assign 完全够用。只有当你明确依赖了 writable: false(防意外修改)、configurable: false(防删除或重定义)、或 enumerable: false(控制遍历行为)时,才必须走 defineProperty 这条路。


















