JavaScript
Article

Quick Tip: Function Expressions vs Function Declarations

By Paul Wilkins

This article was peer reviewed by Jeff Mott. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

JavaScript has two different ways of creating functions. Function declarations have been used for a long time, but function expressions have been gradually taking over.

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

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

Differences between Declarations and Expressions

Similar to the var statement, function declarations are hoisted to the top of other code. Function expressions aren’t hoisted, which allows them to retain a copy of the local variables from the scope where they were defined.

Normally function declarations and function expressions can be used interchangeably, but there are times when function expressions result in easier to understand code without the need for a temporary function name.

Benefits of Function Expressions

There are several different ways that function expressions become more useful than function declarations.

  • As closures
  • As arguments to other functions
  • As Immediately Invoked Function Expressions (IIFE)

Creating Closures

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 looping though a NodeList. A closure allows you to retain other information such as the index, in situations where that information will no longer be available when the function is executed.

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

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

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

The attached event handlers are executed at a later time (after the loop is finished), so a closure is needed to retain the appropriate value of the for loop.

// Bad code, demonstrating why a closure is needed
var 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’s easier to understand why the problem occurs by extracting the doSomething() function out from within the for loop.

// Bad code, demonstrating why a closure is needed

var 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’ll commonly see handler functions used to organize the information that an inner returning function needs.

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

var 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);
}

Other good examples of closures and how they can help can be found at this closure examples FAQ.

Passing as Arguments

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

They can be frequently seen in jQuery in the form of an anonymous function, for example:

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

Also when using methods such as forEach(), a function expression is used to handle the array items. They don’t have to be unnamed anonymous functions either. It’s a good idea to name the function expression to help express what the function is supposed to do, and to aid in debugging.

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

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

Immediately Invoked Function Expressions (IIFE)

IIFE’s are used to help prevent your functions and variables from affecting the global scope. All the properties within are scoped to the anonymous function. This is a common design pattern that’s used to prevent your code from having unwanted or undesired side-effects elsewhere.

It’s also used as a module pattern to contain blocks of code in to easy to maintain sections. We take a deeper look at at these in Demystifying JavaScript closures, callbacks and IIFEs.

A simple example of an IIFE is:

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

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

