Destructuring is a new ES6 technique for extracting data from JavaScript objects and arrays using a much tighter, terser, and clearer syntax than that provided by ES5. The result is not just the saving of a few bytes of code; destructuring can change the way you code in radically new ways, and the more you use it, the more ways you’ll find of shaping your data and functions in ways that were simply impossible before. This article goes deep into destructuring, providing you with all you need to know about this magical new syntax.

What is Destructuring?

Destructuring is the opposite of data construction. Rather than constructing a new object or array, for example, destructuring takes data from an existing object or array and literally destructs it to extract only the values you’re interested in.

It does this through the use of a pattern that’s used by ES6 to match the values that you want to extract. This pattern mirrors the structure of the data item you’re destrucuturing, with only those parts of the data item that match the pattern, being extracted.

The data item being destructured lies on the right-hand side of an assignment, and can be any combination of objects and arrays, nested arbitrarily deep. The number of variables you use to assign this data to is not limited.

This article presents a deep dive into everything you need to know about destructuring. To get a better feel for how destructuring works, take a look at the code in runnable form in the accompanying Array Destructuring and Object Destructuring fiddles.

Destructuring Arrays

Array destructuring uses an array as a data item, from which you extract values and assign them to one or more variables according to an array pattern, which is used to match the values you need from the array.

This array pattern uses the position of a value to identify the values you want to extract. It must exactly mirror the structure of the array being destructured, with each variable in the array pattern being assigned the value that corresponds to the same position in the array being destructured.

Some examples will help clarify things.

Example Array Patterns

Assign all items in an array to individual variables


   // Setup our array
   const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];

   // Destructure array into individual variables. The array pattern
   // is on the left of the assignment (i.e. the '=') and the array being
   // destructured on the right.
   const [ironMan, cap, blackWidow] = avengers;

   // ironMan = 'Tony Stark' 
   // cap = 'Steve Rogers'
   // blackWidow = 'Natasha Romanoff'

   // Output ironMan:
   ironMan;


Extract all but the first item


   const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];

   // We don't need you, Tony
   const [, cap, blackWidow] = avengers;

   // ironMan = Error: undefined 
   // cap = 'Steve Rogers'
   // blackWidow = 'Natasha Romanoff'

   // Output cap:
   cap;


Extract all but the second item


   const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];

   // Missing cap
   const [ironMan, , blackWidow] = avengers;

   // ironMan = 'Tony Stark' 
   // cap = Error: undefined
   // blackWidow = 'Natasha Romanoff'

   // Output blackWidow:
   blackWidow;


Extract all but the last item


   const avengers = ['Tony Stark', 'Steve Rogers', 'Natasha Romanoff'];

   // ironMan vs cap
   const [ironMan, cap] = avengers;

   // ironMan = 'Tony Stark' 
   // cap = 'Steve Rogers'
   // blackWidow = Error: undefined

   // Output blackWidow:
   ironMan;

Nested Arrays

This concept of pattern matching also works with nested arrays – just ensure the array pattern on the left of the assignment matches the array structure on the right, and again, each variable declared in the array pattern is assigned the value corresponding to its equivalent position in the destructured array. You can nest arrays arbitrarily deep and still destructure from them.

Destructure a nested array


   // Destructuring Nested Arrays
   const avengers = [
                       'Natasha Romanoff', 
                       ['Tony Stark', 'James Rhodes'], 
                       ['Steve Rogers', 'Sam Wilson']
                    ];
   
   // Avengers and their partners
   const [blackWidow, [ironMan, warMachine], [cap, falcon]] = avengers;
  
   // blackWidow = 'Natasha Romanoff'
   // ironMan = 'Tony Stark'
   // warMachine = 'James Rhodes'
   // cap = 'Steve Rogers'
   // falcon = 'Sam Wilson'

   // Output warMachine:
   warMachine;


