JavaScript Destructuring and Spread Operators Explained

Master array destructuring, object destructuring, rest parameters, and spread operator techniques

JavaScript Destructuring and Spread Operators Explained

Destructuring and spread operators are among the most practical ES6 features. This article covers their various uses and techniques.

Array Destructuring

Basic Usage

// Basic destructuring
const [a, b, c] = [1, 2, 3];
console.log(a, b, c);  // 1 2 3

// Skip elements
const [first, , third] = [1, 2, 3];
console.log(first, third);  // 1 3

// Rest elements
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head);  // 1
console.log(tail);  // [2, 3, 4, 5]

// Default values
const [x = 10, y = 20] = [1];
console.log(x, y);  // 1 20

// Nested destructuring
const [a1, [b1, b2], c1] = [1, [2, 3], 4];
console.log(a1, b1, b2, c1);  // 1 2 3 4

Practical Techniques

// Swap variables
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b);  // 2 1

// Function returning multiple values
function getMinMax(arr) {
  return [Math.min(...arr), Math.max(...arr)];
}

const [min, max] = getMinMax([3, 1, 4, 1, 5]);
console.log(min, max);  // 1 5

// Destructuring function parameters
function processArray([first, second, ...rest]) {
  console.log(first);   // 1
  console.log(second);  // 2
  console.log(rest);    // [3, 4, 5]
}

processArray([1, 2, 3, 4, 5]);

// With regular expressions
const url = 'https://example.com:8080/path';
const [, protocol, host, port] = url.match(/^(\w+):\/\/([^:]+):(\d+)/);
console.log(protocol, host, port);  // 'https' 'example.com' '8080'

Object Destructuring

Basic Usage

// Basic destructuring
const user = { name: 'Alice', age: 25 };
const { name, age } = user;
console.log(name, age);  // 'Alice' 25

// Renaming
const { name: userName, age: userAge } = user;
console.log(userName, userAge);  // 'Alice' 25

// Default values
const { name: n, city = 'Unknown' } = user;
console.log(n, city);  // 'Alice' 'Unknown'

// Rename + default value
const { name: n2, city: c = 'NYC' } = user;
console.log(n2, c);  // 'Alice' 'NYC'

// Nested destructuring
const person = {
  name: 'Bob',
  address: {
    city: 'Tokyo',
    country: 'Japan'
  }
};

const { address: { city, country } } = person;
console.log(city, country);  // 'Tokyo' 'Japan'

Rest Properties

// Extract some properties, collect the rest
const user = {
  id: 1,
  name: 'Alice',
  age: 25,
  email: 'alice@example.com'
};

const { id, ...rest } = user;
console.log(id);    // 1
console.log(rest);  // { name: 'Alice', age: 25, email: '...' }

// Practical: Remove object property
function removeField(obj, field) {
  const { [field]: _, ...rest } = obj;
  return rest;
}

removeField(user, 'email');
// { id: 1, name: 'Alice', age: 25 }

Function Parameter Destructuring

// Destructure parameters
function greet({ name, age }) {
  console.log(`Hello ${name}, you are ${age}`);
}

greet({ name: 'Alice', age: 25 });

// With default values
function createUser({
  name = 'Anonymous',
  age = 0,
  role = 'user'
} = {}) {
  return { name, age, role };
}

createUser();  // { name: 'Anonymous', age: 0, role: 'user' }
createUser({ name: 'Bob' });  // { name: 'Bob', age: 0, role: 'user' }

// Complex default values
function configure({
  host = 'localhost',
  port = 3000,
  ssl: {
    enabled = false,
    cert = null
  } = {}
} = {}) {
  return { host, port, ssl: { enabled, cert } };
}

Spread Operator

Array Spread

// Merge arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2];
// [1, 2, 3, 4, 5, 6]

// Copy array (shallow copy)
const original = [1, 2, 3];
const copy = [...original];

// Insert in middle
const inserted = [...arr1.slice(0, 2), 'new', ...arr1.slice(2)];
// [1, 2, 'new', 3]

// Convert iterables
const str = 'hello';
const chars = [...str];  // ['h', 'e', 'l', 'l', 'o']

const set = new Set([1, 2, 3]);
const arrFromSet = [...set];  // [1, 2, 3]

// Function calls
const numbers = [1, 5, 3, 9, 2];
Math.max(...numbers);  // 9

Object Spread

