admin管理员组

文章数量:1389863

I have constructor function that creates an object

I initialize an array called arr1, calling the function to make starting values.

I map over the arr1 to make arr2

But my original arr1 was changed. Why is this? Is it because I'm making async callbacks when initializing array and event-loops?

For reference, I was trying to take ideas from my previous post about canvas here for refactoring

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

I have constructor function that creates an object

I initialize an array called arr1, calling the function to make starting values.

I map over the arr1 to make arr2

But my original arr1 was changed. Why is this? Is it because I'm making async callbacks when initializing array and event-loops?

For reference, I was trying to take ideas from my previous post about canvas here for refactoring

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

Share Improve this question edited Nov 28, 2018 at 6:46 Nathan 6365 silver badges19 bronze badges asked Nov 28, 2018 at 5:29 Vincent TangVincent Tang 4,1486 gold badges52 silver badges71 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

In your map callback, you are directly altering properties of each object (b)...

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

What I suspect you're after is something more immutable like

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

This will create a new array with +2 values without modifying the original at all.

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

When you use map, you create a new array, but the array holds references to the objects. So when you alter the object b in the map, this is a reference to the the original points, not copies.

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

You could make a new point instead:

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

The reason for the behaviour you are seeing is .map() shallow copies the elements to a new array.

This line mutates x and y values in each element in the source array.

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

Instead you should only return new x and y values without mutating source array element like this

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

You could try the snippet below to create a new array with updated x and y values without mutating the source array elements.

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

Others have pointed out the issue with re-assigning the values of your arr in your map, but I wanted to point out the side effect that you observed with your first console log on arr1 also being updated. This is a limitation (some would argue it isn't) of with how the console works in most browsers. If you change a nested object (or array) before you open and observe the first object in the console log, it will be updated to the new values.

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

Notice how the "opened" arrays show the values at the state of when the console log was called, but if you expand the first console log with the nested array, it shows the updated values.

You can't run this code as a snippet and observe this side effect. It must be run in the browser so it can print to the console.

本文标签: Javascript Array Map unexpectedly changed original array valuesStack Overflow