Reading code: underscore.js

I’ve been spending a bit of time reading through the source code of underscore.js, a JavaScript library that provides lots of functional programming support which my colleague Dave Yeung pointed out to me after reading my post about building a small application with node.js.

I’m still getting used to the way that JavaScript libraries are written but these were some of the interesting things that I got from reading the code:

  • There are a couple of places in the code where the author has some code which runs conditionally and this is achieved by including that expression on the right hand side of an ‘&&’.

    For example on line 129 in the ‘filter’ function:

    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    
      // Return all the elements that pass a truth test.
      // Delegates to JavaScript 1.6's native filter if available.
      _.filter = function(obj, iterator, context) {
        if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
        var results = [];
        each(obj, function(value, index, list) {
          iterator.call(context, value, index, list) && results.push(value);
        });
        return results;
      };

    I would probably have used an if statement to check the result from calling ‘iterator’ but this way is more concise and pretty neat.

    The same type of thing is done on line 150 in the ‘every’ function:

    145
    146
    147
    148
    149
    150
    151
    152
    153
    
      _.every = function(obj, iterator, context) {
        iterator = iterator || _.identity;
        if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
        var result = true;
        each(obj, function(value, index, list) {
          if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
        });
        return result;
      };

    The result is collected and the loop will also exit if the value of ‘result’ is ever false which is again a cool way to organise code.

  • It’s also quite cool that you can assign a value to a variable from within a conditional – this isn’t possible in any of the other languages that I’ve used previously as far as I’m aware.

    It’s even more evident in the ‘max’ function:

    191
    192
    193
    194
    195
    196
    197
    198
    199
    
      _.max = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
        var result = {computed : -Infinity};
        each(obj, function(value, index, list) {
          var computed = iterator ? iterator.call(context, value, index, list) : value;
          computed >= result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
      };

    ‘result’ is conditionally assigned on line 196 but only if the computed value is greater than the current computed value. Again an if statement is avoided.

    Another interesting thing about this function is that it specifically checks the type of the ‘obj’ passed in which reminded me about the discussion around Twitter having those sorts of checks in their Ruby code around a year ago. I guess that type of thing would be more prevalent in library code than in an application though.

  • I hadn’t come across the !! construct which is used to turn a JavaScript expression into its boolean equivalent:
    506
    507
    508
    
      _.isArray = nativeIsArray || function(obj) {
        return !!(obj && obj.concat && obj.unshift && !obj.callee);
      };

    Without using ‘!!” the expression would return ‘undefined’ in the case that one of those functions on ‘obj’ was not set. ‘!!’ forces the return value to be ‘false’.

  • Another technique used in this code base is that of dynamically adding methods to the prototype of an object:
    666
    667
    668
    669
    670
    671
    672
    673
    
      // Add all mutator Array functions to the wrapper.
      each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
        var method = ArrayProto[name];
        wrapper.prototype[name] = function() {
          method.apply(this._wrapped, arguments);
          return result(this._wrapped, this._chain);
        };
      });

    This is quite a cool use of meta programming although it isn’t initially obvious how those functions end up on the object unless you know what to look for. It does significantly reduce the code needed to add these functions to the ‘wrapper’ object’s prototype, avoiding the ‘same whitespace, different values‘ problem that Neal Ford outlines in his article about harvesting idiomatic patterns in our code.

This entry was posted in javascript. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

5 Responses to Reading code: underscore.js

  1. Siim says:

    Same constructs (!! and assignment in conditional) can also be used in PHP, although such an assignment generates warning in Zend studio and I usually don’t like to use such constructs.

  2. Matt Freeman says:

    I would argue that these opinionated techniques hinder the readability of the code, especially to others coming from different languages – most people will be switching in and out of javascript and into their primary language c#/ruby/python etc… As code is compressed, and minified, and even rewritten with Google Clojure, there no excuse for not being as expressive and clear as possible. The double bang operation is logically the same as boolean(obj && obj.concat && obj.unshift && !obj.callee) – but which is clearer at the cost of 5 characters? same as with the &&, an if is clearer.
    Too smart, no benefit. Good article though.

  3. fschwiet says:

    There’s a port of underscore for Lua as well. I think the library offers some pretty useful functionality, but the name is a bit tragic as its so hard to use search engines to find information on it.

  4. Michael Poole says:

    C and C++ allow assignments within a conditional. Good compilers even generate a warning when it looks like you might have done it accidentally (the difference between “if (a = b)” and “if (a == b)” is small — but, for example, gcc will accept “if ((a = b))” without a warning). The !! notation might well have originated with C; it is certainly a well-known idiom there.

  5. Scott Koon says:

    Mark,

    The && and || operators in JavaScript are short-circuited. Which makes those types of conditionals possible. You can also use them to create optional parameters with default values for your functions.

    http://www.lazycoder.com/weblog/2008/02/26/modern-javascript-development-constructors-and-objects/

Leave a Reply