关于javascript:在数组的特定位置替换元素而不改变它

Replace element at specific position in an array without mutating it

如何在不改变数组的情况下完成以下操作:

1
2
3
4
let array = ['item1'];
console.log(array); // ['item1']
array[2] = 'item2'; // array is mutated
console.log(array); // ['item1', undefined, 'item2']

在上面的代码中,array变量是可变的。如何在不改变数组的情况下执行相同的操作?


您可以使用Object.assign

1
Object.assign([], array, {2: newItem});


您可以简单地设置一个新的数组,如下所示:

1
const newItemArray = array.slice();

然后为要为其设置值的索引设置值。

1
newItemArray[position] = newItem

把它还给我。中间索引下的值将有undefined

或者明显的替代方案是:

1
Object.assign([], array, {<position_here>: newItem});


从技术上讲,这不会被取代,因为索引中没有你要更改的项目。

看看它是如何在Clojure语言中处理的,Clojure语言是围绕不可变数据结构的规范实现构建的。

1
2
(assoc [1] 2 3)
;; IndexOutOfBoundsException

它不仅失败了,而且也崩溃了。这些数据结构被设计成尽可能强大,当您遇到这些错误时,通常并不是因为您发现了一个边缘情况,而是更可能使用了错误的数据结构。

如果您以稀疏数组结束,那么考虑用对象或映射来建模它们。

1
2
3
4
5
6
7
let items = { 0: 1 };
{ ...items, 2: 3 };
// => { 0: 1, 2: 3 }

let items = new Map([ [0, 1] ]);
items(2, 3);
// => Map {0 => 1, 2 => 3}

然而,map是一个基本上可变的数据结构,所以您需要将它换成一个不可变的变量,并使用一个库(如immutable.js或mori)。

1
2
3
4
5
6
7
let items = Immutable.Map([ [0, 2] ]);
items.set(2, 3);
// => Immutable.Map {0 => 1, 2 => 3}

let items = mori.hashMap();
mori.assoc(items, 2, 3);
// => mori.hashMap {0 => 1, 2 => 3}

当然,可能有一个非常好的理由想要使用javascript的数组,所以这里有一个很好的度量方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function set(arr, index, val) {
  if(index < arr.length) {
    return [
      ...arr.slice(0, position),
      val,
      ...arr.slice(position + 1)
    ];
  } else {
    return [
      ...arr,
      ...Array(index - arr.length),
      val
    ];
  }
}

快车道

1
2
3
4
5
function replaceAt(array, index, value) {
  const ret = array.slice(0);
  ret[index] = value;
  return ret;
}

查看jspef(感谢@bess)

相关员额:

  • javascript复制数组的最快方法-切片vs for循环
  • https://github.com/lodash/lodash/issues/2053问题注释-188776090


我想这样做:

1
2
3
function update(array, newItem, atIndex) {
    return array.map((item, index) => index === atIndex ? newItem : item);
}

一般来说,数组扩展操作为您生成的临时数组很少,但map不会,因此可以更快。您也可以将此讨论视为参考


1
2
3
4
5
var list1 = ['a','b','c'];
var list2 = list1.slice();
list2.splice(2, 0,"beta","gamma");
console.log(list1);
console.log(list2);

这就是你想要的吗?


另一种方法是使用具有slice as的spread运算符

1
2
3
4
5
let newVal = 33, position = 3;
let arr = [1,2,3,4,5];
let newArr = [...arr.slice(0,position - 1), newVal, ...arr.slice(position)];
console.log(newArr); //logs [1, 2, 33, 4, 5]
console.log(arr); //logs [1, 2, 3, 4, 5]