object.create 配合 object.getownpropertydescriptors 可实现保留原型链、属性特性及访问器的完美浅克隆,因前者捕获完整描述符(含不可枚举、get/set等),后者按描述符与原型精确重建对象,避免 object.assign 等丢失元信息。

用 Object.create 配合 Object.getOwnPropertyDescriptors,可以实现**保留原型链、属性特性(如 writable、enumerable、configurable)、访问器属性(get/set)的浅克隆**,这是普通 Object.assign 或展开运算符做不到的。
为什么需要这两个方法配合?
Object.getOwnPropertyDescriptors(obj) 能完整捕获对象自身所有属性的描述符(包括不可枚举、不可配置、访问器等);Object.create(proto, descriptors) 则能按指定原型和描述符精确重建对象。两者结合,就绕过了赋值带来的“丢失元信息”问题。
基础完美浅克隆函数
以下函数克隆对象自身属性 + 原型链,不递归嵌套对象:
function perfectShallowClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const descriptors = Object.getOwnPropertyDescriptors(obj);
return Object.create(Object.getPrototypeOf(obj), descriptors);
}
- 支持普通数据属性(保留
writable: false等) - 正确复制
get/set访问器(Object.assign会直接调用get取值,丢失访问器本身) - 继承原对象的原型(
instanceof仍成立) - 保留不可枚举属性(如
Object.keys看不到但for...in或Reflect.ownKeys可见)
处理特殊情况:Symbol 属性与内置对象
Object.getOwnPropertyDescriptors 默认只返回字符串键的描述符,不包含 Symbol 键。如需完整克隆,需手动合并:
function perfectShallowCloneWithSymbols(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const descriptors = Object.getOwnPropertyDescriptors(obj);
const symbolKeys = Object.getOwnPropertySymbols(obj);
symbolKeys.forEach(sym => {
descriptors[sym] = Object.getOwnPropertyDescriptor(obj, sym);
});
return Object.create(Object.getPrototypeOf(obj), descriptors);
}
- 对
Date、RegExp等内置对象,该方法仅克隆其**自有属性描述符**,不会复现内部插槽(如[[DateValue]]),所以不能替代new Date(obj)等构造方式 - 若需深度克隆,需在此基础上递归处理对象/数组类型的属性值(注意循环引用)
对比常见克隆方式
-
{...obj}或Object.assign({}, obj):丢失原型、访问器、不可枚举属性、属性特性 -
JSON.parse(JSON.stringify(obj)):丢函数、undefined、Symbol、Date、RegExp、循环引用,且所有属性都变成可写可枚举 -
Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)):唯一能保全“对象结构语义”的标准方案











