DEV Community

Cover image for Exploring Destructuring in JavaScript
Debajyati Dey
Debajyati Dey

Posted on

Exploring Destructuring in JavaScript

What is Destructuring?

Destructuring is a special really cool syntax feature in JavaScript, which lets us to extract values from arrays, objects, or other iterable structures and assign them to variables.

It's a shorthand way to access properties or elements of a data structure without having to use dot notation or array indices.

How is it beneficial for us (who write code in JavaScript)?

Destructuring has several benefits that make our code more concise, readable, and maintainable!

  • Improved Readability: Destructuring simplifies code by reducing the need for complex variable assignments and dot notation.
  • Less Boilerplate Code: You can extract values directly from data structures without needing to create intermediate variables.
  • More Concise Code: Destructuring can reduce the number of lines of code needed to achieve the same result.
  • Flexibility: You can destructure data structures of any type (objects, arrays, iterables), making it a versatile tool in your JavaScript toolkit.

Effective destructuring 🚀 enables us to write more expressive, maintainable, and efficient code that's easier to understand and debug.

Basic Example

const person = { name: 'John', age: 30 };
const { name, age } = person;
console.log(name); // "John"
console.log(age); // 30
Enter fullscreen mode Exit fullscreen mode

Here we have destructured an object person with two properties: name and age.

When destructuring an JavaScript object, the values we extract must be the exact same keys in the object. You can't place userName in place of name in the line
const { name, age } = person;. Which simply means - const { userName, age } = person; won't work.
But yes! We can apply aliasing while destructuring an object.
E.G. -

const person = { name: 'John', age: 30 };
const { name:userName, age:userAge } = person;
console.log(userName); // "John"
console.log(userAge); // 30
Enter fullscreen mode Exit fullscreen mode

Most probably you have seen destructuring an object for the first time when you were importing a module. For example when importing the exec function -

import { exec } from "node:child_process"; // ES Module syntax
Enter fullscreen mode Exit fullscreen mode
const { exec } = require("child_process"); // commonJS syntax
Enter fullscreen mode Exit fullscreen mode

Similarly we can destructure arrays also -

const numbers = [4, 5, 6];
const [x, y, z] = numbers;
console.log(x); // 4
console.log(y); // 5
console.log(z); // 6
Enter fullscreen mode Exit fullscreen mode

Here when destructuring arrays, you don't need to use aliasing to assign any element to a custom variable name. Because array elements are simply just values, they aren't bound with some keys.

Default Values

Destructuring allows you to assign default values to variables if the property doesn't exist in the object.

const person = { name: 'John' };
const { name = 'Anonymous', age } = person; // age will be undefined
console.log(name); // "John"
console.log(age); // undefined
Enter fullscreen mode Exit fullscreen mode

Here the string value 'John' wasn't substituted by the value 'Anonymous'in the variable name because it already existed in the object.
Whereas -

const person = { name: 'John' };
const { name, age = 30 } = person; // age defaults to 30 if not present
console.log(name); // "John"
console.log(age); // 30
Enter fullscreen mode Exit fullscreen mode

Spread Syntax

The spread syntax or say, operator (...) can be used with destructuring to capture remaining elements of an array or properties of an object into a new variable.

  • spread syntax with Arrays -
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first);  // 1
console.log(second); // 2
console.log(rest);    // [3, 4, 5] (remaining elements)
Enter fullscreen mode Exit fullscreen mode
  • spread syntax with Objects -
const person = { name: 'John', age: 30, city: 'New York' };
const { name, ...info } = person;
console.log(name);  // "John"
console.log(info);   // { age: 30, city: "New York"} (remaining properties)
Enter fullscreen mode Exit fullscreen mode

Nested Destructuring

Destructuring can be nested to extract values from deeply nested objects or arrays.

const data = {
  user: {
    name: 'Alicia',
    origin: 'Romania',
    eyes: 'blue',
    address: {
      city: 'London',
    }
  }
};

const { user: { name, address: { city } } } = data;
console.log(name);  // "Alicia"
console.log(city);   // "London"
Enter fullscreen mode Exit fullscreen mode

Destructuring in function parameter list

Suppose we've an JavaScript object named credentials -

