Object Destructuring and a Semicolon

I’ve spent hours to figure this out. My project is configured to us standardjs, so there is no semicolon after each line.

Now consider the following example of object destructuring where variable is declared before assignment:

let href
({href} = window.location)
console.log(href)

Notice the round braces ( … ) around the assignment statement is required syntax when using object literal destructuring assignment without a declaration.

Let’s do another destructuring right below it:

let href, pathname
({href} = window.location)
({pathname} = window.location)
console.log(href, pathname)

And that gives you a SyntaxError:

Uncaught SyntaxError: Unexpected token (

So what’s going on here? It even complains if I do the destructuring right after a function call like:

let href
somefunc()
({href} = window.location)

Turns out that I missed a little note in the MDN documentation:

NOTE: Your ( ..) expression needs to be preceded by a semicolon or it may be used to execute a function on the previous line.

Without the semicolon, when parsing, Javascript engine considers both lines as a single call expression. First line is the Callee and second line is parsed as arguments to it. You can run it through any parsers available at astexplorer.net and get a similar AST like following(removed some properties for brevity):

{
  "body": [
    {
      "type": "ExpressionStatement",
      "expression": {
        "type": "CallExpression",
        "callee": {
          "type": "CallExpression",
          "callee": {
            "type": "Identifier",
            "name": "somefunc"
          }
        },
        "arguments": [
          {
            "type": "AssignmentExpression",
            "operator": "=",
            "left": {
              "type": "ObjectPattern",
              "properties": [
                {
                  "type": "Property",
                  "key": {
                    "type": "Identifier",
                    "name": "href"
                  }
                }
              ]
            },
            "right": {
              "type": "MemberExpression",
              "object": {
                "type": "Identifier",
                "name": "window"
              },
              "property": {
                "type": "Identifier",
                "name": "location"
              }
            }
          }
        ]
      }
    }
  ]
}

So the fix here is to put a semi-color right before the destructuring expression and surprisingly the linter doesn’t mind this semicolon either:

let href
somefunc()
;({href} = window.location)

References

  1. astexplorer.net
  2. Object Destructuring on MDN