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;
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;
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;
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;
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;
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;
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;
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;
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;
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];
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() || [];
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]);
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;
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;
- Trying to extract non-existing values.
const person = { name: "Hrishi", age: 27, email: "example@email.com" };
const { name, email, address } = person;
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;
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;
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;
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);
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() || {};
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;
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 });
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;
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)