JavaScriptT2 Dark_1200x303

We'll look at the four ways of creating a function in JavaScript: as a statement, as an expression, as an arrow function, and using the Function constructor. 

“I wish undefined was a function in JavaScript.”

There are four ways a function can be created in JavaScript. They are as follows:

  • A function as a statement
  • A function as an expression
  • A function as an arrow function
  • A function created using the Function constructor

All four ways of function creation have distinct features such as an arrow function that does not have its own this object, a function statement that is hoisted on the top of the execution context, and a function expression that can be immediately invoked without creating a separate scope. Having a good understanding of various characteristics of different types of JavaScript functions is useful to write better code. This article explains these functions.

A Function as a Statement

A function as a statement can be created as shown the following code example:

function Add(num1,num2){
    let sum = num1+ num2; 
    return sum; 
}

let res = Add(7,8);
console.log(res); // 15

A function statement starts with the function keyword. It can return a primitive type value, object, or another function. For example, a function statement can return an object as shown in the following code example:

function getProduct(){
    let product = {
        Id:1,
        Title:'Book',
        Price: 30
    };
    return product; 
}

let p1 = getProduct();
console.log(p1); // prints product object 

The main characteristic of a function statement is it is hoisted at the top of the execution context. Therefore, you can call a function statement before it is declared, as shown in the following code example:

let res = Add(7,8);
console.log(res); // 15

// .... other codes 

function Add(num1,num2){
    let sum = num1+ num2; 
    return sum; 
}

As you see, that Add function is called before it is created, and this is possible because a function statement is hoisted at the top of the execution context.

A function statement is hoisted at the top of the execution context. So, it can be invoked before it is created.

In a function statement, you can pass primitive values as either parameters or non-primitive values, such as an object or array. The primitive parameters are passed as a value, and the non-primitive values are passed as a reference. So, if you pass an object to a function statement and the function changes the object’s properties, that change is visible outside the function, as shown in the following code example:

 function updateProduct(product){
    product.Title = 'Updated Book';
}

let product = {
    Id:1,
    Title:'Book',
    Price: 30
};

console.log(product.Title); // Book
updateProduct(product);
console.log(product.Title); // Updated Book 

In the above code, JavaScript updates the Title of the product object. However, if you pass a string, number, or Boolean parameters in the function, it won’t be reflected globally.

In a function statement, primitive parameters are passed as a value, and non-primitive parameters such as objects and arrays are passed as a reference.

A Function as an Expression

A function as an expression can be created as shown in the following code example.

let add = function a(num1,num2){
    let sum = num1+ num2; 
    return sum;
}

let res = add(8,9);
console.log(res);// 17

In a function expression, you assign a function to a variable. A function expression can also be created as anonymous without a name, as shown in the following code example:

let add = function (num1,num2){
    let sum = num1+ num2; 
    return sum;
}

let res = add(8,9);
console.log(res);// 17

The name of the function expression is local to the function body and very useful for recursions or any scenario in which you need to refer to the function inside the function body. You can write a factorial function by using function expression name:

var Calculator = {

    factoriral : function fact(n){
      if(n<=1){
        return 1; 
      }
      return n*fact(n-1);
    }
}

let result = Calculator.factoriral(7);
console.log(result); // 5040

The main differences between a function statement and a function expression are:

  • A function expression can be created without a name, whereas a function statement must have a name
  • A function expression is not hoisted on the top of the execution context, whereas a function statement is hoisted at the top of the execution context

Since a function expression is not hoisted at the top of the execution context, calling the function before it is created throws ReferenceError, as shown in the following code example:

let res = add(8,9);
console.log(res); // ReferenceError : add  is not a function 

let add = function (num1,num2){
    let sum = num1+ num2; 
    return sum;
}

So, you can summarize the hoisting difference as:

  • A function statement is hoisted at the top of the execution context, so it can be invoked before it is created
  • A function expression is not hoisted at the top of the execution context, so it cannot be invoked before it is created

A function expression is not hoisted at the top of the execution context. So, it cannot be invoked before it is created.

One other important feature of a function expression is that it can be immediately invoked as soon as it is defined, which is also known as Immediately Invoked Function Expression:

