About Unboxing

Unboxing is our regular feature where someone at Box UK spends a few hours playing with a new framework, library, tool or technique and blogs about his or her experience.

Map, reduce and Underscore.js

Goodness me, the web moves quickly, and it seems that nothing moves more quickly than JavaScript. I often feel that I’m drowning in a sea of things called {insert abstract term here}.js. The guys here were discussing these things on the Box UK coders mailing list and our #dev IRC channel recently, and my ignorance got the better of me so I decided to take a look.

What is it?

I’ve been overhearing a lot of chatter about map/reduce around the water cooler, and I’d assumed it was some advanced mathematical concept beyond the likes of me, intended for the kind of superboffin who took something away from A Brief History Of Time beyond “well, Professor Hawking seems like a nice bloke” (which is all I got from it – well, that and a headache). In the end, though, I braved it and decided to have a look anyway! I realised the source of my confusion quickly – MapReduce is a Google software framework, whereas map and reduce (AKA fold) are common functions in functional programming – it was nothing scary after all!

JavaScript 1.6 brought three new array iterative functions, including map(), with JavaScript 1.8 bringing us the reduce() function. All map does is apply a given function to each element of a list, returning a list of all the results. Similarly, reduce uses a function to go through a data structure to build up a return value.

So, all sounds good, right? Well, it’s the usual story: while every version of Firefox from 1.5 onwards has supported version JavaScript Standard 1.6 and above (Firefox 3.0 and better support JavaScript 1.8). Internet Explorer 8, however, only supports JavaScript 1.5, so we can’t reliably use these functions cross-browser.

Step in Underscore.js, version 1.2.1 of which came out on Oct 24th, 2011. Underscore.js provides functions that support map, reduce etc. but without having to extend built-in JavaScript objects, meaning it plays more nicely when using a whole fistful of {insert abstract term here}.js libraries, as we are wont to do nowadays!

Getting to grips

I grabbed a copy of the source code and created a very simple test bed. Underscore.js simply names itself as a variable “_” in the global namespace, so I could test it out in Chrome:

_([1,2]).map(function(x) { return x * 4; }); 

Outputs:

[4, 8]

This is the functional way of doing things and it worked first time, which was pleasing, as at this point I had little clue what I was doing! I decided to write a script that did both map and reduce, adapting some of the sample code to sort a mixed collection of fruit and veg into a single, flattened array:

var foodParcel = [
   {type: 'fruit', contents: 'apple,banana,pineapple,banana' },
   {type: 'veg', contents: 'carrot,beetroot' }
];
 
_(foodParcel).chain()
 .map(function(type) { return type.contents.split(','); })
 // break down types
 .flatten() // squash it down to a single array
 .reduce(function(counts, item) {
     counts[item] = (counts[item] || 0) + 1;
     return counts;
 }, {}).value(); 

Outputs:

Object
1.  apple: 1
2.  banana: 2
3.  beetroot: 1
4.  carrot: 1
5.  pineapple: 1
6.  __proto__: Object

Going deeper

There are a whole bunch of functions available in the Underscore library, but before trying any of those I checked that it worked on Internet Explorer 8. Results were good!

The beauty of Underscore.js is that it falls back to native implementations where possible, giving maximum performance. It won’t pollute your global objects, making it safe for inclusion. As a primarily OO guy, I’m no expert in functional programming paradigms, but playing with Underscore.js has been another step down the road to understanding the power and elegance the approach affords.

Want to find out more?

This is the article which prompted the discussion.

At Box UK we have a strong team of bespoke software consultants with more than two decades of bespoke software development experience. If you’re interested in finding out more about how we can help you, contact us on +44 (0)20 7439 1900 or email info@boxuk.com.