Javascript .map () на скопированный массив - PullRequest
0 голосов
/ 29 декабря 2018

Я заметил, что вызов .map () без присвоения его переменной заставляет возвращать весь массив вместо только измененных свойств:

const employees = [{
    name: "John Doe",
    age: 41,
    occupation: "NYPD",
    killCount: 32,
  },
  {
    name: "Sarah Smith",
    age: 26,
    occupation: "LAPD",
    killCount: 12,
  },
  {
    name: "Robert Downey Jr.",
    age: 48,
    occupation: "Iron Man",
    killCount: 653,
  },

]

const workers = employees.concat();

workers.map(employee =>
  employee.occupation == "Iron Man" ? employee.occupation = "Philantropist" : employee.occupation
);

console.log(employees);

Но, учитывая, что .concat () создал копию исходного массива и присвоил ее рабочим, почему сотрудники также видоизменяются?

Ответы [ 4 ]

0 голосов
/ 29 декабря 2018

Анализ проблем

workers = workers.map(employee => 
  employee.occupation == "Iron Man" ? (employee.occupation = "Philantropist", employee) : (employee.occupation, employee)
);

[...] почему сотрудники также видоизменяются?

array.map() вызывает переданную функцию скаждый элемент из array и возвращает новый массив, содержащий значения, возвращаемые этой функцией.

Ваша функция просто возвращает результат выражения

element.baz = condition ? foo : bar;

, которое в зависимости отусловие,

  • оценивает foo или bar
  • , присваивает этот результат baz и
  • возвращает этот результат

Далее (expression1, expression2) оценит оба выражения и вернет expression2 (см. оператор запятой ).

Таким образом, хотя вы возвращаете employee в обоих случаях, вы изменяетеисходный объект с левым выражением (выражение 1).

Возможное решение

Возможно, вы захотите создать новый объект, используя Object.assign()

array.map((employee) => Object.assign({ }, employee))

вместо использования этого array.concat() "трюка".Используя это сопоставление, вы создаете не только новый массив, но и новые объекты с их скопированными атрибутами.Хотя это не будет «глубокой копией» вложенных объектов, таких как { foo: { ... } } - объект, доступный через свойство foo, все равно будет той же ссылкой, что и оригинал.В таких случаях вы можете захотеть взглянуть на модули глубокого копирования, упомянутые в других ответах.

0 голосов
/ 29 декабря 2018

Ссылки на массив изменяются, но скопированный массив все еще ссылается на исходные объекты в исходном массивеТаким образом, любое изменение объектов в массиве отражается во всех копиях массива.Если вы не сделаете глубокую копию массива, есть вероятность, что некоторые изменения во внутренних объектах будут отражены в каждой копии

В чем разница между глубокой копией и мелкой копией?

Глубокие копии могут быть сделаны несколькими способами.В этом посте конкретно обсуждается, что: Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript?

0 голосов
/ 29 декабря 2018

map создает новый массив из значений, возвращаемых из обратного вызова, который можно легко использовать для клонирования объектов в массиве:

 const workers = employees.map(employee => ({
     ...employee, // take everything from employee
     occupation: employee.ocupation == "Iron Man" ? "Philantropist" : employee.occupation
 }));

Или вы можете глубоко клонировать массив, затеммутировать его с помощью простого for:

 const workers = JSON.parse(JSON.stringify(workers));
 for(const worker of workers)
   if(worker.ocupation == "Iron Man")
    worker.ocupation = "Philantropist";
0 голосов
/ 29 декабря 2018

Это происходит потому, что на ваши объекты в массиве все еще ссылаются те же указатели.(ваш массив все еще ссылается на те же объекты в памяти).Кроме того, Array.prototype.map() всегда возвращает массив, и его результат должен быть присвоен переменной, поскольку он не выполняет сопоставление на месте .Поскольку вы изменяете свойства объекта в вашем методе map, вам следует рассмотреть возможность использования вместо него .forEach(), чтобы изменить свойства объекта в скопированном массиве сотрудников.Чтобы сделать копию массива сотрудников, вы можете использовать следующее:

const workers = JSON.parse(JSON.stringify(employees));

См. Пример ниже:

const employees = [
  {
    name: "John Doe",
    age: 41,
    occupation: "NYPD",
    killCount: 32,
  },
  {
    name: "Sarah Smith",
    age: 26,
    occupation: "LAPD",
    killCount: 12,
  },
  {
    name: "Robert Downey Jr.",
    age: 48,
    occupation: "Iron Man",
    killCount: 653,
  },

]


const workers = JSON.parse(JSON.stringify(employees));
workers.forEach(emp => {
  if(emp.occupation == "Iron Man") emp.occupation = "Philantropist";
});

console.log("--Employees--")
console.log(employees);
console.log("\n--Workers--");
console.log(workers);
  • Примечание. Если у ваших данных есть какие-либо методы, вам необходимо использовать другой метод для глубокого копирования
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...