Home > Programming > Easy functional programming in JavaScript with Underscore.js — part 1

Easy functional programming in JavaScript with Underscore.js — part 1

So, you’ve been developing in JavaScript for a while, you’re getting on quite well with your for and while loops, when somebody comes along and tells you you shouldn’t be doing that, that JavaScript is a functional programming language and there’s much better ways to solve most problems that with loops. Whaaa…? Well, that’s what I’m here to tell you anyway.

What is functional programming?

Functional programming (FP) is all about the idea of functions as a mapping from one value to another. An FP function just turns one value into another – it doesn’t have side effects. Side effects are anything that happens within the function that changes something outside of the function. For example, changing the value of a variable not defined in the function, or logging output, or showing an alert message … basically anything that happens in the function. The only thing an FP function does is takes in a value, and returns a new value.

Another interesting thing about FP is the use of higher-order functions. These are functions that either take or return functions as values (or both). I’m mainly going to be looking at functions that take other functions as parameters, because there are some interesting things you can do with that.

An underscore, courtesy of Wikipedia

Functional programming in JavaScript is made a lot easier with a suite of functions called Underscore.js all packed into a minified script of just 3kb. Underscore provides a selection of common FP functions for working on collections, like map, each, reduce, select etc. I’ll walk through some of these to demonstrate the power of FP. Note that functional programming isn’t just about working with collections – there are lots of other exciting things you can do – but for now I’ll concentrate on the collections.

Mapping over an array

One of the most widely used Underscore functions is _.map. This takes an array and a transforming function, and creates a new array based on the return value of the transforming function. That’s a bit abstract so I’ll give you an example:

So, _.map is passed an array, and a function. That function is called on each element of the array in turn, and the return value of the function gives the corresponding element in the new array. Note that the original array is left intact. The _.map function takes an array, and returns another array – it’s a mapping from one value to another.

You can do much more interesting things with _.map than just multiplying numbers though. You could transform an array of strings into an array of cats!

I hope you’ll forgive me for using two Underscore functions there. First off, we’ve got _.map. In this case, we’re going through the array of cat names, and creating an array of cats. The second is _.each. This, like _.map, goes through each element of the array, passing them into the function, but it doesn’t care about the return value. It just executes the function and carries on with its life. Now, if you’re concentrating, you may have noticed that each isn’t actually a mapping from one value to another, and you’d be right. _.each is only useful if you allow side effects, for example console.loging. A JavaScript program isn’t much fun without any side effects, because you’d have no idea if anything happened otherwise. The key to functional programming is minimising the side effects.

What’s great about _.map is that once you’ve learned to read it, and understand what it does, it really succinctly explains the meaning of your code. In that cat example, you can see that all the _.map function is doing is turning strings into cats. That’s all you need to know. The old-school JavaScript technique would look like this:

In comparison, isn’t that just damn ugly? I mean, to read that you need to keep track of the array, and the array index, and the length of the array, and you have to make a new blank array to contain the new cats, and … you get the point. It’s mixing up the how with the what. All I care about is that I’m getting an array of cats, from an array of cat names. Don’t bother me with insignificant details like array indices.

Here’s another example: constructing a query string:

This one uses an object, but the same principles apply. From a list of key/value pairs, we’re constructing an array of ‘key=value’ strings. Then all you need to do is join the array with &s. This describes how a query string is formed much more declaratively than the standard

append the key, then an equals, then the value, then an ampersand, then the next key, then the next value, then another ampersand, then – oooh we’re at the end – better get rid of that last ampersand, whoops!

Go forth and map-ify!

I hope that’s given you some ideas as to how functional programming can be used in JavaScript. And I really hope that you can begin to see how much cleaner your code can get when you cast out the for loops and embrace the _.map. If all you’re after is map and each, and you’re using jQuery, you’ll be glad to know both functions have jQuery equivalents: jQuery.map and jQuery.each, albeit with a slightly different API. Next time I’ll be looking at some of Underscore’s other functions, for the times when _.map just won’t cut it.


Part 2 is now up!

Categories: Programming Tags: ,
  1. July 27th, 2011 at 13:47 | #1

    Another interesting thing about FP is the use of higher-order functions. These are functions that either take or return functions as values

    Just a small correction here. Support for higher-order functions means the language handles functions as values; they can be stored in variables, accepted as function arguments and returned from functions.

  2. July 27th, 2011 at 14:14 | #2

    @mhitza Yes, you’re right – higher-order functions are dependent on functions being first-class citizens.

    I think what I said is correct as-is though, I didn’t want to muddy the waters by talking about first-class functions and higher-order functions.

  3. Florin
    July 27th, 2011 at 16:48 | #3

    Great introductory article. Now imagine that CoffeeScript is to Javascript what underscore is to non-underscore programming :).. Here is the example in CoffeeScript:

    CatMaker = (name) -> speak: -> console.log 'My name is ' + name
    catNames = ['Charlie', 'Fluffy', 'Mouse']
    cats = _.map catNames, (name) -> CatMaker name
    _.each cats, (cat) -> cat.speak()
    

    Now a more compact version:

    _.each (_.map ['Charlie', 'Fluffy', 'Mouse'], (name) -> speak: -> console.log 'My name is ' + name), (cat) -> cat.speak()
    

    And a non-underscore version:

    CatMaker = (name) -> speak: -> console.log 'My name is ' + name
    cat.speak() for cat in (CatMaker(name) for name in ['Charlie', 'Fluffy', 'Mouse'])
    

    Btw, underscore was written by the same guy who created CoffeeScript (and also backbone.js – another gem).

  4. July 27th, 2011 at 16:58 | #4

    @Florin Hey, thanks for the comment. The code got a bit mangled – I’ve tried to nurse it back to full health but it may not be perfect.

    Yeah – I’m planning on having a go with CoffeeScript at some point, it looks really good.

    Backbone was actually my introduction to Underscore. I’ve got a blog post on Backbone and Jasmine in the works hopefully :)

  5. March 2nd, 2012 at 19:51 | #5

    Underscore.js has another set of functions chain(), wrap(), compose() that are very powerful. Consider your cat.speak() sample… revised below:

            _.chain(catNames)
              .map( function (name) {
                return CatMaker(name);
              })
              .each( function (cat) {
                cat.speak();
              });
    

    Talk about DRY and code terseness… love it! Thanks for the article.

    • ThomasB
  6. August 30th, 2012 at 08:09 | #6

    Instead of doing

    var cats = _.map(catNames, function (name) {
        return CatMaker(name);
    });
    

    I think you can just do

    var cats = _.map(catNames, CatMaker);
    

    map should pass the name right to CatMaker as an argument, and then get back a new cat :D

  1. July 29th, 2011 at 09:37 | #1
  2. July 29th, 2011 at 15:56 | #2

Comments parsed as Markdown.