Spread Operator and Rest Parameters
The spread operator (...) and rest parameters are powerful features for working with arrays, objects, and function arguments.
Spread Operator
The spread operator expands an iterable into individual elements.
Spreading Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Without spread
const combined1 = arr1.concat(arr2);
// With spread
const combined2 = [...arr1, ...arr2];
console.log(combined2); // [1, 2, 3, 4, 5, 6]
Adding Elements
const arr = [1, 2, 3];
const withStart = [0, ...arr];
console.log(withStart); // [0, 1, 2, 3]
const withEnd = [...arr, 4];
console.log(withEnd); // [1, 2, 3, 4]
const withMiddle = [1, ...arr, 5];
console.log(withMiddle); // [1, 1, 2, 3, 5]
Copying Arrays
const original = [1, 2, 3];
// Shallow copy
const copy = [...original];
console.log(copy); // [1, 2, 3]
console.log(copy === original); // false (different arrays)
Spreading Strings
const str = "hello";
const chars = [...str];
console.log(chars); // ["h", "e", "l", "l", "o"]
Spreading Objects
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 2, c: 3, d: 4 }
Overriding Properties
const defaults = { host: "localhost", port: 3000, ssl: false };
const config = { port: 8080, ssl: true };
const final = { ...defaults, ...config };
console.log(final); // { host: "localhost", port: 8080, ssl: true }
Copying Objects
const original = { name: "Alice", age: 30 };
// Shallow copy
const copy = { ...original };
console.log(copy === original); // false
Rest Parameters
Rest parameters collect multiple arguments into an array.
Basic Rest Parameters
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
Mixed Parameters
function greet(greeting, ...names) {
return `${greeting} ${names.join(" and ")}!`;
}
console.log(greet("Hello", "Alice")); // "Hello Alice!"
console.log(greet("Hi", "Bob", "Charlie")); // "Hi Bob and Charlie!"
Rest Must Be Last
// Correct
function test(a, b, ...rest) {
console.log(a, b, rest);
}
// Error - rest must be last
// function test(...rest, a, b) { }
Rest in Arrow Functions
const sum = (...numbers) => numbers.reduce((a, b) => a + b, 0);
console.log(sum(1, 2, 3, 4)); // 10
Practical Examples
Function with Variable Arguments
function createList(...items) {
return items.map((item, index) => `${index + 1}. ${item}`);
}
console.log(createList("Learn", "Practice", "Master"));
// ["1. Learn", "2. Practice", "3. Master"]
Merging Multiple Objects
function merge(...objects) {
return Object.assign({}, ...objects);
}
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };
console.log(merge(obj1, obj2, obj3)); // { a: 1, b: 2, c: 3 }
Removing Duplicates
const arr = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(arr)];
console.log(unique); // [1, 2, 3, 4]
Flattening Arrays
const nested = [[1, 2], [3, 4], [5, 6]];
const flat = [...nested[0], ...nested[1], ...nested[2]];
console.log(flat); // [1, 2, 3, 4, 5, 6]
// Or with flat()
console.log(nested.flat()); // [1, 2, 3, 4, 5, 6]
Passing Array as Arguments
function multiply(a, b, c) {
return a * b * c;
}
const numbers = [2, 3, 4];
console.log(multiply(...numbers)); // 24
Combining Spread and Rest
function logArgs(first, ...rest) {
console.log("First:", first);
console.log("Rest:", rest);
}
const args = [1, 2, 3, 4];
logArgs(...args);
// First: 1
// Rest: [2, 3, 4]
Cloning with Modifications
const user = { id: 1, name: "Alice", role: "user" };
// Create admin version
const admin = { ...user, role: "admin" };
console.log(admin); // { id: 1, name: "Alice", role: "admin" }
console.log(user); // { id: 1, name: "Alice", role: "user" } (unchanged)
Collecting Function Arguments
function formatMessage(template, ...values) {
let result = template;
values.forEach((value, index) => {
result = result.replace(`{${index}}`, value);
});
return result;
}
console.log(formatMessage("Hello {0}, you are {1} years old", "Alice", 30));
// "Hello Alice, you are 30 years old"
Shallow vs Deep Copy
Shallow Copy
const original = { a: 1, b: { c: 2 } };
// Shallow copy - nested objects are still referenced
const copy = { ...original };
copy.b.c = 99;
console.log(original.b.c); // 99 (affected!)
Deep Copy
const original = { a: 1, b: { c: 2 } };
// Deep copy using JSON
const copy = JSON.parse(JSON.stringify(original));
copy.b.c = 99;
console.log(original.b.c); // 2 (not affected)
Performance Considerations
Spread vs concat()
// Spread
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const result1 = [...arr1, ...arr2];
// concat()
const result2 = arr1.concat(arr2);
// Both are similar in performance
Spread vs Object.assign()
// Spread
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const result1 = { ...obj1, ...obj2 };
// Object.assign()
const result2 = Object.assign({}, obj1, obj2);
// Spread is more readable
Common Patterns
Default Parameters with Rest
function request(url, options = {}) {
const { method = "GET", timeout = 5000, ...headers } = options;
console.log(method, timeout, headers);
}
request("https://api.example.com", {
method: "POST",
timeout: 10000,
"Content-Type": "application/json"
});
Destructuring with Rest
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
Combining Arrays and Objects
const arr = [1, 2, 3];
const obj = { a: 1, b: 2 };
const combined = {
items: [...arr],
config: { ...obj }
};
console.log(combined);
// { items: [1, 2, 3], config: { a: 1, b: 2 } }
Summary
- Spread operator: expands iterables into elements
- Arrays: combine, copy, add elements
- Objects: merge, copy, override properties
- Rest parameters: collect arguments into array
- Must be last: rest parameters must be final parameter
- Shallow copy: nested objects still referenced
- Performance: similar to traditional methods
Related Resources
Official Documentation
Next Steps
- Destructuring: Arrays and Objects
- Array Methods: map, filter, reduce, forEach
- Arrow Functions and Function Expressions
Comments