const credentials = {
  name: 'Debajyati',
  age: 20,
  address: {
    city: 'Kolkata',
    state: 'West Bengal',
    country: 'India'
  },
  phone: '',
  email: '',
  hobbies: ['reading', 'listening to music', 'coding', 'watching Anime'],
  skills: {
    programming: true,
    blogging: true,
    singing: false
  }
}
Enter fullscreen mode Exit fullscreen mode

And a function named showCredentials which takes only 1 argument value which is an object and Standard outputs a string based on some of the object properties.
Well, we could write the function definition in this way -

function showCredential(obj) {
  const hasSkill = (skill) => obj.skills[skill];
  console.log(
    `${obj.name} is ${obj.age} years old.\n Lives in ${obj.address.city}, ${obj.address.country}.\n`,
    `He has the following hobbies: ${obj.hobbies.join(", ")}`,
  );
  if (hasSkill("programming")) {
    console.log(`He is a programmer.`);
  }
  if (hasSkill("singing")) {
    console.log(`He is a singer.`);
  }
  if (hasSkill("blogging")) {
    console.log(`He is also a tech blogger.`);
  }
}

Enter fullscreen mode Exit fullscreen mode

Calling it with -

showCredential(credentials);
Enter fullscreen mode Exit fullscreen mode

Getting this output -

Debajyati is 20 years old.
 Lives in Kolkata, India.
 He has the following hobbies: reading, listening to music, coding, watch
ing Anime
He is a programmer.
He is also a tech blogger.
Enter fullscreen mode Exit fullscreen mode

Instead we can destructure the object argument in the parameter list while defining the function. Like this -

function showCredential({ name, age, address: { city, country}, hobbies, skills }) {
  const hasSkill = (skill) => skills[skill];
  console.log(
    `${name} is ${age} years old.\n Lives in ${city}, ${country}.\n`,
    `He has the following hobbies: ${hobbies.join(", ")}`,
  );
  if (hasSkill("programming")) {
    console.log(`He is a programmer.`);
  }
  if (hasSkill("singing")) {
    console.log(`He is a singer.`);
  }
  if (hasSkill("blogging")) {
    console.log(`He is also a tech blogger.`);
  }
}
Enter fullscreen mode Exit fullscreen mode

which gives the same output.

ℹ️ NOTE

The function still takes only one argument. Destructuring didn't increase number of arguments in the function parameter list.

Also, calling the function didn't change as well. It still is -

showCredential(credentials);
Enter fullscreen mode Exit fullscreen mode

So, Why destructure objects in Function Parameter List?

While destructuring in function arguments list may seem cumbersome or tedious at first but it has it's quite important benefits.

Important Points to Consider

  • Safer Code: Destructuring can help prevent errors by making it clear which properties are expected by the function. If a property is missing in the passed object, destructuring will result in an error during function execution, aiding in early detection of potential issues.
  • Reduced Verbosity: By directly extracting properties into variables within the parameter list, you avoid repetitive object property access using dot notation. This leads to cleaner and more concise function definitions.
  • Focus on Functionality: By destructuring within the parameter list, you separate data access logic from the function's core functionality. This improves code organization and makes the function's purpose clearer.

Destructuring Strings

Just how we destructure arrays, similarly we can also unpack strings as array elements. A clever usage of our intelligence.

const fruit = 'grape';
const [first, second, ...rest] = fruit;
const animal = rest.join('');
console.log(animal); // ape
Enter fullscreen mode Exit fullscreen mode
⚠️ Remember !

When you use the spread operator (...) to capture the remaining characters from a string, you don't get a string. You get an array of those characters.

Some Handy Application Examples of Destructuring

  • Destructuring for swapping without 3rd variable:
    JavaScript traditionally required a temporary variable to swap the values of two variables. Destructuring offers a more concise and readable way to achieve this.

    • Before Destructuring:

      let a = 10;
      let b = 20;
      
      let temp = a;
      a = b;
      b = temp;
      console.log(a, b); // Output: 20 10
      
    • After Destructuring:

      let a = 10;
      let b = 20;
      
      [a, b] = [b, a];
      
      console.log(a, b); // Output: 20 10
      

    So nifty & elegant✨! Isn't it?

  • Destructuring Function Return Values: Functions can return multiple values as an array or object. Destructuring allows you to unpack these returned values into separate variables, improving code clarity.
    Let's suppose you have a function that fetches data from an API and returns a response object:

    function getUserUpdates(id) {
      // Simulating some API call with a GET request
      return {
        data: {
          player: response.group.names[id],
          brain: "rotting",
          powerLevel: Number(response.group.power[id]),
          useAsDecoy: true,
        },
        statusCode: Number(response.status),
      };
    }
    

