Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Wzorce niemutowalności danych

W laboratoriach Parku Jurajskiego obowiązuje surowa zasada - nigdy nie modyfikujesz oryginalnej próbki DNA. Każda zmiana tworzy nową kopię. To samo podejście stosujemy w programowaniu funkcyjnym z danymi - oryginalne struktury pozostają nienaruszone, a każda modyfikacja tworzy nowy obiekt.

Spread operator - kopiowanie i rozszerzanie

Operator spread (

...
) to podstawowe narzędzie do tworzenia niemutowalnych kopii obiektów i tablic:

1// Kopiowanie obiektu z modyfikacja
2const dinosaur = { name: 'Rex', health: 100, zone: 'A' };
3const movedDino = { ...dinosaur, zone: 'B' };
4// dinosaur: { name: 'Rex', health: 100, zone: 'A' } - niezmieniony
5// movedDino: { name: 'Rex', health: 100, zone: 'B' } - nowy obiekt
6
7// Kopiowanie tablicy z dodaniem elementu
8const zones = ['A', 'B', 'C'];
9const extendedZones = [...zones, 'D'];
10// zones: ['A', 'B', 'C'] - niezmieniona
11// extendedZones: ['A', 'B', 'C', 'D']
12
13// Usuwanie elementu z tablicy (bez mutacji)
14const dinosaurs = ['Rex', 'Blue', 'Brachio', 'Stego'];
15const withoutBlue = dinosaurs.filter((d) => d !== 'Blue');
16// dinosaurs: ['Rex', 'Blue', 'Brachio', 'Stego'] - niezmieniona
17// withoutBlue: ['Rex', 'Brachio', 'Stego']

Zagnieżdżone obiekty - głęboka niemutowalność

Spread operator tworzy płytką kopię - zagnieżdżone obiekty nadal są współdzielone! Musisz spreadować na każdym poziomie:

1const park = {
2  name: 'Jurassic Park',
3  zones: {
4    A: { dinosaurs: ['Rex'], voltage: 10000 },
5    B: { dinosaurs: ['Brachio'], voltage: 5000 },
6  },
7};
8
9// ZLE - plytka kopia, zones jest wspoldzielone
10const badCopy = { ...park };
11badCopy.zones.A.voltage = 0; // ZMIENIA tez oryginal!
12
13// DOBRZE - gleboka kopia na kazdym poziomie
14const updatedPark = {
15  ...park,
16  zones: {
17    ...park.zones,
18    A: {
19      ...park.zones.A,
20      voltage: 15000,
21    },
22  },
23};
24// park.zones.A.voltage: 10000 (niezmieniony)
25// updatedPark.zones.A.voltage: 15000 (nowy obiekt)

Object.freeze() - zamrażanie obiektów

Object.freeze()
zapobiega modyfikacji obiektu w runtime. Próba zmiany jest po cichu ignorowana (lub rzuca błąd w strict mode):

1const CONFIG = Object.freeze({
2  maxDinosaurs: 100,
3  maxVoltage: 50000,
4  alertThreshold: 3,
5});
6
7CONFIG.maxDinosaurs = 200; // Ignorowane! (lub Error w strict mode)
8console.log(CONFIG.maxDinosaurs); // nadal 100
9
10// UWAGA: freeze jest plytki!
11const deepConfig = Object.freeze({
12  zones: { A: { limit: 10 } },
13});
14deepConfig.zones.A.limit = 999; // TO ZADZIALA - freeze jest plytki

structuredClone() - głębokie kopiowanie

structuredClone()
tworzy głęboką kopię obiektu - wszystkie zagnieżdżone struktury są niezależne:

1const original = {
2  name: 'Jurassic Park',
3  zones: [
4    { id: 'A', dinosaurs: [{ name: 'Rex', health: 100 }] },
5    { id: 'B', dinosaurs: [{ name: 'Blue', health: 95 }] },
6  ],
7};
8
9const deepCopy = structuredClone(original);
10deepCopy.zones[0].dinosaurs[0].health = 50;
11
12console.log(original.zones[0].dinosaurs[0].health); // 100 (niezmieniony!)
13console.log(deepCopy.zones[0].dinosaurs[0].health);  // 50 (niezalezna kopia)

Niemutowalne aktualizacje tablic

Pełny zestaw operacji na tablicach bez mutacji:

1const dinosaurs = [
2  { id: 1, name: 'Rex', health: 100 },
3  { id: 2, name: 'Blue', health: 95 },
4  { id: 3, name: 'Brachio', health: 88 },
5];
6
7// Dodawanie
8const added = [...dinosaurs, { id: 4, name: 'Stego', health: 100 }];
9
10// Usuwanie
11const removed = dinosaurs.filter((d) => d.id !== 2);
12
13// Aktualizacja
14const updated = dinosaurs.map((d) =>
15  d.id === 1 ? { ...d, health: 80 } : d
16);
17
18// Sortowanie (bez mutacji - tworzymy kopie przed sort)
19const sorted = [...dinosaurs].sort((a, b) => a.health - b.health);
Przejdź do CodeWorlds