почему map () мутирует оригинальные объекты во вложенном массиве? - PullRequest
1 голос
/ 29 мая 2019

Я пытаюсь создать новый массив объектов (usersData) с помощью map (), чтобы добавить новое свойство, которому присвоено значение из вторичного массива (стран). Во время моих тестов я заметил, что мой исходный массив объектов (пользователей) был изменен и к нему добавлено новое свойство (countryName). То же самое не происходило, когда я использую map для создания нового массива объектов для стран моего массива. Может ли кто-нибудь сказать мне, что вызывает это, и помочь мне понять, как избежать такого поведения?

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=> {
  const newUser = {};
  newUser.name = user.name;
  newUser.contactDetails = user.contactDetails;
  newUser.contactDetails.countryName = "UK";
  return newUser;
});

const countriesData = countries.map(country =>
  {
    const newCountry = {};
    newCountry.name = country.countryName;
    newCountry.continent = "Europe";
    return newCountry;
});
console.log(countries);  
console.log(countriesData); 
console.log(users);
console.log(usersData);

Я ожидаю, что элементы в массиве сохранят свою первоначальную структуру, но теперь для свойства contactDetails.countryName установлено значение "UK"

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

На каждой итерации users.map() user.contactDetails содержит ссылку на object, который вы храните в новом newUser.contactDetails. Так что оба будут ссылаться на один и тот же объект в памяти. В вашем конкретном случае вы можете решить эту проблему путем распространения user.contactDetails на новый объект (например, способ его клонирования). Но учтите, что это будет работать только для объекта глубиной 1-level. Вам следует искать deep-cloning, если ваша структура более сложная.

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 =>
{
    const newUser = {};
    newUser.name = user.name;
    newUser.contactDetails = {...user.contactDetails};
    newUser.contactDetails.countryName = "UK";
    return newUser;
});

const countriesData = countries.map(country =>
{
    const newCountry = {};
    newCountry.name = country.countryName;
    newCountry.continent = "Europe";
    return newCountry;
});

console.log("countries:", countries);  
console.log("countriesData:",countriesData); 
console.log("users:", users);
console.log("usersData:", usersData);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
1 голос
/ 29 мая 2019

Вы создаете новый массив. Это не значит, что вы тоже создаете новое все внутри массива.

Это:

newUser.contactDetails = user.contactDetails;

повторно использует объект user.contactDetails из исходного элемента массива, так что:

newUser.contactDetails.countryName = "UK";

изменяет объект, совместно используемый как новым, так и старым массивом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...