why a js map on an array modify the original array?

送分小仙女□ 提交于 2019-11-27 00:34:13

问题


I'm quite confuse by the behaviour of map().

I have an array of objects like this :

const products = [{
    ...,
    'productType' = 'premium',
    ...
}, ...]

and i'm passing this array to a function that should return the same array but with all product made free :

[{
    ...,
    'productType' = 'free',
    ...
}, ...]

The function is :

const freeProduct = function(products){
    return products.map(x => x.productType = "free")
}

Which returns the following array :

["free", "free", ...]

So i rewrote my function to be :

const freeProduct = function(products){
    return products.map(x => {x.productType = "free"; return x})
}

Which returns the array as intended.

BUT ! And that's the moment where i loose my mind, in both cases my original products array is modified.

Documentation around map() says that it shouldn't ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map ).

I even tried to create a clone of my array turning my function like this

const freeProduct = function(products){
    p = products.splice()
    return p.map(x => {x.productType = "free"; return x})
}

But i still get the same result (which starts to drive me crazy).

I would be very thankful to anyone who can explain me what i'm doing wrong !

Thank you


回答1:


You're not modifying your original array. You're modifying the objects in the array. If you want to avoid mutating the objects in your array, you can use Object.assign to create a new object with the original's properties plus any changes you need:

const freeProduct = function(products) {
  return products.map(x => {
    return Object.assign({}, x, {
      productType: "free"
    });
  });
};

2018 Edit:

In most browsers you can now use the object spread syntax instead of Object.assign to accomplish this:

const freeProduct = function(products) {
  return products.map(x => {
    return {
      ...x,
      productType: "free"
    };
  });
};



回答2:


To elaborate on SimpleJ's answer - if you were to === the two arrays, you would find that they would not be equal (not same address in memory) confirming that the mapped array is in fact a new array. The issue is that you're returning a new array, that is full of references to the SAME objects in the original array (it's not returning new object literals, it's returning references to the same object). So you need to be creating new objects that are copies of the old objects - ie, w/ the Object.assign example given by SimpleJ.




回答3:


Unfortunately, whether the spread operator nor the object assign operator does a deep copy.... You need to use a lodash like function to get areal copy not just a reference copy.

const util = require('util');
const print = (...val) => {
    console.log(util.inspect(val, false, null, false /* enable colors */));
};
const _ = require('lodash');

const obj1 =     {foo:{bar:[{foo:3}]}};
const obj2 =     {foo:{bar:[{foo:3}]}};

const array = [obj1, obj2];

const objAssignCopy = x => { return Object.assign({}, x, {})};
const spreadCopy = x => { return {...x}};
const _Copy = x => _.cloneDeep(x);

const map1 = array.map(objAssignCopy);
const map2 = array.map(spreadCopy);
const map3 = array.map(_Copy);

print('map1', map1);
print('map2', map2);
print('map3', map3);
obj2.foo.bar[0].foo = "foobar";
print('map1 after manipulation of obj2', map1); // value changed 
print('map2 after manipulation of obj2', map2); // value changed
print('map3 after manipulation of obj2', map3); // value hasn't changed!



回答4:


Array Iterator Array.map() creates the new array with the same number of elements or does not change the original array. There might be the problem with referencing if there is object inside the array as it copies the same reference, so, when you are making any changes on the property of the object it will change the original value of the element which holds the same reference.

The solution would be to copy the object, well, array.Splice() and [...array](spread Operator) would not help in this case, you can use JavaScript Utility library like Loadash or just use below mention code:

const newList = JSON.parse(JSON.stringify(orinalArr))


来源:https://stackoverflow.com/questions/35922429/why-a-js-map-on-an-array-modify-the-original-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!