如何深度合并而不是浅层合并?

Object.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()相同。

有没有办法做到这一点?


有谁知道ES6 / ES7规范中是否存在深度合并?

不,不是的。


我知道这是一个老问题,但ES2015 / ES6中最简单的解决方案实际上很简单,使用Object.assign(),

希望这有助于:

/**
 * Simple object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item));
}

/**
 * Deep merge two objects.
 * @param target
 * @param ...sources
 */
export function mergeDeep(target, ...sources) {
  if (!sources.length) return target;
  const source = sources.shift();

  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }

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

用法示例:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }

你会在下面的答案中找到这个不变的版本。

请注意,这将导致循环引用无限递归。 如果您认为您会遇到这个问题,那么在这里有关于如何检测循环引用的一些很好的答案。


当涉及到主机对象或任何类型的比一包值更复杂的对象时,这个问题并不重要

  • 你是否调用getter来获取值或者是否复制属性描述符?
  • 如果合并目标有一个设置者(自己的财产或原型链)? 你认为这个值是否已经存在,或者调用setter来更新当前值?
  • 你是否调用自己的属性函数或复制它们? 如果它们在定义时根据其范围链中的某些内容绑定了函数或箭头函数呢?
  • 如果它像DOM节点那样呢? 您当然不希望将其视为简单的对象,只是将其所有属性深入合并
  • 如何处理像数组,地图或集合这样的“简单”结构? 考虑他们已经存在或合并它们呢?
  • 如何处理不可枚举的属性?
  • 那么新的子树呢? 只需通过参考或深度克隆进行分配?
  • 如何处理冻结/密封/不可扩展的对象?
  • 还有一件事要记住:包含循环的对象图。 处理通常不难 - 只保留一Set已经访问过的源对象 - 但经常被遗忘。

    您可能应该编写一个深度合并函数,该函数仅将原始值和简单对象(至多是结构化克隆算法可处理的那些类型)视为合并源。 如果遇到无法处理的任何内容,或者仅通过引用分配而不是深度合并,则抛出它。

    换句话说,没有一种万能的算法,你必须自己推出或寻找适合你的用例的库方法。

    链接地址: http://www.djcxy.com/p/4693.html

    上一篇: How to deep merge instead of shallow merge?

    下一篇: `if (0 in array)` — is this even legal?