You may not know destructuring yet

mpratapdev

Mahesh Pratap

Posted on November 17, 2020

You may not know destructuring yet

It's been a while since ES6 introduced the destructuring assignment, which is now supported in all major browsers. It can be used in any valid assignment operation i.e., variable assignment, function parameter assignment, etc. Let's get a basic overview of what destructing is first.

The syntax before the introduction of destructuring was too verbose for assigning values of an array or object to individual variables.

const array = [1, 2, 3];
const obj = { x: 4, y: 5, z: 6 };

const a = array[0], b = array[1], c = array[2];
const x = obj.x, y = obj.y, z = obj.z

console.log(a, b, c); // 1 2 3
console.log(x, y, z); // 4 5 6
Enter fullscreen mode Exit fullscreen mode

That's how we used to do in the pre-destructuring era. Now let's do it the ES6 way.

const array = [1, 2, 3];
const obj = { x: 4, y: 5, z: 6 };

const [ a, b, c ] = array;
const { x, y, z } = obj; 

console.log(a, b, c); // 1 2 3
console.log(x, y, z); // 4 5 6
Enter fullscreen mode Exit fullscreen mode

Way better. Having a basic idea, let's dig deeper.


Object property assignment pattern

Let's dig into that const { x, y, z } = obj syntax from the previous snippet. It's actually shorthand for const { x: x, y: y, z: z } = obj. If the property name being matched is the same as the variable you want to declare you can shorten the syntax. Here we leave x: part of { x: x, .. }.

Usually, assignment operations follow target=source or target: source pattern but in the destructuring assignment, source: target pattern is followed. Consider:

const obj = { x: 4, y: 5, z: 6 };
const { x: X, y: Y, z: Z } = obj;

console.log(X, Y, Z); // 4, 5, 6
Enter fullscreen mode Exit fullscreen mode

Here variables named X, Y, Z are declared and the values of obj.x, obj.y, obj.z is being assigned to them respectively. Hence, if the property name being matched is the same as the variable, you can use the shorthand. JS engine will do our work for us while we keep our code clean.

Assign later

As mentioned earlier destructuring can be used in any valid assignment operation. This means you don't always need to use destructuring operation while declaring variables. For already declared variable destructuring only does assignments, exactly as we have seen with other variable assignments. Consider:

let a, b, c, x, y, z;

[a, b, c] = [1, 2, 3];
({x, y, z} = { x: 4, y: 5, z: 6 });

console.log(a, b, c, x, y, z); // 1 2 3 4 5 6
Enter fullscreen mode Exit fullscreen mode

We need to wrap the whole assignment expression in () for object destructuring, otherwise { .. } on the LHS will be treated as a block statement instead of an object.

The assignment expressions don't need to be just variable identifiers. Anything that's a valid assignment expression is allowed. For example:

// Object assignment
const obj = {};
const computedProp = 'z';

[obj.a, obj.b, obj.c] = [1, 2, 3];
({ x: obj.x, y: obj.y, [computedProp]: obj[computedProp] } = { x: 4, y: 5, z: 6 });

console.log(obj.a, obj.b, obj.c); // 1 2 3
console.log(obj.x, obj.y, obj.z); // 4 5 6
Enter fullscreen mode Exit fullscreen mode
// Array assignment
let array = [];

({ x: array[0], y: array[1], z: array[2]  } = { x: 4, y: 5, z: 6 });

console.log(array); // [4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

Remember that traditional "swap two variables without temp variable" question, now we have a new solution for that:

let x = 10, y = 20;

[y, x] = [x, y];

console.log(x, y); // 20 10
Enter fullscreen mode Exit fullscreen mode

Repeated Assignments

The object destructuring form allows a source property to be listed multiple times. For example:

const { a: X, a: Y } = { a: 1 };

console.log(X, Y); // 1 1
Enter fullscreen mode Exit fullscreen mode

This is not possible in array destructuring, obviously 😒️.

Chaining

The return value of any destructuring assignment expression is the source object/array. Let's see what that means:

let a, b, c, x, y, z;

console.log({x, y, z } = { x: 4, y: 5, z: 6 }); // { x: 4, y: 5, z: 6 }
console.log([a, b, c] = [1, 2, 3]); // [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

By carrying the object value through as the completion, you can chain destructuring assignment expressions together:

let a, b, c, x, y, z;

[a, b] = [c] = [1, 2, 3];
( {x} = {y,z} = {x: 4, y: 5, z: 6} );

console.log(a, b, c); // 1 2 1
console.log(x, y, z); // 4 5 6
Enter fullscreen mode Exit fullscreen mode

[a, b] = [c] = [1, 2, 3] & ( {x} = {y,z} = {x: 4, y: 5, z: 6} ) is evaluated right to left (i.e., return value of [c] = [1, 2, 3] is assigned to [a, b] similarly, the return value of {y,z} = {x: 4, y: 5, z: 6} is assigned to {x}.

Optional Assignment

You don't have to assign all the values that are present in the source object/array in the destructuring assignment. For example:

const [,,c] = [1, 2, 3];
const { y } = { x: 4, y: 5, z: 6 };

console.log(c, y); // 3 5 
Enter fullscreen mode Exit fullscreen mode

You can skip the values that are not required in the current scope.

Gathering

You can use the rest syntax in a destructuring assignment to gather values in a single variable. For example:

const [a, ...b] = [1, 2, 3];
const { x, ...y } = { x: 4, y: 5, z: 6 };

console.log(a, b); // 1 [2, 3]
console.log(x, y); // 4 { y: 5, z: 6 }
Enter fullscreen mode Exit fullscreen mode

It behaves similarly to the Functions Rest Parameters.

Default Value Assignment

You can provide a default value for an assignment in both object and array destructuring assignments. For example:

const { w = 7, x = 8, y, z } = { x: 4, y: 5, z: 6 };
const [ a = 9, b, c, d = 10 ] = [1, 2, 3];

console.log(w, x, y, z); // 7 4 5 6
console.log(a, b, c, d); // 1 2 3 10
Enter fullscreen mode Exit fullscreen mode

Default values will be applied for missing values in the source array/object. It is similar to the Default function parameters.

You can combine the default variable assignment with alternative assignment expression syntax. For example:

const { w: WW = 10, x, y, z } = { x: 4, y: 5, z: 6 };

console.log(WW, x, y, z); // 10 4 5 6
Enter fullscreen mode Exit fullscreen mode

Nested Destructuring

If the values you're destructuring have nested objects or arrays, you can destructure those values too:

const array = [ 1, [2, 3, 4], 5 ];

const obj = { 
  x: {
    y: {
      z: 6
    }   
  }
}

const [ a, [ b, c, d ], e ] = array;

const { 
  x: { 
    y: { 
      z: w 
    } 
  } 
} = obj;

console.log(a, b, c, d, e); // 1 2 3 4 5
consoel.log(x); // {y: {z: 6}}
console.log(y) // {z: 6}
console.log(w); // 6
Enter fullscreen mode Exit fullscreen mode

Destructuring Parameters

All the above rules apply while destructuring function parameters too, as behind the scene the arguments are being assigned to parameters. For example:

function baz([x, y]) {
  console.log(x, y);
}

baz([1, 2]); // 1 2
baz([1]); // 1 undefined
baz([, 2]); // undefined 2
Enter fullscreen mode Exit fullscreen mode

Source
[1]: You Don't Know JS: ES6 & Beyond By Kyle Simpson

💖 💪 🙅 🚩
mpratapdev
Mahesh Pratap

Posted on November 17, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

You may not know destructuring yet
javascript You may not know destructuring yet

November 17, 2020