echo $my_thoughts > /dev/null

Code, philosophy and scribblings

Implement Decorators in Javascript ES5

There’s an amazing pattern in Python, called function decorators. It’s a set of declarations at the top of a function definition, that slightly enhances how the function behaves without actually polluting the function definition with related logic. I find it a really neat way to define a function and to re-use these enhancements/additional logic across functions.

If you are like me, in love with decorators and now in the wildness of Javascript, missing them – here’s a quick way to implement decorators in JS. My solution here, uses underscore’s compose method. But it’s easy to whip up your own version of compose, if you don’t really want to use underscorejs.

Here’s the short version:

Say, you have a couple of decorators.

One, which logs the return value of the function it decorates.

Two, which makes sure the function is called exactly and only once, no matter how many times it gets invoked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Decorator 1 */
var shouldLog = function(original_fn) {
  var decorated_fn = function() {
      var returnVal = original_fn(arguments);
      console.log(returnVal);
    }
    return decorated_fn;
}

/* Decorator 2 */
var runOnlyOnce = function(original_fn) {
  var isAlreadyRun = false;
  var decorated_fn = function() {
      if (!isAlreadyRun) {
          original_fn(arguments);
          isAlreadyRun = true;
        }
    }
    return decorated_fn;
}

var myLittleFunction = function() {
  // here goes your function definition
}

// now decorate it.
myLittleFunction = _.compose(shouldLog, runOnlyOnce)(myLittleFunction);

Or you can go for another version, if you aren’t really a fan of two liners.

1
2
3
var myLittleFunction = U.compose(shouldLog, runOnlyOnce)(function() {
  // here goes your function definition
});

All done! Now every time you call your function, it passes through the decorators around it.

Now, for the longer version:

A decorator function is nothing fancy. It’s a function that takes a function as input and returns a function that invokes the original input function, with extra logic executed before or/and after the invocation. It might even decide to not invoke the function at all, like our runOnlyOnce decorator above.

If you like mathematics, you might better understand this:

Say, f(x) is your function Your decorator is g(f(x)) where g(x) = { invoke x with some additional code padding }

There might be more than one decorator that decorates a function. In fact, the real power of decorators lies in the mixing and matching of these decorators – so there’s likely going to be more than one decorator decorating a function.

With that, it’s more like h(g(f(x))) and it might grow infinitely.

We want to define the function f such that, when we actually invoke f(x), we actually do h(g(f(x))), where g, h are the decorator functions for f.

If you are into functional programming, you can easily tell that this is a function composition.

Underscore has a useful util to compose a set of functions.

_.compose(g, f) = g(f())

Remember we haven’t really executed the function. It’s just a composed higher order function. To execute it, you might want to do something like this:

1
2
var composed = _.compose(g, f)
composed(x) = g(f(x))

If you are very anxious about implementing decorators, you might have come up with your brilliant idea of

1
var decorated_fn = _.compose(decorator_1, decorator_2, actual_fn)

If yes, you actually are very close, but still incorrect.

Because that would technically mean,

decorated_fn(x) = execute actual_fn(x) and pass the return value to decorator_2 as parameter. When that finishes, again pass the return value to decorator_1 as parameter.

That’s not what we want. We want to execute actual_fn, only after passing through decorator_1 and decorator_2.

To get there, there’s only this tiny little change to our “brilliant idea”

We’ll first compose the decorators together. Then assign our actual_fn as the input for this composition to work on. This is like throwing a function at this composition, expecting it to spit out a function, that wraps this function with multiple layers of padding.

1
2
3
var decorations = _.compose(decoration_1, decoration_2)

var decorated_fn = decorations(actual_fn)

That’s it. Now when you call decorated_fn(), it’s going to funnel through the decorators!

Relax, if you can’t comprehend it fully. I suck at explaining things, sometimes. It will all get easy, if you quickly try it in a javascript console.