Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is { a: y = 1 } = { b: 2 } valid and { a: 1 } = { b: 2 } a SyntaxError?

Tags:

javascript

I do not understand why these two JS expressions are not equivalent

In order to get better at JS, I am experimenting with some javascript expressions. Here is my latest discovery:

{ a: y = 1 } = { b: 2 } // {b: 2}
{ a: 1     } = { b: 2 } // Uncaught SyntaxError: Unexpected token =

Could anyone help me understand that?

like image 788
bartocc Avatar asked Sep 04 '19 08:09

bartocc


1 Answers

First of all, that is not the correct syntax for destructuring assignments without declarations.

The parentheses ( ... ) around the assignment statement are required when using object literal destructuring assignment without a declaration.

{a, b} = {a: 1, b: 2} is not valid stand-alone syntax, as the {a, b} on the left-hand side is considered a block and not an object literal.

You can write one of the following:

// assignment with declaration
const { a: y = 1 } = { b: 2 }
const { a: 1     } = { b: 2 }

// without declaration
({ a: y = 1 } = { b: 2 })
({ a: 1     } = { b: 2 })

const { a: y = 1 } = { b: 2 } will create a new variable y with value 1. a cannot be destructured from { b: 2 }, but has a default value of 1. a will also be assigned to a new variable name y.

({ a: 1 } = { b: 2 }) won't work, because a cannot be destructured and has no default value. Hence, you get SyntaxError: invalid destructuring target.

Update - Some more background:

The destructuring assignment is an expression. If you type { a: y = 1 } = { b: 2 } in browser console, you'll get SyntaxError: expected expression, got '=', so the code cannot interpreted as an expression - instead it is considered a block (zero or more statements). There is a solution - you can use parentheses to enforce an explicit expression context. That's the reason, why ({ a: y = 1 } = { b: 2 }) works. You can also type console.log({ a: y = 1 } = { b: 2 }) in browser console, as the engine can be sure of the function argument to be an expression.

Also have a look at this quote:

[...] with expression statements, there is an overlap: There, you have expressions that appear in a statement context. In order to prevent ambiguity, the JavaScript grammar forbids expression statements to start with a curly brace or with the keyword function.

So what do you do if you want to write an expression statement that starts with either of those two tokens? You can put it in parentheses, which does not change its result, but ensures that it appears in an expression-only context.

Update 2 - Regarding browser/JavaScript engine differences

When you type { a: y = 1 } = { b: 2 } in the console, you get following output:

  • Firefox: SyntaxError: expected expression, got '='
  • Chrome and Node (both V8 engine):{b: 2}

Duh, why is that? The output from Chrome/Node is a sign that the code is indeed evaluated as expression by console, as it evaluates to the value {b:2} on the right side of the equality sign (quote):

[...] conceptually, there are two types of expressions: with side effects (for example: those that assign value to a variable) and those that in some sense evaluate and therefore resolve to a value.

The expression x = 7 is an example of the first type. This expression uses the = operator to assign the value seven to the variable x. The expression itself evaluates to seven.

If you type eval('{ a: y = 1 } = { b: 2 }') instead in Chrome/Node console, you'll get Uncaught SyntaxError: Unexpected token '=', which is the correct behavior! eval('var { a: y = 1 } = { b: 2 }') works as usual. I think, it's a strong sign, that the console itself actively tries to interpret the code as expression here and V8 engine works properly without a bug.

like image 138
ford04 Avatar answered Sep 27 '22 22:09

ford04