如何深度克隆以Symbol()为键的嵌套对象?
深度克隆含Symbol键的对象的方法
常规的JSON.parse(JSON.stringify())和structuredClone()都会忽略对象的Symbol类型键,要实现包含Symbol键的深度克隆,可以用以下几种方式:
1. 手动递归实现(无依赖)
自己实现克隆逻辑,通过Reflect.ownKeys()获取对象的所有自身属性键(包括Symbol和不可枚举字符串键),同时处理循环引用和属性描述符:
function deepCloneWithSymbol(obj, cache = new WeakMap()) { // 处理原始值和null if (obj === null || typeof obj !== 'object') { return obj; } // 处理已克隆过的对象(解决循环引用) if (cache.has(obj)) { return cache.get(obj); } // 克隆数组 if (Array.isArray(obj)) { const clonedArr = []; cache.set(obj, clonedArr); return obj.map(item => deepCloneWithSymbol(item, cache)); } // 克隆普通对象,保留原型 const clonedObj = Object.create(Object.getPrototypeOf(obj)); cache.set(obj, clonedObj); // 获取所有键(含Symbol) const allKeys = Reflect.ownKeys(obj); allKeys.forEach(key => { const propDesc = Object.getOwnPropertyDescriptor(obj, key); if (propDesc) { // 递归克隆属性值 propDesc.value = deepCloneWithSymbol(propDesc.value, cache); Object.defineProperty(clonedObj, key, propDesc); } }); return clonedObj; } // 测试示例 const testSym = Symbol('demo'); const nestedSym = Symbol('nested'); const original = { [testSym]: 42, name: 'foo', nested: { [nestedSym]: 'bar' } }; // 加循环引用测试 original.self = original; const cloned = deepCloneWithSymbol(original); console.log(cloned[testSym]); // 输出 42 console.log(cloned.nested[nestedSym]); // 输出 'bar' console.log(cloned.self === cloned); // 输出 true(正确处理循环引用) console.log(cloned === original); // 输出 false(确认是深克隆)
这个方法完全自定义,不需要依赖第三方库,同时能完整保留对象的所有属性特性(包括可枚举性、读写权限等)。
2. 使用第三方库(如Lodash)
如果你的项目已经引入Lodash,它的cloneDeep方法原生支持Symbol键的深度克隆,无需额外处理:
const _ = require('lodash'); const testSym = Symbol('demo'); const original = { [testSym]: 42 }; const cloned = _.cloneDeep(original); console.log(cloned[testSym]); // 输出 42
内容的提问来源于stack exchange,提问作者hl037_
相关产品推荐
相关产品推荐