// Merge objects
const defaults = { host: 'localhost', port: 3000 };
const options = { port: 8080, ssl: true };
const config = { ...defaults, ...options };
// { host: 'localhost', port: 8080, ssl: true }

// Copy object (shallow copy)
const original = { a: 1, b: 2 };
const copy = { ...original };

// Add/override properties
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26, city: 'NYC' };
// { name: 'Alice', age: 26, city: 'NYC' }

// Conditional spread
const condition = true;
const obj = {
  always: true,
  ...(condition && { sometimes: true })
};
// { always: true, sometimes: true }

// Or use ternary
const obj2 = {
  ...baseObj,
  ...(isAdmin ? adminProps : userProps)
};

Rest Parameters

Function Parameters

// Collect all arguments
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}

sum(1, 2, 3, 4, 5);  // 15

// Combine with fixed parameters
function log(level, ...messages) {
  console.log(`[${level}]`, ...messages);
}

log('INFO', 'User logged in', 'at 10:00');
// [INFO] User logged in at 10:00

// Replace arguments object
// Old way
function oldWay() {
  const args = Array.prototype.slice.call(arguments);
  return args.join(' ');
}

// New way (recommended)
function newWay(...args) {
  return args.join(' ');
}

Rest in Destructuring

// Array destructuring
const [first, second, ...others] = [1, 2, 3, 4, 5];
console.log(others);  // [3, 4, 5]

// Object destructuring
const { a, b, ...remaining } = { a: 1, b: 2, c: 3, d: 4 };
console.log(remaining);  // { c: 3, d: 4 }

Advanced Patterns

Dynamic Property Destructuring

const key = 'name';
const obj = { name: 'Alice', age: 25 };

// Computed property name destructuring
const { [key]: value } = obj;
console.log(value);  // 'Alice'

// Utility function
function pick(obj, ...keys) {
  return keys.reduce((result, key) => {
    if (key in obj) {
      result[key] = obj[key];
    }
    return result;
  }, {});
}

pick(obj, 'name');  // { name: 'Alice' }

Deep Merge

// Shallow merge (spread operator)
const merged = { ...obj1, ...obj2 };  // Nested objects are overwritten

// Deep merge function
function deepMerge(target, source) {
  const result = { ...target };

  for (const key of Object.keys(source)) {
    if (
      source[key] !== null &&
      typeof source[key] === 'object' &&
      !Array.isArray(source[key]) &&
      target[key] !== null &&
      typeof target[key] === 'object'
    ) {
      result[key] = deepMerge(target[key], source[key]);
    } else {
      result[key] = source[key];
    }
  }

  return result;
}

const obj1 = { a: 1, nested: { x: 1, y: 2 } };
const obj2 = { b: 2, nested: { y: 3, z: 4 } };

deepMerge(obj1, obj2);
// { a: 1, b: 2, nested: { x: 1, y: 3, z: 4 } }

React Applications

// Props passing
function ParentComponent() {
  const commonProps = { className: 'common', onClick: handleClick };

  return <ChildComponent {...commonProps} id="child1" />;
}

// State updates
const [state, setState] = useState({ name: '', age: 0 });

setState(prev => ({ ...prev, name: 'Alice' }));

// Destructure props
function UserCard({ name, age, ...rest }) {
  return (
    <div {...rest}>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
}

Best Practices Summary

Destructuring and Spread Best Practices:
┌─────────────────────────────────────────────────────┐
│                                                     │
│   Destructuring Usage                               │
│   ├── Extract needed properties for cleaner code   │
│   ├── Use in function params for readability       │
│   ├── Provide sensible default values              │
│   └── Avoid deeply nested destructuring            │
│                                                     │
│   Spread Usage                                      │
│   ├── Keep immutability when merging objects/arrays│
│   ├── Remember it's a shallow copy                 │
│   ├── Use && or ternary for conditional spread     │
│   └── Later properties override earlier ones       │
│                                                     │
│   Performance Considerations                        │
│   ├── Large object spreads have performance cost   │
│   ├── Consider alternatives for frequent spreads   │
│   └── Deep nesting requires deep merge             │
│                                                     │
└─────────────────────────────────────────────────────┘
OperationSyntaxPurpose
Array destructuring[a, b] = arrExtract array elements
Object destructuring{a, b} = objExtract object properties
Array spread[...arr]Merge/copy arrays
Object spread{...obj}Merge/copy objects
Rest parameters...restCollect remaining elements

Master destructuring and spread for more concise and elegant code.