合并嵌套对象而不进行变异

时间:2016-07-20 22:22:02

标签: javascript ecmascript-6 redux

我有以下2个JavaScript对象:

let o1 = {
  entities: {
    1: {
      text: "fooo",
      nested: {
        ids: [1, 2, 3],
        flag: true
      }
    }
  }
};

let o2 = {
  ids: [4, 5, 6]
}

我希望在不改变它们的情况下合并它们,以获得一个看起来像这样的Object:

let o3 = {
  entities: {
    1: {
      text: "fooo",
      nested: {
        ids: [1, 2, 3, 4, 5, 6],
        flag: true
      }
    }
  }
};

可能有n entities,但只有entityId定义的那个应该受到影响。 我尝试了什么:

let entityId = 1;

let o3 = Object.assign({}, o1, {
         entities: Object.assign({}, o1.entities, {
           [entityId]: Object.assign({}, o1.entities[entityId].nested,
            { ids: [...o1.entities[entityId].nested.ids, ...o2.ids] }
          )
        })
      });

问题是text: "fooo",nested:完全消失了。

我的方法是对的吗?这段代码可以优化吗?

5 个答案:

答案 0 :(得分:3)

由于您标记了Redux,我将假设您使用的是React,并建议您使用不变性助手 - https://facebook.github.io/react/docs/update.html

您的代码如下所示:

let o3 = update(o1, {
    entities: {
        [entityId]: {
            nested: {
                ids: {
                    $push: [4, 5, 6]
                }
            }
        }
    }
})

<强> ES6

您的逻辑是正确的,但您错过了代码中的nested对象:

let o3 = Object.assign({}, o1, {
     entities: Object.assign({}, o1.entities, {
       [entityId]: Object.assign({}, o1.entities[entityId], { 
          nested : Object.assign({}, o1.entities[entityId].nested ,{
            ids: [...o1.entities[entityId].nested.ids, ...o2.ids] }) 
        }
      )
    })
  });

答案 1 :(得分:0)

如果您知道您的数据不包含任何日期或方法,则可以使用JSON深度克隆技巧:

let o3 = JSON.parse(JSON.stringify(o1));
Array.prototype.push.apply(o3.entities[1].nested.ids, o2.ids);

答案 2 :(得分:0)

嗯,你的第一个问题是:

{
       [entityId]: Object.assign({}, o1.entities[entityId].nested,

您将o1.entities[1].nested的值复制到键o3.entities[1]中,从而丢失o1.entities[1]中保留的对象中的其他键。

这很难看,因为正如其他评论所指出的那样,这不是很漂亮的代码。

当然,您希望(而且意味着)使用o1.entities[entityId]

但是,如果你只是对你当前感兴趣的o1部分执行副本,那么还有一个问题。{{1}将复制对象引用,而不是创建完全新鲜的对象。因此,如果您稍后修改Object.assign()的值,您也会改变o3.entities[1].text

答案 3 :(得分:0)

您似乎错过了一层合并 - 您的示例代码包含entities.1.ids而不是entities.1.nested.ids。尝试

let entityId = 1;

let o3 = Object.assign(
  {},
  o1,
  {
    entities: Object.assign(
      {},
      o1.entities,
      {
        [entityId]: Object.assign(
          {},
          o1.entities[entityId],
          Object.assign(
            {},
            o1.entities[entityId].nested,
            { ids: [...o1.entities[entityId].nested.ids, ...o2.ids] }
          )
        )
      }
    )
  }
);

此时,您可能希望从每个Object.assign调用中构建一些中间变量,这样您就可以更好地跟踪所有内容。

答案 4 :(得分:0)

我会做:

const merged = {
    entities: {
        [entityId]: {
            text: o1.entities[entityId].text,
            nested: {
                ids: [...o1.entities[entityId].nested.ids, ...o2.ids],
                flag: o1.entities[entityId].nested.flag
            }
        }
    }
}