A Practical Guide to Array and Object Destructuring

Object in JavaScript is used to store multiple values as a complex data structure. We create objects with curly braces ({...}) and one or more properties separated by a comma. Each of the properties is a key-value pair separated by the colon(:) symbol. The key must be a string or JavaScript Symbol type. The value can be of any type, including another object.

Below is an example of an object. The left side of the colon is the key and the right side is the value.

const teacher = {
    'name': 'ABC',
    'age': 35,
    'subjects':['Maths','English', 'Science'],
    'address': {
        'street' : '65/2, Broooklyn Road',
        'city':'Vizag',
        'country':'India',
        'Pincode':'xxxxxx'
    }
}

Object Destructuring

We store data in objects to retrieve it based on needs at a later point in time. For example, if you want to retrieve the value of the name and city information from the 'teacher' object, we can do

const name = teacher.name;
const city = teacher.address.city;
console.log(name, city);

First, we use the dot(.) notation to access the values. We also need to declare a couple of variables to assign the values accordingly.

Use Destructuring to retrieve values from an object.

We can simplify the value retrieval from the JavaScript objects using the Object destructuring syntax. It is a new syntax introduced in ECMAScript version 6 (ES6). It helps to retrieve values from the object property and assign them to variables.

The expression to retrieve the name property value from the teacher object using object destructuring is the following:

const {name} = teacher;
console.log(name) // ABC

On the left side of the expression, we use the Object property key(in this case, it is name) and place it inside the {}. It also becomes the variable name to hold the property value. We mention the const and let keywords define the variable scope. No separate variable declaration is required.

So, how do we retrieve more than one property value using object destructuring? We keep adding the object kets inside the {} on the left side of the expression. In the example below, we retrieve the name and age from the teacher object using Object destructuring syntax.

const {name, age}  = teacher;
console.log(name, age) // ABC 35

Use destructuring to retrieve values from a nested object

In practical life, your data object may not be as simple as the "teacher" object. The object's key can have another object as a value an form a nested object. Let us see how to retrieve the value for a key from a nested object.

const employee = {
    id: 1,
    name: 'ABC',
    dept: {
        id: 'D1',
        name: 'DEF',
        address: {
            street: 'Street No 30',
            city: 'Hyderabad'
        }
    }
}

Now, if you want to retrieve the value of the address from the employee object in the traditional way, you would do as below:

const address = employee.dept.address
// Now, to retrieve street
const street = employee.dept.address.street

With destructuring, things are simple. You can define the key name using its predecessor key. So to retrieve the value of the address, we will start with its predecessor key dept. So, the dept is the top-level key with no predecessor.

const {dept: {address}} = employee;
console.log(address);
const { dept: { address: { street} } } = employee;
console.log(street);

This can be rewritten as

const { dept } = employee;
const { address } = dept;
const { street } = address;
console.log(street);

Define a new variable with Default values

There could be a situation where you are unsure if the object has a specific key while retrieving its value. Also, you may want to create a new variable with a default value in case the key is unavailable in the object.

const student =  {
    'name': 'John',
    'std': 3,
    'subjects': ['Science','Maths','English'],
    'parents': {
        'father': 'ABC',
        'mother': 'DEF',
        'email': 'XYZ@gmail.com'
    },
    'address': {
        'street': '123  Road No 30',
        'city': 'Hyderabad',
        'country': 'India',
        'zip':'xxxx'
    }
}

Now, let's assume we are trying to retrieve the value of the age property which is not present in the object. A traditional way to do that is:

const age = student.age ? student.age : 25;

If we find the age property, access its value and assign it to the variable else, assign a default value of 25. So, how will we do that with Object destructuring syntax?

const {name, age=25} = student;
console.log(age);

As you see, we can do it easily by specifying the key name along with the default value. It has a similar impact as the traditional way. The destructuring part has got more magic to show. How about creating a brand new variable and assigning a value computed using the object property values?

const {name, dept, message = `${name} is ${dept}`} = employee;
console.log(message);

Object Destructuring Aliases:

In JavaScript object destructuring, you can give your destructured variables an alias name. It comes in very handy to reduce the changes of a variable name conflicts.

const employee =  {
    id: 1,
    name: 'ABC',
    dept:'XYZ'
}

Let's assume your source code has an existing variable names dept. So if we use the same variable name in destructuring, there will be a name conflict.

Instead, you can use an alias name to create the variable with this new name. For example, an alias name of department can be used.

const {dept: department} = employee;
console.log(department);

Now, we have destructured with the alias name, not the actual key name that is still not defined

console.log(dept);
Uncaught ReferenceError: dept is not defined

Handle dynamic name properties

We often handle API response data as JavaScript objects. These objects may contain dynamic data such that, as a client, we may not even know the property key names in advance.

const employee = {
    id: 1,
    name: 'ABC',
    dept: 'XYZ'
}

Can we write a function that returns the value of the employee object properties when we pass a key as an argument? Yeah, so it means we will not hard-code the key name inside the function. It is dynamic for the function.

const id = getPropertyValue('id');
const name = getPropertyValue('name');
console.log(id, name);
function getPropertyValue(key) {
    const { [key]: returnValue } = employee;
    return returnValue;
}

Please note the square brackets ([...]) around the key in the destructuring assignment. The key we pass to the function gets evaluated and the value is retrieved from the object.

Destructuring Function Parameters

We can write precise and smart code using object destructuring and pass it as function parameters.

const student =  {
    'name': 'John',
    'std': 3,
    'subjects': ['Science','Maths','English'],
    'parents': {
        'father': 'ABC',
        'mother': 'DEF',
        'email': 'XYZ@gmail.com'
    },
    'address': {
        'street': '123  Road No 30',
        'city': 'Hyderabad',
        'country': 'India',
        'zip':'xxxx'
    }
}

