In Jurassic Park we often need to combine data from different monitoring systems, copy sets of parameters, or dynamically handle a variable number of arguments. The spread (
...) and rest (...) operators use the same notation - three dots - but serve two different roles: spread "unpacks" elements, while rest "packs" them into a single structure.Spread "spreads" array elements into a place where individual values are expected:
1const carnivores = ['T-Rex', 'Velociraptor', 'Spinosaurus'];
2const herbivores = ['Triceratops', 'Brachiosaurus', 'Stegosaurus'];
3
4// Merging arrays
5const allDinos = [...carnivores, ...herbivores];
6console.log(allDinos);
7// ['T-Rex', 'Velociraptor', 'Spinosaurus', 'Triceratops', 'Brachiosaurus', 'Stegosaurus']
8
9// Adding elements while merging
10const withNew = ['Pteranodon', ...carnivores, 'Dilophosaurus'];
11console.log(withNew);
12// ['Pteranodon', 'T-Rex', 'Velociraptor', 'Spinosaurus', 'Dilophosaurus']Spread creates a shallow copy of the array - a new array with the same elements:
1const originalZones = ['A', 'B', 'C'];
2const zonesCopy = [...originalZones];
3
4zonesCopy.push('D');
5console.log(originalZones); // ['A', 'B', 'C'] - original unchanged!
6console.log(zonesCopy); // ['A', 'B', 'C', 'D']Warning - shallow copy! If the array contains objects, references are copied, not the objects themselves:
1const dinos = [{ name: 'Rex', health: 100 }];
2const dinosCopy = [...dinos];
3
4dinosCopy[0].health = 50;
5console.log(dinos[0].health); // 50 - original also changed!
6// Because both elements point to the same object in memorySpread lets you "unpack" an array into function arguments:
1const temperatures = [36.5, 37.2, 38.1, 35.8, 39.0];
2
3// Instead of 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 also works with objects - it "unpacks" key-value pairs:
1const baseDino = { species: 'Unknown', health: 100, zone: 'X' };
2
3// Copying an object
4const dinoCopy = { ...baseDino };
5console.log(dinoCopy); // { species: 'Unknown', health: 100, zone: 'X' }
6
7// Overriding properties (last one wins!)
8const rex = { ...baseDino, species: 'T-Rex', zone: 'A' };
9console.log(rex); // { species: 'T-Rex', health: 100, zone: 'A' }
10
11// Merging objects
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: ... }When merging objects with spread, later properties override earlier ones:
1const defaults = { voltage: 10000, locked: true, zone: 'A' };
2const userSettings = { voltage: 15000, zone: 'B' };
3
4// Defaults first, then override
5const config = { ...defaults, ...userSettings };
6console.log(config);
7// { voltage: 15000, locked: true, zone: 'B' }
8
9// Reversed order - defaults would override settings!
10const wrong = { ...userSettings, ...defaults };
11console.log(wrong);
12// { voltage: 10000, locked: true, zone: 'A' } - wrong!Rest (
...) in function parameters collects all remaining arguments into an array:1// Rest parameter - collects variable number of arguments
2function logSighting(observer, ...dinosaurs) {
3 console.log(`${observer} observed: ${dinosaurs.join(', ')}`);
4 console.log(`Species count: ${dinosaurs.length}`);
5}
6
7logSighting('Dr. Rex', 'T-Rex', 'Velociraptor', 'Triceratops');
8// "Dr. Rex observed: T-Rex, Velociraptor, Triceratops"
9// "Species count: 3"
10
11logSighting('Dr. Rex', 'Brachio');
12// "Dr. Rex observed: Brachio"
13// "Species count: 1"1// Correct - rest at end
2function feedDinos(keeper, time, ...dinoNames) {
3 dinoNames.forEach(name => {
4 console.log(`${keeper} feeds ${name} at ${time}`);
5 });
6}
7
8feedDinos('Alan', '08:00', 'Rex', 'Blue', 'Delta');
9
10// Error! Rest cannot come before other parameters
11// function wrong(...names, time) {} // SyntaxError!Rest also works in array and object destructuring:
1// Rest in array destructuring
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 in object destructuring
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// Pull out what you want to remove, the rest stays
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 - original unchanged!"Spread and rest are like the park's transport system" - says Dr. Rex. "Spread unloads containers of samples to individual workstations, and rest packs many samples into one container. Three dots, so many possibilities!"