合并 JSON 对象:深度合并、展开运算符及其他策略

jsonjavascriptmergepatterns

合并 JSON 对象对于组合配置、更新数据和处理默认值至关重要。以下是您应该了解的策略。

使用展开运算符浅合并

const defaults = { theme: "light", lang: "en", fontSize: 14 };

const user = { theme: "dark", fontSize: 16 };

const merged = { ...defaults, ...user };

// { theme: "dark", lang: "en", fontSize: 16 }

第二个对象的属性会覆盖第一个。

Object.assign()

const merged = Object.assign({}, defaults, user);

与展开运算符行为相同,但如果不加 {},会修改目标对象。

深度合并

浅合并无法处理嵌套对象:

// 浅合并丢失嵌套数据

const a = { config: { theme: "light", lang: "en" } };

const b = { config: { theme: "dark" } };

const shallow = { ...a, ...b };

// { config: { theme: "dark" } } — lang 丢失了!

深度合并递归组合嵌套对象:

function deepMerge(target, source) {

const result = { ...target };

for (const key of Object.keys(source)) {

if (isObject(target[key]) && isObject(source[key])) {

result[key] = deepMerge(target[key], source[key]);

} else {

result[key] = source[key];

}

}

return result;

}

const deep = deepMerge(a, b);

// { config: { theme: "dark", lang: "en" } } — lang 保留了!

数组合并策略

当两个对象都有数组时:

// 替换(默认行为)

const replace = { ...a, items: b.items };

// 连接

const concat = { ...a, items: [...a.items, ...b.items] };

// 按 ID 合并

const mergeById = {

...a,

items: a.items.map(item => {

const override = b.items.find(i => i.id === item.id);

return override ? { ...item, ...override } : item;

})

};

使用库

生产代码建议使用成熟的库:

  • lodash.merge — 经过实战检验的深度合并
  • deepmerge — 可自定义合并行为
  • ts-deepmerge — TypeScript 友好
  • 使用我们的 JSON 格式化器 格式化合并结果以便检查。

    相关工具