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

有办法做到这一点吗?


当前回答

我们可以使用$.extend(true,object1,object2)进行深度合并。值true表示递归合并两个对象,修改第一个对象。

美元扩展(真的,目标,对象)

其他回答

有时候你并不需要深度合并,即使你这样认为。例如,如果您有一个带有嵌套对象的默认配置,并且您希望用自己的配置对其进行深入扩展,您可以为此创建一个类。概念很简单:

function AjaxConfig(config) {

  // Default values + config

  Object.assign(this, {
    method: 'POST',
    contentType: 'text/plain'
  }, config);

  // Default values in nested objects

  this.headers = Object.assign({}, this.headers, { 
    'X-Requested-With': 'custom'
  });
}

// Define your config

var config = {
  url: 'https://google.com',
  headers: {
    'x-client-data': 'CI22yQEI'
  }
};

// Extend the default values with your own
var fullMergedConfig = new AjaxConfig(config);

// View in DevTools
console.log(fullMergedConfig);

您可以将其转换为函数(而不是构造函数)。

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

/*!
 * 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;

};

ES5的一个简单解决方案(覆盖现有值):

function merge(current, update) { Object.keys(update).forEach(function(key) { // if update[key] exist, and it's not a string or array, // we go in one level deeper if (current.hasOwnProperty(key) && typeof current[key] === 'object' && !(current[key] instanceof Array)) { merge(current[key], update[key]); // if update[key] doesn't exist in current, or it's a string // or array, then assign/overwrite current[key] to update[key] } else { current[key] = update[key]; } }); return current; } var x = { a: { a: 1 } } var y = { a: { b: 1 } } console.log(merge(x, y));

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

有人知道深度合并在ES6/ES7规范中存在吗?

对象。赋值文档建议它不做深度克隆。