Function Expression vs Declaration vs IIFE

Introduction

Functions in JavaScript can be created in many different ways. But, these methods have different meanings and work differently. In this blog post, we'll attempt to understand the different ways functions can be defined include pros and cons of each method.

Function Expression

The function is written on the right-hand side of the assignment operator. This functions can be named or unnamed (anonymous). Function expressions usually take the name of the variable said function is assigned to.

const expr = function (a) { 
    // do something with a
}

// or

const expr = (a) => { 
    // do something with a
};

// or

// looks weird, but it works
const expr = function namedFunction (a) {
    // do something with a
}

// or

[ ... ].forEach(function (a) {
    // do something with a
})

One disadvantage of doing it this way is, these functions are not hoisted. These functions can be used in such a way that they don't pollute the global scope.

Function Declaration

These function are named and not assigned to any variables.

function namedFunction(a) {
    // do something with a
}

This is the most widely used type of function definition. These functions are hoisted and can be called before they are defined.

function namedFunction(a) {
    // do something with a
}

[ ... ].forEach(namedFunction);

IIFE

Immediately Invoked Function Expressions, as the name goes this when when a function is created at the same time as it's being used. They generally take these formats:

(function() {
    // do some work
})();

// or

(() => {
    // do some work
})();

These functions are discarded after they are done as they are not assigned to any variables. A tricky example to name will be something like:

function SomeFunction() {
    return () => {
        console.log("hello world");
    }
}

SomeFunction()();

Can this be referred to as an IIFE? Share your opinion as a comment.

When to use them

Generally, use function declaration when the function is expected to exist in the global scope and reusable publicly. Function expressions are very useful when the intention to limit the scope within which this function is available. See example below:

function DoubleInput(inputArray) {
    const doubleValue = function (value) {
        return value * 2;
    }

    for (let i = 0; i < inputArray.length; i++) {
        console.log(doubleValue(inputArray[i]));
    }
}

// or

function DoubleInput(inputArray) {
    inputArray.forEach((value) => {
        console.log(value * 2);
    });
}

First example uses a function expression within a function declaration, while the second example uses a function expression as a callback within a Higher Order Function. In both examples, we don't want to make the internal functions publicly available.

IIFE are especially helpful when the intention is to created scoped function/variables or private properties.

const counter = (function() {
    let count = 0;
    return function() {
        return ++count;
    };
})();

console.log(counter()); // result: 1
console.log(counter()); // result: 2
console.log(counter()); // result: 3

console.log(count);  // ReferenceError: count is not defined

Conclusion

There are many use cases not covered in this article. Note that barring some optimization (which may or may not be significant), there are performance benefits of using any one style over the other. Also, be wary of defining function expressions within loops as this could mean recreating that function n times (n being the number of times the loop is executed).

Note that JavaScript has First-class Functions. All functions, if assigned or named and matching the correct signature can be used as callbacks.

No Comments Yet