This essay is an unpublished work in progress. Please check back for updates. If you choose to share it, please mention that it is unfinished at this time.


A little something that has fallen out of writing JavaScript Spessore:

function flavourize (body) {

  function flavoured (arg) {
    var args = [].slice.call(arguments);

    for (var i in flavoured.befores) {
      var flavouring = flavoured.befores[i];
      if (flavouring.apply(this, args) === false) return;
    }

    var returnValue = flavoured.body.apply(this, arguments);

    for (var i in flavoured.afters) {
      var flavouring = flavoured.afters[i];
      flavouring.apply(this, returnValue);
    }

    return returnValue;
  }

  Object.defineProperties(flavoured, {
    befores: {
      enumerable: true,
      writable: false,
      value: []
    },
    body: {
      enumerable: true,
      writable: false,
      value: body
    },
    afters: {
      enumerable: true,
      writable: false,
      value: []
    },
    unshift: {
      enumerable: false,
      writable: false,
      value: function (fn) {
        return this.befores.unshift(fn);
      }
    },
    push: {
      enumerable: false,
      writable: false,
      value: function (fn) {
        return this.afters.push(fn);
      }
    }
  });

  return flavoured;
}

Now you can take a function, and add flavours to taste:

var double = flavourize(function (n) { return n * 2; });

double(2)
  //=> 4

double('two')
  //=> NaN

function mustBeNumeric () {
  var args = [].slice.call(arguments);

  args.forEach(function (arg) {
    if (typeof(arg) !== 'number') throw ('Argument Error, "' + arg + '" is not a number');
  });
}

double.unshift(mustBeNumeric);

double(2)
  //=> 4

double('two')
  //=> Argument Error, "two" is not a number

The “API” is simple: unshift adds functions that are executed before the function body, push adds functions that are executed after the function body. Think of it like an array, you unshift things onto the begiing and push them onto the end.

These “flavourings” are normally executed for side effects, but you can write guard clauses. Return false from a function you unshift to bail from the whole thing. Note that null and undefined won’t do, it must be false.

Cheers!

Hey! If you like this sort of thing, my books “JavaScript Allongé,” “Kestrels, Quirky Birds, and Hopeless Egocentricity,” and others will be just the sort of this you'll like! Pull requests & issues are welcome. Some rights reserved. Creative Commons License