Function Expressions
Function Expressions
function fun() {
//
}
To declare a function the first item of the instruction is the function keyword. So whenever the
first token of the instruction to declare a function starts with function keyword we call it as
function declaration .
Here we are creating a function but the first valid token is not the function keyword, hence we
call this type of instruction as function expression .
**Example 2:
Example 3:
Example 4:
Now here the name fun is the name of the function expression and this function expression is
stored in a variable myFun .
Now here the function expression has no name and this function expression is stored in a
variable called as myFun .
function fun(fn) {
const arr = [1,2,3,4,5];
fn(arr);
}
fun(function gun(arr) {
console.trace("call stack");
})
Now in the above code, we can see the stack prints name of each function called.
In the above code, the function expression is anonymous hence the call stack trace is not
having any name entry, so if we have say 10 back to back function expression calls then it will
be having 10 entries without a name, making hard to debug.
Anonymous functions are hard to use in recursion whereas named function expression
can be easily integrated in a recursive environment. To understand this let's take an
example with array.map.
map is an inbuilt function for arrays in JS. It takes an argument which is expected to
be a function. The function which we pass as an argument is automatically internally
called by map function. This function expression that we pass is expected to have a
parameter. Inside this parameter map function automatically passes one by one all
the elements of our array. And then whatever is returned collectively by all the
function expression calls, the returned values are populated in a new array and
returned.
Anonymous function expressions are useful when code logic is too simple, or if we are
storing the anonymous function expression in a variable and that variable explains most of
the logic of the function expression, then also there is no hard in using anonymous
function expression.
Let's say I want to use map function to calculate factorial of every single value in a given array.
In this case, if we use a recursive approach then we are bound to use named function
expression.
arr.map(function factorial(n) {
if(n == 1) return 1;
return n * factorial(n-1);
})
Here to call the function recursively we need to know the name of the function, hence named
function expression become superior in this case.
arr.map(function (n) {
if(n == 1) return 1;
return n * (n-1); // what to put here ? this code is wrong
})
There is a deprecated function called as arguments.callee which can be used to apply
recursion.
arr.map(function (n) {
if(n == 1) return 1;
return n * arguments.callee(n-1); // deprecated function, not
recommended
});
Arrow functions
This function expression is generally preferred for concise syntax.
There is one very fundamental difference in using arrow functions and other function
expression i.e. in arrow functions the this keyword is resolved lexically whereas in other
the this keyword is resolved by the call site.
If arrow function has only one line logic i.e. to return something then we don't need to use
return keyword.
In the above piece of code the only think square is expected to do is return x*x so using
arrow function we don't need to write return keyword
If the arrow function is only taking a single argument then parenthesis is not mandatory
(function square(x) {
return x*x;
})(10);
To define an IIFE, we first wrap a function inside a pair of parenthesis and then immediately call
the function by putting a subsequent pair of parenthesis and pass arguments inside it.
Once we have prepared the IIFE and called it, post that we can never use it again.
because IIFE get's wiped off from the memory once the execution is done.
IIFE can be very useful to avoid name conflict because they don't conflict with those
variables who are in outer scopes.
IIFE can be useful for some temporary logic as well.