Let's assume we have a function that sends an email to the student's parent. There is an email property under the parents key. This function also logs a statement for a successful email sent.

We can use destructuring to pass the email value to the function definition. There is no need to pass the entire student object and then retrieve the required value inside the function.

const sendEmail = ({parents: {email}}) => {
    console.log(`Sent email to ${email}`);
}

Please note, that we have performed the nested object destructuring in the above function to retrieve the email value.

Destructure Function Return Value

In JavaScript, a function may return an object. When we call that function, we may not be interested in the entire object but its specific property values. Here is another opportunity to use object destructuring.

In the example below, the function getStudent returns an object

const getStudent = () => {
    return {
        'name': 'ABC',
        'age': 9,
        'std': 3,
        'subjects': ['Maths','English','EVS'],
        'parents': {
            'father': 'ABC',
            'mother': 'DEF',
            'email': 'XYZ@gmail.com'
        },
        'address': {
            'street': '124 Road',
            'city': 'Hyderabad',
            'country': 'India',
            'zip': 'xxxx'
        }
    }
}

We are only interested in the name and subject key values. We can retrieve them using the destructuring expression

const {name, subjects} = getStudent();
console.log(name, subjects);

Destructure in Loops

Let's think of an array of employee objects. We want to iterate through the array and want to use the property values of each of the employee object.

const employees = [
    {
        'name': 'ABC',
        'address': '15th Park Avenue',
        'age': 43
    },
    {
        'name':'DEF',
        'address': 'USA',
        'age': 33
    },
    {
        'name': 'XYZ',
        'address': 'Bangalore',
        'age': 16
    }
];

You can use the for-of loop to loop through the employees array and then use the object destructuring assignment syntax to retrieve the details. Let us log the name and age of each employee in the browser console.

for (let {name, age} of employees) {
    console.log(`${name} is ${age} years old!!!`);
}

Fallbacks when destructuring nullable objects

JavaScript is a loosely typed language and thus programs are prone to runtime errors. A runtime error is an error that occurs during the execution of the program also known as the exceptions. In the example that is given below the program is syntactically correct, but at runtime, it is trying to destructure a null object and throws an Error.

let {name, age, favColor} = player;
// Here player could be null

If we must do conditional destructuring and assignment with null checks, then we might need to write up boilerplate code to reduce the frequency of this kind of error.

This code snippet checks if a variable is defined before assigning it to a class property and thus prevents errors.

if (file == undefined) {
    file = false;
}
if (file) {
    this.file = file
}

To solve this issue via destructuring, you can use an empty object as a fallback, and if the object is null or undefined the assigned variables will be undefined.

Sample code snippet using empty object as a fallback strategy

function getAge( player = {}) {
    const {age} = player;
}
getAge(); // No error
const { age, name, favColor } = player || {};
console.log(age, name, favColor);

Array Destructuring

Let's assume you have an array of numbers called myNumbers. You can use destructuring to create variables from the elements of the array.

const myNumbers = [1, 2, 3, 4, 5];
const [first, second, third, fourth, fifth] = myNumbers;
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3
console.log(fourth); // 4
console.log(fifth); // 5

As you can see, destructuring lets you extract data from arrays and assign it to variables.

Default values:

const phones = ['iPhone 8','Samsung S22','iPhone XS'];
const [firstPhone, secondPhone, thirdPhone, fourthPhone = 'Oppo ultra Max'] = phones;
console.log(`${firstPhone}, ${secondPhone}, ${thirdPhone}, ${fourthPhone}`);

Skipping Elements:

const phones = ['iPhone 8', 'Samsung S22', 'iPhone XS', 'Oppo New Release', 'iPhone 11', 'iPhone 12', 'iPhone 13'];

const [firstPhone, , thirdPhone, fourthPhone = 'Oppo Ultra Max', , , seventhPhone] = phones;

console.log(`${firstPhone}, ${thirdPhone}, ${fourthPhone}, ${seventhPhone}`); // iPhone 8, iPhone XS, Oppo New Release, iPhone 13

Nested Array

const phones = ['iPhone 8', 'Samsung S22', ['Unnamed Phone 1', 'Unnamed Phone 2', 'Unnamed Phone 3']];

const [, , [firstNestedPhone, secondNestedPhone, thirdNestedPhone]] = phones;

console.log(`${firstNestedPhone}, ${secondNestedPhone}, ${thirdNestedPhone}`); // Unnamed Phone 1, Unnamed Phone 2, Unnamed Phone 3
const phones = ['iPhone 8', 'Samsung S22', ['Unnamed Phone 1', 'Unnamed Phone 2', ['Clear Phone 1', 'Clear Phone 2']]];

const [, , [firstNestedPhone, , [firstDeepNestedPhone, secondDeepNestedPhone]]] = phones;

console.log(`${firstNestedPhone}, ${firstDeepNestedPhone}, ${secondDeepNestedPhone}`); // Unnamed Phone 1, Clear Phone 1, Clear Phone 2

Using Spread Parameters

const phones = ['iPhone 8', 'Samsung S22', 'iPhone XS', 'Google Pixel 6'];

const [firstPhone, ...restPhones] = phones;

console.log(`${restPhones}`); // Samsung S22,iPhone XS,Google Pixel 6

Swapping

let firstPhone = 'iPhone 13 Pro Max',
  secondPhone = 'iPhone 12 Pro Max';

[firstPhone, secondPhone] = [secondPhone, firstPhone];

console.log(`${firstPhone}, ${secondPhone}`); // iPhone 12 Pro Max, iPhone 13 Pro Max

Thanks for reading!!