Pluck a single value from a deeply nested array


   // Plucking Pepper Potts from a deeply nested Array
   const avengers = [
                        'Natasha Romanoff', 
                        [['Tony Stark', 'Pepper Potts'], 'James Rhodes'], 
                        ['Steve Rogers', 'Sam Wilson']
                    ];

   // Destructure
   const [
             ,    // Skip over 'Natasha Romanoff'
             [[
             ,    // Skip over 'Tony Stark'
             hera // Pepper Potts, assigned to a variable called 'hera'
         ]]] = avengers;

   // Note: you can also write this like so:
   // const [, [[, hera ]]] = avengers;
  
   // Output hera:
   hera;

   // hera = 'Pepper Potts'

Capture all remaining items with …rest

If you want to capture specific array items, but dump the remaining items in their own array, you can do so by destructuring with the rest operator (…), like so:


   // Destructuring with the ...rest operator
   const avengers = ['Natasha Romanoff', 'Tony Stark', 'Steve Rogers'];
   
   const [blackWidow, ...theOthers] = avengers;

   theOthers;
   // blackWidow = 'Natasha Romanoff'
   // theOthers = ['Tony Stark', 'Steve Rogers']

   // Output theOthers:
   theOthers;


Destructuring Objects

Destructuring objects is even more awesome, particularly if you have a complex, deeply nested object whose property values you want to extract. Again, the same rules apply as with arrays – just create an object pattern on the left-hand side of your assignment with the position of the variables you wish to assign to matching the position of values you wish to extract from the object.

With object destructuring, you need to provide the property name whose value you wish to extract, and the name of the variable you want to store the property value in. As with arrays, we need to create an object pattern on the left side of our destructuring assignment that mirrors the object being destructured.

In this case, though, the value that we’re trying to extract is an object property’s value (i.e. we want value in { prop: value }). Accordingly, our object pattern must have a variable in exactly the same position as the property value we’re trying to extract.

Simple Examples

Extract a single object property value

To assign the value 'Tony Stark' to a variable called a from the property ironMan in the object { ironMan: 'Tony Stark' }, we’d do the following:


  // Destructure object's property value to an individual variable called 'a'
  const { ironMan: a } = { ironMan: 'Tony Stark' };
  
  // Output a:
  a;   // a = 'Tony Stark '


Extract multiple property values

To extract multiple property values from an object, we just extend the same pattern:


  // Setup our object
  const avengers = {
    ironMan: 'Tony Stark', 
    cap: 'Steve Rogers', 
    blackWidow: 'Natasha Romanoff'
  };

  // Destructure object to individual variables
  const { 
    ironMan: a, 
    cap: b, 
    blackWidow: c 
  } = avengers;

  // a = 'Tony Stark '
  // b = 'Steve Rogers'
  // c ='Natasha Romanoff'

  // Output a:
  a;


Notice how the destructuring pattern matches exactly the object that we’re destructuring.


Nested Object destructuring

Like nested arrays, we can destructure nested objects of arbitrary depth.


  // Setup our object
  const avengers = {
    blackWidow: 'Natasha Romanoff',
    ironManCharacters: {
      couple: {
        ironMan: 'Tony Stark', 
        hera: 'Pepper Potts',
    },
    partner: {
      warMachine: 'James Brodie'
    }
    },
    capCharacters: {
      cap: 'Steve Rogers', 
      partner: {
        falcon: 'Sam Wilson'
      }
    }
  };

  // Destructure object to individual variables
  const { 
    blackWidow: a,
    ironManCharacters: { 
      couple: {
        ironMan: b,
        hera: c
    },
      partner: {
        warMachine: d
      }
    },
    capCharacters: {
      cap: e,
      partner: {
       falcon: f
      }
    }
  } = avengers;

  // a = 'Natasha Romanoff'
  // b = 'Tony Stark '
  // c = 'Pepper Potts'
  // d = 'James Brodie'
  // e = 'Steve Rogers'
  // f = 'Sam Wilson'

  // Output a:
  a;


Naming our extracted variables

Of course, naming our variables a, b, c, etc. is horrible, so let’s name them something more meaningful.

