One of my favorite aspects of developing in Rails is the console. The ability to load and interact with my Ruby objects without using the browser is powerful.
Thanks to Firebug for Firefox and Web Inspector for Webkit, I also have a console for my client-side JavaScript. I wish jQuery were as powerful when traversing raw JavaScript objects as it is traversing the DOM. Well it seems I have two wishes left for the first has been granted in Underscore.js.
Underscore.js is a new JavaScript framework from DocumentCloud that brings
a powerful set of utility functions to JavaScript with a disctinct Ruby flavor
and without monkey-patching the native JavaScript types by extending via
prototype
. Just as Prototype.js and jQuery employ the $
function,
Underscore adds all of this goodness via the _
function.
So, what's in the box? Let's just ask _
himself, Ruby style:
>>> _.methods();
=> ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
"compose", "defer", "delay", "detect", "each", "every", "extend", "filter",
"first", "flatten", "foldl", "foldr", "forEach", "functions", "identity",
"include", "indexOf", "inject", "intersect", "invoke", "isArray",
"isElement", "isEmpty", "isEqual", "isFunction", "isUndefined", "keys",
"last", "lastIndexOf", "map", "max", "methods", "min", "pluck", "reduce",
"reduceRight", "reject", "select", "size", "some", "sortBy", "sortedIndex",
"template", "toArray", "uniq", "uniqueId", "values", "without", "wrap",
"zip"]
Nifty, huh? That should look very familiar. Let's look at map
as
an example.
>>> _.map([1, 2, 3], function(num){ return num*num });
=> [1, 4, 9]
Pretty straightforward. But we can also call Underscore OOP style:
>>> _([1, 2, 3]).map(function(num){ return num*num });
=> [1, 4, 9]
What's the advantage you ask? Chaining!
>>> _([1, 2, 3]).chain().map(function(num){ return num*num
>>> }).size().value();
=> 3
Whoa! Why the value()
at the end?
When chaining, Underscore returns a wrapped set, a special container object
(like jQuery does for wrapped sets of elements returned via a selector). To get
the last value in the chain, simply call value
.
Many of the same Ruby Enumerable and Array functions you've come to know and
love are implemented including: each
, map
, detect
, select
, reject
,
all
, any
, include
, max
, min
, sortBy
, toArray
, size
, first
,
last
, compact
, flatten
, uniq
, and zip
plus some new ones
you'll love.
Underscore also includes also some really useful utility functions.
bind
method
bind
a function to a context object, meaning that whenever the function is called, the value of this will be the context. Optionally, bind arguments to the function to pre-fill them, also known as currying.
var func = function(greeting){ return greeting + ', ' + this.name }; func =
_.bind(func, {name : 'Adrian'}, 'Yo'); func(); => "Yo, Adrian"
template
methodCompiles JavaScript templates into functions that can be evaluated for rendering. Useful for rendering complicated bits of HTML from JSON data sources. Template functions can both interpolate variables, using
<%= … %>
, as well as execute arbitrary JavaScript code, with<% … %>
. When you evaluate a template function, pass in a context object that has properties corresponding to the template's free variables. If you're writing a one-off, you can pass the context object as the second parameter to template in order to render immediately instead of returning a template function.
Here's an example from the docs:
var list = "<% _.each(people, function(name) { %> <li><%= name %></li> <%
}); %>"; _.template(list, {people : ['moe', 'curly', 'larry']}); => "
<li>moe</li> <li>curly</li> <li>larry</li> "
Underscore.js is available in both production and development flavors.
Engineering Director at Adobe Creative Cloud, team builder, DFW GraphQL meetup organizer, platform nerd, author, and Jesus follower.