Code Review: Underscore

Alex R. Young





functional code-review

Code Review: Underscore

Posted by Alex R. Young on .

functional code-review

Code Review: Underscore

Posted by Alex R. Young on .
*Code Review* is a series on DailyJS where I take a look at an open source project to see how it's built. Along the way we'll learn patterns and techniques by JavaScript masters. If you're looking for tips to write better apps, or just want to see how they're structured in established projects, then this is the tutorial series for you.

Underscore provides functional programming tools for JavaScript. Let's take a look inside to
see how key functions are implemented.

About Underscore

Underscore (GitHub: documentcloud / underscore,
License, npm: underscore) from DocumentCloud provides a rich set of functions
that help when dealing with arrays and objects. Many of these functions
are available in other languages, and some can even be found natively in
JavaScript depending on the browser or interpreter.

Underscore's API is accessed through an object rather than changing
Array or Object. That means it's easy to drop
into a project without affecting existing code.


The canonical example of Underscore is the each function:

_.each([1, 2, 3], function(num) {

The map function is similar, but allows the list to be

_.map([1, 2, 3], function(num) {
  return num * 3;

// Returns [3, 6, 9]

I really like reduce:

_.reduce([1, 2, 3], function(memo, num) { return memo + num; }, 0);
// Returns 6

Underscore quickly became popular for client-side programming, but an
increasing number of Node packages depend on it.


Like most JavaScript modules, Underscore is distributed in an anonymous

(function() {
  // Establish the root object, `window` in the browser, or `global` on the server.
  var root = this;

  // Save the previous value of the `_` variable.
  var previousUnderscore = root._;

  // Establish the object that gets returned to break out of a loop iteration.
  var breaker = {};

  // Save bytes in the minified (but not gzipped) version:
  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

  // ... snip

The author (Jeremy Ashkenas) has written detailed comments through the

Underscore will attempt to use native JavaScript methods where
available. We see this intention straight away at around line 35:

// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
  nativeForEach      = ArrayProto.forEach,
  nativeMap          = ArrayProto.map,
  nativeReduce       = ArrayProto.reduce,
  nativeReduceRight  = ArrayProto.reduceRight,
  nativeFilter       = ArrayProto.filter,
  nativeEvery        = ArrayProto.every,
  nativeSome         = ArrayProto.some,
  nativeIndexOf      = ArrayProto.indexOf,
  nativeLastIndexOf  = ArrayProto.lastIndexOf,
  nativeIsArray      = Array.isArray,
  nativeKeys         = Object.keys,
  nativeBind         = FuncProto.bind;

The most important function in Underscore is each, because
so many other methods are built on it. Because it delegates to
ECMAScript 5's native forEach it has to be compatible. It's
also defined in the each variable, which makes using it
throughout the rest of the file more straightforward (and save bytes):

var each = _.each = _.forEach = function(obj, iterator, context) {
  if (obj == null) return;
  if (nativeForEach && obj.forEach === nativeForEach) {
    obj.forEach(iterator, context);
  } else if (_.isNumber(obj.length)) {
    for (var i = 0, l = obj.length; i < l; i++) {
      if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
  } else {
    for (var key in obj) {
      if (hasOwnProperty.call(obj, key)) {
        if (iterator.call(context, obj[key], key, obj) === breaker) return;

A guard against null values is used, then
nativeForEach is tested. If this isn't available and the
object looks like an array, a simple for loop is used to iterate over
each value and run the callback. If the object looks like an
Object, a for... in loop is used instead.

However, because the nativeForEach && obj.forEach ===
test is used, nativeForEach will only
ever be used for arrays. The Mozilla Developer Network has some guidance
on implementing forEach-compatible methods, in the Array

if (!Array.prototype.forEach)
  Array.prototype.forEach = function(fun /*, thisp */)
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
      if (i in t)
        fun.call(thisp, t[i], i, t);

Since forEach is defined on Array.prototype,
Underscore has to provide its own functionality for objects. That means
this will work as expected:

_.each({ a: '1', b: '2' }, function(a, b) { console.log(a, b) });

Building on each

The map function works in a very similar way, testing for
native support then calling each if required:

_.map = function(obj, iterator, context) {
  var results = [];
  if (obj == null) return results;
  if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
  each(obj, function(value, index, list) {
    results[results.length] = iterator.call(context, value, index, list);
  return results;

If the native method can be used, the results are returned right away.
Otherwise, the results are collected up and returned by using

The context parameter is used throughout Underscore. This
is used by call to bind the callback. The first parameter
of call is thisArg

If thisArg is null or undefined, this will be the global object. Otherwise, this will be equal to Object(thisArg)

The MDN documentation on

has more information and examples.


The tests are written with QUnit, so
they can be run in a browser very easily: Underscore


Underscore's source reads almost like JavaScript documentation for the
methods it implements. And it's nice to see that a library that can give
so many productivity gains is actually simple and easy to follow.

Do you fancy building your own functional programming library? Start
with each and see how far you can get!