Verbose naming


  // Setup our object
  const avengers = {
    ironMan: 'Tony Stark', 
    cap: 'Steve Rogers', 
    blackWidow: 'Natasha Romanoff'
  };

  // Destructure object to individual variables with meaningful names
  const { 
    ironMan: ironMan,
    cap: cap, 
    blackWidow: blackWidow
  } = avengers;

  // blackWidow = 'Natasha Romanoff'
  // ironMan = 'Tony Stark '
  // cap = 'Steve Rogers'

  // Output blackWidow:
  blackWidow;

Better – but we can do better still. { ironMan: ironMan } seems somewhat ugly and not exactly DRY.

Syntactical naming shortcuts

If you want to assign the value of an object property to a variable of the same name as the property’s, you can simply list the property name once in the destructuring pattern, like so:


  // Setup our object
  const avenger = {
    ironMan: 'Tony Stark'
  };

  // Destructure object to individual variables with meaningful names
  const { 
    ironMan   // equivalent to 'ironMan: ironMan'
  } = avenger;

  // ironMan = 'Tony Stark '

  // Output ironMan:
  ironMan;


Because both destructured property name and the name of the variable we’re assigning it to are the same, we only need to list the name once.


Final terse syntax

By reformatting our code slightly, we can make it look terser and cleaner:


  // Setup our object
  const avengers = {
    ironMan: 'Tony Stark', 
    cap: 'Steve Rogers', 
    blackWidow: 'Natasha Romanoff'
  };

  // Destructure object to individual variables with meaningful names
  const { ironMan, cap, blackWidow } = avengers;

  // Output ironMan:
  ironMan;


Extracting a deeply nested property form an object

Things get even more interesting when we want to extract the value of a deeply nested property:


// Setup our object
const avengers = {
   blackWidow: 'Natasha Romanoff',
   ironManCharacters: {
      couple: {
         ironMan: 'Tony Stark',
         hera: 'Pepper Potts',
      },
      partner: {
         warMachine: 'James Brodie'
      }
   },
   capCharacters: {
      cap: 'Steve Rogers',
      partner: {
         falcon: 'Sam Wilson'
      }
   }
};

// Destructure a deeply nested object
const { ironManCharacters: { couple } } = avengers;

// couple = {
//    ironMan: 'Tony Stark', 
//    hera: 'Pepper Potts',
// }

// Output couple:
couple;


Wait, WTF?! How do you read this? And how in the world is couple the variable being defined here?

By breaking this down, we see that the left side of our assignment is mirroring part of the object we’re destructuring:


  const avengers = {
    ironManCharacters: {
      couple: {
          ironMan: 'Tony Stark', 
          hera: 'Pepper Potts',
      }
    }
};


const { 
   ironManCharacters: { 
      couple 
   }
} = avengers;

// Output couple:
couple;


Just using const { couple } = avengers; isn’t enough to extract the value of couple – you have to mirror the position of the property you want to extract as well as the property name. By doing this, you give the JavaScript compiler the information it needs to walk down the object’s properties and extract exactly the value you’re interested in.

Also notice that couple is using the syntactical shorthand for variable naming, so it’s actually:

const { 
   ironManCharacters: { 
      couple: couple
   }
} = avengers;

So that’s how couple is the variable that’s being defined, and its value is that of the object property named couple in the avengers object.

Destructure to object properties

So far we’ve destructured an object’s values to individual variables, but we can also destructure to another object’s properties:



const avengers = {
  blackWidow: 'Natasha Romanoff',
  ironManCharacters: {
    couple: {
      ironMan: 'Tony Stark',
      hera: 'Pepper Potts'
    }
  }
};

const ironManProperties = {
  family: {}
};

({
  ironManCharacters: {
    couple: ironManProperties.family
  }
} = avengers);

ironManProperties.family
// ironManProperties.family = {
//    ironMan: 'Tony Stark',
//    hera: 'Pepper Potts'
// }

// Output ironManProperties.family:
ironManProperties.family;


