We spent the last couple of days of week 2 at Hack Reactor re-implementing underscore.js functions. It may seem like an odd and useless exercise, but I feel I've gotten some good things out of it.
What is Underscore.js?
Underscore is pretty cool. If you include this js file in a web page, then you'll have a variable called _
. This new underscore variable offers a variety of higher-order functions that will probably be familiar (and probably sorely missed), at least if you're used to Ruby or other languages with powerful functional features. One particularly popular example is map. Suppose you've got an array of elements and you want to get the square root of all of them. In plain JavaScript, you'd have to do something like this:
var a = [4, 9, 16]; var result = []; for(var i=0; i<a.length; i++) { result.push(Math.sqrt(a[i])); }
In ruby, which has many built-in higher-order functions, you can use map
and do the same calculation with much less work:
a = [4, 9, 16] result = a.map { |x| Math.sqrt(x) }
As someone who did a bit of Ruby programming before really diving into JavaScript, I found it a bit awkward moving to a lower level language. There are just a lot of cases in which JavaScript requires way more typing than it should. Fortunately, Underscore helps quite a bit. Here's the same calculation, done with underscore utilities:
var a = [4, 9, 16]; var result = _.map(a, Math.sqrt);
The benefits of re-writing underscore
Building solid familiarity
One obvious benefit is that after spending hours and hours writing underscore library functions, my classmates and I are completely comfortable using them. We may not have memorized all the parameters of everything, but pretty much everything is familiar at least. Furthermore, we're learning common tools used in many other modern languages and once you know how to use filter
in one language, you can pretty much use filter in any language.
Being forced to learn some CS
Many of the functions, such as each
, map
and last
were pretty easy for us. But some were mind-bending. The function once
, for example, pretty much forced us to learn how to use closures. Here is the basic description:
Once:
Write a function that takes an input function as an argument and returns a function that will behave exactly the same as the input function the first time it is run, store the result, and then on subsequent calls, return the stored result without executing the function.
It took my partner and I nearly an hour of writing and then deleting various convoluted attempts before arriving at this solution:
var once = function(func) { var beenCalled = false; var answer; return function() { if (beenCalled === true) { return answer; } else { beenCalled = true; answer = func(); return answer; } } }
Since that experience, I've felt much much more comfortable with closures and some of the later more complicated features of underscore actually went more quickly. One interesting side-effect of this exercise is that I feel a pretty strong desire to go back and re-write all my foreign-language related JS tools on Toshuo to use jQuery and Underscore. The more I learn, the greater the gulf I feel between what I've written and what I could have written if I'd known what I know now.