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.