51

Background

When I tried destructuring assignment with arrays I was able to pre-declare my variables:

let a, b, c;
let arr = [1, 2, 3, 4, 5];
[a, b, c] = arr;

console.log(a) // logs 1
console.log(b) // logs 2
console.log(c) // logs 3

This went through the Babel compiler just fine.

However when I tried to do the same with objects I got an error

let a, b, c
let obj = {cat: 'meow', dog: 'woof', mouse: 'squeak'};
{cat: a, dog: b, mouse: c} = obj;

console.log(a) // I want this to log 'meow'
console.log(b) // I want this to log 'woof'
console.log(c) // I want this to log 'squeak'

Question

Is this an ES6 or Babel quirk/problem? If it's intentional for ES6, why the difference from the way arrays are treated?

Note

I understand that replacing var with let means I'm not required to pre-declare my variables and that having the let inline is valid (and, I believe, generally prefered). I'd like to know about the difference between implementations rather than a "don't do it like that at all" answer.

Lucy Bain
  • 2,496
  • 7
  • 30
  • 45
  • What are you even trying to accomplish with this: `{cat: a, dog: b, mouse: c} = obj;`? You have a fully formed object in `obj`. If you want to copy it to another object, you use `Object.assign()`. – jfriend00 Jan 17 '16 at 07:36
  • @jfriend00 I'm learning about how destructing assignment works - the examples are purely for learning purposes. But the general purpose would be to assign values to `a`, `b`, `c` rather than creating a new object. Destructuring should *break down* rather than copy. – Lucy Bain Jan 17 '16 at 07:41
  • Then, you can just use a normal declaration: `let myObj = {cat: a, dog: b, mouse: c};`. You don't need destructuring for that. If you want to assign the properties in your already existing object from the values of `a`, `b` and `c`, then you just have to assign them manually `obj.cat = a;`. – jfriend00 Jan 17 '16 at 07:42
  • But I want to assign `'meow'` to `a`, `'woof'` to b, and `'squeak'` to `c`. In your example what is the value of `a`? – Lucy Bain Jan 17 '16 at 07:46

1 Answers1

132

When you are destructuring an Object,

  1. you need to use the same variable names as the keys in the object. Only then you will get one to one correspondence and the values will be destructured properly.

  2. and you need to wrap the entire assignment in parenthesis if you are not using declaration statement, otherwise the object literal in the left hand side expression would be considered as a block and you will get syntax error.


So your fixed code would look like this

'use strict';
let cat, dog, mouse;
let obj = {cat: 'meow', dog: 'woof', mouse: 'squeak'};
({cat, dog, mouse} = obj);     // Note the `()` around

which is equivalent to

'use strict';
let obj = {cat: 'meow', dog: 'woof', mouse: 'squeak'};
let {cat, dog, mouse} = obj;
Damian Green
  • 6,895
  • 2
  • 31
  • 43
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 3
    Ah, thank you! It was the wrapping parens I didn't understand. Thanks for clarifying that it would otherwise be considered a block - makes much more sense now :) – Lucy Bain Jan 17 '16 at 07:36
  • Except for the "wrapping parens", The answer is wrong :( – Refael Ackermann Jan 18 '17 at 19:01
  • @Refael Could you explain why the answer is wrong? – thefourtheye Jan 19 '17 at 07:35
  • @thefourtheye I have no idea what I was thinking back then... probably ```let a, b, c; let obj = {cat: 'meow', dog: 'woof', mouse: 'squeak'}; ({cat: a, dog: b, mouse: c} = obj);``` – Refael Ackermann Aug 03 '17 at 03:25
  • 3
    Note that automatic semicolon insertion fails when a line starts with "opening something", including a parenthesis. So if you're omitting semicolons, there needs to be one _somewhere_ between it and the previous statement, e.g.: `;({cat, dog, mouse} = obj)` – Eric Haynes Aug 18 '18 at 03:07
  • @thefourtheye let a, b, c let obj = {cat: 'meow', dog: 'woof', mouse: 'squeak'}; ({cat: a, dog: b, mouse: c} = obj) This also works fine. Which contradicts your first point. – Gaurav Jain Aug 07 '20 at 12:23