When to use a function expression or function declaration

0

There are two ways to create functions in JavaScript: function expressions and function declarations. In this article, we’ll see when to use function expressions versus function declarations, and explain the differences between them.

Function declarations have been used for a long time, but function expressions have gradually taken over. Many developers don’t know when to use one or the other, so they end up using the wrong one.

There are a few key differences between function expressions and function declarations. Let’s take a closer look at these differences and when to use function expressions versus function declarations in your code.

function funcDeclaration() {
    return 'A function declaration';
}

let funcExpression = function () {
    return 'A function expression';
}

What are function declarations?

Function declarations are when you create a function and give it a name. You declare the function name when you write the function keyword, followed by the function name. For example:

let myFunction = function() {
  // do something
};

As you can see, the function name (myFunction) is declared when creating the function. This means you can call the function before it is defined.

Here is an example of a function declaration:

function add (a, b) {
  return a + b;
};

What are function expressions?

Function expressions are when you create a function and assign it to a variable. The function is anonymous, which means it has no name. For example:

let myFunction = function() {
  // do something
};

As you can see, the function is assigned to the myFunction variable. This means that you must define the function before you can call it.

Here is an example of a function expression:

let add = function (a, b) {
  return a + b;
};

The differences between function expressions and declarations

There are a few key differences between function expressions and function declarations:

  • Function declarations are hoisted, while function expressions are not. This means you can call a function declaration before it’s defined, but you can’t call it with a function expression.
  • With function expressions, you can use a function immediately after it is defined. With function declarations, you have to wait until the entire script has been parsed.
  • Function expressions can be used as an argument of another function, but function declarations cannot.
  • Function expressions can be anonymous, but function declarations cannot.

Understanding the scope of your function expression: JavaScript lifting differences

Similar to the let declaration, function declarations are hoisted on top of other code.

Function expressions are not hoisted. This allows them to keep a copy of the local variables of the scope where they were defined.

Normally, you can use function declarations and function expressions interchangeably. But there are times when function expressions result in easier to understand code without needing a temporary function name.

How to choose between expressions and declarations

So when should you use function expressions rather than function declarations?

The answer depends on your needs. If you need a more flexible or non-hoisting function, a function expression is the way to go. If you need a more readable and understandable function, use a function declaration.

As you have seen, the two syntaxes are similar. The most obvious difference is that function expressions are anonymous, while function declarations have a name.

Today, you would typically use a function declaration when you need to do something that function expressions cannot. If you don’t need to do anything that can only be done with a function declaration, it’s usually better to use a function expression.

Use function declarations when you need to create a recursive function or when you need to call the function before defining it. As a general rule, use function expressions for cleaner code when you don’t need to do either of these things.

Benefits of function declarations

Using function declarations has a few key advantages.

  • This can make your code more readable. If you have a long function, giving it a name can help you keep track of what it does.
  • Function declarations are hoisted, which means they are available before you define them in your code. This helps if you need to use the function before it’s defined.

Benefits of Function Expressions

Function expressions also have a few advantages.

  • They are more flexible than function declarations. You can create function expressions and assign them to different variables, which can be useful when you need to use the same function in different places.
  • Function expressions are not hoisted, so you can’t use them until they’re defined in your code. This helps if you want to ensure that a function is only used after it has been defined.

When to Choose a Function Declaration or Function Expression

In most cases, it is easy to determine which method of defining a function is best suited to your needs. These guidelines will help you make a quick decision in most situations.

Use a function declaration when:

  • you need a more readable and understandable function (like a long function or a function you’ll need to use in different places)
  • an anonymous function will not suit your needs
  • create a recursive function
  • you must call the function before it is defined

Use a function expression when:

  • you need a more flexible function
  • you need a function that is not hoisted
  • the function should only be used when defined
  • the function is anonymous or does not need a name for further use
  • you want to control when the function is executed, using techniques such as Immediately Invoked Function Expressions (IIFE)
  • you want to pass the function as an argument to another function

That said, there are a number of cases where the flexibility of function expressions becomes a powerful asset.

