两个对象。assign和Object spread只做浅合并。

这个问题的一个例子:

// No object nesting
const x = { a: 1 }
const y = { b: 1 }
const z = { ...x, ...y } // { a: 1, b: 1 }

输出是您所期望的。然而,如果我尝试这样做:

// Object nesting
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = { ...x, ...y } // { a: { b: 1 } }

而不是

{ a: { a: 1, b: 1 } }

你得到

{ a: { b: 1 } }

X被完全覆盖,因为扩展语法只覆盖了一层。这与Object.assign()相同。

有办法做到这一点吗?


当前回答

另一个使用递归的变体,希望你觉得有用。

const merge = (obj1, obj2) => {

    const recursiveMerge = (obj, entries) => {
         for (const [key, value] of entries) {
            if (typeof value === "object") {
               obj[key] = obj[key] ? {...obj[key]} : {};
               recursiveMerge(obj[key], Object.entries(value))
            else {
               obj[key] = value;
            }
          }

          return obj;
    }

    return recursiveMerge(obj1, Object.entries(obj2))
}

其他回答

如果你想要一个单行程序,而不需要像lodash那样庞大的库,我建议你使用deepmerge (npm install deepmerge)或deepmerge-ts (npm install deepmerge-ts)。

deepmerge也为TypeScript提供了类型,并且更加稳定(因为它比较老),但是deepmerge-ts也可用于Deno,并且从设计上看更快,尽管顾名思义是用TypeScript编写的。

一旦导入就可以了

deepmerge({ a: 1, b: 2, c: 3 }, { a: 2, d: 3 });

得到

{ a: 2, b: 2, c: 3, d: 3 }

这对于复杂的对象和数组非常有效。这是一个真正的全面解决方案。

2022年更新:

我创建mergician是为了满足评论中讨论的各种合并/克隆需求。它基于与我最初的答案相同的概念(如下),但提供了可配置的选项:

Unlike native methods and other merge/clone utilities, Mergician provides advanced options for customizing the merge/clone process. These options make it easy to inspect, filter, and modify keys and properties; merge or skip unique, common, and universal keys (i.e., intersections, unions, and differences); and merge, sort, and remove duplicates from arrays. Property accessors and descriptors are also handled properly, ensuring that getter/setter functions are retained and descriptor values are defined on new merged/cloned objects.

值得注意的是,mergician比lodash等类似工具要小得多(1.5k min+gzip)。合并(5.1k min+gzip)。

GitHub: https://github.com/jhildenbiddle/mergician NPM: https://www.npmjs.com/package/mergician 文档:https://jhildenbiddle.github.io/mergician/


最初的回答:

由于这个问题仍然存在,这里有另一种方法:

ES6/2015 不可变(不修改原始对象) 处理数组(连接它们)

/** * Performs a deep merge of objects and returns new object. Does not modify * objects (immutable) and merges arrays via concatenation. * * @param {...object} objects - Objects to merge * @returns {object} New object with merged key/values */ function mergeDeep(...objects) { const isObject = obj => obj && typeof obj === 'object'; return objects.reduce((prev, obj) => { Object.keys(obj).forEach(key => { const pVal = prev[key]; const oVal = obj[key]; if (Array.isArray(pVal) && Array.isArray(oVal)) { prev[key] = pVal.concat(...oVal); } else if (isObject(pVal) && isObject(oVal)) { prev[key] = mergeDeep(pVal, oVal); } else { prev[key] = oVal; } }); return prev; }, {}); } // Test objects const obj1 = { a: 1, b: 1, c: { x: 1, y: 1 }, d: [ 1, 1 ] } const obj2 = { b: 2, c: { y: 2, z: 2 }, d: [ 2, 2 ], e: 2 } const obj3 = mergeDeep(obj1, obj2); // Out console.log(obj3);

与减少

export const merge = (objFrom, objTo) => Object.keys(objFrom)
    .reduce(
        (merged, key) => {
            merged[key] = objFrom[key] instanceof Object && !Array.isArray(objFrom[key])
                ? merge(objFrom[key], merged[key] ?? {})
                : objFrom[key]
            return merged
        }, { ...objTo }
    )
test('merge', async () => {
    const obj1 = { par1: -1, par2: { par2_1: -21, par2_5: -25 }, arr: [0,1,2] }
    const obj2 = { par1: 1, par2: { par2_1: 21 }, par3: 3, arr: [3,4,5] }
    const obj3 = merge3(obj1, obj2)
    expect(obj3).toEqual(
        { par1: -1, par2: { par2_1: -21, par2_5: -25 }, par3: 3, arr: [0,1,2] }
    )
})

你可以使用Lodash合并:

Var对象= { 'a': [{'b': 2}, {'d': 4}] }; Var other = { 'a': [{'c': 3}, {'e': 5}] }; console.log(_。合并(对象,其他)); / / = > {a: [{b: 2,“c”:3},{' d ': 4,“e”:5}]} < script src = " https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js " > < /脚本>

(本机解决方案)如果你知道你想要深度合并的属性,那么

const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
Object.assign(y.a, x.a);
Object.assign(x, y);
// output: a: {b: 1, a: 1}