JavaScript 数组映射 (Array Map) 意外改变了原始数组的值

3
我有一个构造函数,可以创建一个对象。
我初始化了一个名为arr1的数组,并调用该函数来设置起始值。
我映射arr1以创建arr2
但是我的原始arr1被更改了。这是为什么?是因为我在初始化数组和事件循环时进行了异步回调吗?
供参考,我试图从我之前关于canvas的帖子(链接)中获取一些想法进行重构。

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个回答

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


2
当你使用map时,你创建了一个新的数组,但是这个数组保存的是指向对象的引用。所以当你在map中修改对象b时,这其实是原始点的引用,而不是副本。请保留html标签。

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


2

其他人已经指出了在 map 中重新分配 arr 值的问题,但是我想指出你在第一个 console log 上观察到的副作用也被更新的 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

注意,“opened”数组显示的是控制台日志调用时的状态,但如果您展开嵌套数组的第一个控制台日志,则会显示更新后的值。

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


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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接