let add = function (num1,num2){
    let sum = num1+ num2; 
    return sum;
}(8,9);

console.log(add); // 17 

On the other hand, a function statement cannot be immediately invoked as soon as it is defined without creating a separate scope, as shown in the following code example.

(function add(num1,num2){
    let sum = num1+num2; 
    console.log(sum); //17
})(8,9);

An Arrow Function

The arrow functions were introduced in ECMA 2015 with the main purpose of giving a shorter syntax to a function expression. Besides providing shorter syntax, which increases the readability of the code, it does not have its own value of the this object. The value of this object inside an arrow function is inherited from the enclosing scope.

You can write an arrow function to add two numbers as shown in the next code example.

var add = (num1, num2)=> num1+num2; 
let res = add(5,2);
console.log(res); // 7 

Some syntax rules for an arrow function are:

  • Parameters should be passed in a small bracket
  • If there is only one parameter, then the bracket is optional
  • If there is no parameter, then it must have a small empty bracket
  • If there is only a single expression in the function body, then using parentheses is optional
  • If there is only a single expression in the function body, then using the return statement is optional

You can apply the above syntax rules to create arrow functions, as shown in the following code example.

// More the one parameters and only one expression 
var add = (num1, num2)=> num1+num2; 

// No parameters and no return statment 

let greet = ()=>console.log('hey');

// More than one paramter and more than one expression in body 
var divide = (num1,num2)=>{
   if(num2 ==0){
    return 'can not divide';
   }
   else {
       return num1 / num2; 
   }
}

To return an object from an arrow function, you can either use a return statement or a slightly different syntax of enclosing the object in a small bracket, as shown in the following example:

let product = (title,price)=>({
    title:title,
    price : price
})

let p1 = product('pen',100);
console.log(p1);

Some other important features of an arrow function are:

  • It supports the rest parameters
  • It supports the default parameters
  • It does not have arguments object
  • It does not have its own this object
  • It cannot be used as a constructor

The value of this object inside an arrow function is inherited from the enclosing scope. To understand it in a better way, consider the following code example:

let Product = {
    Title :'Pen',
    Price : 100
  }


  function foo(){

      console.log(this); // Product object 

     function koo(){

           console.log(this); // global object 
     }

     koo();
  }

  foo.call(Product);

The function foo is called indirectly using the call() method to pass the Product object as the value of this inside it. And since the function koo is called using the function invocation pattern, the value of this object for it is the global object. So, even though koo is an internal function of foo, it has its own value of this object.

But, if you refactor the koo function as an arrow function, then instead of having its own this object, it inherits it from the enclosing scope, as shown in the next code example.

let Product = {
    Title :'Pen',
    Price : 100
  }


  function foo(){

      let that = this; 

      console.log(this); // Product object 
      var koo = ()=> console.log(this);
      koo();
  }

  foo.call(Product);

The other restriction on arrow functions is that they cannot be used as constructors, so the following code example throws an exception.

  var Product = (Title,Price)=>{

    return {
      Title:Title,
      Price: Price
    }
}

let p1 = new Product('Pen',200); // Error Product is not a constructor 

Using Function Constructor

A function can be dynamically created using the Function constructor, but it suffers from security and performance issues and is not advisable to use.

You can create a function using the Function constructor as shown in the following example.

var add = Function('num1','num2','return num1+num2');
let res = add (7,8);
console.log(res); // 15

In the Function constructor, you pass parameters and function body as a string. The function created with the Function constructor is always created in the global scope.

Summary

In this article you learned about various ways of creating a function and their characteristics – for example, a function statement is hoisted at the top of the execution context, a function expression is not hoisted and can be created without a name, and an arrow function does not have its own this object.

I hope you found the article useful. Thanks for reading.


Dhananjay Kumar
About the Author

Dhananjay Kumar

Dhananjay Kumar is an independent trainer and consultant from India. He is a published author, a well-known speaker, a Google Developer Expert, and a 10-time winner of the Microsoft MVP Award. He is the founder of geek97, which trains developers on various technologies so that they can be job-ready, and organizes India's largest Angular Conference, ng-India. He is the author of the best-selling book on Angular, Angular Essential. Find him on Twitter or GitHub.

Related Posts

Comments

Comments are disabled in preview mode.