What we’re doing here is assigning the ironManCharacters.couple property to the ironManProperties.family property. There are two things to note here:

  1. The destructuring assignment is wrapped in parentheses
    We have to do this as we’re destructuring to an existing variable (ironManProperties in this case), rather than declaring a new variable (see below).
  2. We’re still pattern matching
    { ironManCharacters: { couple... } } matches the ironManCharacters pattern of the avengers object. This extracts the value of ironManCharacters.couple from the avengers object, as you’d expect. But now, as the new object ironManProperties and its property family is placed next to couple, it’s the object property ironManProperties.family that is assigned this value.

Confusing? Only when you try to explain it! Play around with it in this fiddle, and it’ll soon make sense.

If you’re wondering why you’d ever want to do something like this, take a look at the examples in the next post, where you’ll see how just such a pattern is used to destructure a JSON object from an API call. Then you’ll see how powerful destructuring can be.

Default Values

You can give a variable a default value during destructuring:


  // Setup our object
  const avengers = {
    ironMan: 'Tony Stark', 
    cap: 'Steve Rogers', 
    blackWidow: 'Natasha Romanoff'
  };

  // Destructure using defaults
  const { ironMan, cap, blackWidow, theHulk='Bruce Banner' } = avengers;

  // ironMan = 'Tony Stark' 
  // cap = 'Steve Rogers'
  // blackWidow = 'Natasha Romanoff'
  // theHulk = 'Bruce Banner'

  // Output blackWidow:
  blackWidow;

Things you can’t do with destructuring

Destructuring assignment without const, let or var

We already touched on this when discussing destructuring to an object property, but it’s worth noting again for clarity:

You can’t directly destructure to a variable that’s already been declared.

That is, you can only destructure to a variable that’s being declared at the same time (i.e. with a const, let, or var).


   // Setup our object
   const avengers = {
     ironMan: 'Tony Stark', 
     cap: 'Steve Rogers', 
     blackWidow: 'Natasha Romanoff',
     theHulk: 'Bruce Banner'
   };

   // Valid destructuring
   const { ironMan } = avengers;

   let { cap } = avengers;

   var { blackWidow } = avengers;

   // Invalid destructuring
   let theHulk;

   { theHulk } = avengers;
   // Error

   // Output theHulk:
   theHulk;

