Hostingheaderbarlogoj
Join InMotion Hosting for $3.49/mo & get a year on Tuts+ FREE (worth $180). Start today.
Advertisement

Getting Cozy With Underscore.js

by
Gift

Want a free year on Tuts+ (worth $180)? Start an InMotion Hosting plan for $3.49/mo.

As JavaScript is slowly moving out of the browser, several tools have emerged that significantly improve JavaScript's robustness.

One such tool is called Underscore.js and that's what we're going to take a look at today. Let's get started!


Meet Underscore.js

So what exactly does Underscore do?

Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects.

One of the nicer things about working in Python or Ruby are the fancy constructs like map that make life a lot easier. The current version of JavaScript, sadly, is fairly barebones when it comes to low level utilities.

As you read above, Underscore.js is a nifty little JavaScript library that brings in a ridiculous amount of functionality at a mere 4kb.


Underscore in Action

"Enough yapping about the library", I can hear you say. Right you are! Let's take a look at Underscore in action first before I resume my yapping.

Let's assume you have a random array of test scores and you need a list of those with 90+ score. You'd usually write up something like so:

var scores = [84, 99, 91, 65, 87, 55, 72, 68, 95, 42], 
topScorers = [], scoreLimit = 90;

for (i=0; i<=scores.length; i++)
{
	if (scores[i]>scoreLimit)
	{
		topScorers.push(scores[i]);
	}
}

console.log(topScorers);

It's pretty simple and even with optimization, it's fairly verbose for what we're trying to do.

Let's look at what we can achieve with Underscore next.


var scores = [84, 99, 91, 65, 87, 55, 72, 68, 95, 42], 
topScorers = [], scoreLimit = 90;

topScorers = _.select(scores, function(score){ return score > scoreLimit;});

console.log(topScorers);

I don't know about you but I just had a nerdgasm. That's some incredibly concise and readable code right there.


Sweet but Do I Really Need This?

Well, it all depends on what you're trying to do. If your use of JavaScript is limited to merely playing around with the DOM, then the answer is mostly no since jQuery does most of what you'd want to do.

Yes.

On the other hand, if you're dealing with non-DOM code or even complex, think MVC, front end code, Underscore is an absolute boon.

While some of the functionality exposed by the library is slowly making its way into the ECMA specifications, it's not available in all browsers and making your code work cross browser is another nightmare on its own. Underscore provides you with a nice set of abstractions that work everywhere.

And if you're a performance oriented person, as you should be, Underscore falls back to native implementations, if available, to make sure performance is as optimal as possible.


Getting Started

Just grab the source here, include it in your page and you're good to go.

If you were expecting a big set up process, you're going to be sorely disappointed. Just grab the source here, include it in your page and you're good to go.

Underscore creates and exposes all its functionality via a single object, in global scope. This object is the titular underscore character, _.

If you're wondering, yes, this is quite similar to how jQuery works with the dollar [$] symbol. And just like jQuery, you can remap this character in case you run into conflicts. Or if you're like me and have an irrational love for the tilde.


Functional or Object Oriented?

While the official marketing blurb for the library states that it adds functional programming support, there is actually another way of doing things.

Let's take our earlier code as an example:


var scores = [84, 99, 91, 65, 87, 55, 72, 68, 95, 42], topScorers = [], scoreLimit = 90;

topScorers = _.select(scores, function(score){ return score > scoreLimit;});

console.log(topScorers);

This method above is the functional, or procedural, approach. You can also use a more straightforward, probably more apparent, object oriented approach.


var scores = [84, 99, 91, 65, 87, 55, 72, 68, 95, 42], topScorers = [], scoreLimit = 90;

topScorers = _(scores).select(function(score){ return score > scoreLimit;});

console.log(topScorers);

There is no real 'right' way to do things but keep in mind that you can jQuery-esque method chaining with the latter method.


Checking Out the Functionality

Underscore provides a little more than 60 functions that span a number of functionalities. At their core, they can be classified into groups of functions that operate on:

  • Collections
  • Arrays
  • Objects
  • Functions
  • Utilities

Let's take a look at what each does and if applicable,one or two of my favorites from each section.


Collections

A collection can either be an array or an object, an associate array in JavaScript if I'm to be semantically correct.

Underscore provides a lot of methods that operate on collections. We saw the select method earlier. Here are a few more incredibly useful ones.

Pluck

Let's say you have a nice little array containing key value pairs and you'd like to extract just a specific property from each. With Underscore, it's a cinch.


var Tuts = [{name : 'NetTuts', niche : 'Web Development'}, {name : 'WPTuts', niche : 'WordPress'}, {name : 'PSDTuts', niche : 'PhotoShop'}, {name : 'AeTuts', niche : 'After Effects'}];
var niches = _.pluck(Tuts, 'niche');

console.log(niches);

// ["Web Development", "WordPress", "PhotoShop", "After Effects"]

Using pluck is as simply as passing in the target object or array as well as which property to pick out. Here, I'm merely extracting the niche for each site.

Map

Map creates an array from a collection where each element can be mutated or otherwise changed through a function.

Let's take the earlier example and extend it a bit.


var Tuts = [{name : 'NetTuts', niche : 'Web Development'}, {name : 'WPTuts', niche : 'WordPress'}, {name : 'PSDTuts', niche : 'PhotoShop'}, {name : 'AeTuts', niche : 'After Effects'}];

