W Parku Jurajskim często trzeba łączyć dane z różnych systemów monitoringu, kopiować zestawy parametrów czy dynamicznie obsługiwać zmienną liczbę argumentów. Operatory spread (`...`) i rest (`...`) to ten sam zapis - trzy kropki - ale pełnią dwie różne role: spread "rozpakowuje" elementy, a rest "pakuje" je w jedną strukturę.
Spread "rozprowadza" elementy tablicy w miejsce, gdzie oczekiwane są poszczególne wartości:
1const carnivores = ['T-Rex', 'Velociraptor', 'Spinosaurus'];
2const herbivores = ['Triceratops', 'Brachiosaurus', 'Stegosaurus'];
3
4// Łączenie tablic
5const allDinos = [...carnivores, ...herbivores];
6console.log(allDinos);
7// ['T-Rex', 'Velociraptor', 'Spinosaurus', 'Triceratops', 'Brachiosaurus', 'Stegosaurus']
8
9// Dodawanie elementów podczas łączenia
10const withNew = ['Pteranodon', ...carnivores, 'Dilophosaurus'];
11console.log(withNew);
12// ['Pteranodon', 'T-Rex', 'Velociraptor', 'Spinosaurus', 'Dilophosaurus']Spread tworzy płytką kopię tablicy - nowa tablica z tymi samymi elementami:
1const originalZones = ['A', 'B', 'C'];
2const zonesCopy = [...originalZones];
3
4zonesCopy.push('D');
5console.log(originalZones); // ['A', 'B', 'C'] - oryginał niezmieniony!
6console.log(zonesCopy); // ['A', 'B', 'C', 'D']Uwaga - płytka kopia! Jeśli tablica zawiera obiekty, kopiowane są referencje, nie same obiekty:
1const dinos = [{ name: 'Rex', health: 100 }];
2const dinosCopy = [...dinos];
3
4dinosCopy[0].health = 50;
5console.log(dinos[0].health); // 50 - oryginał też się zmienił!
6// Bo oba elementy wskazują na ten sam obiekt w pamięciSpread pozwala "rozpakować" tablicę do argumentów funkcji:
1const temperatures = [36.5, 37.2, 38.1, 35.8, 39.0];
2
3// Zamiast Math.max(36.5, 37.2, 38.1, 35.8, 39.0)
4const maxTemp = Math.max(...temperatures);
5const minTemp = Math.min(...temperatures);
6console.log('Max:', maxTemp); // 39.0
7console.log('Min:', minTemp); // 35.8Spread działa również z obiektami - "rozpakowuje" pary klucz-wartość:
1const baseDino = { species: 'Unknown', health: 100, zone: 'X' };
2
3// Kopiowanie obiektu
4const dinoCopy = { ...baseDino };
5console.log(dinoCopy); // { species: 'Unknown', health: 100, zone: 'X' }
6
7// Nadpisywanie właściwości (ostatnia wygrywa!)
8const rex = { ...baseDino, species: 'T-Rex', zone: 'A' };
9console.log(rex); // { species: 'T-Rex', health: 100, zone: 'A' }
10
11// Łączenie obiektów
12const position = { lat: 12.34, lon: 56.78 };
13const status = { health: 85, alert: false };
14const fullReport = { ...position, ...status, timestamp: Date.now() };
15console.log(fullReport);
16// { lat: 12.34, lon: 56.78, health: 85, alert: false, timestamp: ... }Przy łączeniu obiektów ze spread, późniejsze właściwości nadpisują wcześniejsze:
1const defaults = { voltage: 10000, locked: true, zone: 'A' };
2const userSettings = { voltage: 15000, zone: 'B' };
3
4// Defaults najpierw, potem nadpisanie
5const config = { ...defaults, ...userSettings };
6console.log(config);
7// { voltage: 15000, locked: true, zone: 'B' }
8
9// Odwrotna kolejność - defaults nadpisałyby ustawienia!
10const wrong = { ...userSettings, ...defaults };
11console.log(wrong);
12// { voltage: 10000, locked: true, zone: 'A' } - źle!Rest (`...`) w parametrach funkcji zbiera wszystkie pozostałe argumenty do tablicy:
1// Rest parameter - zbiera zmienną liczbę argumentów
2function logSighting(observer, ...dinosaurs) {
3 console.log(\`\${observer} zaobserwował: \${dinosaurs.join(', ')}\`);
4 console.log(\`Liczba gatunków: \${dinosaurs.length}\`);
5}
6
7logSighting('Dr. Rex', 'T-Rex', 'Velociraptor', 'Triceratops');
8// "Dr. Rex zaobserwował: T-Rex, Velociraptor, Triceratops"
9// "Liczba gatunków: 3"
10
11logSighting('Dr. Rex', 'Brachio');
12// "Dr. Rex zaobserwował: Brachio"
13// "Liczba gatunków: 1"1// Poprawnie - rest na końcu
2function feedDinos(keeper, time, ...dinoNames) {
3 dinoNames.forEach(name => {
4 console.log(\`\${keeper} karmi \${name} o \${time}\`);
5 });
6}
7
8feedDinos('Alan', '08:00', 'Rex', 'Blue', 'Delta');
9
10// Błąd! Rest nie może być przed innymi parametrami
11// function wrong(...names, time) {} // SyntaxError!Rest działa również w destrukturyzacji tablic i obiektów:
1// Rest w destrukturyzacji tablicy
2const rankings = ['T-Rex', 'Velociraptor', 'Spinosaurus', 'Giganotosaurus'];
3const [champion, runnerUp, ...others] = rankings;
4console.log(champion); // "T-Rex"
5console.log(runnerUp); // "Velociraptor"
6console.log(others); // ["Spinosaurus", "Giganotosaurus"]
7
8// Rest w destrukturyzacji obiektu
9const sensor = { id: 'S-001', value: 42, unit: 'C', zone: 'A', active: true };
10const { id: sensorId, value: sensorValue, ...metadata } = sensor;
11console.log(sensorId); // "S-001"
12console.log(sensorValue); // 42
13console.log(metadata); // { unit: 'C', zone: 'A', active: true }1const dino = { name: 'Rex', _secret: 'code', health: 100, _internal: true };
2
3// Wyciągnij to, co chcesz usunąć, reszta zostaje
4const { _secret, _internal, ...publicData } = dino;
5console.log(publicData); // { name: 'Rex', health: 100 }1function updateDino(dino, updates) {
2 return { ...dino, ...updates, lastModified: Date.now() };
3}
4
5const rex = { name: 'Rex', health: 100, zone: 'A' };
6const updatedRex = updateDino(rex, { health: 85, zone: 'B' });
7console.log(updatedRex);
8// { name: 'Rex', health: 85, zone: 'B', lastModified: ... }
9console.log(rex.health); // 100 - oryginał niezmieniony!"Spread i rest to jak system transportowy w Parku Jurajskim" - mówi Dr. Rex. "Spread rozładowuje kontenery z próbkami do osobnych stanowisk, a rest pakuje wiele próbek do jednego kontenera. Trzy kropki, a tyle możliwości!"