Destructuring Assignment is an amazing feature introduced with EcmaScript 2016, which is now available in both browsers and Node.js.

If you’re writing CommonJs or ES6 modules, you’re probably already using it! Let’s pretend we have a file called math.js, where we have a bunch of functions to be exported:

export const add5   = (num) => num + 5;
export const double = (num) => num * 2;
export const half   = (num) => num / 2;

If we create a new file, let’s say index.js, we can import the functions above in block:

import math from "./math.js";

const example1 = math.double(10); // => 20
const example2 = math.add5(10);   // => 15
const example3 = math.half(30);   // => 15

But now imagine if our math.js file had hundreds of functions. Why do we import them all, if we only need (for example) math.double?
Here comes the concept of object destructuring:

import { double } from "./math.js";

const example1 = double(10); // => 20

Our maths.js file exports an object containing every exported function. So, if we don’t want to import a lot of useless functions from that file, we can just destructure the exported object and get back only the functions we really need!

Simple Object Destructuring

const user = {
  name: {
    first: "John",
    middle: "Mitch",
    last: "Doe"
  },
  contacts: {
    email: "john.doe@foo.dev",
    phone: "333 000000"
  }
}

const { name, contacts } = user;

console.log(name);     // => { first: "John", middle: "Mitch", last: "Doe" }
console.log(contacts); // => { email: "john.doe@foo.dev", phone: "333 000000" }

In the code above, we defined an object (user) with some nested properties.
We got access to name and contacts by destructuring the user object, so after the destructuring assignment we’ll always be able to call name and contacts properties without typing user.name and user.contacts. Pretty handy, isn’t it?

Nested Object Destructuring

Let’s try something a bit more complex, nested object destructuring.

const developer = {
  name: "Mitch",
  age: 24,
  languages: {
    favorite: "Haskell",
    mostUsed: "JavaScript"
  }
}

const { name, age, languages: { mostUsed, favorite } } = developer;

const bio = `${name} is a ${age} years old developer.\n`
          + `He codes in ${mostUsed} but prefers ${favorite}`;

// => "Mitch is a 24 years old developer.
//     He codes in JavaScript but prefers Haskell"

Let’s analyze the code above! We defined a new object called developer, where we have a nested property, languages.
In our destructuring assignment, we got access to name and age. Nothing new! But when we wanted to access both favorite and mostUsed properties, from the languages key, we had to destructure languages itself.
That way, we’ll have two new constant values (favorite and mostUsed), and we don’t need to access the developer object everytime we need them!

Tip: you can add a new property just by using the ES6 default parameter feature!

const developer = {
  name: "Mitch",
  age: 24,
  languages: {
    favorite: "Haskell",
    mostUsed: "JavaScript"
  }
}

const { name, age, languages: { mostUsed, favorite, dreaded = "PHP" } } = developer;

const bio = `${name} is a ${age} years old developer.\n`
          + `He codes in ${mostUsed} but prefers ${favorite}\n`
          + `He fearse ${dreaded}`;

// => "Mitch is a 24 years old developer.
//     He codes in JavaScript but prefers Haskell.
//     He fears PHP."

Array Destructuring

Arrays can be destructured too!
Let’s see the easiest case:

const phrase        = ["Hello", "John", "!"];
const [greet, name] = phrase;

console.log(greet); // => "Hello"
console.log(name);  // => "John"

Way better than accessing those values by using indexes (phrase[0], phrase[1])! But what if (for some reason) we want to get just the exclamation point ( phrase[2])?

const phrase           = ["Hello", "John", "!"];
const [,, exclamation] = phrase;

console.log(exclamation); // => "!"

Here we are! I don’t find this to be a clean way to get just a certain element from an array… but it may be useful, what do you think?

Default Values

As we’ve seen during object destructuring, we can assign default values to our array while we’re destructuring it:

const RGB = [55, 155];

const [R, G, B = 255] = RGB;

console.log(R); // => 55
console.log(G); // => 155
console.log(B); // => 255

That way, we’ll be sure that we have a fallback value in case B is undefined!

Head and Tail

If you’re coming from a functional language such as Haskell, you may be familiar with the concept of head and tail.
Let’s see an example:

let list = [1, 2, 3, 4, 5]
let h    = head list
let t    = tail list

print h -- 1
print t -- [2,3,4,5]

So as you can see in the example above, we’re getting the first element of a list (array in Haskell) using the head function, and the rest of the list using the tail function. This is super useful in recursive functions, but we’re not gonna talk about that in this article; we just want to achieve the same result using array destructuring in JavaScript:

const list = [1, 2, 3, 4, 5];
const [head, ...tail] = list;

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

So easy! We just used the formidable spread operator and array destructuring together!

Nested Array Destructuring

Just like objects, nested arrays can be destructured too!
Let’s say we have a grid, which is represented the following way:

+-—--+----+----+
| 10 | 10 | 10 |   <- FIRST ROW
+-—--+----+----+
| 60 | 50 | 60 |   <- SECOND ROW
+-—--+----+----+
| 90 | 90 | 90 |   <- THIRD ROW
+-—--+----+----+

We want to get the first row, the center value (50) and the third row:

const grid = [[10, 10, 10],
              [60, 50, 60],
              [90, 90, 90]];

const [first, [, center, ,], third] = grid;

console.log(first);  // => [10, 10, 10]
console.log(center); // => 50
console.log(third);  // => [90, 90, 90]

A lot easier than accessing those values by using grid[0], grid[1][1] and grid[2]!

Cloning An Array

Array destructuring also makes immutable array cloning a lot easier:

const myArray = [1, 2, 3, 4, 5];
const clone   = myArray;

myArray[1] = "two";

console.log(myArray); // => [1, "two", 3, 4, 5]
console.log(clone);   // => [1, "two", 3, 4, 5]

As you can see, when we clone an array by reference, if we mutate the original one, the change will also affect the clone… we can simply avoid this by cloning by value:

const myArray = [1, 2, 3, 4, 5];
const clone   = [...myArray];

myArray[1] = "two";

console.log(myArray); // => [1, "two", 3, 4, 5]
console.log(clone);   // => [1, 2, 3, 4, 5]

Well done, array destructuring!

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.