两个对象。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()相同。

有办法做到这一点吗?


当前回答

有一些维护良好的库已经做到了这一点。npm注册表中的一个例子是merge-deep

其他回答

你可以使用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 " > < /脚本>

简单递归解

使用对象。条目,遍历其中一个对象。如果条目不存在,则添加该条目;如果条目是对象,则递归。

常量x = {a: {a: 1}} Const y = {a: {b: 1}} JSON.parse(JSON.stringify(y)) const mergeIntoZ = (firstObj, secondObj) => { Object.entries (firstObj) .forEach(([key, value]) => { if (secondObj[key] === undefined) { secondObj[key] = value } else if (typeof value === 'object') { mergeIntoZ (firstObj(关键),secondObj[主要]) } }) } mergeIntoZ (x, z) console.log (z)

适用于对象和数组的Vanilla Script解决方案:

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

function deepmerge() {
  merge = function () {
    let target = arguments[0];
    for (let i = 1; i < arguments.length ; i++) {
      let arr = arguments[i];
            for (let k in arr) {
         if (Array.isArray(arr[k])) {
            if (target[k] === undefined) {            
                 target[k] = [];
            }            
            target[k] = [...new Set(target[k].concat(...arr[k]))];
         } else if (typeof arr[k] === 'object') {
            if (target[k] === undefined) {            
                 target[k] = {};
            }
            target[k] = merge(target[k], arr[k]);
         } else {
              target[k] = arr[k];         
         }
      }
    }
    return target;
  }
  return merge(...arguments);
}
console.log(deepmerge(x,y));

输出:

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

如果您想合并多个普通对象(不要修改输入对象)。基于对象。分配polyfill

function isPlainObject(a) { return (!!a) && (a.constructor === Object); } function merge(target) { let to = Object.assign({}, target); for (let index = 1; index < arguments.length; index++) { let nextSource = arguments[index]; if (nextSource !== null && nextSource !== undefined) { for (let nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { if (isPlainObject(to[nextKey]) && isPlainObject(nextSource[nextKey])) { to[nextKey] = merge(to[nextKey], nextSource[nextKey]); } else { to[nextKey] = nextSource[nextKey]; } } } } } return to; } // Usage var obj1 = { a: 1, b: { x: 2, y: { t: 3, u: 4 } }, c: "hi" }; var obj2 = { b: { x: 200, y: { u: 4000, v: 5000 } } }; var obj3 = { c: "hello" }; console.log("result", merge(obj1, obj2, obj3)); console.log("obj1", obj1); console.log("obj2", obj2); console.log("obj3", obj3);

如果你想合并有限的深度

function isPlainObject(a) { return (!!a) && (a.constructor === Object); } function merge(target) { let to = Object.assign({}, target); const hasDepth = arguments.length > 2 && typeof arguments[arguments.length - 1] === 'number'; const depth = hasDepth ? arguments[arguments.length - 1] : Infinity; const lastObjectIndex = hasDepth ? arguments.length - 2 : arguments.length - 1; for (let index = 1; index <= lastObjectIndex; index++) { let nextSource = arguments[index]; if (nextSource !== null && nextSource !== undefined) { for (let nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { if (depth > 0 && isPlainObject(to[nextKey]) && isPlainObject(nextSource[nextKey])) { to[nextKey] = merge(to[nextKey], nextSource[nextKey], depth - 1); } else { to[nextKey] = nextSource[nextKey]; } } } } } return to; } // Usage var obj1 = { a: 1, b: { x: 2, y: { t: 3, u: 4, z: {zzz: 100} } }, c: "hi" }; var obj2 = { b: { y: { u: 4000, v: 5000, z: {} } } }; var obj3 = { c: "hello" }; console.log('deep 0', merge(obj1, obj2, obj3, 0)); console.log('deep 1', merge(obj1, obj2, obj3, 1)); console.log('deep 2', merge(obj1, obj2, obj3, 2)); console.log('deep 2', merge(obj1, obj2, obj3, 4));

function isObject(obj) {
    return obj !== null && typeof obj === 'object';
}
const isArray = Array.isArray;

function isPlainObject(obj) {
    return isObject(obj) && (
        obj.constructor === Object  // obj = {}
        || obj.constructor === undefined // obj = Object.create(null)
    );
}

function mergeDeep(target, ...sources){
    if (!sources.length) return target;
    const source = sources.shift();

    if (isPlainObject(source) || isArray(source)) {
        for (const key in source) {
            if (isPlainObject(source[key]) || isArray(source[key])) {
                if (isPlainObject(source[key]) && !isPlainObject(target[key])) {
                    target[key] = {};
                }else if (isArray(source[key]) && !isArray(target[key])) {
                    target[key] = [];
                }
                mergeDeep(target[key], source[key]);
            } else if (source[key] !== undefined && source[key] !== '') {
                target[key] = source[key];
            }
        }
    }

    return mergeDeep(target, ...sources);
}

// test...
var source = {b:333};
var source2 = {c:32, arr: [33,11]}
var n = mergeDeep({a:33}, source, source2);
source2.arr[1] = 22;
console.log(n.arr); // out: [33, 11]