var myModule = (function () {
    var 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 don’t offer much that can’t be achieved with function declarations, but using them can often result in cleaner and more readable code. Their widespread use makes them an essential part of every developer’s toolbox. Do you use function expressions in your code in any interesting ways that I haven’t mentioned above? Comment and let me know!

  • Marc Curry

    Shouldn’t tabs[index].onclick = tabsHandler(i); be tabs[i].onclick = tabsHandler(i);?

    • paulwilkins

      Thanks Marc, somehow that slipped through, but it’s fixed now.

  • xkizer

    Function declarations are better for debugging, because they produce a more detailed stack trace. Named function expressions are best of both worlds, combining the clarity of function expressions with ease of debugging of function declarations.

  • golden number

    “JavaScript has two different ways of creating functions.” By my count JavaScript has at least seven different ways of creating functions:

    I use function declarations (function A(){};) when a function expression is not appropriate or when it is important that that a function is hoisted.

    I use function declaration generators (function* B(){};) when I want to exit and then re-enter a function.

    I use anonymous function expressions (var C = function(){};) when I want to pass a function as an argument to another function or I want to form a closure.

    I use function expression generators (var D = function* [name](){};) when I want to exit and then re-enter a nested function.

    I use arrow function expressions (() => {};) when I want to lexically bind the ‘this’ value.

    I use named function expressions (var E = function F(){};) when I am doing recursion or want to see the function name in the debugger.

    I used immediately-invoked function expressions (var F = (function(){return function(){}})();) when I want to use the module pattern.
    I’m actually aware of at least three more ways of creating functions, but those are such edge cases that they aren’t worth mentioning. But there are certainly more than two different ways of creating functions in javascript.

    • http://Phi.Lho.free.fr/ Philippe Lhoste

      Well, obviously the article was in the ES5 realm, it doesn’t use ES6 syntax at all. This excludes generators and arrows.
      Anonymous and named function expressions aren’t really different things.

      Same for immediately-invoked function expressions: that’s just a way of using an expression, not a new way of creating them.

      • Ian Hofmann-Hicks

        Even in ES5 it is bad practice to use assignment, unless you really have to. Hoisting has always been a thing. There is no real reason to use assignment unless your case is in the 1% where it is needed. It signals to future you and any other team m8 that, hey there is something special here. Never do anything extra unless you have a need, early optimization is the devil’s playground. And know the consequences of doing extra work.

        *** Replied to the wrong person, sorry about that Philippe Lhoste ***

    • paulwilkins

      Thank you for the further details there. It’s somewhat out of scope for a quick tip article, but we’ll definitely keep it in mind for when we cover it in greater depth.

  • Yao Ding

    There are two typos in the paragraph explaining the differences between expression and declarations:

    “Normally function declarations and function expressions can be used [interchangably], but there are times when function expressions result in [easiler] to understand code without the need for a temporary function name.”

  • http://andrew.hedges.name Andrew Hedges

    The article doesn’t point out any real benefits of using expressions beyond the subjective ‘cleaner and more readable code’. There is an actual functional difference as well. When created as a declaration, the function scope object is created and retained in the interpretation phase (which uses memory), whereas when created as an expression, the variable is created and the scope is only created if and when the function is invoked. It’s not a big difference in most cases, but it’s an actual benefit of one approach over the other rather than just a stylistic preference.

    • Aaron Boushley

      Agreed. This article seems to imply that closures are unique to function expressions, which just isn’t the case.

      You could just as easily use:

      function doSomethingHandler(itemIndex) {
      return doSomething;
      function doSomething(evt) {
      console.log(‘Doing something with ‘ + list[itemIndex]);
      }
      }

      Which uses only function declarations and has the same effect.

  • Ian Hofmann-Hicks

    There is a lot more to it than just pretty. TBH, if a developer HAS to still use var’s in their code, then using expression is the wrong move 99% of the time. The reason for this is due to how expressions are hoisted. When a person var func = function() {} then func is hoisted to the top of the file as undefined and the symbol does not receive it’s functionality until the assignment is reached. Total Bad News Bears and pointless unless you have an ACTUAL reason to do so. Now that said, the rest of us using let and const can do this without the side effect of hoisting, but really should only be used when doing Functional JS, for making small, one-liner compossible functions using arrow functions (because they CANNOT and should not be bound to a context (this)). Anything that is not a one-liner, should use function declaration.

  • nomaed

    I’ve seen a lot of code that uses only function expressions. The entire code base is “var something = function()…” I think that it’s an abuse of function expressions.
    For IIFEs, passing as arguments and all that, great. Use it. When it’s referenced only once, it’s very well.
    But if it’s a function that is used in many places, declare it as it what it really is: a function.
    Even from a stylistic point of view, function declarations make the code so much cleaner, it’s easier to find functions at a glance when looking at the file, and hoisting gives a huge benefit.

    I would never choose this:
    var library = (function(){
    var someFunc1 = function() { … };
    var someFunc2 = function() { … };
    var someFunc3 = function() { … };
    return {
    someFunc1: someFunc1,
    someFunc2: someFunc2,
    someFunc3: someFunc3
    }
    }());

    over this, much cleaner solution:
    var library = (function(){
    return {
    someFunc1: someFunc1,
    someFunc2: someFunc2,
    someFunc3: someFunc3
    }
    function someFunc1() { … }
    function someFunc2() { … }
    function someFunc3() { … }
    }());

    And it this example there’s no code.
    If there is actual code in the function body, the first version is much harder to read and track.
    Also, having the return statement on the top of the scope makes is very easy to see at a glance what the library/namespace/module actually does or what API it provides.

  • Bob Holben

    If we favor function declarations over function expressions, we can use hoisting to our advantage and make our code more readable at a glance by putting our most important (public) functions up top. I only use function expressions where I can’t use function declarations.

  • Bill Bird

    Hello,
    First of all, thanks for this nice article.
    Please let me ask a question not related directly to this article. I’m learning now Ruby on Rails. During a discussion with some friends, they said that JavaScript’s frameworks, are now the most faster scripts for any scalable application. They was talking about 10K issue, and for that JS is faster than Ruby (and sure Ruby on Rails). Can you give me your opinion about this point ?

    • paulwilkins

      Ruby on Rails is highly opinionated, it’s faster to initially develop your project, but has a steeper learning curve when compared to the like of Node.js. Factors of speed rarely become an issue so I suggest that you create a few projects with both. That way you’ll be able to apply your hand to both, depending on the situation.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.