2

alert("There will be an error")
[1, 2].forEach(alert)

Now if I run the code, only the first alert is shown and then we have an error! I know why we have an error (no Automatic semicolon insertion) but I don`t understand error message: Uncaught TypeError: Cannot read property '2' of undefined. How JavaScript interpreter read this code?

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • 2
    I know, my question is : How JavaScript interpreter read this code? Why can JS read property '2' of undefined ? – Juraj Pecháč Jul 11 '19 at 11:28
  • [What are the rules for JavaScript's automatic semicolon insertion (ASI)?](https://stackoverflow.com/questions/2846283) – adiga Jul 11 '19 at 11:28
  • 2
    It sees your code as `alert("There will be an error")[1, 2].forEach(alert)`, i.e. it's all one statement. The first alert returns undefined, so you have `undefined[1,2].forEach(alert)`. So you're trying to access the `2` property of *undefined*. – RobG Jul 11 '19 at 11:32
  • Possible duplicate of [What are the rules for JavaScript's automatic semicolon insertion (ASI)?](https://stackoverflow.com/questions/2846283/what-are-the-rules-for-javascripts-automatic-semicolon-insertion-asi) – VLAZ Jul 11 '19 at 13:29

2 Answers2

7

When you have <expression>[...], the interpreter will attempt to look up a property on expression. When the inside of the brackets contains commas, you're invoking the comma operator, which evaluates to the value of the last item in the list. So

foo[1, 2]

is equivalent to

foo[2]

That's exactly what's happening here:

alert("There will be an error")
[1, 2].forEach(alert)

equivalent to

alert("There will be an error")
[2].forEach(alert)

equivalent to

alert("There will be an error")[2].forEach(alert)

equivalent to (without the alert message)

undefined[2].forEach(alert)

That's where the "2" comes from. alert returns undefined, so the error message is Uncaught TypeError: Cannot read property '2' of undefined.

The [1, 2] does not get evaluated as an array, even though it kind of looks like one.

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
0

If you write JS without semicolons at the end of each line it will sometimes complain if you start a line with:

[, (, or any of the arithmetic operators +, -, *, /.

Explained further here: https://medium.com/@goatslacker/no-you-dont-need-semicolons-148d936b9cf2

So you can avoid this by defining an array as a variable.

alert("There will be an error")
var a = [1, 2]
a.forEach(alert)
Rob Kwasowski
  • 2,415
  • 2
  • 7
  • 28
  • "*It will complain*" only if the resulting expression causes a syntax or runtime error. It's fairly common to split long statements over multiple lines, often at a dot property accessor (though I'm not a fan of that). – RobG Jul 11 '19 at 11:45