var names = _(Tuts).pluck('name').map(function (value){return value + '+'});

console.log(names);

// ["NetTuts+", "WPTuts+", "PSDTuts+", "AeTuts+"]

Since I noticed the names missing the plus sign at the end, I'm adding them in the extracted array.

You're not limited to simple concatenation here. You're free to modify the passed value to your heart's desires.

All

all is useful if you need to check every value in a collection passes a certain criteria. To check whether a student has passed in every subject, for example.


var Scores = [95, 82, 98, 78, 65];
var hasPassed = _(Scores).all(function (value){return value>50; });

console.log(hasPassed);

// true

Arrays

Underscore has a bunch of functions that work exclusively on arrays which is highly welcome since, compared to other languages, JavaScript provides awfully few methods dealing with arrays.

Uniq

This method basically parses an array and removes all duplicate elements providing you with only unique elements.


var uniqTest = _.uniq([1,5,4,4,5,2,1,1,3,2,2,3,4,1]);

console.log(uniqTest);

// [1, 5, 4, 2, 3]

This comes in extremely handy when you're parsing huge datasets and need to weed out the duplicates. Keep in mind that only the first instance of an element is counted so the original order is kept.

Range

An extremely handy method that lets you create a 'range' or list of numbers. Let's look at a super quick example.


var tens = _.range(0, 100, 10);

console.log(tens);

// [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

The method's parameters are, in order, starting value, ending value and step value. If you're wondering, using a negative step value leads to a decrementing range.

Intersection

This method compares two arrays to each others and returns the list of elements that are found in all of the passed arrays i.e. an intersection in set theory.

Let's extend the earlier example to see how this works.


var tens = _.range(0, 100, 10), eights = _.range(0, 100, 8), fives = _.range(0, 100, 5);

var common = _.intersection(tens, eights, fives );

console.log(common);

// [0, 40, 80]

Easy, right? You just pass in the list of arrays to compare and Underscore does the rest.


Objects

In addition to the fairly expected is checks, Underscore provides various methods to clone, extend and other manipulate objects.

Here are a few of my favorites.

Keys and Values

Have a massive object where you need only the keys or only the values? It's so darn easy with Underscore.


var Tuts = { NetTuts : 'Web Development',  WPTuts : 'WordPress',  PSDTuts : 'PhotoShop', AeTuts : 'After Effects'};
var keys = _.keys(Tuts), values = _.values(Tuts);

console.log(keys + values);

// NetTuts,WPTuts,PSDTuts,AeTutsWeb Development,WordPress,PhotoShop,After Effects

Defaults

This method is quite useful when you need to create objects with sensible defaults when one might not be used when creating it.


var tuts = { NetTuts : 'Web Development'};
var defaults = { NetTuts : 'Web Development', niche: 'Education'};

_.defaults(tuts, defaults);

console.log(tuts);

// Object { NetTuts="Web Development", niche="Education"}

Functions

As wonky as it sounds, Underscore has functions that work on functions. Most of the functions tend to be fairly complicated to explain here, so we'll take a look at the simplest.

Bind

this is an elusive part of JavaScript and tends to leave a lot of developers really confused. This method seeks to make it a bit easier to tackle.


var o = { greeting: "Howdy" }, 
	f = function(name) { return this.greeting +" "+ name; };

  var greet = _.bind(f, o); 

  greet("Jess")

It's a bit confusing so stay with me here. The bind functions basically lets you keep the value of this whenever and wherever the function is called.

This is specially useful when you're working with event handlers where this is hijacked.


Utilities

And to further sweeten the deal, Underscore provides a ton of utility functions. Since we're fairly out of time, let's just look at the biggie.

Templating

There are already a ton of templating solutions out there but Underscore makes its solution worth a look by being fairly tiny in its implementation whilst being fairly powerful.

Let's take a look at a quickie example.


var data =   {site: 'NetTuts'}, template =   'Welcome! You are at <%= site %>';

var parsedTemplate = _.template(template,  data );

console.log(parsedTemplate);

// Welcome! You are at NetTuts

First up, we create the data to populate the template followed by the template itself. By default, Underscore uses ERB style delimiters though this is entirely customizable.

With those in place, we can simply call the template passing in our template and the data. We store the result in a separate string to be used later to update content, as needed.

Keep in mind that this is an extremely simple demonstration of Underscore's templating. You can find use any JavaScript code inside the template using the <% %> delimiters. When you need to iterate over complex objects, say JSON sources, you can pair up with Underscore's excellent collection functions to create templates rapidly.


Still Not Convinced That You Should Pick This

jQuery and Underscore go hand in hand.

No, no, you've got it all wrong! If anything, jQuery and Underscore complement each other well and go hand in hand. Really!

See, jQuery does a few things extremely well. DOM manipulation and animation are chief amongst those. It doesn't deal with anything in the higher or lower levels. If frameworks like Backbone or Knockout deal with the higher level issues, Underscore tackles all the relatively bare metal ones.

For even more perspective, jQuery has little purpose outside the browser as the bulk of its functionality deals with the DOM. Underscore, on the other hand, can be used on the browser or on the server side without any issues. In fact, Underscore has the most number of Node modules dependent on it.

Well, that's about it for today. Considering the scope of Underscore, we've barely scratched the surface here. Make sure to check out more of the library and let me know if you have any questions in the comments below. Thank you so much for reading!

Advertisement