Comment effectuer l'opération suivante sans muter le tableau:
let array = ['item1'];
console.log(array); // ['item1']
array[2] = 'item2'; // array is mutated
console.log(array); // ['item1', undefined, 'item2']
Dans le code ci-dessus, la variable array
est mutée. Comment puis-je effectuer la même opération sans muter la baie?
Vous pouvez utiliser Object.assign
:
Object.assign([], array, {2: newItem});
Vous pouvez simplement configurer un nouveau tableau en tant que tel:
const newItemArray = array.slice();
Et puis définissez la valeur de l'index pour lequel vous souhaitez avoir une valeur.
newItemArray[position] = newItem
et retournez-le. Les valeurs sous les index intermédiaires auront undefined
.
Ou l'alternative évidente serait:
Object.assign([], array, {<position_here>: newItem});
Eh bien, techniquement, ce ne serait pas remplacer car il n'y a pas d'élément à l'index que vous modifiez.
Regardez comment cela est géré dans Clojure, un langage construit autour d'implémentations canoniques pour des structures de données immuables.
(assoc [1] 2 3)
;; IndexOutOfBoundsException
Non seulement il échoue, mais il se bloque également. Ces structures de données sont conçues pour être aussi robustes que possible et lorsque vous rencontrez ce type d'erreurs, ce n'est généralement pas parce que vous avez découvert un cas Edge, mais plus probablement que vous utilisez la mauvaise structure de données.
Si vous vous retrouvez avec des tableaux clairsemés, envisagez plutôt de les modéliser avec des objets ou des cartes.
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}
Cependant, Map est une structure de données fondamentalement mutable, vous devez donc l'échanger contre une variante immuable avec une bibliothèque comme Immutable.js ou Mori .
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}
Bien sûr, il pourrait y avoir une bonne raison de vouloir utiliser les tableaux de JavaScript, alors voici une solution pour faire bonne mesure.
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
];
}
}
Voici comment j'aimerais le faire:
function update(array, newItem, atIndex) {
return array.map((item, index) => index === atIndex ? newItem : item);
}
En règle générale, l'opération de répartition sur tableau produit peu de tableaux temporaires pour vous, mais pas map
, ce qui peut être plus rapide. Vous pouvez également regarder cette discussion comme référence
var list1 = ['a','b','c'];
var list2 = list1.slice();
list2.splice(2, 0, "beta", "gamma");
console.log(list1);
console.log(list2);
C'est ce que tu veux?
Une autre façon pourrait être d'utiliser l'opérateur d'étalement avec une tranche comme
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]