Javascript数组映射意外更改了原始数组值

时间:2018-11-28 05:29:29

标签: javascript arrays

我具有创建对象的构造函数

我初始化了一个名为arr1的数组,调用该函数以获取初始值。

我在arr1上绘制arr2

但是我原来的arr1被更改了。为什么是这样?是因为初始化数组和事件循环时正在进行异步回调吗?

作为参考,我试图从上一篇有关画布here的帖子中提取构想,以供重构

function point(x,y){
  return {x,y}
}

arr1 = [point(1,2), point(3,4)];
console.log(arr1, "arr1");

arr2 = arr1.map(b=>{
  b.x = b.x+2;
  b.y = b.y+2;
  return b;
})
console.log(arr1, "arr1");
console.log(arr2, "arr2");

enter image description here

4 个答案:

答案 0 :(得分:3)

在您的map回调中,您正在直接更改每个对象的属性(b)...

b.x = b.x+2;
b.y = b.y+2;

我怀疑你追求的是更不变的东西

const arr2 = arr1.map(({x, y}) => ({
  x: x + 2,
  y: y + 2
}))

这将创建一个具有+2值的新数组,而完全不修改原始数组。

function point(x,y){
  return {x,y}
}

const arr1 = [point(1,2), point(3,4)];
console.log('arr1', arr1);

const arr2 = arr1.map(({x, y}) => ({
  x: x + 2,
  y: y + 2
}))

console.info('arr1', arr1);
console.info('arr2', arr2);

答案 1 :(得分:2)

其他人指出了在地图中重新分配arr的值的问题,但是我想指出您在arr1上第一次控制台登录时观察到的副作用正在更新。这是控制台在大多数浏览器中的工作方式的局限性(有人会说并非如此)。如果您在打开嵌套对象(或数组)之前更改了嵌套对象(或数组),并观察到控制台日志中的第一个对象,它将被更新为新值。

function point(x,y){
  return {x,y}
}

arr1 = [point(1,2), point(3,4)];
console.log("arr1 closed", arr1);
console.log("arr1 opened:", arr1[0], arr1[1]);

arr1[0] = {x: 15, y:42};
console.log("arr1 closed", arr1);
console.log("arr1 opened:", arr1[0], arr1[1]);

jsFiddle

请注意“打开的”数组如何在调用控制台日志时显示状态值,但是如果您使用嵌套数组扩展第一个控制台日志,它将显示更新后的值。

您不能将此代码作为片段运行并观察到这种副作用。它必须在浏览器中运行,以便可以打印到控制台。

答案 2 :(得分:2)

使用map时,将创建一个新数组,但该数组保留对对象的引用。因此,当您更改地图中的对象b时,这是对原始点的引用,而不是副本。

function point(x,y){
  return {x,y}
}

arr1 = [point(1,2), point(3,4)];

arr2 = arr1.map((b, i)=>{
  // b IS on of the objects from arr1
  console.log(`b === arr1[${i}]`, b === arr1[i])
  b.x = b.x+2;
  b.y = b.y+2;
  return b;
})

您可以改成新的point

function point(x,y){
  return {x,y}
}

arr1 = [point(1,2), point(3,4)];
arr2 = arr1.map(({x, y}) => point(x + 2, y + 2))

console.log(arr1, "arr1")
console.log(arr2, "arr2")

答案 3 :(得分:2)

您看到此行为的原因是.map() 浅复制元素到新数组。

此行使源数组中每个元素的xy值发生变化。

arr2 = arr1.map(b=>{
  b.x = b.x+2;
  b.y = b.y+2;
  return b;
})

相反,您应该只返回新的xy值,而不用像这样修改源数组元素

arr2 = arr1.map(b => {
  return {
    x: b.x + 2,
    y: b.y + 2
  };
})

您可以尝试使用下面的代码片段创建一个具有更新的xy值的新数组,而无需更改源数组元素。

function point(x, y) {
  return { x, y }
}

arr1 = [point(1, 2), point(3, 4)];
console.log(arr1, "arr1");

arr2 = arr1.map(b => {
  return {
    x: b.x + 2,
    y: b.y + 2
  };
})
console.log(arr1, "arr1");
console.log(arr2, "arr2");