Declare that function! But, how?

So, I read a blog post about declaring functions in JavaScript recently. It was just about technically correct as far as it went, but, ow, the way it was written hurt (missing semicolons, invalid code samples, etc). I’ll decline to link to it, thanks very much, but instead I’ll bring out its main points together with a recommendation or two (that, in fact, the original blog post did not).

There are two ways to declare a function in JavaScript, although we can spin ’em out a bit. Ready?

"use strict";

// example 1 - function expression
var doThis = function () { console.log("doThis"); };
doThis();

// example 2 - function statement
function doThat() { console.log("doThat"); };
doThat();

// example 3 - a mix?
var doTheOther = function orThisOther(again) {
    if (again) {
        console.log("orThisOther");
    }
    else {
        console.log("doTheOther");
        orThisOther(true);
    }
};
doTheOther(false);

// example 4 - IIFE
(function () { console.log("anonymous"); })();

(If you run this code in your browser’s console, you’ll get …

doThis
doThat
doTheOther
orThisOther
anonymous

… of course.)

Whitby wave action warning

Whitby wave action warning

In essence, we have a variable being set to a function expression in the first example, and we have a function statement in the second example. The other two examples I’ll get to in a moment. The first example, then, reinforces the fact that functions are objects. You can create them, pass them around, save them in variables (or in properties – in which case, we call them methods – or in arrays or whatever), use them in callbacks, and invoke them. For me, this is by far one of the most important features of JavaScript, the fact that it is a functional language. Functions are objects; remember that.

The second example gives you one added benefit: function statements are “hoisted” to the start of the scope. You don’t have to declare the function before using it, in other words. The JavaScript compiler will, in essence, invisibly move the function statement to the top of the scope so that you can call it whenever you want in the scope. Yes, you got it: you can be lazy and call a function in your code before you’ve actually coded it. This is, to be honest, a pretty shady way of coding in my view. I do not recommend it at all; it makes reading and understanding the code just that little bit harder. Anyway, apart from that little trick, a function statement acts just like a function expression that’s saved in a variable, except that you are hiding the functions are objects concept. And yes, you can assign a function statement to a variable, and invoke it through that variable:

var foobar = doThat;
foobar(); // prints "doThat"

The fun starts when you mix the two, as in the third example. Actually this shows a named function expression, not a function statement being immediately assigned to a variable. The name of the function expression can be used inside the function itself to allow for recursion. The name of the function expression is not visible outside the function expression; I can’t for example just call doThisOther() in my main code: I’ll get the error “undefined”. So, example 3 is a use-case, but very limited. I can’t say I’ve ever used it in “real code”, apart from in examples like this one.

And then finally in example 4, we have an IIFE, an Immediately-Invoked Function Expression. As its name says, it’s a function expression that is called immediately. It is not saved anywhere, for example in some variable. If it weren’t immediately invoked it would be lost, there would be no reference to it anywhere. IIFEs are used all over the place in JavaScript code, it is an extremely common pattern. (Note the extra parentheses around the function expression: that’s so the JavaScript compiler determines that you are not declaring a function statement when it parses function.)

As for callbacks where commonly you provide an anonymous function expression to the function that will do the callback, all that’s happening is that the anonymous function is assigned to a parameter (that is, a variable):

var callSomeFunction = function (f) {
    console.log("Calling f...");
    f();
};

callSomeFunction(function () {
    console.log("a callback function");
});

And this produces:

Calling f...
a callback function

So, all in all, my advice is to stick to function expressions exclusively. The one single feature a function statement has that an expression does not, hoisting, can lead to less readable code, and we wouldn’t want that.

Album cover for DJ-KicksNow playing:
Thievery Corporation - Coming from the Top
(from DJ-Kicks)

 

Loading similar posts...   Loading links to posts on similar topics...

2 Responses

 avatar
#1 James Curran said...
04-Feb-15 2:13 PM

Funny, I'd say the exact opposite: stick to function statements exclusively.

There's no benefit at all to function expressions, and without hoisting, function expression allow you to call a function before it's declared. (going BOOM!)

It makes more sense if you realize, ALL function declarations (statements, and expressions) are "hoisted" (actually processed first, during what is comparable to the "compile" phase) and all anonymous function are given machine-generated names. So, JavaScript really considers your first example as if it were written:

function _anon_1111 () { console.log("doThis"); };
function doThat() { console.log("doThat"); };
function orThisOther(again) {
    if (again) {
        console.log("orThisOther");
    }
    else {
        console.log("doTheOther");
        orThisOther(true);
    }
}
function _anon_2222() { console.log("anonymous"); }
// example 1 - function expression
var doThis = _anon_1111; 
doThis();
// example 2 - function statement
doThat();
// example 3 - a mix?
var doTheOther = orThisOther;
doTheOther(false);
// example 4 - IIFE
_anon_2222();
    .

So, function definitions are handled during the "compile" phase, followed by the code actually running during the "execution" phase. Using function expressions, you just have that pointless assignment at "runtime".

julian m bucknall avatar
#2 julian m bucknall said...
04-Feb-15 8:22 PM

@James: thanks for the comment. Let em see if I can't elucidate further.

First of all, I guess I didn't state strongly enough that either way -- should a function be declared as a statement or expression -- it is perfectly valid JavaScript. I suppose you are right (although I've never investigated): the compile phase would generate names for function expressions via some non-published randomized naming scheme and then hoist away. My thoughts are not about that, but about defining a practice that one should stick to in one's programming.

Now the thing is hoisting happens with every variable, be it function, number, boolean, object, string, array, whatever. So the first standard practice you learn is to declare your variables first when you are in a function scope. Agreed? In fact, unless you turn that option off, the various lint apps check that. So you get used to (at least I did) to declaring your variables at the top, and generally as a sequence of variables separated by commas and terminated by the ubiquitous semicolon. And of course function expressions are just values for variables, so I put them in that same list. Agreed, I don't have to, but I do.

Another example: returning a function from a function. Sometimes it really is easier to return a function expression, although, agreed, you don't have to.

Another example is when you're declaring some quick off-the-cuff object, say a default configuration object, inside a function. The API allows the user of the function to pass in an other configuration object with values that should be used instead. (This design requires the use of an extend function, such as the one in jQuery; a topic for another time.) It is easier to declare methods in this default configuration object as expressions in the normal flow of declaring properties of the object. Agreed you don't have to, but it keeps all the code for the default object together. Here's an example from the jQuery code:

jQuery.extend({
 // Unique for each copy of jQuery on the page
 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
 // Assume jQuery is ready without the ready module
 isReady: true,
 error: function( msg ) {
  throw new Error( msg );
 },
  // and so on, so forth...

So, all in all, even though each of these examples could be written quite easily with function statements, they are easier to write with expressions. And once you get used to the practice of using expressions, you use them everywhere, since for me anyway they constantly remind me that functions are objects.

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response