Guard Functions in JS Classes

by Andrew Stewart
published July 24, 2015

Thought I’d write up a quick JavaScript refactor technique that’s come up in some code I’ve been working on lately.

For this example, assume we have a Client class. This Client has many methods, some of which are network-based, only intended to be used when the Client is connected. These methods also accept callbacks.

Our current implementation looks something like this:

var Client = function Client() {
  this.connected = false;
}

Client.prototype.connect = function() {
  this.connected = true;
}

Client.prototype.disconnect = function() {
  this.connected = false;
}

Client.prototype.fetch = function(callback) {
  if (!this.connected) {
    return callback("Not connected");
  }

  // ...
  callback(null, data);
}

Client.prototype.getDetails = function(callback) {
  if (!this.connected) {
    return callback("Not connected");
  }

  // ...
  callback(null, data);
}

Client.prototype.post = function(message, callback) {
  if (!this.connected) {
    return callback("Not connected");
  }

  // ...
  callback(null, data);
}

Now, this is at least a bit better than the slightly alternate approach these methods seem to take more often:

Client.prototype.post = function(message, callback) {
  if (this.connected) {
    // ...
    callback(null, data);
  } else {
    callback("Not connected");
  }
}

But either way we’re clogging up these methods with duplicated checking code that doesn’t really need to be there.

JS makes it trivial to construct functions that wrap other functions:

function wrapper(fn) {
  return function() {
    console.log("before");
    fn.apply(null, arguments);
    console.log("after");
  }
}

var wrapped = wrapper(function(arg) {
  console.log("during, with argument", arg);
});

wrapped("hello, world");
//=> before
//=> during, with argument hello, world
//=> after

It’s a fairly simple technique, but one that yields dividends, particularly when you start finding useful places to apply it.

Let’s do so now, and see if we can find a solution to this duplicated code:

function connected(fn) {
  return function() {
    // assume last argument is a callback
    var callback = arguments[arguments.length - 1];

    if (!this.connected) {
      return callback("Not connected");
    }

    return fn.apply(this, arguments);
  }
}

Still nothing too fancy going on here, but we can apply it to our class’ instance methods to make life a little easier:

Client.prototype.fetch = connected(function(callback) {
  // ...
  callback(null, data);
});

Client.prototype.getDetails = connected(function(callback) {
  // ...
  callback(null, data);
});

Client.prototype.post = connected(function(message, callback) {
  // ...
  callback(null, data);
});

Lo and behold, suddenly the bodies of these methods are focused on the actual work they need to perform!

This is still a pretty simple refactoring and technique, but little things like this make a difference. Applying similar techniques can help in many situations, so look out for them.

If you’re new(er) to JavaScript, or otherwise haven’t come across code like this before, I hope you found this helpful. I also cannot recommend Reginald Braithwaite’s book, JavaScript AllongĂ©, highly enough.

If you write JS, and want to get better, you really do need to read this book. It’s even generously been made available free online, so no excuses.