Three Ways to Define Functions in JavaScript
Get a handle on declaring your functions.
Join the DZone community and get the full member experience.
Join For FreeFunctions are one of the key components in programming. They are defined to perform a specific task and can be called again and again to execute that task. The main difference between functions in JavaScript and other programming languages is that in JavaScript, functions are first-class objects, which means that they behave like objects and can be assigned to variables, arrays, and other objects.
This post discusses three different ways to define functions:
- Function Declaration.
- Function Expression.
- Generator Function.
Function Declaration
Function declaration is probably the most common way to declare a function. Let’s look at its syntax:
function name (parameter)
{
statements
}
Function Declaration is made up 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 the parameter and argument of a function. A parameter is a variable used to define a function. Arguments are the actual data you pass into the function's parameters when calling it.
First, let's look at a simple example:
function hello(name)
{
console.log("Hello "+ name)
}
hello('stuti')
// Hello stuti
hello(12)
// Hello 12
A function, hello
, is declared with an argument, name
, which logs a message in the console. As you can see from the example, since no type is specified on the argument, it works for both a string and an integer. However, what if I just want my function to greet a name, not a number? Sadly there is no pre-built method of doing this in Javascript, so we have to manually check the type of the argument that’s passed in the function like this:
function hello(name) {
if (typeof name === 'string')
console.log("Hello " + name)
else
console.log("Please input a Name")
}
hello(12) // Plese input a Name
By default, functions return undefined values. To return any other value, the function must have a return statement that specifies the value to return.
function something(){
}
console.log(something()) // undefined
function notSomething(){
return 1
}
console.log(notSomething()) // 1
Hoisting in 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:
myName()
// My name is Stuti Chahuhan
function myName() {
console.log(`My name is Stuti Chauhan`)
}
Here I called the function before I even declared it — this is hoisting.
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
. The name
of the function is also optional. (Unnamed functions are called Anonymous Function.) If the function has a name
then it is called a Named Function Expression.
let checkNumber = function check (num){
return (num %2==0)?"even" : "odd"
}
console.log(checkNumber(50))
// even
//Anonymous Function
let checkNumber = function (num){
return (num %2==0)?"even" : "odd"
}
console.log(checkNumber(50))
// even
myName()
// ReferenceError: myName is not defined
let myName =function () {
console.log(`My name is Stuti Chauhan`)
}
IIFE (Immediately Invoked Function Expression)
This means that the function runs as soon as it is defined. Here, the function expression is enclosed within a Grouping Operator ().
( function () {
let num = 4
return num
})()
//4
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 call the function only once to produce an output and that's it? This is where IIFE comes in. It is immediately executed and never in the future is it 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.
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 the middle of execution, you have to return or throw an error.
A 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 an asterisk * after the function
keyword; any number of spaces can be included between them.
One more thing to note: in JavaScript a generator is a function which returns an object on which you can call next()
. Every invocation of next()
will return an object with a structure like this:
{
value: Any,
done: true|false
}
Now, this object has two properties: value
and done
. 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:
function * generatorFunction()
{
console.log('first to execute');
yield 'takes a pause';
console.log(' printed after the pause');
yield 'end of the function';
}
const gen = generatorFunction();
console.log(gen.next().value); // first to execute
// takes a pause
console.log(gen.next().value); // printed after the pause
// end of the function
console.log(gen.next().value);
// undefined
Inside the function body, we don't use the return keyword — instead yeild
is used. Ifreturn
was used, it would change the property done
to 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, and 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 next()
and value
property,
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, 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.
function* generator() {
yield "some value";
return "ends here";
yield "will never execute";
yield "never reach here"
}
var gen = generator()
console.log(gen.next()); // { value: "some value", done: false }
console.log(gen.next()); // { value: "ends here", done: true }
console.log(gen.next()); // { value: undefined, done: true }
console.log(gen.next()); // { value: undefined, done: true }
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, issues with callbacks.
Conclusion: Which Way is Best?
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 the Generator Function for better Async functionality and the Anonymous Function Expression for the function you want to execute immediately.
Reference
Published at DZone with permission of Ashutosh Singh, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments