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

有办法做到这一点吗?


当前回答

这是我刚刚写的另一个支持数组的程序。它把它们连接起来。

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


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(Array.isArray(target)) {
        if(Array.isArray(source)) {
            target.push(...source);
        } else {
            target.push(source);
        }
    } else if(isPlainObject(target)) {
        if(isPlainObject(source)) {
            for(let key of Object.keys(source)) {
                if(!target[key]) {
                    target[key] = source[key];
                } else {
                    mergeDeep(target[key], source[key]);
                }
            }
        } else {
            throw new Error(`Cannot merge object with non-object`);
        }
    } else {
        target = source;
    }

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

其他回答

这很简单,也很有效:

let item = {
    firstName: 'Jonnie',
    lastName: 'Walker',
    fullName: function fullName() {
            return 'Jonnie Walker';
    }
Object.assign(Object.create(item), item);

解释:

create()创建新对象。如果你传递参数给函数,它将创建你的对象与其他对象的原型。如果你在一个对象的原型上有任何函数它们会被传递给另一个对象的原型。

object .assign()合并两个对象并创建一个全新的对象,它们不再有引用。这个例子对我来说很好。

我不喜欢现有的解决方案。所以,我开始写我自己的。

Object.prototype.merge = function(object) {
    for (const key in object) {
        if (object.hasOwnProperty(key)) {
            if (typeof this[key] === "object" && typeof object[key] === "object") {
                this[key].merge(object[key]);

                continue;
            }

            this[key] = object[key];
        }
    }

    return this;
}

我希望这能帮助那些努力理解正在发生的事情的人。我在这里看到了很多无意义的变量。

谢谢

适用于对象和数组的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
  }
}

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

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}

Ramda是一个很好的javascript函数库,它有mergeDeepLeft和mergeDeepRight。这些方法都能解决这个问题。请在这里查看文档:https://ramdajs.com/docs/#mergeDeepLeft

对于问题中的具体例子,我们可以使用:

import { mergeDeepLeft } from 'ramda'
const x = { a: { a: 1 } }
const y = { a: { b: 1 } }
const z = mergeDeepLeft(x, y)) // {"a":{"a":1,"b":1}}