DEV Community

Hrishikesh
Hrishikesh

Posted on

ES6 Destructuring 101

ES6, also known as ES2015, brought forth the concept of destructuring, which involves efficiently breaking down larger data structures into their individual components. Essentially, destructuring enables us to assign extracted values from arrays or objects directly to variables. This powerful feature simplifies the process of working with complex data structures and enhances the readability and conciseness of our code.

Array Destructuring

const array = [1, 2, 3, 4, 5];
const [a, b, c, d, e] = array;
Enter fullscreen mode Exit fullscreen mode

In the above code snippet, we utilize destructuring to extract elements from the array on the right-hand side of the assignment (line 2). The syntax employed on the left-hand side of the assignment is not an array itself; rather, it represents a pattern of the structure we anticipate to find on the right-hand side. Each variable on the left corresponds to an element on the right, allowing 'a' to receive 1, 'b' to receive 2, and so forth. It's worth noting that destructuring does not alter the original array. It remains unaffected by this operation.

Typical use cases / patterns

  • Extract only few needed values
const array = [1, 2, 3, 4, 5];
const [a, b] = array;
Enter fullscreen mode Exit fullscreen mode

We are allowed to only get stuff that we need.

  • Trying to extract non-existing values.
const array = [1, 2];
const [a, b, c, d] = array;
Enter fullscreen mode Exit fullscreen mode

c and d will get undefined because there's nothing in the array at those indices.

  • Default value in case extracted value is undefined.
const array = [10]
const [a, b = 0, c = 0] = array;
Enter fullscreen mode Exit fullscreen mode

Please note that default assignment functions exclusively for undefined. It does not apply to falsy values like null, 0, '', or false. The default assignment process first checks for strict equality with undefined before resorting to the default value.

  • Skip positions.
const array = [1, 2, 3, 4, 5];
const [, , c] = array;
Enter fullscreen mode Exit fullscreen mode

commas will skip first 2 indices and c gets value 3.

  • Take a slice using spread operator.
const array = [1, 2, 3, 4, 5];
const [, , ...array2] = array;
Enter fullscreen mode Exit fullscreen mode

we skipped first 2 elements. array2 will have [3,4,5], basically we did array.slice(2). Please note that the ... (spread) syntax can only appear at the end or as the only element on the left-hand side of a destructuring pattern. It is used to gather the remaining elements of an array into a new array.

  • If spread operator is used but there's nothing to spread then it ends up being empty array.
const array = [1, 2];
const [a,b,...rest] = array;
Enter fullscreen mode Exit fullscreen mode

a gets 1 and b gets 2, after that there's nothing left so rest becomes empty array. This is good and it follows same behavior as slice. If you did array.slice(2) you will get empty array.

  • Nested pattern for nested array.
const data = [1, 2, [3, 4, 5], 6];
const [a, b, [c, d, e], f] = data;
Enter fullscreen mode Exit fullscreen mode

Makes sense, we use nested pattern whenever there's nested array, all other principles apply the same to nested pattern.

  • Declaration and assignment doesn't have to be on same line.
const array = [1, 2, 3, 4, 5];
let a, b, c;
[a, b, c] = array;

const obj = {};
[obj.a, obj.b, obj.c] = array;

Enter fullscreen mode Exit fullscreen mode

With 2nd example of obj it shows that as long as you have something valid to assign to , it will work. obj ends up being { a: 1, b: 2, c: 3 }.

  • Swap variables the cool way
let x = 5; 
let y = 10;

[x,y] = [y,x];
Enter fullscreen mode Exit fullscreen mode

x is now 10 and y is 5.

  • Fallback in case whole structure is undefined / null.
function getLocation() {
 // returns [lat, lng] if available else returns null. 
}
const [lat = 0.0, lng = 0.0] = getLocation() || [];
Enter fullscreen mode Exit fullscreen mode

if the fallback using || is not provided then above code will fail with TypeError. It's good practice to always provide such fallbacks when using destructuring and employ default assignments.

  • Destructuring in function parameters.
function doSomething([first = 10, second = 20, third= 30] = []) {
  //do something cool.
}
doSomething([1, 2]);
Enter fullscreen mode Exit fullscreen mode

We can directly use destructuring pattern in function definition whenever we expect an argument to be an array. In above code snippet function doSomething expects a single argument of an array. We are extracting first 3 values into first , second and third. We have given a fallback with default arguments feature and we also utilized default assignment in case if array is empty or undefined. first gets 1 , second gets 2. Since there's nothing left to assign to third it resorts to default assignment which is 30.

