能保留属性描述符的通用对象克隆函数需用Object.getOwnPropertyDescriptors获取所有自有属性描述符,再用Object.defineProperties定义到继承原原型的新对象上。

要编写一个能保留属性描述符的通用对象克隆函数,核心是使用 Object.getOwnPropertyDescriptors() 获取源对象所有自有属性的完整描述符(包括 value、writable、enumerable、configurable、get、set),再用 Object.defineProperties() 将其批量定义到新对象上。
支持 getter/setter 和不可枚举属性
浅克隆不能只复制属性值,否则会丢失访问器属性和属性特性。例如:
const obj = {
get x() { return 42; }
};
Object.defineProperty(obj, 'y', {
value: 'hidden',
enumerable: false,
writable: false,
configurable: true
});
直接 {...obj} 或 Object.assign() 会丢掉 x 的 getter 和 y 的不可枚举性、不可写性。
基础实现(不递归)
以下函数执行**浅克隆**,但完整保留所有自有属性的描述符:
立即学习“Java免费学习笔记(深入)”;
- 用
Object.getOwnPropertyDescriptors(obj)提取全部描述符 - 用
Object.getPrototypeOf(obj)获取原型,确保新对象继承相同原型 - 用
Object.defineProperties()定义属性,而非简单赋值
function cloneDescriptor(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const descriptors = Object.getOwnPropertyDescriptors(obj);
const prototype = Object.getPrototypeOf(obj);
const cloned = Object.create(prototype);
Object.defineProperties(cloned, descriptors);
return cloned;
}
处理 Symbol 属性和不可扩展对象
上述函数默认不包含 Symbol 属性。如需支持,需显式获取并合并:
- 用
Object.getOwnPropertySymbols(obj)获取 Symbol 键 - 对每个 Symbol 键调用
Object.getOwnPropertyDescriptor(obj, sym) - 将 Symbol 描述符合并进 descriptors 对象再 define
若原对象不可扩展(Object.isExtensible(obj) === false),需先创建可扩展对象再冻结,或直接抛出提示——因为无法向不可扩展对象添加新属性。
深克隆需额外递归逻辑
若需深克隆,应在定义每个属性前判断其值是否为对象(且非 null),再递归调用自身:
- 对
value字段:若为对象/数组,递归克隆;否则保持原值 - 对
get/set函数:通常不递归(它们是函数本身),除非你明确想克隆函数体(极少见) - 注意循环引用:需用 WeakMap 缓存已克隆对象,避免栈溢出
深克隆版本更复杂,建议按需实现,多数场景浅克隆 + 描述符保留已满足需求。


















