object.assign({}, obj) 和 {...obj} 实现浅克隆,仅复制自身可枚举属性,断开原型链;不处理 symbol、不可枚举属性及特殊对象,需 reflect.ownkeys 配合 defineproperty 实现更完整自有属性克隆。

直接用 Object.assign({}, obj) 或展开运算符 {...obj} 就能实现不拷贝原型链的对象克隆。
这两种方式只复制对象自身的、可枚举的自有属性(own enumerable properties),完全忽略原型链上的方法和继承属性。这是它们的设计本意,不是缺陷,而是明确的行为边界。
关键点在于:
- 原型上的属性(比如
obj.toString()或自定义的obj.customMethod())不会出现在克隆结果中 -
Object.keys(obj)和Object.assign的遍历逻辑一致,都不触达[[Prototype]] - 克隆后得到的是一个纯粹的“字面量对象”,其
__proto__指向Object.prototype,与原对象的原型链彻底断开
常见写法对比:
const parent = { name: 'Base' };
const child = Object.create(parent);
child.id = 123;
child.say = () => 'hello';
console.log(child.name); // 'Base' ← 来自原型
console.log(child.hasOwnProperty('name')); // false
console.log(child.hasOwnProperty('id')); // true
const clone = Object.assign({}, child);
// 或 const clone = { ...child };
console.log(clone); // { id: 123, say: [Function] }
console.log(clone.name); // undefined
console.log(clone.say()); // 'hello' ← 函数被复制了(但只是引用)
注意几个实际限制:
- 不处理
Symbol键(需手动用Reflect.ownKeys+ 过滤) - 不拷贝不可枚举属性(如
Object.defineProperty(obj, 'hidden', { value: 42, enumerable: false })) - 函数、正则、日期等特殊值会被浅拷贝(函数仍是同一引用,Date 变成毫秒时间戳再还原为普通数字等)
如果需要更完整地保留自有属性(含 Symbol 和不可枚举属性),可用:
function shallowClone(obj) {
const clone = {};
const keys = Reflect.ownKeys(obj); // 包含 Symbol 和不可枚举键
for (const key of keys) {
Object.defineProperty(clone, key, Object.getOwnPropertyDescriptor(obj, key));
}
return clone;
}
这种写法能精确复刻对象自身的全部属性描述符,但仍不涉及原型链。