In the context of building APIs or handling server responses, it offers distinct advantages that enhance code quality and maintainability.
Accessing individual properties is going to be breeze, because you can directly extract the properties you need from the function's return value into separate variables during the function call itself.

const {
  data: {player, useAsDecoy, powerLevel},
  statusCode,
} = getUserUpdates(1);
Enter fullscreen mode Exit fullscreen mode

Whenever a function returns an object and you are interested in specific property values, always apply destructuring straight away.
If you're still thinking destructuring in return values isn't a good idea, these 2 more advantages may convince you -
(A) Simplified Mental Model: Destructuring simplifies the thought process required to understand data flow for the developer who will be using your function. Instead of memorizing intricate property access chains, developers can focus on the meaning conveyed by the variable names used in the destructuring pattern. This reduces cognitive load and promotes better code comprehension.
(B) Reduced Boilerplate Code for Complex Return Objects:
When functions return objects with numerous or nested properties, destructuring significantly reduces the boilerplate code needed to access them individually. This leads to a more concise and less cluttered codebase, improving overall code quality.

  • Destructuring with Conditions:Destructuring can be combined with conditional statements to handle different scenarios based on the structure of an object. If you've a function that receives an object with optional properties:

    function greetUser(user) {
      const { name = "Anonymous" } = user || {}; // Destructuring with default value
    
      console.log(`Hello, ${name}!`);
    }
    
    greetUser({ name: "Bob" });       // Output: "Hello, Bob!"
    greetUser({});                    // Output: "Hello, Anonymous!" (no name property)
    greetUser(undefined);           // Output: "Hello, Anonymous!" (function receives no argument)
    
    

Conclusion

Throughout the whole article, we've learnt that 'Destructuring' is a powerful and versatile feature in JavaScript that can significantly improve your code's readability, maintainability, and efficiency. By effectively using destructuring techniques, you can write cleaner, more concise, and less error-prone code. So, embrace destructuring and take your JavaScript skills to the next level!

If you found this POST helpful, if this blog added some value to your time and energy, please show some love by giving the article some likes and share it with your friends.

Feel free to connect with me at - Twitter, LinkedIn or GitHub :)

Happy Coding 🧑🏽‍💻👩🏽‍💻! Have a nice day ahead! 🚀

Top comments (19)

Collapse
 
mikhaelesa profile image
Mikhael Esa • Edited

I was a huge fan of destructuring as it gives me a more concise looking code. But when things get big and many objects are destructured, everything is just losing its context. Take this example

const { prop } = obj
const myObj = obj

// You might have to check to which object this prop belongs to, or even you might not realize if it's a property of an object.
console.log(prop)

// You know immediately that prop belongs to myObj
console.log(myObj.prop)
Enter fullscreen mode Exit fullscreen mode

Not mentioning if you have a colliding property names then you have to make an alias for the colliding property name so you would still ended up in a messy code

Collapse
 
ddebajyati profile image
Debajyati Dey

Understood! I shall keep this in mind.

Collapse
 
jahid6597 profile image
MD. JAHID HOSSAIN

When using the spread syntax to copy objects that have nested properties, it is crucial to understand how JavaScript handles references to these nested properties. The spread operator creates a shallow copy of the object. This means that while the top-level properties are copied, any nested objects or arrays are still referenced from the original object. Consequently, changes to nested properties in the copied object will also reflect in the original object and vice versa.

Let's take an example:

const person = {
    name: 'John',
    age: 30,
    address: {
        city: 'New York',
        zip: '10001'
    }
};
Enter fullscreen mode Exit fullscreen mode

Here, we define an object person with properties like name, age and address. And address object contains city and zip.

Shallow Copy with Spread Operator

const personCopy = { ...person };
Enter fullscreen mode Exit fullscreen mode

The spread operator { ...person } creates a shallow copy of person. This means that the top-level properties (name, age, and address) are copied directly into personCopy. However, since address is an object (a nested property), only the reference to this object is copied, not the actual nested object itself.

Modifying Nested Property

personCopy.address.city = 'Los Angeles';

