Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Freckle Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Little JavaScript hints, episode 2: stay DRY

December 20th, 2008

Here’s a technique you can use to DRY (Don’t repeat yourself) up your code, if you have very similiar methods that just do the “opposite”.

An example of this are controls that do scrolling or paging, and often include a forward/back button.

I often see code like this:

function nextPage(){ 
   // do something 
}
function previousPage(){
  // do something
}

The “do something” part in methods like these is almost identical, except for the direction. Basically, it all resolves around incrementing or decrementing a “position” variable, checking bounds, and then rendering the result.

I find it more convenient to merge this into one function, with a direction parameter, that gets +1 or -1. Here’s an example:

// pages are numbered from 1 to 10
var currentPage = 1, pageCount = 10; 

function turnPage(dir){
  currentPage += dir || 0;

  currentPage = 
    (currentPage == 0) ? pageCount :
    (currentPage == pageCount+1) ? 1 : currentPage;
 
  // here we would do whatever is necessary to render
}

Of course it’s not nice to write

turnPage(-1);

everytime you want to page to the previous page, so here’s where Prototype comes to the rescue (and yes, I’m pimping Prototype here):

var nextPage = turnPage.curry(1), 
  previousPage = turnPage.curry(-1);

With curry, you get instant next and previous functions, which you can call like any ol’ function:

nextPage(); // same as turnPage(1);
previousPage(); // same as turnPage(-1);

// or maybe in an event handler
$('previous_button').observe('click',previousPage);

How sweet is that!