Node.js中如何复制任意对象的所有自有属性?
问题分析与解决方案
你的推测完全正确:Error实例的message、stack等核心属性属于自身非枚举属性,而Object.assign()和对象展开语法({...obj})仅会复制对象的可枚举自身属性,这就是你复制后拿不到这些属性的原因。同时浏览器控制台对Error实例有特殊格式化逻辑,直接打印Error时会显示这些非枚举属性,但打印复制后的普通对象就不会。
通用解决方案(支持所有对象,包括Error)
如果想要复制对象的所有自身属性(含非枚举),同时可选保留原型链,可通过以下两种方式实现:
1. 保留原型链(保持instanceof判定)
这个方法会创建一个与原对象原型一致的新对象,并复制所有自身属性(包括非枚举):
function copyWithAllProperties(obj) { // 创建继承原对象原型的新实例 const copy = Object.create(Object.getPrototypeOf(obj)); // 获取原对象所有自身属性的描述符(含非枚举) const propDescriptors = Object.getOwnPropertyDescriptors(obj); // 将所有属性定义到新对象上 Object.defineProperties(copy, propDescriptors); return copy; }
测试示例:
const err = new Error('foo'); err.bar = 'bar'; const copiedErr = copyWithAllProperties(err); console.log(copiedErr); // 会显示message、stack、bar属性 console.log(copiedErr instanceof Error); // true console.log(copiedErr.message); // 'foo' console.log(copiedErr.stack); // 完整栈信息 console.log(copiedErr.bar); // 'bar'
2. 仅复制属性(转为普通对象,不保留原型)
如果不需要保留原对象的原型链,只需要把所有自身属性(含非枚举)复制到一个普通对象中:
function extractAllOwnProperties(obj) { const propDescriptors = Object.getOwnPropertyDescriptors(obj); return Object.defineProperties({}, propDescriptors); }
测试示例:
const plainObj = extractAllOwnProperties(new Error('foo')); console.log(plainObj); // { message: 'foo', stack: '...' } console.log(plainObj instanceof Error); // false
说明
- 以上方法是通用的,不仅适用于Error,对任何包含非枚举自身属性的对象(比如自定义类实例、Date实例等)都有效。
- 上述实现为浅拷贝,如果需要深层复制非枚举属性,可在函数中递归处理嵌套对象。
内容的提问来源于stack exchange,提问作者Alexander Mills
相关产品推荐
相关产品推荐

