function Foo() {
var that = this;
that.bar = function() {}
that.baz = function() {}
(function() {
that.baz();
}());
}
new Foo;
Uncaught TypeError: Object #<Foo> has no method 'baz'
that.bar
works fine, it's only the last function that doesn't exist. Adding a ;
after the baz
function definition fixes everything.
I know excluding ;
can mess some things up, but I thought for sure you're not supposed to put ;
after functions. No language does that. Why does excluding the ;
after the baz
function cause this to break? Should I be putting ;
after my function definitions?
Contrary to Michael Geary's answer, assignment statements do not require semicolons.
Consider the humble immediately-invoked function expression:
(function() { /* do something */ })();
What are the extra parentheses wrapping the function() { ... }
for? They're to prevent it from being interpreted as a function definition, forcing it to be interpreted as a function expression. It's basically equivalent to this, but without creating another variable:
var temp = function() { /* do something */ };
temp();
But parentheses are only one way to introduce something that must be an expression. In particular, an initializer of an assignment statement will introduce an expression1:
someVar = /* what goes here must be an expression */;
Clearly, composing these concepts shows that in this:
someVar = (function() { return 5; })();
The wrapping parentheses are not actually needed! We could just as easily write this because the function()
cannot be interpreted as a function definition:
someVar = function() { return 5; } ();
So what does this have to do with semicolons? It turns out that if the next line can continue the statement or expression, it will.2 You've written this:
that.baz = function() {}
(function() {
that.baz();
}());
With this knowledge, you know it's actually being interpreted as this:
that.baz = (function() {})(function() {
that.baz();
}());
That's a bit tricky, so here's what's happening:
function() {}
is evaluated (not executed), yielding a function object.The only argument is the expression
function() {
that.baz();
}()
That's obviously an immediately-invoked function expression, so we'll begin executing it.
that.baz
and call it, but it fails because that.baz
does not exist and thus resolves to undefined
! Oh no! The JavaScript engine stops here because an uncaught exception was thrown, but for clarity, let's pretend it went on.
function() { that.baz(); }
, so the argument to function() {}
is undefined
.function() {}
proper. It never binds its argument, so the undefined
is ignored. It doesn't return anything, so the call results in undefined
.that.baz
to the result, undefined
.Hopefully you see now that the parser misinterpreted your immediately-invoked function expression as, well, an argument to another anonymous function, immediately invoking it.
As mentioned previously, parentheses are not the only way to unambiguously introduce an expression. In fact, when they're in the middle of the expression unintentionally, it can cause problems like this. We also mentioned assignments, but we don't want to assign something.
What's left? Unary operators. There's a few we can use. I like !
, so we'll use that. Rather than using:
(function() {
that.baz();
}());
We use:
!function() {
that.baz();
}();
The !
can only come at the start of an expression, so JavaScript starts parsing an expression. Only an expression can come after !
, so the function is parsed as a function expression rather than a function definition. Because of precedence, the function is called first. It doesn't return anything, so it returns undefined
. undefined
is falsy, so !
flips it and yields true
. Since we never did anything with the result of this expression, the true
is discarded. (It wouldn't have mattered if we returned a truthy value either; then !
would have yielded false
and that would be discarded. No matter what, it'll be discarded.)
1Technically, assignment is an expression, not a statement, but for our purposes it does not matter.
2 With the exception of return
, continue
, break
, and similar statements where it would confuse much more confusion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With