Defining one of the key components in programming
This post discusses three different ways to define functions:
- Function Declaration
- Function Expression
- Generator Function
1. Function Declaration
Probably the most common way to declare a function. Let’s look at its syntax:
Function Declaration comprises of the keyword
function followed by the mandatory name of the function and then the parameter within a pair of parenthesis (you can also define a function without an argument). Finally, within a pair of curly braces is the body of the function, which performs an actual task.
It’s important that you know the difference between parameter and argument of a function. A parameter is a variable when defining a function. When a function is called, the arguments are the actual data you pass into the functions parameters.
First, let's look at a simple example:
A function named
hello is declared with an argument
By default, functions return undefined. To return any other value, the function must have a return statement that specifies the value to return.
Hoisting in the Function Declaration?
Simply put, it means no matter where you declare functions or variables when the code is executed, they’re moved to the top of their scope. This is known as hoisting.
Let's take a look at an example:
Here I called the function before I even declared — this is hoisting.
2. Function Expression
A function expression is very similar to, and has almost the same syntax as, a function statement. The main difference is that a function expression does not start with the keyword
function and the
name of the function is also optional, in which case it becomes an Anonymous Function. If the function has a
name then it is called Named Function Expression.
Now let's look at the anonymous way of defining the above function.
An important point of difference between Function Declaration and Function Expression is that there is no hoisting in Function Expression. If you try the same program as the one in hoisting Function Declaration, you’ll encounter an error.
IIFE (Immediately Invoked Function Expression)
This means that the function runs as soon as it is defined, here function expression is enclosed within Grouping Operator (),
Why do we need an IIFE in our typical function expression? We define the function and then call it sometime later any number of times, but what if I want to just call the function only once to produce an output and that's it — I don't want to use it again? This is where IIFE comes in. It is immediately executed and never ever in the future it is accessed by the program again. Since it is not called again, it doesn’t need a name, so an anonymous function expression is preferred for IIFE.
3. Generator Function
Normal functions follow a run-to-completion model and cannot be stopped before executing the last line. If you want to exit in mid the execution you have to return or throw an error.
Generator Function can be stopped midway through execution. When it is called back it continues from where it stopped.
It is declared like a normal function but with the difference that generator function has an asterisk * after the
function keyword and any number of spaces can be included between them.
next(). Every invocation of
next() will return an object with a structure like this:
Now, this object has two properties:
Value is the actual value of the object, whereas
done is the property that specifies the termination of the function — the default value is false and when it becomes true, the function stops.
Let's understand it better with a simple example:
Inside the function body, we don't use return keyword — instead
yeild is used, if
return was used, it would change the property
true and the function would end — anything after it will not execute.
Yield gives out the value assigned to it.
First, we define our function then we invoke it, invoking a generator function results in a generator object which is stored in the variable gen.
Then we call the object using
The first time
next() is used the execution of the function begins. First it runs console.log (“First to execute”) and logs it in the console and then it encounters
yield — yields value “take a pause” and the execution stops.
The second time
next() is called, it picks off where it left last time. Again, it first runs
console.log() and then encounters
yield and the value “end of the function” is yielded, then the function stops.
The third time
next() is called, undefined is seen as the result. This happens because an object generated from generator function can only be iterated once — the object is now useless and a new object has to be generated for the program to start again.
If I were to use
return instead of
yield, the value of data is changed to
true and nothing is executed after that.
Generators when combined with Promises are a very powerful tool for asynchronous programming. They mitigate, if not entirely eliminate, the problems with callbacks.
Conclusion: Which Way is Better?
Well, we can't compare them and say one is better than others — the type of declaration depends on the situation or condition.
You can use Generator Function for better Async functionality, and Anonymous Function Expression for the function you want to execute immediately.