Here’s a Nickel, Kid

One of my favorite Dilbert cartoons depicts a rotund, bearded dude in suspenders snubbing Wally by saying “Here’s a nickel, kid.  Get yourself a better computer.”  (I’m not going to reproduce it here for copyright reasons, but I’m sure the Google Machine will happily serve up the image for you.)  The joke, of course, is that the bearded dude is one of those “condescending UNIX users”.  Being a condescending UNIX user is second only in computer science snobbery to functional programmers.  You know the type: turning their noses up at the unwashed masses of procedural programmers, preferring ivory tower languages like Clojure, ML, Erlang, or Haskell (not to mention those F# black sheep).

I have a confession to make: I’ve always wanted to be one of those functional programming snobs.  But I also like making a living, so instead I toil in the procedural mines.  I fell in love with ML in university.  The intellectual purity of it was so appealing.  Good luck finding a functional programming job outside of academia or rarefied think tanks, though.

I’m happy to report that the times they are a changing, and not because of traditional functional programming languages, but because of JavaScript.  Now even the cool kids are talking about closures, lambdas, and currying.  And it’s all thanks to the underdog welterweight that is JavasScript.

JavaScript continues to impress me with its irreverent and indolent agnosticism.  It’s not there to tell you how to do things, man.  JavaScript is like that hippie stoner who’s at every party, and makes shockingly astute observations.  Years later, you find out he’s actually finishing up double PhDs and his start-up just got seventeen million dollars of start-up funding.

Today I’m going to share with you some of my favorite little JavaScript extensions I’ve written, all functional style.  Some are all highbrow (like Array.prototype.complement) and some are decidedly lowbrow (like Array.prototype.trim).

Note that in all cases, I’m using Object.defineProperty instead of setting the property directly on the prototype object. The reason I do this is so that I can make the functions non-enumerable. Otherewise, they will show up in a for/in enumeration of the object, and who knows what kind of terrible side-effects that could have. It’s always a good practice when you’re extending core objects (some would argue that you shouldn’t extend core objects at all, but not me).

Enjoy:

// given an array of strings (or objects that can be
// coerced into strings),
// returns an array of trimmed strings
Object.defineProperty(Array.prototype,'trim',{
    value: function() {
        return this.map( function(s) {
            return s.toString().trim();
        } );
    },
    enumerable: false
});

// given an an array of numbers, will return the largest
// number.  if any one of the elements is not a number,
// NaN will be returned.  alternately, you can provide a
// selector function that returns a number.
Object.defineProperty(Array.prototype,"max",{
    value: function(selector) {
        if( !selector ) selector = function(x) { return x; };
        return Math.max.apply( null, this.map( function(x) {
            return selector(x);
        } ) );
        // alternate approach:
        // return this.reduce( function(s,x) {
        //    return Math.max( s, selector(x) ); }, -Infinity );
        // };
    },
    enumerable: false
});

// returns true if an array contains some value (using
// strict comparison)
Object.defineProperty(Array.prototype,"contains",{
    value: function(x) {
        return this.some( function(z) { return z===x; } );
    },
    enumerable: false
});

// returns the complement of an array (that is, what's
// NOT in the array, selected out of some "universe"
// array).  example:
// [1,3,5].complement( [1,2,3,4,5] ) returns [2,4]
Object.defineProperty(Array.prototype, "complement",{
    value: function(b) {
        var a = this;
        return b.reduce( function(s,x) {
            if( !a.contains(x) ) s.push(x); return s;
        }, [] );
    },
    enumerable: false
});

// determines if a string contains only whitespace
Object.defineProperty(String.prototype,"isWhitespace",{
    value: function() {
        return !!this.match(/^\s*$/);
    },
    enumerable: false
});

// retrieves all of the properties of an object as an array,
// omitting properties in the prototype chain
Object.defineProperty(Object.prototype,"ownProps",{
  enumerable: false,
  value: function() {
    var props = []; for( var prop in this ) {
        if( this.hasOwnProperty( prop ) ) props.push( prop );
    }
    return props;
  }
});

3 Comments on Here’s a Nickel, Kid

  1. You’re analogies are perfect and it’s no wonder I love JavaScript so much. Nice list of helpers. One thing to note for ‘Array.prototype.contains’ is that ‘.some’ is not supported in IE8 and below.

    p.s. You need to write a book.

  2. Thanks, Greg! I’m glad you like the analogies. Fortunately, if you’re working in an environment in which Array.prototype.some isn’t available, it’s super easy to polyfill: `Array.prototype.some = function(f) { return !!this.filter(f).length; }`.

  3. Or `or Array.prototype.some = function(f) { for( var i=0; i<this.length; i++ ) if( f(this[i]) ) return true; return false; }`