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

有办法做到这一点吗?


当前回答

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

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;
}

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

谢谢

其他回答

如果你想要一个单行程序,而不需要像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 }

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

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}}

简单递归解

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

常量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)

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]

我使用下面的短函数进行深度合并对象。 这对我来说很有效。 作者在这里完全解释了它是如何工作的。

/*!
 * Merge two or more objects together.
 * (c) 2017 Chris Ferdinandi, MIT License, https://gomakethings.com
 * @param   {Boolean}  deep     If true, do a deep (or recursive) merge [optional]
 * @param   {Object}   objects  The objects to merge together
 * @returns {Object}            Merged values of defaults and options
 * 
 * Use the function as follows:
 * let shallowMerge = extend(obj1, obj2);
 * let deepMerge = extend(true, obj1, obj2)
 */

var extend = function () {

    // Variables
    var extended = {};
    var deep = false;
    var i = 0;

    // Check if a deep merge
    if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
        deep = arguments[0];
        i++;
    }

    // Merge the object into the extended object
    var merge = function (obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                // If property is an object, merge properties
                if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                    extended[prop] = extend(extended[prop], obj[prop]);
                } else {
                    extended[prop] = obj[prop];
                }
            }
        }
    };

    // Loop through each object and conduct a merge
    for (; i < arguments.length; i++) {
        merge(arguments[i]);
    }

    return extended;

};