Spread & Rest Operators in JavaScript
The Spread operator (...) and the Rest operator (...) use the same syntax but have opposite purposes. Spread "unpacks" or "spreads" elements from an array/object. Rest "collects" elements into a new array/object. Both are very powerful ES6 features for data manipulation.
Spread Operator
Spread in Arrays
// Combine arrays
const mondayLecture = ["Algorithms", "Web Dev"];
const wednesdayLecture = ["Database", "Networking"];
const allLectures = [...mondayLecture, ...wednesdayLecture];
console.log(allLectures);
// ["Algorithms", "Web Dev", "Database", "Networking"]
// Copy an array (shallow copy)
const original = [1, 2, 3, 4, 5];
const copy = [...original];
copy.push(6);
console.log(original); // [1, 2, 3, 4, 5] — unchanged
console.log(copy); // [1, 2, 3, 4, 5, 6]
// Add elements at a specific position
const numbers = [1, 2, 5, 6];
const with34 = [...numbers.slice(0, 2), 3, 4, ...numbers.slice(2)];
console.log(with34); // [1, 2, 3, 4, 5, 6]
// Remove duplicates
const grade = [85, 92, 78, 92, 85, 90, 78];
const unique = [...new Set(grade)];
console.log(unique); // [85, 92, 78, 90]
Spread in Objects
// Merge objects
const studentData = { name: "John", studentId: "2023001" };
const academicData = { gpa: 3.75, semester: 4 };
const gabungan = { ...studentData, ...academicData };
console.log(gabungan);
// { name: "John", studentId: "2023001", gpa: 3.75, semester: 4 }
// Override properties (the later one wins)
const config = { theme: "light", font: "Arial", size: 14 };
const customConfig = { ...config, theme: "dark", size: 16 };
console.log(customConfig);
// { theme: "dark", font: "Arial", size: 16 }
// Copy an object (shallow copy)
const student = { name: "John", majorCode: { name: "CS" } };
const studentCopy = { ...student };
// ⚠️ Shallow copy — nested objects remain references
studentCopy.name = "Amy";
studentCopy.majorCode.name = "IS"; // also changes the original!
console.log(student.name); // "John" (unchanged — primitive)
console.log(student.majorCode.name); // "IS" (changed! — reference)
Code Example: Spread in Function Calls
// Math.max with spread
const grade = [85, 92, 78, 90, 88];
const highest = Math.max(...grade);
console.log(highest); // 92
const lowest = Math.min(...grade);
console.log(lowest); // 78
// Combining arguments
function calculateCost(credits, ...extraCost) {
const creditCost = credits * 200000;
const extraTotal = extraCost.reduce((a, b) => a + b, 0);
return creditCost + extraTotal;
}
console.log(calculateCost(14, 500000, 300000)); // 3600000
Rest Operator
Rest in Function Parameters
// Collect all parameters into an array
function calculateAverage(...grade) {
const total = grade.reduce((a, b) => a + b, 0);
return total / grade.length;
}
console.log(calculateAverage(85, 92, 78)); // 85
console.log(calculateAverage(85, 92, 78, 90, 88)); // 86.6
// Combining regular parameters + rest
function createAnnouncement(type, ...studentName) {
return `${type}: ${studentName.join(", ")}`;
}
console.log(createAnnouncement("Pass", "John", "Amy", "Mike"));
// "Pass: John, Amy, Mike"
Rest in Destructuring
// Rest in array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5, 6];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5, 6]
// Rest in object destructuring
const student = {
name: "John",
studentId: "2023001",
majorCode: "CS",
gpa: 3.75,
semester: 4,
active: true
};
const { name, studentId, ...academicSystem } = student;
console.log(name); // "John"
console.log(studentId); // "2023001"
console.log(academicSystem); // { majorCode: "CS", gpa: 3.75, semester: 4, active: true }
// Very useful for excluding properties
const { password, ...safeData } = {
name: "John",
email: "[email protected]",
password: "rahasia123"
};
console.log(safeData);
// { name: "John", email: "[email protected]" }
Code Explanation
| Operator | Syntax | Function |
|---|---|---|
| Spread | ...iterable |
Spreads elements from an array/object |
| Rest | ...identifiers |
Collects elements into an array/object |
When to use Spread:
- Merging arrays/objects
- Copying arrays/objects
- Passing an array as multiple arguments
When to use Rest:
- Collecting remaining function parameters
- Collecting remaining elements in destructuring
- Excluding properties from an object
Real-World Examples
1. Merging Student Data
// Data from various sources
const profileData = {
name: "John Smith",
email: "[email protected]",
photo: "john.jpg"
};
const academicData = {
studentId: "2023001",
majorCode: "Computer Science",
gpa: 3.75,
semester: 4
};
const financeData = {
billing: 5000000,
hasPaid: 3000000,
remainingPayment: 2000000
};
// Merge all data
const fullProfile = { ...profileData, ...academicData, ...financeData };
console.log(fullProfile);
// Update data without changing the original
const updateProfile = {
...fullProfile,
gpa: 3.80, // update GPA
semester: 5, // advanced to next semester
billing: fullProfile.billing + 500000 // new billing
};
console.log(`Old GPA: ${fullProfile.gpa}, new: ${updateProfile.gpa}`);
// "Old GPA: 3.75, new: 3.80"
// Remove password from data before displaying it
const userWithPassword = {
name: "John",
role: "admin",
password: "hashed_password_123"
};
const { password, ...safeUser } = userWithPassword;
console.log(safeUser); // { name: "John", role: "admin" }
2. Copying Objects Safely
// Shallow copy with spread
const originalData = {
name: "John",
grades: [85, 92, 78],
majorCode: { name: "CS", departmentHead: "Dr. Aaron" }
};
// Shallow copy — only the first level
const shallowCopy = { ...originalData };
shallowCopy.name = "Amy"; // safe — doesn't change the original
shallowCopy.grades.push(90); // ⚠️ ALSO CHANGES the original!
console.log(originalData.grades.length); // 4 (changed!)
// Deep copy — use structuredClone (modern)
const deepCopy = structuredClone(originalData);
deepCopy.grades.push(100);
console.log(originalData.grades.length); // 4 (unchanged!)
3. Flexible Function Input
// A function that accepts flexible input
function createSchedule(day, ...activities) {
const schedule = {
day,
activity: activities.map(activity => {
const [time, name] = activity.split(" ");
return { time, name };
})
};
return schedule;
}
const mondaySchedule = createSchedule(
"Monday",
"08:00 Algorithms",
"10:00 Web Dev",
"13:00 Practicum Database",
"15:00 Rapat Organisasi"
);
console.log(mondaySchedule);
// {
// day: "Monday",
// activity: [
// { time: "08:00", name: "Algorithms" },
// { time: "10:00", name: "Web Dev" },
// ...
// ]
// }
// Function with named options + rest
function generateReport(options = {}, ...data) {
const {
title = "Report",
format = "text",
includeDate = true
} = options;
const lines = [];
if (includeDate) {
lines.push(`📅 ${new Date().toLocaleDateString("en-US")}`);
}
lines.push(`📊 ${title}`);
lines.push("---");
data.forEach(item => lines.push(`• ${item}`));
return format === "html"
? lines.map(l => `<p>${l}</p>`).join("\n")
: lines.join("\n");
}
const report = generateReport(
{ title: "Attendance Report", format: "text" },
"John: Present",
"Amy: Present",
"Mike: Excused"
);
console.log(report);
4. Array Manipulation with Spread & Rest
// Remove an element from an array (immutable)
const attendanceList = ["John", "Amy", "Mike", "Anna", "David"];
function removeStudent(list, name) {
return list.filter(m => m !== name);
}
const afterRemove = removeStudent(attendanceList, "Mike");
console.log(afterRemove); // ["John", "Amy", "Anna", "David"]
console.log(attendanceList); // ["John", "Amy", "Mike", "Anna", "David"] — unchanged
// Insert at a specific position (immutable)
function insert(list, index, ...newItems) {
return [...list.slice(0, index), ...newItems, ...list.slice(index)];
}
const list = ["A", "B", "E", "F"];
const final = insert(list, 2, "C", "D");
console.log(final); // ["A", "B", "C", "D", "E", "F"]
// Flatten a nested array
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = nested.flatMap(arr => [...arr]);
console.log(flat); // [1, 2, 3, 4, 5, 6]
Conclusion
- Spread (
...iterable) unpacks/spreads elements: merging, copying, or passing as arguments. - Rest (
...identifiers) collects elements: remaining function parameters or remaining destructuring. - Spread in arrays:
[...arr1, ...arr2]for merging. - Spread in objects:
{...obj1, ...obj2}for merging (later properties win). - Rest in parameters:
function(...args)for flexible input. - Rest in destructuring:
const { a, ...rest } = objfor excluding properties. - Shallow copy: spread only copies the first level — nested objects remain references. Use
structuredClone()for a deep copy.