Unlock function expression: JavaScript lifting differences

Function expressions become more useful than function declarations in different ways.

  • Closures
  • Arguments to other functions
  • Immediately Invoked Function Expressions (IIFE)

Creating closures with function expressions

Closures are used when you want to give parameters to a function before that function is executed. A good example of how this can benefit you is when you cycle through a loop NodeList.

A closure allows you to retain other information, such as the index, in situations where that information is not available after the function is executed.

function tabsHandler(index) {
    return function tabClickEvent(evt) {
        // Do stuff with tab.
        // The index variable can be accessed from within here.
    };
}

let tabs = document.querySelectorAll('.tab'),
    i;

for (i = 0; i < tabs.length; i += 1) {
    tabs[i].onclick = tabsHandler(i);
}

Attached event handlers are executed later (once the loop is finished), so a closure is needed to hold the appropriate value of for loop.

// Bad code, demonstrating why a closure is needed
let i;

for (i = 0; i < list.length; i += 1) {
    document.querySelector('#item' + i).onclick = function doSomething(evt) {
        // Do something with item i
        // But, by the time this function executes, the value of i is always list.length
    }
}

It is easier to understand why the problem occurs by extracting the doSomething() operate inside the for loop.

// Bad code, demonstrating why a closure is needed

let list = document.querySelectorAll('.item'),
    i,
    doSomething = function (evt) {
        // Do something with item i.
        // But, by the time this function executes, the value of i is not what it was in the loop.
    };

for (i = 0; i < list.length; i += 1) {
    item[i].onclick = doSomething;
}

The solution here is to pass the index as a function argument to an outer function so that it can pass that value to an inner function. You will typically see handler functions used to organize the information an internal return function needs.

// The following is good code, demonstrating the use of a closure

let list = ['item1', 'item2', 'item3'],
    i,
    doSomethingHandler = function (itemIndex) {
        return function doSomething(evt) {
            // now this doSomething function can retain knowledge of
            // the index variable via the itemIndex parameter,
            // along with other variables that may be available too.
            console.log('Doing something with ' + list[itemIndex]);
        };
    };

for (i = 0; i < list.length; i += 1) {
    list[i].onclick = doSomethingHandler(i);
}

Learn more about closures and how to use them.

Passing function expressions as arguments

Function expressions can be passed directly to functions without having to be assigned to an intermediate temporary variable.

You will most often see them as an anonymous function. Here is an example of a familiar jQuery function expression:

$(document).ready(function () {
    console.log('An anonymous function');
});

A function expression is also used to handle array elements when using methods such as forEach().

They also don’t have to be nameless anonymous functions. It’s a good idea to name the function expression to help express what the function is supposed to do and to make debugging easier:

let productIds = ['12356', '13771', '15492'];

productIds.forEach(function showProduct(productId) {
    ...
});

Immediately Invoked Function Expressions (IIFE)

IIFEs help prevent your functions and variables from affecting global scope.

All properties inside are within the scope of the anonymous function. This is a common design pattern used to prevent your code from having unwanted or unwanted side effects elsewhere.

It is also used as a module template to contain blocks of code in manageable sections. We look at them in more detail in Demystifying JavaScript Closures, Callbacks, and IIFEs.

Here is a simple IIFE example:

(function () {
    // code in here
}());

…which, when used as a module, can result in easy-to-achieve maintainability for your code.

let myModule = (function () {
    let privateMethod = function () {
        console.log('A private method');
    },
    someMethod = function () {
        console.log('A public method');
    },
    anotherMethod = function () {
        console.log('Another public method');
    };

    return {
        someMethod: someMethod,
        anotherMethod: anotherMethod
    };
}());

Conclusion

As we’ve seen, function expressions aren’t radically different from function declarations, but they can often result in cleaner, more readable code.

Their widespread use makes them an essential part of every developer’s toolkit. Do you use function expressions in your code in interesting ways that I haven’t mentioned above? Comment and let me know!

Share.

About Author

Comments are closed.