Skillversitas

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 } = obj for excluding properties.
  • Shallow copy: spread only copies the first level — nested objects remain references. Use structuredClone() for a deep copy.