2

When I run this code, it works, as you would expect:

var b = {}
b['foo']=[]
b['foo'].push(1)

But when I try doing this as a one-liner, like this:

var b = {}
(b['foo']=[]).push(1)

It throws: Cannot set properties of undefined (setting 'foo'), even though b is very clearly defined.

Could someone explain this behavior? Thanks in advance.

Edit: For some reason, adding the semicolon fixes the issue, which confirms that the compiler was in fact trying to run it as a function. But now I have another question: Why did it throw an error saying b is not defined, instead of b is not a function?

Daavee18
  • 142
  • 8
  • 3
    Try adding a `;` at the end of your lines. Because right now it is trying to execute `{}` as a function, which obviously won't work – Reyno Jul 09 '22 at 11:58
  • 2
    Does this answer your question? [Is a semicolon required before a function closure in javascript?](https://stackoverflow.com/questions/56195773/is-a-semicolon-required-before-a-function-closure-in-javascript) – Reyno Jul 09 '22 at 11:59
  • @Reyno That could be the answer, but wouldn't it throw something along the lines of `b` isn't a function if that were the case? – Daavee18 Jul 09 '22 at 12:04
  • Reyno: If it was parsed that way, shouldn't the error message be "Uncaught TypeError: {} is not a function"? – Luatic Jul 09 '22 at 12:04
  • @Daavee18 yes and no. Since `b['foo']=[]` is evaluated before `{}()` it will throw your error. Otherwise we indeed get something like *"{} is not a function"* or *"unexpected token ')'"* – Reyno Jul 09 '22 at 12:09
  • @Reyno Oh, I get it now, it was trying to parse `b['foo']` as an argument. If you post this as an answer, I'll accept it. Thanks! – Daavee18 Jul 09 '22 at 12:11
  • @LMD already did a great job creating an answer, no need for duplicate answers. I got my credits, you can mark his as an answer. – Reyno Jul 09 '22 at 12:15

1 Answers1

2

As noted by Reyno, this is parsed as

var b = {}(b['foo']=[]).push(1)

since there is no semicolon delimiting var b = {} and (b['foo']=[]).push(1), thus the rules of automatic semicolon insertion apply. The question that remains is why this throws

Cannot set properties of undefined (setting 'foo')

rather than

Uncaught TypeError: {} is not a function

which ought to be thrown for {}(). The reason for this is that

var b = {}(b['foo']=[]).push(1)

is equivalent to

var b; b = {}(b['foo']=[]).push(1)

The right-hand side of the assignment is evaluated first, so before the call is made, it evaluates b['foo'] to evaluate the inner assignment, but b is undefined, leading to the error Cannot set properties of undefined (setting 'foo').

Luatic
  • 8,513
  • 2
  • 13
  • 34
  • The [Rules of Automatic Semicolon Insertion](https://tc39.es/ecma262/#sec-rules-of-automatic-semicolon-insertion) should be mentioned, as they explain why the new line is parsed as a function call. – Christopher Jul 09 '22 at 12:35