Function Declaration vs Function Expression vs Arrow Function — Right Tool for the Right Job

Which function type to use in JavaScript

zmjdev
5 min readJul 10, 2021
Cover Photo

Contents

  1. Why I’m writing this?
  2. An introduction to types of functions in JavaScript
  3. Explanation on the behaviors of function declarations.
  4. More precise explanation of function expressions.
  5. Explanation on the exact usage of arrow functions. Where you should use them and where you should not

Why am I writing this?

The first programming language I learned was C# then I moved to Python because of its popularity.

After sometime, one of my friends suggested JavaScript. Then, I started learning JavaScript. But, I found it difficult to understand, coming from other languages. I got entirely different results from my code. The worst thing is, I couldn’t understand tutorials because of this. At some point, I was frustrated by this language. I’m happy that I didn’t give up.

I dug deep into JavaScript and studied how exactly JavaScript works under the hood. Eventually, I started to love JavaScript. So I am writing this to provide my contribution to the growth of the JavaScript community.

And I notice something strange in the tutorials, blog posts, and articles that people use tools that aren’t meant to be used in such places especially arrow functions.

So, I want to express my views on where the tools best. By reading this article, I hope you will become a better programmer whose code is more readable.

Functions in JavaScript

There are many types of functions in JavaScript. Today we are going to explore:

  1. Function Declarations function foo(){}
  2. Function Expressions var foo=function foo(){}
  3. Anonymous Functions var foo=function(){}
  4. Arrow Functions var foo=()=>{}

Each of these functions behaves differently. You can’t replace one with another.

I don’t use anonymous functions and, I strongly recommend you not to use them as well. You’ll see why.

Function declarations

The Syntax

function foo(){// your code}

Behaviors

1. function declaration attach themselves to enclosing scope.

function foo(){//your code}

If you declare a function in the global scope using function declaration, The scope of the function is global. this is one of the key differences compared to function expressions

2. Function declarations are affected by hoisting.

sayHello() // Hellofunction sayHello(){     console.log(“Hello”);}

You can call a function before you declare it. because of hoisting.

Advantages

You can have your executable code on top of all function declarations.

Thanks for hosting! You don’t need to declare all the functions before the executable code. So, you don’t have to scroll to the bottom of your code to see the executable code. instead, keep your executable code at the top and declare all the functions below that.

Best Practice

Use function declaration Generally unless some special occasions.

Function Expressions

The Syntax

var foo=function anotherFoo(){// your code}

Behaviors

1. Function Expressions attach themselves to their own scope.

var foo=function bar(){console.log(bar) // [Function]}console.log(bar)// RefferanceError

Here, bar is inside its own scope that is why we get an error when we try to access them from outside the scope.

2. Functions Expression are read-only.

var foo=function bar(){      bar= “fooooo”;      console.log(bar) // [Function : bar]}
foo();

Here, in the above code, we are assigning bar to a string and when we run the program we still get [Function:bar].

Advantages

Function Expressions are the best way to self-reference.

Disadvantages

The syntax is very complex.

//function declarations
function sayHello(){
// your code }
// function expressions
var sayHello=function sayHello(){
//your code
}

Best Practice

Use function expressions only, when you need self-reference.

Anonymous Functions

The Syntax

var foo=function(){//you code}

Most commonly used as callback.

foo(function(){//your code})

Behaviors

It functions as all the other functions. but, it has no name.

Advantages

The code looks more simpler and cleaner.

foo(function calculateAverage(input){//your code})
//Named function
foo(function(input){//your code})
//Anonymous functions

You would all agree that coming up with names for functions and variables is so Hard. Anonymous functions solve this problem.

Disadvantages

Your code will not be self-documented — Every time a programmer reads your code he needs to go through all the lines of codes inside a function to understand what this function is doing.

foo(function calculateAverage(input){//your code})
//Named function
foo(function(input){//your code})
//Anonymous functions

in the above example in Named function we know, the function is to calculate average just by looking at its name. in contrast in the Anonymous function we have to go through the whole body of the code to understand what it’s doing.

You can’t self-reference your function when using function expressions.

var calculate_average=function calculateAverage(input){
console.log(calculteAverage)}
//Named function
var calculate_average=function(input){console.log(//???)})
//Anonymous functions

As we saw in the function expressions section, we have to function expressions only if we were to self-reference. by using anonymous functions in function expressions you can’t do that.

Best Practice

Don’t ever use anonymous functions.

Arrow Functions

The Syntax

()=>{}

Behavior

To understand the following code you should have a good understanding of this keyword. if you don’t read my article

var user = {
name:"abc",
foo:foo
}
function foo(){
function bar(){
console.log(this)// Window Object
}
bar()
console.log(this) //{name:"abc",foo:foo}
}
user.foo()

The console.log(this)statement inside bar function will log Window Object on the console.

To prevent this, earlier we did the following hack

var user = {
name:"abc",
foo:foo
}
function foo(){
let that = this;
function bar(){
console.log(that)// {name:"abc",foo:foo}
}
bar()
console.log(this) //{name:"abc",foo:foo}
}
user.foo()

The above solution is perfectly fine. But in ES6 JavaScript introduced arrow functions to solve this problem.

var user = {
name:"abc",
foo:foo
}
function foo(){
let bar=()=>{
console.log(this)// {name:"abc",foo:foo}
}
bar()
console.log(this) //{name:"abc",foo:foo}
}
user.foo()

Here, arrow functions solve that problem. because this inside arrow function is undefined. So arrow functions lexically resolve the value of this.

This is the main purpose of arrow functions. So use arrow functions only where you need lexically resolve for this.

eg — In React, when you use class components to use setState() use Arrow functions.

Advantages

  • Lexically resolve for this.
  • Code is very simpler and cleaner.

Disadvantages

Arrow functions are anonymous functions. so all the disadvantages we had for anonymous functions are applicable here.

Best Practice

Don’t ever use arrow functions unless you need lexical behavior

Conclusion

I don’t know about you but, in my code when I review, I keep all executable code at the very top and all the function declarations below that. So most of the time I use function declarations. when I see a function expression in my code I know for sure there is a self-reference.

Likewise, when I see an arrow function I know I wanted some lexical this behavior inside the function. and I don’t use anonymous functions except for arrow functions. That way my code is more readable.

The usage of right tool for the right job makes your code more readable.

Thank You for Reading.

More content at plainenglish.io

--

--