Function in JavaScript

Function in JavaScript

The function is a fundamental concept of JavaScript. A function is a block of code that is used to execute a particular task or calculation in the computer, which can be used multiple times. In this article, we will deep dive into the concept of functions and understand how they are used in JavaScript. This is going to be a long article. So grab your tea, fire up your code editor and start with me.

Declaring a Function:

To declare a function, we use the function keyword, then the name of the function, then within parenthesis the parameters of the function are declared and then within the curly braces the main code of the function goes in. Example:

function addition(num1, num2){
    return num1 + num2;
}

There are other ways to declare functions and we will talk about them later.

Calling a Function:

After declaring a function, we can use that function at any time or any place in that code just by calling the function. To call a function, we have to write the function followed by a parenthesis and the arguments of the function in it. Example:

console.log(addition(5, 3)) //8

We can also call a function even before defining it, and it happens only in JavaScript. The reason behind this phenomenon is the unique way of executing code in JavaScript. In JavaScript, all the functions and variables of the code get hoisted first and then the code execution started. I have discussed Function Hoisting and its difference from variable Hoisting in this article.

I want to discuss another topic from the fundamental elements of javascript functions which sometimes makes beginners confused, and that is:

Difference between parameter and argument:

At the time of declaring a function, the variables we pass into that function are called parameters. In the above examples num1 and num2 and parameters. Later, when we call that function, we provide the values to the variables (parameters) and that value is called an argument. In the above example 5 and 3 are arguments.

Anonymous Function:

This is another way to declare a function. It is a function without a name. In most cases, we use an anonymous function by assigning it to a variable or using it as a callback to another function or as a self-executing function. Example:

//assigned to a variable
let greeting = function(){
console.log("bob")
}

//as callback to a function
 setTimeout(function () {
       console.log("Bob is my dog!");
   }, 3000);

//as self-executing function
(function () {
       console.log("Bob is a good dog!");
   })();

Default value:

If we don't pass the arguments while calling a function, JavaScript will not return any error, but it will take a default value and apply that to the function. In general, this default value is set to undefined, but we can change this value by assigning a value to it while declaring the function. Example:

function Add(x,y,z=15){
  console.log(`Value of x= ${x}, y=${y}, z=${z}`);
}
Add(2,3) //Value of x= 2, y=3, z=15

In this example, we did not pass any argument in place of z, but we have assigned the value 15 to it while declaring the function and that value is used here.

Optional arguments:

JavaScript allows us to pass more or fewer arguments than the number of parameters in the function declaration. If we pass more arguments than the parameter, it will ignore the excessive arguments and execute the code with the arguments it requires from the start. If we pass fewer arguments than it requires, it will use the default value undefined as the value for the rest of the arguments. We will see both these cases in the following example:

function Add(x,y,z){
  console.log(`Value of x= ${x}, y=${y}, z=${z}`);
}
Add(2,3,5,8) //Value of x= 2, y=3, z=5
Add(2,3) //Value of x= 2, y=3, z=undefined

Self-executing function:

This is a special type of function that is invoked just after declaring the function. There is no need of calling the function again. Example:

(function (name) {
  console.log(name);
})("Subham"); //'Subham'

Higher order function (HOF):

It is a function that takes one or more functions as its argument or returns as its result. map(), filter(), reduce() etc. are some inbuilt methods in JavaScript that operates as a Higher order function. Example:

function higherOrderFunction(func){
  console.log('I am higher order function')
  func()
}
function sayName(){
  console.log("subham");
}
higherOrderFunction(sayName);
//I am higher order function
//subham

Callback function:

A callback is a function that is passed to another function as an argument. Using callback, we can make a function execute after something else happens or some other function executes. In the above example of Higher order function, the function sayName is passed into the function higherOrderFunction as an argument, so sayName is a callback function. Let's see this with another example:

const message = function() {  
    console.log("See you after 2 sec");
}

setTimeout(message, 2000);

In the above example, message was passed as a callback to the setTimeout method.

Arrow function:

The arrow function was introduced to JavaScript in ES6. It is a more simple and more compact version of regular function. We don't need the function keyword to declare the arrow function. The basic syntax is: mention the parameters in parentheses, use the arrow symbol(=>) and write the code body in curly braces. We can even ignore the parenthesis of the function parameter if there is only one parameter. Its body is also concise, we don't need to use return keyword and curly braces for one-liner functions, we can simply write the code using the arrow symbol. A simple example of an arrow function is like this:

const greet = name => console.log(`Welcome ${name}!`);
greet("Subham") //Welcome Subham!

