Is the below behavior expected for nodejs? It looks buggy to me. If not what am I missing?
var abc = function(){
console.log("hello");
}
(function(){
console.log("welcome");
})();
I get the below exception
TypeError: undefined is not a function
at Object.<anonymous> (C:\node\main.js:8:3)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3
If I alter the code to
var abc = function(){
console.log("hello");
}
(function(){
console.log("welcome");
}());
it produces
welcome
hello
I'm forced to believe node parsing mistakenly assumes nested IIFE (function(){...})()) executed first and and outer () of IIFE triggers execution of function definition above it (it does not matter if I introduce a comment line in between abc definition and IIFE).
It's not just a node.js problem. You'll get the same error in the browser. As mentioned by others the bug is the missing semicolon in the first function. But what's going on?
Well, first let's explain what exactly is an IIFE. You may be aware of this syntax:
(function(){})();
But it's not the only syntax for IIFE. IIFE is Immediately Invoked Function Expression. So it is invoking a function expression immediately after declaring it.
So, what is a function expression? It is simply a function declared in expression context. One way to evaluate something in expression context is to use the brace operator: ()
. Here, the brace operator is actually the same brace operator in math: it enforces precedence of math operations.
So the braces in this:
(function(){})
mean exactly the same as this:
(1+1)
It tells the interpreter that the code inside it is an expression that returns a value. So that's what expression context means - any place you can do calculations to return values.
There are other places where the language interprets as expression context. One of them is immediately after an operator. For example the !
operator or the -
operator (to make a number negative). So, for example just as you can write:
-12 + 5
you can also write an IIFE like this:
-function(){}()
Another place that javascript interprets as expression context is everything to the right of an =
sign. For example:
var x = 12 + 5;
Which means, you can write an IIFE like this:
var x = function(){}();
This is what's causing problems in your code. Basically, javascript interprets your code like this:
var abc = function(){
console.log("hello");
}(function(){console.log("welcome")})();
That is, your first function is treated as an IIFE and it is called by passing your second function as an argument and tries to call the return value of the first function (which is undefined because you don't return anything but just log "hello").
In other words, if we break it down, it's doing this:
function first_function () { console.log('hello') }
function second_function () { console.log('world') }
var temp = first_function(second_function);
var abc = temp; // it errors here because temp is undefined
The lesson is, you don't need a semicolon after a function declaration but you need it after a function expression.
Second, less useful lesson: there's more than one way to IIFE.
A missing semicolon is the cause of your issues.
var abc = function(){
console.log("hello");
}; // missing semicolon!
(function(){
console.log("welcome");
})();