Why can't we immediately invoke function declaration?

Viewed 257

Why do we need to write an expression that evaluates to a type of function in order to invoke a function immediately? Why can't we just declare a function and invoke it right away?

Why

(function(){}()) or !function(){}()

And why not just

function(){}()

It has to do with how things are put in the memory I suppose, but I struggle to find a complete answer.

2 Answers

Because when the final } of a function declaration is reached, the interpreter sees the whole function declaration that comes before it as a single statement. If you put anything after the }, it will be interpreted as a separate, standalone, unused expression:

function foo() {
}('bar')

This creates a bar string, but the interpreter doesn't do anything with it - it's like

function foo() {
}
'bar'

The string is declared, but not used anywhere.

If you don't put anything into the parentheses, a SyntaxError is thrown because the interpreter is expecting a statement or expression, but () alone is neither.

This is all a bit like putting things after an if block. No matter what you put after the } of an if block, what follows will be interpreted as a completely standalone statement/expression:

if (true) {
  // do something
}'foo';

Here, just like with the function declaration example, you're creating a string containing foo, but the expression goes unused.

The reason is in the way ECMAScript code is processed.

During initialisation, function declarations are processed first, then variable declarations (a process often called "hoisting"). Then execution begins.

Function expressions are evaluated during execution.

So you can't execute function declarations immediately because even variables don't exist yet and other code that the function might depend on hasn't been executed either.

Consider something as simple as:

foo(); // shows undefined

var randomNumber = function() { // function expression
  return Math.random();
}();  // () makes it an IIFE

foo(); // shows value assigned to randomNumber

function foo() {  // function declaration
  alert(randomNumber);
} 

Function foo exists before randomNumber (despite the sequence of the code), so attempting to execute it immediately would throw a reference error. Once initialisation is complete, both foo and randomNumber have been declared.

The code on the RHS of the assignment to randomNumber is parsed during initialisation for syntax errors, but not executed until the execution phase.

Now execution begins, the function expression is executed and assigns a value to randomNumber so when foo is called, randomNumber exists and has whatever value the function expression on the RHS returned.

Related