Friday, July 10, 2009

JavaScript Expression Closures and Why They Rock

JavaScript expression closures (new for JS 1.7 but syntactically even cleaner in 1.8) are one of those things that seem very so-what the first time you hear about it, but leaves you slapping your forehead and saying "OMG this is so darn freakin' cool" repeatedly after you start using it. Why? Because OMG. It's so darn freakin' cool.

The basic notion is that instead of writing short utility functions (which I have a million of) as, for example
function square( x ) {
return x * x;
}
you just write
function square( x ) x * x
which (yes yes, I know) looks very so-what, but bear with me for a moment. The short syntax starts to become more compelling when you begin using it in anonymous functions, particularly callback functions (which, as you know, tend to be anonymous a great deal of the time). For example, suppose you have a custom comparator for the sort() method of Array:

function descending( a,b) {
return b > a;
}

[5,1,3,2,4].sort(descending); // [5,4,3,2,1]

You can instead write it as:
[5,1,3,2,4].sort( function(a,b) b > a );
Another fairly trivial example: Suppose you want a function that will constrain strings to a certain length. You can do something like:
function limit(s, n) s.length > n ? s.substring(0,n): s
As a more elaborate example, suppose you have the following code, designed to convert a "camelCase" string to underscore_format.
function underscore( str ) {

function toUnderscore( s ) {
return '_' + s.toLowerCase();
}

return str.replace(/[A-Z]/g, toUnderscore );
}

// underscore( "aName") --> "a_name"

With the new closure syntax, you can do:
function underscore( str )
str.replace( /[A-Z]/g,
function(s) '_' + s.toLowerCase() );
Here I've converted not only the outer function, but also the callback to replace(), to expression-closure form. (I split it into 3 lines for readability, but it will still execute correctly as a 3-liner. You don't have to write these things as one-liners.)

Still not convinced? Try using this syntax (supported in Firefox 3+, and anywhere else JS 1.7 or 1.8 are implemented) in some functions yourself, and see if your code doesn't become easier to write, shorter, and (in most cases) more readable. It may be only a small improvement on the more verbose older syntax, but an improvement is an improvement. I'll take it.

6 comments:

  1. I might be confused, but it seems that the only difference between the lambda functions and the expression closures is the lack of brackets and an implied return() statement. Is there something else that I am missing?

    I find the expression closure to be less readable as it lacks the visual delimiters of the anonymous functions.

    ReplyDelete
  2. @Ben
    I'm tired of people making readability arguments about any reduction/change in syntax. What they really mean is, "that's different and unfamilliar, I'm scared."

    It's like complaining that Spanish is a less readable language because of verb conjugation. If you don't know Spanish well, that might be true, but if you do know Spanish, you realize that it is both shorter and more efficient, as well as less ambiguous than English.

    Give yourself a chance to get used to the new syntax and you'll realize that the delimiters and return statement are unnecessary cruft. Your eyes will learn to recognize expression closures by the rules: function (without a {) and a single line. Easy.

    @Kas, if you indented that last code snippet a little better, it might seem more readable.

    ReplyDelete
  3. To Ben: Well, in spite of the apparent lack of readability (which is true, but honestly depends on the way you write and indent your code) closures are very useful to define value of callback parameter. No the only purpose but one on the main interest to me.

    ReplyDelete
  4. Nice. But you're exaggerating the benefit somewhat. In the old syntax you don't need a separate named function, you can just do this:

    [5,1,3,2,4].sort(function(a,b){return b > a;});

    Which is basically the same thing, but in my opinion actually less readable.

    ReplyDelete
  5. Anonymous8:16 PM

    to me it looks like lazy programming, if your 100% you'll never need that function again your probably wrong. Then what refactoring later.

    ReplyDelete
  6. I think the term "expression closure" will just make it confusing for something that's just a lambda, people have a hard time understanding these concepts, and if we start mixing up names we have no hope

    ReplyDelete

Add a comment.

Note: Only a member of this blog may post a comment.