We use cookies to enhance your experience on the site
CodeWorlds

Spread and Rest Operators

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 Operator for Arrays

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']

Copying an Array (Shallow Copy)

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 memory

Spread with Functions

Spread 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.8

Spread Operator for Objects

Spread 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: ... }

Order Matters

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 Operator in Functions

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"

Rest Must Be Last Parameter

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 in Destructuring

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 }

Practical Patterns

Removing Properties from an Object

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 }

Creating a Copy with Modifications

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!"

Go to CodeWorlds