Why can you not destructure to a variable that’s already been declared? Because you cannot start a statement with a curly bracket ( { ), as JavaScript thinks you’re declaring a block.

The solution is to wrap the whole destructuring assignment up in parentheses

How to destructure to an already-declared variable


   // Setup our object
   const avengers = {
     ironMan: 'Tony Stark', 
     cap: 'Steve Rogers', 
     blackWidow: 'Natasha Romanoff',
     theHulk: 'Bruce Banner'
   };

   // A valid Hulk
   let theHulk;

   ({ theHulk } = avengers);
   // theHulk = 'Bruce Banner'

   // Output theHulk:
   theHulk;

Now we’re not starting the line with a curly bracket, so JavaScript doesn’t think we’re declaring a block, and so will start destructuring like we want it to.

Directly return a destructured assignment

You cannot directly return a value from a destructured assignment without first creating a variable that you then subsequently return. For example, the following will return the entire ironMan object, and not the value ‘Tony Stark’ that the function name promises:


  // Note: this doesn't work!
  function getTonyStark(avengers){
    return { ironMan: { realName } } = avengers;
    // return the avengers object, not the realName value
  }
  
  const avengers = {
    ironMan: {
      realName: 'Tony Stark'
    }
  };
  
  const tonyStark = getTonyStark(avengers);

  // tonyStark = {
  //   ironMan: {
  //     realName: 'Tony Stark'
  //   }
  // };

  // Output tonyStark:
  tonyStark;


To extract a value from a destructured object, you must first assign it to a variable, and then return that variable separately:


  // Note: this DOES work!
  function getTonyStark(avengers){
    const { ironMan: { realName } } = avengers;
    return realName;
  }
  
  const avengers = {
    ironMan: {
      realName: 'Tony Stark'
    }
  };
  
  const tonyStark = getTonyStark(avengers);
  
  // tonyStark = 'Tony Stark'

  // Output tonyStark:
  tonyStark;


This is annoying, as separating the assignment and return on two lines is ugly and seems unnecessary. Unfortunately, that’s how JavaScript destructuring works – you must first assign the destructured value to a variable and then return it separately.

Summary

That’s quite a deep dive of the key principles of destructuring. Just knowing how things work, though, isn’t enough to show you what you can actually do with this powerful construct.

In the next article, therefore, I’ve put together a list of some advanced destructuring techniques that really show the power of destructuring in ways you may never have thought of.

All posts in this series on destructuring

Fiddles for this article

Destructuring Articles around the Web

If you still want more, check out the following:

Comments
  • Harvey Specter
    Posted at 10:15 pm Jul 21, 2016
    Juan Jovi
    Reply
    Author

    I like the writeup, but would like to point out that currently there are some performance hits to array destructuring. So they are bad for tight loops.
    In my test, destructuring was about 24x times slower

    console.time('destructuring')
    for(var i=0; i<1e5; i++) { var [x,y] = [i, 2*i] }
    console.timeEnd('destructuring')
    // was ~ 40ms for me on chrome 51
    console.time('destructuring')
    for(var i=0; i<1e5; i++) { var x = i; var y = 2*i }
    console.timeEnd('destructuring')
    // was about 1.7 ms on chrome 51

  • Harvey Specter
    Posted at 8:38 am Jul 22, 2016
    Mike Evans
    Reply
    Author

    Thanks Juan, I wasn’t aware of that. Hopefully the JavaScript engines will optimize this performance issue soon.

  • Harvey Specter
    Posted at 9:50 am Jul 22, 2016
    Ivan
    Reply
    Author

    amazing. Nice structured and inline editing! Thank you for great reading :)

    p.s. please add a button – Facebook share

    • Harvey Specter
      Posted at 10:17 am Jul 22, 2016
      Mike Evans
      Reply
      Author

      Thanks Ivan. The Website’s still a bit rough around the edges, but I’ll certainly add the Facebook share button.

  • Harvey Specter
    Posted at 4:28 am Jul 25, 2016
    Allan Baptista
    Reply
    Author

    Nice article.

    But please, avoid the suggested:


    // ...
    return ({
    ironMan: {
    realName
    }
    } = avengers) && realName
    // ...

    … as it will introduce a new variable in the global scope.

    • Harvey Specter
      Posted at 8:55 am Jul 26, 2016
      Mike Evans
      Reply
      Author

      Yes, you’re right, Allan. Hadn’t even noticed that! I’ve removed the offending code. For those wondering what this referred to, in the section “Directly return a destructured argument”, I’d written a bit of code that returned a destructured argument in a much more terse manner using JavaScript’s short-circuit logical operator &&. Specifically, the code was as follows:

      
        function getTonyStark(avengers){
          return ({ ironMan: { realName } } = avengers) && realName;
        }
        
        const avengers = {
          ironMan: {
            realName: 'Tony Stark'
          }
        };
        
        const tonyStark = getTonyStark(avengers);
        // tonyStark = 'Tony Stark'
      
        // Output tonyStark:
        tonyStark;
      
      
      

      However, as Allan’s pointed out, because realName in the getTonyStark() function hasn’t been declared, JavaScript will declare it as a global variable. This can be fixed by declaring realName first (e.g. let realName; return ({ ironMan: { realName } } = avengers) && realName;), but then the code is just as verbose as the example it was meant to be replacing!

      Ultimately, I decided to remove the example altogether.

      Thanks for pointing this out, Allan.

  • Harvey Specter
    Posted at 8:50 am Mar 21, 2017
    Nenad
    Reply
    Author

    Love your website and all the knowledge shared :)
    keep up the good work
    cheers

  • Leave a Reply to Ivan
    Cancel Reply

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>