javascript-today

Destructuring

Destructuring

Destructuring is a convenient way to extract values from arrays or properties from objects into distinct variables. It makes your code cleaner and more readable.

Array Destructuring

Basic syntax:

const numbers = [1, 2, 3];

// Old way
const first = numbers[0];
const second = numbers[1];

// Destructuring
const [first, second, third] = numbers;

console.log(first);   // 1
console.log(second);  // 2
console.log(third);   // 3

Skipping elements:

const colors = ["red", "green", "blue", "yellow"];

const [primary, , tertiary] = colors;  // Skip green

console.log(primary);   // "red"
console.log(tertiary);  // "blue"

Default values:

const [a, b, c, d = "default"] = [1, 2, 3];

console.log(a);  // 1
console.log(d);  // "default" (not in array)

Rest pattern:

const [first, ...rest] = [1, 2, 3, 4, 5];

console.log(first);  // 1
console.log(rest);   // [2, 3, 4, 5]

Swapping variables:

let x = 1;
let y = 2;

[x, y] = [y, x];  // Swap!

console.log(x);  // 2
console.log(y);  // 1

Object Destructuring

Basic syntax:

const person = {
  name: "Alice",
  age: 25,
  city: "NYC"
};

// Old way
const name = person.name;
const age = person.age;

// Destructuring
const { name, age, city } = person;

console.log(name);  // "Alice"
console.log(age);   // 25
console.log(city);  // "NYC"

Renaming variables:

const person = { name: "Alice", age: 25 };

// Rename 'name' to 'userName'
const { name: userName, age: userAge } = person;

console.log(userName);  // "Alice"
console.log(userAge);   // 25
console.log(name);      // ReferenceError - 'name' doesn't exist

Default values:

const person = { name: "Alice" };

const { name, age = 18, country = "USA" } = person;

console.log(name);     // "Alice"
console.log(age);      // 18 (default)
console.log(country);  // "USA" (default)

Rest pattern:

const person = {
  name: "Alice",
  age: 25,
  city: "NYC",
  country: "USA"
};

const { name, ...address } = person;

console.log(name);     // "Alice"
console.log(address);  // { age: 25, city: "NYC", country: "USA" }

Nested Destructuring

Nested objects:

const user = {
  id: 1,
  name: "Alice",
  address: {
    city: "NYC",
    country: "USA"
  }
};

const {
  name,
  address: { city, country }
} = user;

console.log(name);     // "Alice"
console.log(city);     // "NYC"
console.log(country);  // "USA"
console.log(address);  // ReferenceError - we didn't assign 'address'

Nested arrays:

const data = ["Alice", 25, ["NYC", "USA"]];

const [name, age, [city, country]] = data;

console.log(name);     // "Alice"
console.log(age);      // 25
console.log(city);     // "NYC"
console.log(country);  // "USA"

Function Parameters

Destructuring in function parameters:

// Instead of this:
function displayUser(user) {
  console.log(user.name);
  console.log(user.age);
  console.log(user.city);
}

// Do this:
function displayUser({ name, age, city }) {
  console.log(name);
  console.log(age);
  console.log(city);
}

displayUser({ name: "Alice", age: 25, city: "NYC" });

With default values:

function createUser({ name, age = 18, role = "user" }) {
  return { name, age, role };
}

console.log(createUser({ name: "Alice" }));
// { name: "Alice", age: 18, role: "user" }

console.log(createUser({ name: "Bob", role: "admin" }));
// { name: "Bob", age: 18, role: "admin" }

Default parameter object:

function configure({ theme = "light", lang = "en" } = {}) {
  console.log(theme, lang);
}

configure({ theme: "dark" });  // "dark" "en"
configure({});                 // "light" "en"
configure();                   // "light" "en" - {} is default

Array parameters:

function plotPoint([x, y]) {
  console.log(`Point at (${x}, ${y})`);
}

plotPoint([10, 20]);  // "Point at (10, 20)"

Practical Examples

Example 1: API Response Handling

// Typical API response
const response = {
  data: {
    user: {
      id: 1,
      name: "Alice",
      email: "alice@example.com"
    },
    posts: [/* ... */]
  },
  status: 200,
  message: "Success"
};

