3

Can someone explain me why

const getabc = ()=> ({a:'aa',b:'bb',c:123});
let a, b, c;
{ a, b, c } = {...getabc()}

this works

and

const getabc = ()=> ({a:'aa',b:'bb',c:123});
let a, b, c;
{ a, b, c } = {...getabc()};

this does not (note semicolon at the end)

DevThiman
  • 920
  • 1
  • 9
  • 24
Andrey Putilov
  • 148
  • 4
  • 13
  • 3
    why spreading? it is superfluous. – Nina Scholz Jun 23 '18 at 17:06
  • 1
    @NinaScholz https://stackoverflow.com/help/mcve This is a minimum example. – Raymond Chen Jun 23 '18 at 17:07
  • First one doesn't work on Firefox, got `SyntaxError: expected expression, got '=' ` – Jorjon Jun 23 '18 at 17:10
  • 1
    @RaymondChen, what have i to do with mcve? the object is generated with another object. the generated object is used for destructuring and never used again. the properties are transfered. so it is superfluous. – Nina Scholz Jun 23 '18 at 17:10
  • 1
    Both of them produce an error in Chrome. – JLRishe Jun 23 '18 at 17:20
  • @NinaScholz Presumably the OP has a more complicated example of the spread operator not working, but simplified to the three-line example so that we can focus on the specific issue rather than being distracted by the rest of the program which is not related to the problem. – Raymond Chen Jun 24 '18 at 02:20

3 Answers3

7

This has nothing to do with spread syntax or semicolons.

Object destructuring assignments that are not preceded with something like var, const, or let must use parentheses (or in some other way occur as a an expression within a larger statement containing it) because otherwise JS will parse the opening brace as the beginning of a block:

const getabc = ()=>({a:'aa',b:'bb',c:123});
let a, b, c;
({ a, b, c } = {...getabc()});

At the same time, there is no point in using spread syntax here, so you can remove that:

const getabc = ()=>({a:'aa',b:'bb',c:123});
let a, b, c;
({ a, b, c } = getabc());
JLRishe
  • 99,490
  • 19
  • 131
  • 169
5

You are missing the parentheshis, as per MDN documentation:

A variable can be assigned its value with destructuring separate from its declaration.

var a, b;

({a, b} = {a: 1, b: 2});

const getabc = ()=>({a:'aa',b:'bb',c:123});
let a, b, c;
({ a, b, c } = {...getabc()});
console.log(a,b,c);

My guess is that the first one is an error in Chrome implementation, since Firefox throws an error.

Chrome

enter image description here

Firefox

enter image description here

Jorjon
  • 5,316
  • 1
  • 41
  • 58
  • Chrome gives the same error in both by OP given example also. – Ivar Jun 23 '18 at 17:16
  • @Ivar no, they are different. I have attached the output from the console from both Chrome and FF. – Jorjon Jun 23 '18 at 20:53
  • That is odd. It does indeed work that way from the command line. If I run the code snippets in OP's post, I do get the same error twice though. – Ivar Jun 23 '18 at 21:09
  • Like I said, probably a bug in the implementation – Jorjon Jun 23 '18 at 22:08
1

This is an artefact of Chrome's hidden way of helping developers. Namely it will auto-wrap certain expressions in parentheses (or evaluate them as if wrapped, there is no difference) so

{a} = {a: true}

is actually evaluated as if

({a} = {a: true})

The first one is not a valid statement, however, since the {} is evaluated as a code block - the same construct as if (cond) {} or for() {} or function() {}, instead of an object literal syntax or an object destructuring syntax.

Should be noted that this is the correct interpretation of the code - it should throw a syntax error because it's not valid:

{a} = {a: true}

adding parentheses can be done in to avoid the starting { being interpreted as a code block:

({a} = {a: true})

console.log(a);

Chrome's console hides that away from you. For comparison, Firefox also produces the same result - an error.

However, when you add a semicolon, then the expression stops being valid for parentheses: ({a} = {a: true};) makes no sense, so Chrome evaluates it exactly as written which is also the correct interpretation in both cases:

{a} = {a: true};

This behaviour is only present in V8 related REPL environments. The same can be observed in Opera or a Node.JS REPL, for example. When evaluating code which is in a normal context and not the REPLs regular parsing rules are used and the expression {a} = {a: true} throws an error. See here on repl.it or test at another place

  • create a file that contains {a} = {a: true} and execute it via node (middle panel in repl.it)
  • entering the same code in a node REPL (right panel in repl.it)

In case you wonder "why not just ignore the code blocks in the general case", that will potentially lead to errors or at the very least confusing grammar. For example, this is valid code which uses code blocks:

let a = 1;

{
  let a = 2;
  console.log("inside block", a);
}

console.log("outside block", a);

Treating the { and } as anything other than a code block would be a problem.

VLAZ
  • 26,331
  • 9
  • 49
  • 67