JS 递归对象合并

11

我了解到使用Object.assign()方法时,它只会扩展顶层对象。那么如何深度扩展对象呢?例如,假设我有以下源对象:

const source = {
  id: 1,
  otherKey: {},
  params: {
    page: {
      a: 1,
      b: {}
    },
    data: {
      b: 1
    }
  }
}

我正在这样使用 Object.assign():

Object.assign({}, source, {
  params: {
    page: {
      a: 2
    }
  }
}

结果将是:

{
      id: 1,
      otherKey: {},
      params: {
        page: {
          a: 2
        }
      }
}

如何以浅克隆的方式保留params.data和params.page.b键。

oldObject.params.data === newObject.params.data  // true
oldObject.params.page === newObject.params.page  // false
oldObject.params.page.b === newObject.params.page.b // true

注意: 此问题与 如何深度合并而不是浅合并 不同。那里的答案不能给出预期的结果。

请检查此 bin,它使用了上述链接中的一个答案。


1
注意:这个问题不同于如何进行深度合并而不是浅层合并。那里的答案没有给出预期结果。它看起来完全像一个重复的问题。例如,关于这个答案,有什么具体的地方不能满足你的期望?示例:https://jsfiddle.net/9oczv2a0/ - T.J. Crowder
@T.J.Crowder 给我几分钟来展示给你。 - undefined
你能否同时指出 oldObject.params === newObject.paramsoldObject === newObject 的预期结果? - klugjo
@T.J.Crowder,你可以看到这不是重复的。请查看此bin http://jsbin.com/wufalikovo/edit?js,output - undefined
这就是我目前困惑的地方,我不知道如何将 jsbin 中的代码转换为预期结果。我需要帮助。 - undefined
显示剩余4条评论
1个回答

5

在您发布的代码中,如果源和目标都包含相同的键,则什么也不会发生。对象会递归到其子级。但是,如果您仅将内部块更改为以下内容:

if (!target[key]) { 
  Object.assign(target, { [key]: {} });
}else{          
  target[key] = Object.assign({}, target[key])
}
mergeDeep(target[key], source[key]);

这将为在源和目标中都存在的任何键创建一个新的分配对象。有趣的是,如果您这样做,预期的falseys不会显示在控制台中。这是因为目标将始终匹配结果,因为它是最终突变的对象。因此,为了获得您期望的false结果,您需要执行以下操作:
var tester = source.params
const result = mergeDeep(source, b)
console.log(tester === result.params) // this will be false after the above addition

您可以在这里查看您想要的结果:http://jsbin.com/vicemiqiqu/1/edit?js,console

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接