使用map()时克隆对象属性的最佳方法是什么?

时间:2019-05-29 00:04:01

标签: javascript ecmascript-6

我想添加一个新属性(contactDetails.countryName),并使用map()函数将值分配给存储在称为用户的数组中的嵌套对象。

我最近了解到我应该使用散布运算符(...),然后创建/分配新属性,以避免变异对象的原始数组,因此我为此开发了2种不同的实现,但是我并没有真正的信心遵循最佳实践来实现我想要的语义和性能。

在您看来,实现我想做的最好的方法是什么?

const countries = [
  { id: 3, countryName : "UK" },
  { id: 4, countryName : "Spain" },
  { id: 6, countryName : "Germany"}
];


const users = [
  { id : 1,
    name: "Douglas Camp",
    dateOfBirth: "23-06-1984",
    contactDetails:
      {
        country: 3,
        phone: "7373724997"
      }
  },
  {
    id : 2,
    name: "Martin Stein",
    dateOfBirth: "19-08-1992",
    contactDetails:
      {
        country: 6,
        phone: "3334343434"
      }
  },
];


const usersData = users.map(user=> {

// Version 1 : using spreading operator twice 

const newUser = {
    ...user,
    contactDetails: {
      ...user.contactDetails,
      countryName: countries.find(c=> c.id == user.contactDetails.country).countryName
    }
  };  
  return newUser;
});

// Version 2: copying the original object property and using spread operator only for cloning the nested object properties

const newUser = {
    id: user.id,
    name: user.name,
    dateOfBirth: user.dateOfBirth,
    contactDetails: {
      ...user.contactDetails,
      countryName: countries.find(c=> c.id == user.contactDetails.country).countryName
    }
  };

console.log(users);
console.log(usersData);

4 个答案:

答案 0 :(得分:1)

这是您可以考虑的一种方法:

  • 首先,我将Array.reduce个国家Map},这样您就可以通过key / value或在这种情况下通过{{1 }},并避免每次都过滤该数组。

  • 您可以映射用户,并为每个用户创建一个新对象。在这种情况下,我称它们为countries.get(key)

  • 您也可以考虑使用Object.assign

  • 请注意,accounts运算符和...都是浅克隆方法。它们不会递归地克隆嵌套的对象/子级。为此,您可以使用Object.assignJSON.stringify等。

JSON.parse

当我们更新let countries = [ { id: 3, countryName : "UK" }, { id: 4, countryName : "Spain" }, { id: 6, countryName : "Germany"} ].reduce((r,{id, countryName}) => (r.set(id, countryName), r), new Map()) // reduce with Map let users = [ { id : 1, name: "Douglas Camp", dateOfBirth: "23-06-1984", contactDetails: { country: 3, phone: "7373724997" } }, { id : 2, name: "Martin Stein", dateOfBirth: "19-08-1992", contactDetails: { country: 6, phone: "3334343434" } }, ]; let accounts = users.map(user => Object.assign({}, user, { // <-- map through contactDetails: { ...user.contactDetails, countryName: countries.get(user.contactDetails.country) // <-- get by key } })) users[0].id = 2 // <-- modify users users[0].contactDetails.phone = "00000" console.log(users, accounts) // <-- no changes to accountsusers[0].id时,帐户值未更新。

答案 1 :(得分:0)

我通常使用版本1,即传播算子两次。我还考虑考虑使用immer,它允许您对克隆的草稿进行可变更新,并为您合并。

const newUser = immer(user, draft => {
  draft.contactDetails.countryName = countries.find(
    c => c.id == user.contactDetails.country).countryName
  )
})

只需编辑所需的特定属性,然后沉浸式处理其余内容。

答案 2 :(得分:0)

克隆和合并MapsSection 就像数组一样,可以克隆地图:

var original = new Map([
  [1, 'one']
]);

var clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false. Useful for shallow comparison

答案 3 :(得分:0)

我个人喜欢使用版本1,因为它使您的代码少了很多冗余,而且更易于阅读。还将“用户”的所有属性传递给newUser。