The key difference between Regular function and Arrow function:

In JavaScript, the this keyword refers to the object that the function is a property of. Example:

const person = {
  name: 'John',
  age: 25,
  sayHello: function(){
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old`);
  }
}
person.sayHello(); //Hello, my name is John and I'm 25 years old

We saw in the above example that the this keyword is referring to its lexical scope where the value of name and age is available, so it can show the values in the output. But in the above example, we use arrow function in place of regular function, it will return something else.

const person = {
    name: 'John',
    age: 25,
    sayHello: () => {
      console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old`);
    }
  }
  person.sayHello();//Hello, my name is undefined and I'm undefined years old

So here, the value of this.name and this.age is undefined because in the arrow function, this refers to the lexical scope of where it is defined, so in this case it is referring to the global scope where the name and age property is not available, that's why it is returning undefined.

Function, the First-class citizen in JavaScript:

If in any programming language, we are allowed to pass the functions as value to a variable and as an argument to another function and also return a function from another function then we can say that the programming language has a first-class function, and we can call the function in that language as a first-class citizen. As we saw in the earlier section where we discussed the Higher order function, callback and anonymous function that JavaScript allows us to do the above-mentioned operations with function, we can say functions are first-class citizens of JavaScript.

Callstack:

The call stack is a data structure in JavaScript that keeps track of the function calls that are currently executing in a program. It's used to store the execution context (i.e. the state of the program) of each function call.

When we call a function, using the call stack mechanism JavaScript first creates an empty stack and then adds the function serial by as they are called, when their work is done it automatically removes that function from the stack. Let's understand this with an example:

function one(){
    console.log(1);
    two()
}
function two(){
    console.log(2);
    three()
}
function three(){
    console.log(3);
}

one()

I have explained this concept in detail in this article.

Closure:

The closure is a very powerful feature of JavaScript. Because of closure, when we call a function in JavaScript, not only the function comes alone but it also brings the lexical scope of that function with it. It means when we call the function, we also get access to its lexical scope. In simple words, closure is referred to a complete package of a function with its lexical scope.

Let's understand the concept with code examples:

function a(){
    let x=2;
    function b(){
        console.log(x);
    }
    return b;
}
console.log(a());

The above code returns the function b. So now if we store the value of a() in a separate variable, it will hold only the function b which console logs the value of x. Now here is the trick, let's assume we have stored the a() to the variable c in global scope, so now it should not get access to the value of x, because it is in the inner scope of the function a, but in reality, it has access to the value of x because the variable c contains the function b and b comes with its lexical scope where this x the variable is defined. So now if we call c(), it will return the value of x which is 2 here.

//continuing the previous code
const c = a()
c() //Output=2

Scope in function:

The concept of scope is another important aspect of functions in JavaScript. The scope of a variable is the part of the code where it is accessible. JavaScript has two types of scope: global and local. Variables that are declared outside of a function are global and can be accessed from anywhere in the code. Variables that are declared inside a function are local and can only be accessed within that function. Example:

let x = 10; // global variable

function example() {
    let y = 20; // local variable
    console.log(x + y);
}
example() //Output: 30
console.log(x); // Output: 10
console.log(y); // ReferenceError: y is not defined

If we define a variable in the global scope and then re-define a variable with the same name but a different value in the local scope, JavaScript will prioritize its local scope value in the local scope but in the outer scope, it will prioritize its global scope value. Example:

let favourite = 'Tom';
const greeting = () => {
let favourite = 'Jerry';
console.log(`inner scope: I love ${favourite}!`)
}
greeting()
console.log(`Outer Scope: I love ${favourite}!`)
//Output:
//inner scope: I love Jerry!
//Outer Scope: I love Tom!

Conclusion:

In this article, we have understood how the function works in JavaScript. We have described various ways to define functions and then call that functions. We understood how scope works in JavaScript functions. We have got introduced to the concepts like closure, call stack, higher order function etc. Now let me summarize the whole concept shortly and simply:

A function in JavaScript is a block of code that can be executed multiple times by calling it with different arguments. Functions can be declared using the function keyword, followed by the function's name and its parameters within parentheses. Functions can also be anonymous, which means they don't have a name. These types of functions are often used as callbacks or self-executing functions. JavaScript also allows for optional and default parameters, where a default value is used if no argument is passed in. Higher-order functions are functions that take one or more functions as arguments or return a function. The closure allows us to use a function bound with its lexical scope from anywhere in the code. Call-stack maintains the complex functionality of executing these functions.