Temat 24 · 2 × 45 min
Referencje, kopiowanie i mutowalność
Dwa najczęstsze „niewytłumaczalne” błędy początkujących brzmią: „zmieniłem kopię, a zmienił się oryginał” i „mam const, a tablica się zmienia”. Oba wynikają z jednego faktu: zmienna w JavaScripcie nie jest pudełkiem z wartością w środku. Jest etykietą (karteczką) przyczepioną do wartości. Dla liczb i napisów to bez znaczenia, dla obiektów i tablic – zmienia wszystko. Ta lekcja daje ci model mentalny, który tłumaczy zachowanie =, const, parametrów funkcji, metod tablic i stanu w React.
Dwa rodzaje wartości
Wartości w JavaScripcie dzielą się na dwie grupy, które zachowują się przy przypisaniu zupełnie inaczej:
Prymityw jest niezmienny: 'abc'.toUpperCase() nie zmienia napisu, tylko tworzy nowy. Zmienna z prymitywem trzyma wartość bezpośrednio, więc let y = x tworzy niezależną kopię. Obiekt leży w pamięci osobno, a zmienna trzyma tylko referencję – „strzałkę” do niego. const b = a kopiuje strzałkę, nie obiekt. Od tej chwili a i b to dwie etykiety na tym samym przedmiocie.
Co wypisze ten kod?
const a = { punkty: 10 };
const b = a;
b.punkty = 99;
console.log(a.punkty);// prymitywy: niezależne kopie
let x = 5;
let y = x;
y = 7;
console.log(x, y); // 5 7
let imie = 'Ala';
let imie2 = imie;
imie2 += 'n';
console.log(imie, imie2); // Ala Alan
// obiekty: jedna rzecz, dwie etykiety
const a = { punkty: 10 };
const b = a;
b.punkty = 99;
console.log(a.punkty, b.punkty); // 99 99
console.log(a === b); // true – ta sama referencja
// tablice to też obiekty
const lista = ['mleko'];
const taSama = lista;
taSama.push('chleb');
console.log(lista); // ['mleko', 'chleb']Słowniczek: mutacja (mutation) to zmiana zawartości istniejącego obiektu (obj.x = 1, tab.push(…)). Przypisanie (zmienna = …) to przeniesienie etykiety na inną wartość. Przypisanie nigdy nie zmienia starego obiektu – tylko od niego „odczepia” zmienną.
let a = { x: 1 };
let b = a;
b = { x: 2 }; // PRZYPISANIE: b dostaje nową strzałkę do nowego obiektu
console.log(a.x); // 1 – stary obiekt nietknięty, a dalej na niego wskazuje
b.x = 3; // MUTACJA nowego obiektu
console.log(a.x); // 1 – a nie ma z nim nic wspólnego
console.log(a === b); // falseArgumenty funkcji: ta sama zasada
Funkcja dostaje kopię tego, co jest w zmiennej. Dla prymitywu to kopia wartości – funkcja nie może zmienić zmiennej z zewnątrz. Dla obiektu to kopia referencji – funkcja widzi ten sam obiekt i może go zmutować, ale przypisanie do parametru nie zmienia zmiennej na zewnątrz (parametr to tylko kolejna etykieta).
Co wypisze ten kod?
function dodaj(tab, n) {
tab.push(n);
n = 100;
}
const liczby = [1];
let wartosc = 2;
dodaj(liczby, wartosc);
console.log(liczby, wartosc);function zmien(obiekt, liczba) {
obiekt.imie = 'ZMIENIONE'; // mutacja – widoczna na zewnątrz
liczba = 0; // przypisanie – lokalne
obiekt = { imie: 'NOWY' }; // przypisanie – też lokalne! od tej chwili obiekt to inna etykieta
obiekt.imie = 'NOWY2'; // mutacja NOWEGO obiektu – oryginał tego nie widzi
}
const uczen = { imie: 'Ala' };
let wiek = 17;
zmien(uczen, wiek);
console.log(uczen.imie, wiek); // ZMIENIONE 17W praktyce: funkcja, która mutuje argument, jest zaskakująca dla czytelnika (wywołujesz oblicz(koszyk), a koszyk się zmienia). Lepszy zwyczaj: funkcja zwraca nowy obiekt, a oryginał zostawia w spokoju. Tego wymaga React i tak piszą współczesne biblioteki.
const nie znaczy „niezmienny”
const zabrania ponownego przypisania zmiennej: etykieta zostaje na tym samym przedmiocie na zawsze. Nie mówi nic o zawartości tego przedmiotu. const tab = [] z tab.push(1) to poprawny i codzienny kod. Zasada praktyczna z lekcji o zmiennych obowiązuje: domyślnie const, a let tylko, gdy etykieta ma być przenoszona (licznik, akumulator, przełącznik).
Która linia rzuci błąd?
const koszyk = ['mysz'];
koszyk.push('kabel'); // 1
koszyk[0] = 'klawiatura'; // 2
koszyk.length = 0; // 3
koszyk = []; // 4const ustawienia = { motyw: 'jasny' };
ustawienia.motyw = 'ciemny'; // OK – mutacja
ustawienia.jezyk = 'pl'; // OK – nowa właściwość
console.log(ustawienia);
const oceny = [4, 5];
oceny.push(3); // OK
console.log(oceny);
oceny = []; // TypeError: Assignment to constant variable.Object.freeze – gdy naprawdę chcesz zablokować zawartość
Object.freeze(obj) zamraża obiekt: nie da się dodać, usunąć ani zmienić jego właściwości. Przydaje się do stałych konfiguracyjnych (cennik, lista statusów). Dwie rzeczy, o których trzeba wiedzieć:
- W zwykłym skrypcie (tryb nieścisły) próba zmiany zamrożonego obiektu po cichu nic nie robi. W modułach i klasach (tryb ścisły) rzuca
TypeError. Sprawdzisz zamrożenie przezObject.isFrozen. freezejest płytkie: zagnieżdżone obiekty i tablice pozostają zmienne.
const CENNIK = Object.freeze({
bilet: 26,
ulgowy: 18,
dodatki: ['popcorn', 'napój'],
});
CENNIK.bilet = 1; // w tym trybie: ignorowane bez błędu (w module byłby TypeError)
CENNIK.nowy = 100; // ignorowane
delete CENNIK.ulgowy; // ignorowane
console.log(CENNIK.bilet, CENNIK.nowy, CENNIK.ulgowy, Object.isFrozen(CENNIK));
CENNIK.dodatki.push('nachosy'); // zagnieżdżona tablica NIE jest zamrożona
console.log(CENNIK.dodatki);Porównywanie obiektów
=== dla obiektów porównuje referencje, nie zawartość: pyta „czy to ten sam przedmiot?”, a nie „czy wyglądają tak samo?”. Dlatego dwa literały o identycznej treści nigdy nie są równe, a tablica jest równa tylko samej sobie. Do porównania zawartości piszesz własną funkcję (lub bibliotekę, np. lodash.isEqual). Sztuczka JSON.stringify(a) === JSON.stringify(b) działa dla prostych danych, ale zależy od kolejności właściwości i gubi undefined.
console.log({} === {}); // false – dwa różne obiekty
console.log([1, 2] === [1, 2]); // false
console.log('ab' === 'ab'); // true – prymitywy porównywane po wartości
const a = { x: 1 };
const b = a;
console.log(a === b); // true – ta sama referencja
// porównanie zawartości (płaskie obiekty)
function taSamaZawartosc(o1, o2) {
const k1 = Object.keys(o1);
const k2 = Object.keys(o2);
return k1.length === k2.length && k1.every((k) => o1[k] === o2[k]);
}
console.log(taSamaZawartosc({ x: 1, y: 2 }, { y: 2, x: 1 })); // true
console.log(taSamaZawartosc({ x: 1 }, { x: 1, y: 2 })); // false
// sztuczka z JSON – uwaga na kolejność kluczy
console.log(JSON.stringify({ x: 1, y: 2 }) === JSON.stringify({ y: 2, x: 1 })); // false!Ta sama zasada obowiązuje przy includes, indexOf i Set: [{ id: 1 }].includes({ id: 1 }) to false. Dla obiektów szukaj przez find((o) => o.id === 1).
Metody, które mutują, i te, które nie
Z lekcji o metodach tablic pamiętasz podział. Teraz wiesz, dlaczego jest ważny: metoda mutująca zmienia obiekt widoczny przez wszystkie etykiety, które na niego wskazują – także przez te w innych częściach programu, o których nie myślisz.
| Mutują oryginał | Zwracają nową wartość, oryginał nietknięty |
|---|---|
push, pop, shift, unshift, splice | slice, concat, [...tab] |
sort, reverse, fill, copyWithin | toSorted, toReversed, toSpliced, with |
obj.x = …, delete obj.x, Object.assign(obj, …) | map, filter, flat, { ...obj }, structuredClone |
el.classList.add, el.textContent = … (DOM) | wszystkie metody napisów (toUpperCase, slice, replace…) |
const wyniki = [12, 45, 7];
const ranking = { oryginal: wyniki, posortowane: wyniki.sort((a, b) => b - a) };
// sort zmutował tablicę, na którą wskazują oba pola – „oryginał” też jest posortowany
console.log(ranking.oryginal, ranking.posortowane, ranking.oryginal === ranking.posortowane);
// poprawnie: toSorted (lub [...wyniki].sort) tworzy nową tablicę
const dane = [12, 45, 7];
const bezMutacji = { oryginal: dane, posortowane: dane.toSorted((a, b) => b - a) };
console.log(bezMutacji.oryginal, bezMutacji.posortowane);Kopia płytka
Kopia płytka (shallow copy) tworzy nowy obiekt zewnętrzny i przepisuje do niego właściwości o jeden poziom. Prymitywy są przy tym kopiowane, ale zagnieżdżone obiekty i tablice – tylko jako referencje. Nowy obiekt i stary mają więc wspólne wnętrze.
Sposoby na kopię płytką: spread [...tab] / { ...obj } (najczęstszy), tab.slice(), Array.from(tab), Object.assign({}, obj).
Co wypisze ten kod?
const uczen = { imie: 'Ala', oceny: [5, 4] };
const kopia = { ...uczen };
kopia.imie = 'Ola';
kopia.oceny.push(3);
console.log(uczen.imie, uczen.oceny.length);const uczen = { imie: 'Ala', oceny: [5, 4] };
const kopia = { ...uczen };
console.log(kopia === uczen); // false – nowy obiekt zewnętrzny
console.log(kopia.oceny === uczen.oceny); // true – wspólna tablica!
kopia.imie = 'Ola';
kopia.oceny.push(3);
console.log(uczen.imie, uczen.oceny); // Ala [5, 4, 3]
// jak zmienić zagnieżdżenie bez dotykania oryginału? Skopiuj też wnętrze:
const bezpieczna = { ...uczen, oceny: [...uczen.oceny, 6] };
console.log(uczen.oceny, bezpieczna.oceny); // [5, 4, 3] [5, 4, 3, 6]Kopia płytka wystarcza, gdy dane są płaskie (same prymitywy) lub gdy zmieniasz tylko pierwszy poziom. To najczęstszy przypadek w codziennym kodzie – wzorzec { ...stan, pole: nowaWartosc }.
Kopia głęboka: structuredClone
Gdy potrzebujesz pełnej, niezależnej kopii z całym zagnieżdżeniem (historia „cofnij”, snapshot formularza, dane do eksperymentów), użyj wbudowanej funkcji structuredClone(wartosc). Jest dostępna we wszystkich przeglądarkach od 2022 r. i w Node od wersji 17. Kopiuje zagnieżdżone obiekty, tablice, Date, Map, Set, a nawet struktury cykliczne.
Ograniczenie: nie kopiuje funkcji – obiekt z metodą rzuci DataCloneError. Elementy DOM też nie przejdą. Dla czystych danych (takich, jakie przechodzą przez JSON) jest idealna.
const zamowienie = {
nr: 1,
klient: { imie: 'Ewa', adres: { miasto: 'Łódź' } },
pozycje: [{ nazwa: 'Kabel', ilosc: 2 }],
data: new Date('2026-10-20'),
};
const kopia = structuredClone(zamowienie);
kopia.klient.adres.miasto = 'Gdańsk';
kopia.pozycje[0].ilosc = 99;
kopia.pozycje.push({ nazwa: 'Mysz', ilosc: 1 });
console.log(zamowienie.klient.adres.miasto, zamowienie.pozycje.length, zamowienie.pozycje[0].ilosc); // Łódź 1 2
console.log(kopia.klient.adres.miasto, kopia.pozycje.length); // Gdańsk 2
console.log(kopia.data.getFullYear(), kopia.data !== zamowienie.data); // 2026 true – data skopiowana jako Date, nie napisconst zMetoda = { nazwa: 'x', pokaz() { return this.nazwa; } };
structuredClone(zMetoda); // DataCloneError: pokaz() { … } could not be clonedDlaczego to ważne: stan aplikacji i „cofnij”
Najczęstszy praktyczny skutek: historia zmian. Jeśli do historii wkładasz referencję do aktualnego stanu, a potem ten stan mutujesz, wszystkie „zapisane” wersje zmieniają się razem z nim – historia pokazuje wszędzie to samo. Rozwiązanie: wkładaj kopie albo nigdy nie mutuj – twórz nowy stan przy każdej zmianie. Dokładnie tak działa React: setStan({ ...stan, pole: x }), a zmutowany obiekt o tej samej referencji jest uznawany za „bez zmian” i widok się nie odświeża.
// WERSJA ZEPSUTA: historia trzyma referencje do jednej tablicy
let lista = [];
const historia = [];
function dodaj(produkt) {
historia.push(lista); // zapisujemy „stan przed” – ale to ta sama tablica…
lista.push(produkt); // …którą zaraz mutujemy
}
dodaj('mleko');
dodaj('chleb');
console.log(historia.map((h) => h.join(','))); // obie wersje identyczne – historia bezużyteczna
// WERSJA POPRAWNA: nowy stan zamiast mutacji
let lista2 = [];
const historia2 = [];
function dodaj2(produkt) {
historia2.push(lista2); // stara tablica zostaje nietknięta…
lista2 = [...lista2, produkt]; // …bo tworzymy nową
}
dodaj2('mleko');
dodaj2('chleb');
console.log(historia2.map((h) => h.join(',') || '(pusto)'), lista2);Ściąga
| Zapis | Co robi | Uwaga |
|---|---|---|
let y = x (prymityw) | kopia wartości | niezależne |
const b = a (obiekt) | kopia referencji | ten sam obiekt, a === b |
b.x = 1 | mutacja wspólnego obiektu | widoczna przez a |
b = { x: 1 } | przypisanie – nowa strzałka | a bez zmian |
f(obj) + obj.x = 1 w f | mutacja widoczna na zewnątrz | parametr to kolejna etykieta |
f(obj) + obj = {} w f | lokalne przypisanie | na zewnątrz bez zmian |
const t = []; t.push(1) | OK – const chroni etykietę | t = [] → TypeError |
Object.freeze(obj) | blokuje zmiany pierwszego poziomu | płytkie; w trybie nieścisłym cicho ignoruje |
Object.isFrozen(obj) | czy zamrożony | true/false |
a === b (obiekty) | ta sama referencja? | {} === {} → false |
[...tab], { ...obj } | kopia płytka | wnętrze wspólne |
tab.slice(), Object.assign({}, obj) | kopia płytka (starszy zapis) | jak wyżej |
{ ...obj, pole: nowa } | kopia ze zmianą jednego pola | wzorzec React |
structuredClone(x) | kopia głęboka | bez funkcji i elementów DOM |
JSON.parse(JSON.stringify(x)) | kopia głęboka (stara) | gubi Date, undefined, NaN |
toSorted, with, map, filter | nowa tablica | bezpieczne dla historii |
sort, splice, push | mutują | zmiana widoczna wszędzie |
Zadania
Przewidź, zanim uruchomisz
Dla każdego z sześciu fragmentów zapisz, co wypisze konsola, i narysuj strzałki (zmienna → wartość) po ostatniej linii. Dopiero potem uruchom rozwiązanie.
// A
let a = 'kot'; let b = a; b = 'pies'; console.log(a);
// B
const o1 = { n: 1 }; const o2 = o1; o2.n = 2; console.log(o1.n);
// C
const t1 = [1]; const t2 = t1; t2 = [2]; console.log(t1);
// D
const t3 = [1]; let t4 = t3; t4 = [2]; console.log(t3, t4);
// E
const k = { a: 1 }; const m = { ...k }; m.a = 5; console.log(k.a);
// F
const z = { lista: [1] }; const w = { ...z }; w.lista.push(2); console.log(z.lista);Pokaż rozwiązanie
// A: prymitywy – b to niezależna kopia; a zostaje
let a = 'kot'; let b = a; b = 'pies';
console.log('A:', a); // kot
// B: o2 wskazuje ten sam obiekt – mutacja widoczna przez o1
const o1 = { n: 1 }; const o2 = o1; o2.n = 2;
console.log('B:', o1.n); // 2
// C: TypeError – t2 jest const, nie można przenieść etykiety (sprawdzamy w try)
try {
const t1 = [1]; const t2 = t1; t2 = [2];
console.log('C:', t1);
} catch (e) {
console.log('C:', e.name); // TypeError
}
// D: t4 to let – przypisanie przenosi etykietę na nową tablicę; t3 bez zmian
const t3 = [1]; let t4 = t3; t4 = [2];
console.log('D:', t3, t4); // [1] [2]
// E: spread kopiuje płytko; a to prymityw, więc kopia niezależna
const k = { a: 1 }; const m = { ...k }; m.a = 5;
console.log('E:', k.a); // 1
// F: spread kopiuje tylko referencję do tablicy lista – jest wspólna
const z = { lista: [1] }; const w = { ...z }; w.lista.push(2);
console.log('F:', z.lista); // [1, 2]Funkcja, która nie psuje danych
Poniższa funkcja ma zwrócić koszyk z cenami po rabacie, ale przy okazji zmienia oryginalny koszyk – po jej wywołaniu koszyk[0].cena nie jest już 100. Przepisz ją tak, żeby oryginał pozostał nietknięty, a wynik był nowym koszykiem. Nie używaj structuredClone – wystarczą map i spread.
const koszyk = [{ nazwa: 'Słuchawki', cena: 100 }, { nazwa: 'Etui', cena: 40 }];
function zRabatem(koszyk, procent) {
for (const p of koszyk) {
p.cena = p.cena * (1 - procent / 100);
}
return koszyk;
}Pokaż rozwiązanie
const koszyk = [{ nazwa: 'Słuchawki', cena: 100 }, { nazwa: 'Etui', cena: 40 }];
// map tworzy nową tablicę, spread tworzy nowy obiekt dla każdej pozycji –
// żaden oryginalny obiekt nie jest mutowany
function zRabatem(koszyk, procent) {
return koszyk.map((p) => ({ ...p, cena: p.cena * (1 - procent / 100) }));
}
const przeceniony = zRabatem(koszyk, 25);
console.log(przeceniony.map((p) => p.cena)); // [75, 30]
console.log(koszyk.map((p) => p.cena)); // [100, 40] – oryginał bez zmian
console.log(koszyk[0] === przeceniony[0]); // false – osobne obiektyUwaga: sam [...koszyk] by nie wystarczył – skopiowałby tablicę, ale obiekty w niej byłyby wspólne, a p.cena = … dalej mutowałoby oryginały.
Lista zakupów z historią „cofnij”
Edytor listy zakupów ma przyciski „Dodaj”, „Usuń ostatni” i „Cofnij”. Wersja poniżej jest zepsuta: po kilku operacjach „Cofnij” nie przywraca poprzedniego stanu, bo historia trzyma referencje do jednej, mutowanej tablicy. Napraw ją, nie zmieniając HTML. Wskazówka: albo zapisuj kopię stanu do historii, albo przestań mutować i twórz nową tablicę przy każdej zmianie.
let lista = [];
const historia = [];
function zapiszStan() { historia.push(lista); }
function dodaj(nazwa) { zapiszStan(); lista.push(nazwa); renderuj(); }
function usunOstatni() { zapiszStan(); lista.pop(); renderuj(); }
function cofnij() { if (historia.length) { lista = historia.pop(); renderuj(); } }Pokaż rozwiązanie
<input id="produkt" placeholder="np. mleko">
<button id="dodaj">Dodaj</button>
<button id="usun">Usuń ostatni</button>
<button id="cofnij">Cofnij</button>
<ul id="lista"></ul>
<p id="info"></p>let lista = [];
const historia = [];
function zapiszStan() {
historia.push(lista); // bezpieczne, bo poniżej NIGDY nie mutujemy tablicy lista
}
function dodaj(nazwa) {
zapiszStan();
lista = [...lista, nazwa]; // nowa tablica zamiast push
renderuj();
}
function usunOstatni() {
if (lista.length === 0) return;
zapiszStan();
lista = lista.slice(0, -1); // nowa tablica zamiast pop
renderuj();
}
function cofnij() {
if (historia.length === 0) return;
lista = historia.pop(); // poprzednia tablica jest nietknięta – można do niej wrócić
renderuj();
}
function renderuj() {
document.getElementById('lista').innerHTML = lista.map((p) => `<li>${p}</li>`).join('');
document.getElementById('info').textContent = `Pozycji: ${lista.length}, kroków do cofnięcia: ${historia.length}`;
}
const pole = document.getElementById('produkt');
document.getElementById('dodaj').addEventListener('click', () => {
const nazwa = pole.value.trim();
if (!nazwa) return;
dodaj(nazwa);
pole.value = '';
pole.focus();
});
document.getElementById('usun').addEventListener('click', usunOstatni);
document.getElementById('cofnij').addEventListener('click', cofnij);
renderuj();Alternatywna naprawa z zachowaniem push/pop: w zapiszStan zapisuj kopię – historia.push([...lista]). Oba podejścia działają; wersja „bez mutacji” jest bliższa temu, jak pisze się stan w React.
Snapshot formularza i porównanie głębokie
Napisz dwie funkcje:
rowne(a, b)– rekurencyjne porównanie zawartości dwóch wartości: prymitywy przez===, tablice element po elemencie, obiekty klucz po kluczu (niezależnie od kolejności kluczy).rowne({ x: 1, y: [1, { z: 2 }] }, { y: [1, { z: 2 }], x: 1 })ma daćtrue.czyZmieniony(snapshot, aktualny)– zwracatrue, jeśli stan formularza różni się od zapisanej kopii. Pokaż na przykładzie, że snapshot zrobiony przezstructuredClonewykrywa zmianę w zagnieżdżonym polu, a snapshot zrobiony przez{ ...stan }nie wykrywa jej (bo porównuje obiekt z samym sobą).
Pokaż rozwiązanie
function rowne(a, b) {
if (a === b) return true; // ta sama referencja lub równe prymitywy
if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;
if (Array.isArray(a) !== Array.isArray(b)) return false;
const klucze = Object.keys(a);
if (klucze.length !== Object.keys(b).length) return false;
// każdy klucz z a musi istnieć w b i mieć równą (rekurencyjnie) wartość
return klucze.every((k) => Object.hasOwn(b, k) && rowne(a[k], b[k]));
}
console.log(rowne({ x: 1, y: [1, { z: 2 }] }, { y: [1, { z: 2 }], x: 1 })); // true
console.log(rowne([1, 2, 3], [1, 2, 4])); // false
console.log(rowne({ a: undefined }, {})); // false – różna liczba kluczy
const czyZmieniony = (snapshot, aktualny) => !rowne(snapshot, aktualny);
// stan formularza z zagnieżdżeniem
const stan = { imie: 'Ala', adres: { miasto: 'Łódź', kod: '90-001' } };
const snapshotGleboki = structuredClone(stan);
const snapshotPlytki = { ...stan };
stan.adres.miasto = 'Gdańsk'; // użytkownik zmienił zagnieżdżone pole
console.log('głęboki wykrywa zmianę:', czyZmieniony(snapshotGleboki, stan)); // true
console.log('płytki wykrywa zmianę:', czyZmieniony(snapshotPlytki, stan)); // false – snapshotPlytki.adres to ten sam obiektPłytki snapshot zawiódł, bo snapshotPlytki.adres === stan.adres – zmiana miasta „zmieniła” też snapshot. Do zapamiętywania stanu z zagnieżdżeniem zawsze używaj kopii głębokiej.
Test powtórkowy
Test powtórkowy
Referencje, kopiowanie i mutowalność: 10 pytań.
Co wypisze ten kod?
const a = [1, 2];
const b = a;
b.push(3);
console.log(a.length);Które zdanie o const obj = { x: 1 } jest prawdziwe?
Co wypisze ten kod?
function ustaw(o) {
o = { nazwa: 'nowa' };
}
const p = { nazwa: 'stara' };
ustaw(p);
console.log(p.nazwa);Co zwróci [1, 2] === [1, 2]?
Co wypisze ten kod?
const org = { dane: { a: 1 } };
const kopia = { ...org };
kopia.dane.a = 2;
console.log(org.dane.a);Która metoda tworzy niezależną kopię zagnieżdżonego obiektu z datami i tablicami?
Co wypisze ten kod?
const t = [3, 1, 2];
const u = t.toSorted();
const w = t.sort();
console.log(t === u, t === w);Co wypisze ten kod uruchomiony w zwykłym skrypcie (bez trybu ścisłego)?
const K = Object.freeze({ cena: 10 });
K.cena = 20;
console.log(K.cena);Dlaczego historia w tym kodzie pokaże dwie identyczne wersje?
let stan = [];
const historia = [];
historia.push(stan); stan.push('a');
historia.push(stan); stan.push('b');Który zapis zmienia pole cena w kopii obiektu p, nie dotykając oryginału?