// Extract what you need
const {
  data: { user: { name, email }, posts },
  status
} = response;

console.log(name);    // "Alice"
console.log(email);   // "alice@example.com"
console.log(status);  // 200

Example 2: React Props

// Common React pattern
function UserCard({ name, age, avatar, isOnline = false }) {
  return (
    <div className="user-card">
      <img src={avatar} alt={name} />
      <h3>{name}</h3>
      <p>Age: {age}</p>
      {isOnline && <span className="online-badge">Online</span>}
    </div>
  );
}

// Usage
<UserCard 
  name="Alice" 
  age={25} 
  avatar="/alice.jpg"
  isOnline={true}
/>

Example 3: Multiple Return Values

function getCoordinates() {
  return [40.7128, -74.0060];  // NYC coordinates
}

const [latitude, longitude] = getCoordinates();

console.log(`Lat: ${latitude}, Long: ${longitude}`);

Example 4: Config Objects

function connectDatabase({
  host = "localhost",
  port = 5432,
  database,
  username,
  password,
  ssl = false,
  ...options
}) {
  console.log(`Connecting to ${host}:${port}/${database}`);
  console.log(`SSL: ${ssl}`);
  console.log("Additional options:", options);
}

connectDatabase({
  database: "myapp",
  username: "admin",
  password: "secret",
  timeout: 5000,
  retries: 3
});

Example 5: Loop Destructuring

const users = [
  { id: 1, name: "Alice", age: 25 },
  { id: 2, name: "Bob", age: 30 },
  { id: 3, name: "Charlie", age: 35 }
];

// Destructure in loop
for (const { name, age } of users) {
  console.log(`${name} is ${age} years old`);
}

// Or with map
const names = users.map(({ name }) => name);
console.log(names);  // ["Alice", "Bob", "Charlie"]

Example 6: State Updates (React)

const [user, setUser] = useState({
  name: "Alice",
  preferences: { theme: "dark", language: "en" }
});

// Update nested property
setUser(prev => ({
  ...prev,
  preferences: {
    ...prev.preferences,
    theme: "light"
  }
}));

// Destructure to read
const { name, preferences: { theme } } = user;

Common Patterns

1. Extracting from arrays returned by functions:

const match = /(\d+)-(\d+)-(\d+)/.exec("2024-01-15");
const [, year, month, day] = match;  // Skip first element

console.log(year, month, day);  // "2024" "01" "15"

2. Excluding properties:

const user = {
  id: 1,
  name: "Alice",
  password: "secret123",
  email: "alice@example.com"
};

// Remove password from object
const { password, ...safeUser } = user;

console.log(safeUser);  // { id: 1, name: "Alice", email: "..." }

3. Renaming and defaults together:

const config = { apiUrl: "https://api.example.com" };

const {
  apiUrl: baseUrl,
  timeout: maxTimeout = 5000,
  retries: maxRetries = 3
} = config;

console.log(baseUrl);      // "https://api.example.com"
console.log(maxTimeout);   // 5000
console.log(maxRetries);   // 3

Gotchas and Tips

1. Can’t destructure null or undefined:

const { name } = null;  // TypeError!

// Use default empty object
const { name } = someValue || {};  // Safe

// Or optional chaining with default
const { name } = someValue ?? {};

2. Computed property names:

const key = "username";
const { [key]: value } = { username: "alice123" };

console.log(value);  // "alice123"

3. Mixed patterns:

const data = {
  id: 1,
  items: [10, 20, 30]
};

const {
  id,
  items: [first, ...restItems]
} = data;

console.log(id);         // 1
console.log(first);      // 10
console.log(restItems);  // [20, 30]

When to Use Destructuring

✅ Good use cases:

  • Extracting data from API responses
  • Function parameters with multiple options
  • React component props
  • Working with arrays/objects in loops
  • Renaming variables for clarity

❌ When to avoid:

  • Simple single-property access: obj.name is clearer than const { name } = obj
  • Deeply nested structures that make code hard to read
  • When you need the whole object anyway