复制数组上的Javascript .map()

时间:2018-12-29 02:25:20

标签: javascript arrays function ecmascript-6

我注意到调用.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()创建了原始数组的副本并将其分配给worker,为什么雇员也会发生变异?

4 个答案:

答案 0 :(得分:1)

之所以会这样,是因为数组中的对象仍被相同的指针引用。 (您的数组仍引用内存中的相同对象)。另外,Array.prototype.map()总是返回一个数组,并且它的结果应该分配给一个变量,因为它不进行就地映射。在map方法中更改对象的属性时,应考虑改用.forEach(),以在复制的employees数组中修改对象的属性。要复制员工数组,可以使用以下命令:

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);

  • 注意:如果数据中包含任何方法,则需要使用另一种方法进行深度复制

答案 1 :(得分:1)

问题分析

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

[...]为什么员工也会发生变异?

{array.map()使用array中的每个元素调用传递的函数,并返回一个包含该函数返回的值的新数组。

您的函数只返回表达式的结果

element.baz = condition ? foo : bar;

根据情况,

  • 评估为foobar
  • 将该结果分配给baz
  • 返回结果

另外(expression1, expression2)将对两个表达式求值并返回expression2(请参见comma operator)。

因此,尽管在两种情况下均返回employee,但是您仍使用左表达式(表达式1)来修改原始对象。

可能的解决方案

您可能想使用Object.assign()

创建一个新对象
array.map((employee) => Object.assign({ }, employee))

代替使用该array.concat()“技巧”。使用该映射,您不仅可以创建一个新数组,还可以创建其属性已复制的新对象。尽管这不会“深度复制”嵌套的对象,例如{ foo: { ... } }-通过属性foo访问的对象仍然与原始对象相同。在这种情况下,您可能想看看其他答案中提到的深度复制模块。

答案 2 :(得分:0)

数组引用发生了变化,但是复制的数组仍然引用原始数组中的原始对象。因此,阵列中对象的任何更改都会反映在阵列的所有副本中。除非您对数组进行深拷贝,否则内部对象中的某些更改可能会在每个拷贝中反映出来

What is the difference between a deep copy and a shallow copy?

深拷贝可以用几种方法制作。这篇文章专门讨论了:What is the most efficient way to deep clone an object in JavaScript?

答案 3 :(得分:0)

import { highlight } from "../constants/Colours.ios"; 根据从回调返回的值构建一个新数组,可以轻松地使用它来克隆数组中的对象:

map

或者您可以深度克隆数组,然后使用简单的 const workers = employees.map(employee => ({ ...employee, // take everything from employee occupation: employee.ocupation == "Iron Man" ? "Philantropist" : employee.occupation })); 对其进行突变:

for