JavaScript Function Declarations vs Function Expressions

I recently revisited the differences between Function Declarations (FD) and Function Expressions (FE). I wanted to see if there were any compelling reasons to use one over the other, or if both were considered acceptable. I’ve taken most of my thoughts from a blog post by Angus Croll. It’s worth a read if this is a new topic for you.

In general, FDs and FEs are interchangeable because they both create a function. However, there can be some interesting gotchas (as always with JavaScript).

Even though all browsers handle Function Declarations within non-function blocks (e.g. if), they are technically prohibited. The caveat is that each browser handles them in its own way.

function a() {
    if (false) {
        function b() { return 'Will it return?'; }
    }
    return b;
}
console.log(a()); // result depends on browser

A Function Declaration is scoped to itself and its parent. As a result, you can call it recursively and in the parent (it would be mostly useless otherwise). For example:

function minusOne(positiveNumber) {
    console.log(positiveNumber--);
    if (positiveNumber > -1) {
        return minusOne(positiveNumber);
    }
}
minusOne(2);   // 2 1 0

A Function Expression works just as well:

var minusOne = function (positiveNumber) {
    console.log(positiveNumber--);
    if (positiveNumber > -1) {
        return minusOne(positiveNumber);
    }
};
minusOne(2);   // 2 1 0

You could make the FE above a Named Function Expression (NFE) by naming the anonymous function subtractOne and it would still work. Furthermore, you could replace the recursive call to minusOne with subtractOne and it would work (assuming you named the anonymous function subtractOne). The following, however, would NOT work:

var minusOne = function subtractOne(positiveNumber) {
    console.log(positiveNumber--);
    if (positiveNumber > -1) {
        return minusOne(positiveNumber);
    }
};
subtractOne(2);   // subtractOne is not defined

You cannot call the named function outside of its assignment.

Here’s another function I wrote just for fun:

function moveToZero(number) {
    var absNumber = Math.abs(number);
    console.log(number);
    if (absNumber-- !== 0) {
        return moveToZero(number > -1 ? absNumber : ++number);
    }
}
moveToZero(2);  // 2 1 0
moveToZero(-2); // -2 -1 0

Function Expressions are more versatile. They are the essence of functional programming. You can create Function Expressions using anonymous functions. You can assign functions to objects as properties or, more specifically, assign them to prototypes. Immediatley Invoked Function Expressions (IIFEs) are considered Function Expressions. As Croll points out, currying and composing use FEs.

One of the caveats to Function Expressions is that functions are often created using anonymous functions, which can make debugging a pain. As a work around you can use Named Function Expressions, as seen in the examples above. However, NFEs are not supported in non-modern browsers (IE8 and below). Always something to keep in mind.

Many developers steer away from Function Declarations because they can be confusing. There aren’t many, if any, times you cannot replace a Function Declaration with a Function Expression. FEs are often favored for consistency and versatility.

Comments, questions and feedback welcome.