Why does this work:
a = []
a.push(['test']);
(function() {alert('poop')})()
But this gives the error "number is not a function":
a = []
a.push(['test'])
(function() {alert('poop')})()
The only difference is the semicolon at the end of line 2. I've been writing Javascript for a long time now. I know about automatic semicolon insertion, but I can't figure out what would be causing this error.
I'm not a Javascript expert (or even a newbie :), but if you combine the second and third lines, it still looks syntactically valid:
That's trying to treat the result of
a.push(['test'])
as a function, passing a function into it... and then calling the result as a function as well.I suspect that the semi-colon is required if the two statements can be syntactically combined into a single statement, but that's not what you want.
a.push(['test'])
will return the length of the array, a number. Without a semicolon following, the compiler will then interpret the opening parentheses of self-invoking function following as if you're trying to execute that number as a function with arguments. Let's say it returned a length of 7, then essentially what is happening here is as if you wrote:Hence the error "number is not a function" because it doesn't know how to invoke 7 as a function.
a.push(['test'])
returns a number.You then attempt to call the number as a function with
function() {alert('poop')}
as the only argument.Hence your error,
number is not a function
.Take a look at this example of chained function calls.
Look familiar? This is how the compiler/interpreter views your code.
Detail
Here is a portion of the grammar used to describe call expressions.
Essentially each group (...) is considered as Arguments to the original MemberExpression
a.push
.Or more formally
The result of a.push() is the size of the returned array, in this case, 1. The enclosing parentheses around your function make the Javascript parser think that you're trying to call:
Or that you're trying to call a function called
1
with an anonymous function as a parameter, then execute the return as a function.There are cases where white space is not required as a token separator but only used to improve readability:
In this case the white space between
a.push(['test'])
and(function() {alert('poop')})()
is not for token separator and thus insignificant. So it’s equivalent to this:And since
a
references an empty array with the length 0, callinga.push(['test'])
appends one element toa
and returns the updated value ofa.length
, i.e.1
:And the rest is history.