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'] |
在上面的代码中,
您可以使用
1 | Object.assign([], array, {2: newItem}); |
您可以简单地设置一个新的数组,如下所示:
1 | const newItemArray = array.slice(); |
然后为要为其设置值的索引设置值。
1 | newItemArray[position] = newItem |
把它还给我。中间索引下的值将有
或者明显的替代方案是:
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); } |
一般来说,数组扩展操作为您生成的临时数组很少,但
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] |