logo image Faisal Rahman
ID EN
My profile picture taken in the summer Faisal Rahman

Destructuring Assignment in JavaScript


One of the new JavaScript features introduced by ECMAScript 2015 (ES6) is destructuring assignment. This feature allows us to ‘unpack’ the contents of arrays and objects to be stored in multiple variables. By using this feature, we can save a significant amount of code.

Array Destructuring

Say we have an array like the following:

const arr = [0, 1, 2, 3];

If we want to place each of its values into variables a through d, we would do:

var a = arr[0];
var b = arr[1];
var c = arr[2];
var d = arr[3];

The entire code for placing the contents of arr into each variable takes 4 lines of code. With destructuring, we can write it in just 1 line.

var [a, b, c, d] = arr;

console.log(a); //0
console.log(b); //1
console.log(c); //2
console.log(d); //3

We can also separate the variable declaration from the assignment.

var a, b, c, d;

[a, b, c, d] = arr;

Arrays in JavaScript return undefined when we try to access a value outside their bounds (index out of bounds). As a consequence, if the length of the array we declare exceeds the length of the source array, we may find that the variables we assigned have a value of undefined. To handle this, we can provide a default value for variables to be assigned via destructuring.

var a, b, c, d, e;

[a, b, c, d, e = 4] = arr;

console.log(e); //4

Conversely, if there are elements in the array we want to skip, we simply leave the variable name empty at the desired position.

var a, b;

[a, , b] = arr;

console.log(a); //0
console.log(b); //2

If the array we want to ‘unpack’ is of unknown length, and we want to extract a few of the leading elements and the rest, we can combine array destructuring with the rest operator.

const arr2 = [0, 1, 3, 4, 5, 6];
var [a, b, ...rest] = arr2;

console.log(a); //0
console.log(b); //1
console.log(rest); //[3, 4, 5, 6]

Object Destructuring

Destructuring can also be performed on objects, and it’s quite powerful. Let’s look at the standard practice.

const person = { name: "Faisal", age: 17 };

const { name, age } = person;

console.log(name); //'Faisal'
console.log(age); //17

Like array destructuring, we can also perform destructuring on an object without declaring the variables on the same line. The difference is that we must wrap it in a pair of parentheses so that the statement on the left side ({ name, age }) is not treated as a block.

let name, age;
const person = { name: "Faisal", age: 17 };

({ name, age } = person);

In object destructuring, the key name on the left side of the statement must match the key name in the source object. However, we can map the destructured result into a variable with a different name as follows.

let nama, umur;
const person = { person: "Faisal", age: 17 };

({ name: nama, age: umur } = person);

console.log(nama); //'Faisal'
console.log(umur); //17

Like array destructuring, we can also provide default values for keys in our destructured object.

let name, age, website;
const person = { name: "Faisal", age: 17 };

({ name, age, website = "icalrn.id" } = person);

console.log(website); //'icalrn.id'

Again, like array destructuring, we can use the rest operator in object destructuring.

const obj = { a: 0, b: 1, c: 2, d: 3 };

const { a, b, ..rest } = obj;

console.log(a); //0
console.log(b); //1
console.log(c); //{ c: 2, d: 3 }

Object Destructuring and Functions

The practical use of object destructuring is especially valuable when writing functions. Here are a few example cases.

Unpacking an Object Passed as a Function Parameter

Object destructuring can be very helpful for shortening and improving the readability of function code that requires an object as its parameter. Consider the following example.

function printAddress(address) {
  var streetName = address.streetName;
  var houseNumber = address.houseNumber;
  var city = address.city;

  return `${streetName} No. ${houseNumber}, ${city}`;
}

var address = printAddress({
  streetName: "Jalan Kasuari",
  houseNumber: "2A",
  city: "Kab. Bogor",
});

console.log(address); //Jalan Kasuari No. 2A, Kab. Bogor

Now let’s use object destructuring on that function’s parameter.

function printAddress({ streetName, houseNumber, city }) {
  return `${streetName} No. ${houseNumber}, ${city}`;
}

var address = printAddress({
  streetName: "Jalan Kasuari",
  houseNumber: "2A",
  city: "Kab. Bogor",
});

console.log(address); //Jalan Kasuari No. 2A, Kab. Bogor

From a function that took 7 lines of code down to just 3 lines. Very helpful, isn’t it? Moreover, just by reading the parameter, we already know what data the function needs and the corresponding key names.

Setting Default Values for a Function’s Parameters

When writing a function with an object as a parameter, determining default values can become very verbose.

function printAddress(address) {
  address = address === undefined ? {} : address;
  var streetName =
    address.streetName === undefined ? "Jalan X" : address.streetName;
  var houseNumber =
    address.houseNumber === undefined ? "0" : address.houseNumber;
  var city = address.city === undefined ? "Kota Y" : address.city;

  return `${streetName} No. ${houseNumber}, ${city}`;
}

var address = printAddress({ streetName: "Jalan Kasuari", city: "Kab. Bogor" });

console.log(address); //'Jalan Kasuari No. 0, Kab. Bogor'

Since we know that the function’s parameter is agreed to be an object, we can perform object destructuring with default values to unpack the parameter passed to that function.

function printAddress({
  streetName = "Jalan X",
  houseNumber = "0",
  city = "Kota Y",
}) {
  return `${streetName} No. ${houseNumber}, ${city}`;
}

var address = printAddress({ streetName: "Jalan Kasuari", city: "Kab. Bogor" });

console.log(address); //'Jalan Kasuari No. 0, Kab. Bogor'

From this example, it’s clear how using object destructuring to set default parameter values greatly improves the readability of our code.

Scoping Global Variables in IIFE Modules

Going back to discussing IIFE, aka immediately-invoked function expressions. When we create an IIFE module that accesses many global variables, we can use object destructuring to pass the global object as a parameter. The goal is so that the JavaScript engine doesn’t have to look all the way up to the global scope for a global variable we use inside the IIFE. Furthermore, when used consistently, we can explicitly see which global variables a given IIFE uses, improving the readability and maintainability of our code.

(function someIIFE({ $, someHelper, anotherHelper: someOtherHelper }) {
  //...
  // within this IIFE, window.$ (jQuery) is available as $
  // window.someHelper is available as someHelper
  // window.anotherHelper is available as someOtherHelper
})(window); // pass the window object as the global scope