Object Destructuring

const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name, age, email } = person;
Enter fullscreen mode Exit fullscreen mode

In this code snippet, we are working with an object named person, which contains information such as name, age, and email. To extract specific values from the object, we use curly braces {} on the left-hand side of the assignment. These curly braces signify that we are expecting an object on the right-hand side.
Unlike arrays where the index or position was crucial for extraction, with objects, we rely on matching property names to correctly extract the values we need. In this case, we use the property names name, age, and email to access the corresponding values from the person object. The order of the properties in the object does not matter, what matters is that the property names specified in the curly braces match the ones in the object to successfully extract the values.
After executing the destructuring assignment, the variable name will hold the value "Hrishi", the variable age will have the value 27, and the variable email will store the value "example@email.com" from the person object.

Typical use cases / patterns

  • Extract only few needed values
const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name, email } = person;
Enter fullscreen mode Exit fullscreen mode
  • Trying to extract non-existing values.
const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name, email, address } = person;
Enter fullscreen mode Exit fullscreen mode

address will be undefined.

  • Variable names different from property names.
const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name: personName, email: personEmail } = person;
Enter fullscreen mode Exit fullscreen mode

property: target is the syntax. Here we are extracting values of name and email from person and assigning them to new variables personName and personEmail accordingly.

  • Using the spread operator to gather bunch of values.
const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name, ...rest } = person;
Enter fullscreen mode Exit fullscreen mode

rest will be an object with all the properties from person except name. This is like taking slice of object.

  • Default values in case extracted value is undefined.
const person = {
  name: "Hrishi",
  age: 27,
  email: "example@email.com",
};
const {
  fname: firstName = "john",
  lname: lastName = "doe",
} = person;
Enter fullscreen mode Exit fullscreen mode

default values can be given using = if extraction results in undefined. Just like we saw earlier, this only works for undefined and not other falsy values. In code snippet, fname and lname don't exist in person so firstName gets default value of john and lastName gets default value of doe.

  • Declaration and assignment don't need to be together.
const person = {
  name: "Hrishi",
  age: 27,
  email: "example@email.com",
};

const tmp = {};
({
  name: tmp.name,
  age: tmp.age,
  email: tmp.email,
} = person);

Enter fullscreen mode Exit fullscreen mode

Here we are declaring empty object tmp and then creating name , age and email properties on it with corresponding values from person. There's slight variation here from array example if you can spot it. It's the () brackets that we wrapped whole destructuring statement with. This is required because without the () javaScript treats it as a block resulting in SyntaxError.

  • Fallback in case whole structure is undefined / null.
function getPerson(){
return null;
};

const {name = 'john' , age = 'doe'} = getPerson() || {};
Enter fullscreen mode Exit fullscreen mode

If getPerson() returns null or undefined and we didn't provide default fallback with ||, this will result in TypeError. It's always good practice to employ default assignment and fallback.

  • Nested pattern for nested objects.
const person = {
  name: "Hrishi",
  age: 27,
  email: "example@email.com",
  address: {
    street: "xyz",
    state: "abc",
    country: "IN",
  },
};

const { name, email, address: { street, country } } = person;
Enter fullscreen mode Exit fullscreen mode

Makes sense. address is a nested object. We specify using nested destructuring pattern that from address property which is an object, we want street and country values. All other principles apply to nested pattern as well.

  • Destructuring in function parameters.
function doSomething({
  name = "john",
  email = "example@email.com",
  age = 0,
} = {}) {
  //do something cool.
}

doSomething({ name: "hrishi", age: 27 });
Enter fullscreen mode Exit fullscreen mode

doSomething expects an object as the only argument. We are destructuring that in place. As a good practice we are providing default assignments and fallback. This doesn't mean you can't pass more arguments or anything like that. When your function expects an object as argument you can destructure it in it's place and get stuff you need. This also emulates the named arguments features of other languages.

Mixing Object & Array destructuring

const city = {
  name: "Xyz",
  state: "Pqr",
  location: [34.30485, 136.5445],
};

const {
  name,
  location: [latitude = 0.0, longitude = 0.0] = [],
} = city;
Enter fullscreen mode Exit fullscreen mode

location is a nested array in city. We are using array destructuring inside object destructuring pattern to get first element from location and assign it to variable latitude. We also provide default assignment to latitude of 0.0 if it doesn't exist. We provided default fallback to location in case it's undefined.
You are allowed to mix object inside array and vice versa when using destructuring.

That covers most of what you will need to know about destructuring when working with ES6 code.


Top comments (0)