console.log(person.address.city); // "Los Angeles"
console.log(personCopy.address.city); // "Los Angeles"
Enter fullscreen mode Exit fullscreen mode

Since personCopy.address is a reference to the same address object as person.address, changing personCopy.address.city to 'Los Angeles' affects both person and personCopy. Hence, both console.log statements output "Los Angeles".

Modifying Nested Property Again

person.address.city = 'New York';

console.log(person.address.city); // "New York"
console.log(personCopy.address.city); // "New York"
Enter fullscreen mode Exit fullscreen mode

Similarly, when we change person.address.city back to 'New York', it also affects personCopy.address.city because they reference the same address object. As a result, both console.log statements output "New York".

Collapse
 
ddebajyati profile image
Debajyati Dey

Massive! That's a brief write up! I learnt something new.
Thank you 😊!

Collapse
 
matin_mollapur profile image
Matin Mollapur

really comprehensive guide on destructuring in javascript! the examples are clear and cover a wide range of use cases, from basic object and array destructuring to more advanced techniques like nested destructuring and using destructuring in function parameters. the section on spread syntax and default values is particularly helpful. thanks for making these concepts so accessible! looking forward to more articles like this.

Collapse
 
ddebajyati profile image
Debajyati Dey

Thank you for your detailed feedback! Pleased to know that you found the guide comprehensive and the examples clear. Looking forward to bringing you more useful content!
And hey!
Thanks again 🙃 for your support!

Collapse
 
swapnoneel123 profile image
Swapnoneel Saha

Really well-explained!!

Collapse
 
ddebajyati profile image
Debajyati Dey

Thanks a lot for your positive feedback! I’m always looking to improve.

Collapse
 
anonsols profile image
Anon Sols

This is amazing, I should also consider writing.

Collapse
 
ddebajyati profile image
Debajyati Dey • Edited

Thank you so much! 😊
Writing is incredibly rewarding, and I'd love to see what you come up with. Let me know if you need any suggestions on getting started, don't hesitate to reach out!

I'd love to read what you write—go for it!

Collapse
 
darshanraval profile image
Darshan Raval

awesome :)

Collapse
 
ddebajyati profile image
Debajyati Dey

Thank u for the appreciation :)

Collapse
 
muhammadanas8 profile image
MuhammadAnas8

Well explained... It was really helpful for me

Collapse
 
ddebajyati profile image
Debajyati Dey

Thank you! It’s great to hear that you've found the explanation helpful!

Collapse
 
sammaji15 profile image
Samyabrata Maji

Great article!!
Would love to know the performance overhead of destructuring. As js devs, we don't really care abt minor performance issue, but still it would be interesting to know.

Collapse
 
ddebajyati profile image
Debajyati Dey

Thank you for your kind words. You asked so I did a quick research on this topic.
I didn't actually thought about the performance consideration before. Well, it is indeed a critical point to think about.

Well as I far as I realised, Destructuring in JavaScript does introduce a slight performance overhead compared to traditional property access (dot notation) due to the extra steps involved in creating and assigning variables. In scenarios where performance is critical, this overhead can become noticeable.

For instance:

  • Server Request Handling: When handling a large number of simultaneous requests, every microsecond counts. Extensively using destructuring in request processing functions can introduce slight delays.
  • WebSocket Data Processing: In a WebSocket server processing high-frequency messages, avoiding destructuring might help reduce overhead.
  • Game Development Loop: In game development, the render loop runs many times per second. Using destructuring could add unnecessary overhead.
// Traditional property access
function updateGameState(state) {
    const x = state.player.x;
    const y = state.player.y;
    // update game state
}

// Destructuring
function updateGameState(state) {
    const { x, y } = state.player;
    // update game state
}
Enter fullscreen mode Exit fullscreen mode
  • Real-time Data Processing: In applications like live data feeds or stock tickers, every bit of performance optimization helps.

There could be more examples. But I think these are enough.

But for most practical purposes, the performance difference is negligible and should not deter you from using destructuring.

As you have been developing applications in JavaScript long before I started, you might know all of this better than I do.

Collapse
 
easywork01 profile image
Pranjal Raj

Great! Loved it

Collapse
 
jon_baso_1c15e0334291a1dc profile image
Jon Baso

All the lightbulbs went off above my head when you tied destructing and imports. Thank you!!!!

Collapse
 
ddebajyati profile image
Debajyati Dey

😊 🙌 😊 🙌