使用ES6扩展语法合并对象时出现属性覆盖问题
嘿,我完全懂你遇到的困扰——用ES6扩展运算符{...obj1, ...obj2}合并两个对象时,如果它们有同名的顶层键(比如你的resolver),后面对象的键值会直接覆盖前面的,这就是为什么你打印出来只能看到最后那个resolver的原因。
问题到底出在哪?
举个具体的例子,假设你的两个对象长这样:
const apiResolvers = { resolver: { query: { getPosts: () => {} } } }; const userResolvers = { resolver: { mutation: { createUser: () => {} } } };
当你用{...apiResolvers, ...userResolvers}合并时,resolver这个键会直接被userResolvers里的版本替换掉,apiResolvers里的query部分就丢失了——扩展运算符只做浅合并,不会处理嵌套对象的合并。
怎么解决?
要保留所有resolver里的内容,我们需要对嵌套的resolver对象单独做合并,而不是直接覆盖。这里有几种实用的方法:
1. 手动嵌套扩展(适合结构简单的场景)
如果你的resolver结构比较固定,直接对嵌套层用扩展语法就行:
const mergedResolvers = { ...apiResolvers, resolver: { ...apiResolvers.resolver, ...userResolvers.resolver } };
这样就能把两个resolver里的子属性(比如query和mutation)都合并在一起,不会丢失任何内容。
2. 写一个通用的深度合并函数(适合复杂嵌套结构)
如果你的对象嵌套层次多,或者需要多次合并不同的resolver对象,最好封装一个递归的深度合并函数:
// 递归深度合并对象 function deepMerge(target, ...sources) { if (!sources.length) return target; const currentSource = sources.shift(); // 只处理对象类型(排除数组) if (isPlainObject(target) && isPlainObject(currentSource)) { for (const key in currentSource) { if (isPlainObject(currentSource[key])) { // 如果目标里没有这个键,先创建空对象 if (!target[key]) target[key] = {}; // 递归合并嵌套对象 deepMerge(target[key], currentSource[key]); } else { // 非对象类型直接赋值 target[key] = currentSource[key]; } } } return deepMerge(target, ...sources); } // 辅助函数:判断是否是纯对象 function isPlainObject(item) { return typeof item === 'object' && item !== null && !Array.isArray(item); } // 使用方式 const mergedResolvers = deepMerge({}, apiResolvers, userResolvers);
这个函数会逐层遍历对象,遇到嵌套对象就继续合并,完美解决多层嵌套的覆盖问题。
3. 用第三方库快速解决(省事儿)
如果你不想自己写函数,可以用现成的库,比如lodash的merge方法,它原生支持深度合并:
import merge from 'lodash.merge'; const mergedResolvers = merge({}, apiResolvers, userResolvers);
一行代码搞定,适合已经在项目里用lodash的情况。
验证一下
合并完成后,你再打印console.log(mergedResolvers.resolver),就能看到原来两个对象里的resolver内容都被完整保留下来啦~
内容的提问来源于stack exchange,提问作者Taylor Austin

