Js Array.prototype.map()碰巧是可变的吗?

时间:2016-01-11 08:04:19

标签: javascript arrays mapping immutability mutable

initial purpose创建新数组时,为什么map方法会改变原始数组?

我有一个对象数组,我将其传递给一个纯函数,该函数依次映射给定数组并返回一个新数组。然后我注意到原始数组也被更改了。我理解Js中的Object通过引用传递的概念,但是仍然无法抓住为什么map的实现会改变原始数组,有点打败目的IMO。

var initialArray = [ { name: 'one' }, { name: 'two' }, { name: 'three'} ];

function doSomething(array) {

  // lodash
  // return _.map(array, (item) => _.assign(item, {isSelected: true}));  

  // vanilla
  return array.map(function(item) {
    item['isSelected'] = true;
    return item
  });

}

var changedArray = doSomething(initialArray);

console.log('initialArray', initialArray); // [{ name: 'one', isSelected: true }, ...]
console.log('changedArray', changedArray); // [{ name: 'one', isSelected: true }, ...]
console.log(initialArray === changedArray); // false

首先我想了解为什么会这样?

Second Id喜欢了解如何在不更改原始数组的情况下映射数组? (即每次._cloneDeep感觉错误之前都要做map

提前致谢!

修改

好的,据我所知,这就是事情。我想我可能因某种原因有更高的期望,但是在Js中可以解释,所以至少存在一定的一致性。

我可以想到用新成员创建新数组的最优雅的解决方案是

return _.map(array, (item) => _.assign({}, ...item, {isSelected: true}));   

5 个答案:

答案 0 :(得分:8)

.map将创建一个新数组,但仍会引用数组中的对象。

所以当您在object item内部.map函数中进行更改时,它会引用输入数组中的原始对象。

修复它的一种方法是在修改每个对象之前克隆它们

var initialArray = [ { name: 'one' }, { name: 'two' }, { name: 'three'} ];

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

function doSomething(array) {

  // lodash
  // return _.map(array, (item) => _.assign(item, {isSelected: true}));  

  // vanilla
  return array.map(function(item) {
    var copy = clone(item);
    copy['isSelected'] = true;
    return copy;
  });

}

var changedArray = doSomething(initialArray);

console.log('initialArray', initialArray); // [{ name: 'one'}, ...]
console.log('changedArray', changedArray); // [{ name: 'one', isSelected: true }, ...]
console.log(initialArray === changedArray); // false

信用:克隆功能是从this post

复制的

答案 1 :(得分:2)

如果您只想解决 OP 的示例,那么您可以将 <html> <head> <meta charset="UTF-8"> <!-- This line prevents jumping fonts on a mobile device --> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"> <!-- JQUERY --> <script src="https://code.jquery.com/jquery-1.11.0.min.js"></script> <script src="https://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script> <!-- CSS FILES --> <link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/orderHistory.css"> </head> <body> <div id="orderHistory"> <label class="title">Order history (overflow)</label> <div id="orderHistoryContent" class="overflow"> <table> <tbody> <tr> <th>Action</th> <th>Market</th> <th>Coin</th> <th>DateTimeEntered</th> <th class="priceCell">Quantity</th> <th class="priceCell">Amount</th> <th class="order-target-price">Target price</th> <th class="order-limit-price">Limit price</th> <th class="priceCell">Price</th> <th>DateTimeExecuted</th> <th>Status</th> <th class="priceCell">Profit</th> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(251, 216, 255);">Buy</td> <td style="background-color: rgb(255, 255, 255);">USDT</td> <td style="background-color: rgb(173, 204, 255);">ETH</td> <td style="background-color: rgb(255, 227, 214);">2021-05-19 02:56:01</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">0.59904000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">2012.27120640</td> <td class="order-target-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">3359.160000</td> <td style="background-color: rgb(251, 255, 191);">2021-05-19 02:56:01</td> <td style="background-color: rgb(210, 255, 209);">Executed</td> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(229, 196, 146);">Sell</td> <td style="background-color: rgb(229, 229, 229);">USDT</td> <td style="background-color: rgb(198, 229, 173);">BTC</td> <td style="background-color: rgb(229, 204, 192);">2021-05-16 15:48:33</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">0.04112200</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">2014.25425280</td> <td class="order-target-price" style="background-color: rgb(229, 204, 192);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(229, 204, 192);">0.000000</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">48982.400000</td> <td style="background-color: rgb(225, 229, 171);">2021-05-16 15:48:34</td> <td style="background-color: rgb(189, 229, 188);">Executed</td> <td class="priceCell" rowspan="0" style="background-color: rgb(155, 237, 137);"> <b> +12.40$<br /> +0.62% </b> </td> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(251, 216, 255);">Buy</td> <td style="background-color: rgb(255, 255, 255);">USDT</td> <td style="background-color: rgb(220, 255, 193);">BTC</td> <td style="background-color: rgb(255, 227, 214);">2021-05-16 15:29:55</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">0.04116400</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">1999.96817068</td> <td class="order-target-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">48585.370000</td> <td style="background-color: rgb(251, 255, 191);">2021-05-16 15:29:56</td> <td style="background-color: rgb(210, 255, 209);">Executed</td> </tr> </tbody> </table> </div> <label class="title">Order history (word-break)</label> <div id="orderHistoryContent" class="word-break"> <table> <tbody> <tr> <th>Action</th> <th>Market</th> <th>Coin</th> <th>DateTimeEntered</th> <th class="priceCell">Quantity</th> <th class="priceCell">Amount</th> <th class="order-target-price">Target price</th> <th class="order-limit-price">Limit price</th> <th class="priceCell">Price</th> <th>DateTimeExecuted</th> <th>Status</th> <th class="priceCell">Profit</th> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(251, 216, 255);">Buy</td> <td style="background-color: rgb(255, 255, 255);">USDT</td> <td style="background-color: rgb(173, 204, 255);">ETH</td> <td style="background-color: rgb(255, 227, 214);">2021-05-19 02:56:01</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">0.59904000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">2012.27120640</td> <td class="order-target-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">3359.160000</td> <td style="background-color: rgb(251, 255, 191);">2021-05-19 02:56:01</td> <td style="background-color: rgb(210, 255, 209);">Executed</td> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(229, 196, 146);">Sell</td> <td style="background-color: rgb(229, 229, 229);">USDT</td> <td style="background-color: rgb(198, 229, 173);">BTC</td> <td style="background-color: rgb(229, 204, 192);">2021-05-16 15:48:33</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">0.04112200</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">2014.25425280</td> <td class="order-target-price" style="background-color: rgb(229, 204, 192);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(229, 204, 192);">0.000000</td> <td class="priceCell" style="background-color: rgb(225, 229, 171);">48982.400000</td> <td style="background-color: rgb(225, 229, 171);">2021-05-16 15:48:34</td> <td style="background-color: rgb(189, 229, 188);">Executed</td> <td class="priceCell" rowspan="0" style="background-color: rgb(155, 237, 137);"> <b> +12.40$<br /> +0.62% </b> </td> </tr> <tr style="border-style: solid; border-color: black; border-width: 1px;"> <td style="background-color: rgb(251, 216, 255);">Buy</td> <td style="background-color: rgb(255, 255, 255);">USDT</td> <td style="background-color: rgb(220, 255, 193);">BTC</td> <td style="background-color: rgb(255, 227, 214);">2021-05-16 15:29:55</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">0.04116400</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">1999.96817068</td> <td class="order-target-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="order-limit-price" style="background-color: rgb(255, 227, 214);">0.000000</td> <td class="priceCell" style="background-color: rgb(251, 255, 191);">48585.370000</td> <td style="background-color: rgb(251, 255, 191);">2021-05-16 15:29:56</td> <td style="background-color: rgb(210, 255, 209);">Executed</td> </tr> </tbody> </table> </div> </div> </body> </html> 对象扩展为从 item 返回的新对象。

Array.map()

注意:此解决方案不允许您在不使用扩展运算符的情况下取消引用任何嵌套在一级之外的对象。

有关 var initialArray = [ { name: 'one' }, { name: 'two' }, { name: 'three'} ]; function doSomething(array) { // lodash // return _.map(array, (item) => _.assign(item, {isSelected: true})); // vanilla return array.map(function(item) { return { ...item, isSelected: true } }); } var changedArray = doSomething(initialArray); console.log('initialArray', initialArray); // initialArray [ { name: 'one' }, { name: 'two' }, { name: 'three' } ]  console.log('changedArray', changedArray); // changedArray [ { name: 'one', isSelected: true }, { name: 'two', isSelected: true }, { name: 'three', isSelected: true } ] console.log(initialArray === changedArray); // false 运算符的更多信息,请参见 here

答案 2 :(得分:1)

修改通过引用map函数传递的对象,而不是获取映射的数组。 changedArrayinitialArray都包含相同的对象。

var initialArray = [ { name: 'one' }, { name: 'two' }, { name: 'three'} ];
var initialArray2 = [ { name: 'one' }, { name: 'two' }, { name: 'three'} ];

function doSomething(array) {
  // vanilla
  return array.map(function(item) {
    item['isSelected'] = true;
    return item
  });

}

function doSomethingElse(array){
  return array.map(function( item ){
    // return a new object don't change the initial one
    return { name: item.name, isSelected: true };
  });
}

var changedArray = doSomething(initialArray),
    differentObjectsInArray = doSomethingElse( initialArray2 );

console.assert( initialArray !== changedArray, 'both arrays are different' );
console.assert( initialArray[0] !== changedArray[0], 'both arrays are referencing different objects' );
console.assert( initialArray2[0] !== differentObjectsInArray[0], 'both arrays are referencing different objects' );
console.log('initialArray', initialArray );
console.log('initialArray2', initialArray2 );
console.log('differentObjectsInArray', differentObjectsInArray );
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

答案 3 :(得分:1)

使用ES6:

let newArray = [...oldArray].map(doStuff);

答案 4 :(得分:0)

Prepared statement