Functions Expression vs Declaration


Declaring functions might seem to be trivial but in the world of Javascript,there are a lot of misconceptions around it .I will try and demistify about what exactly goes on .

1.We will start off with this code snippet.


var fn = function(){
exprFn();
declaredFn();
var exprFn = function(){
console.log("Expression Function ran");
}
function declaredFn(){
console.log("Declared Function ran")
}
}
fn();

Does this work ? No . It says exprFn is undefined.
Conclusion:The reason being even though the variable declaration is hoisted at the top.The expression assigning the function to exprFn did not and hence we are trying to invoke undefined() and hence it is throwing an error.Lets correct it,which will take us to our next point.


2.


var fn = function(){
declaredFn();
var exprFn = function(){
console.log("Expression Function ran");
};
exprFn();
function declaredFn(){
console.log("Declared Function ran")
}
}
fn();

The result is

Declared Function ran
Expression Function ran
declaredFn() apparently was invoked before it was even declared.
Conclusion:This is because function declarations like variable get hoisted.Hence the declaredFn’ s declaration statement was hoisted and hence declaredFn was already declared.function declarations are parsed and evaluated before any other expressions are. Even if declaration is positioned last in a source, it will be evaluated foremost any other expressions contained in a scope


 

3.


var fn = function(){
declaredFn();
test();
var exprFn = function test(){
console.log("Expression Function ran");
};
exprFn();
function declaredFn(){
console.log("Declared Function ran")
}
}
fn();

We have changed the function a bit .We basically have named the anonymous function assigned to exprFn to test.It is called a named function expression.But the above code doesn’t work.
ReferenceError: test is not defined
As named function expression are also not hoisted.


 

4.


var fn = function(){
var exprFn = function test(){
console.log("Expression Function ran");
console.log("inner:expression",typeof exprFn)
console.log("inner:function name",typeof test)
};
exprFn();
console.log("outer:expression",typeof exprFn);
console.log("outer:function name",typeof test);
}
fn();

If you run the above piece of code you will see
Expression Function ran
inner:expression function
inner:function name function
outer:expression function
outer:function name undefined
So you see ,the function identifier (name) is not accessible by the outer scope.The specs says that the identifier should not be available in the scope enclosing it.Hence “test” is undefined

Now that we know the difference between function expression and function declaration.The question we will try and answer is

why the following doesn’t work as an IIFE: function foo(){ }();.

It doesn’t work because brackets after a function declaration doesn’t invoke the function.The function can only be immediately invoked if its an expression.


1+function foo(){console.log("I got executed");}()

The result is
I got executed
NaN
The spec says that the plus operator expects 2 expression.Hence our function declaration is transformed into a function expression and the extra brackets at the end invoke them.Similarly the common practice of using IIFE is putting it within brackets.


(function (){console.log("I got executed");})()

The extra brackets just turns the function declaration into an expression and makes it invokable.You can transform your function declaration to an expression by putting it in an operator that expects expression.Js would do the rest for you 🙂