Javascript 为什么数组上的js映射会修改原始数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35922429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
why a js map on an array modify the original array?
提问by Edwin Joassart
I'm quite confuse by the behaviour of map().
我对 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).
围绕 map() 的文档说它不应该(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
谢谢
回答by SimpleJ
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:
您没有修改原始数组。您正在修改数组中的对象。如果您想避免改变数组中的对象,您可以使用Object.assign
原始属性以及您需要的任何更改来创建一个新对象:
const freeProduct = function(products) {
return products.map(x => {
return Object.assign({}, x, {
productType: "free"
});
});
};
2018 Edit:
2018年编辑:
In most browsersyou can now use the object spread syntax instead of Object.assign
to accomplish this:
在大多数浏览器中,您现在可以使用对象扩展语法Object.assign
来完成此操作:
const freeProduct = function(products) {
return products.map(x => {
return {
...x,
productType: "free"
};
});
};
回答by Geoffrey Abdallah
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.
详细说明 SimpleJ 的答案 - 如果您要 === 两个数组,您会发现它们不会相等(内存中的地址不同)确认映射的数组实际上是一个新数组。问题是您要返回一个新数组,其中包含对原始数组中相同对象的引用(它不返回新的对象文字,而是返回对同一对象的引用)。因此,您需要创建作为旧对象副本的新对象 - 即,使用 SimpleJ 给出的 Object.assign 示例。
回答by Patrick W.
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.
不幸的是,无论是扩展运算符还是对象赋值运算符都进行了深度复制……您需要使用类似 lodash 的函数来获取区域副本,而不仅仅是引用副本。
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!
回答by Kushal Atreya
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.
Array Iterator Array.map() 使用相同数量的元素创建新数组或不更改原始数组。如果数组中有对象,则引用可能会出现问题,因为它复制了相同的引用,因此,当您对对象的属性进行任何更改时,它会更改保存相同引用的元素的原始值。
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 Loadashor just use below mention code:
该解决方案是将复制的对象,那么,array.Splice()
和[...array]
(传播运营商)会在这种情况下没有帮助,您可以使用JavaScript工具库像Loadash或以下提到的代码只是使用:
const newList = JSON.parse(JSON.stringify(orinalArr))