Thinking functionally in JavaScript (part one)

Over the Christmas break, when traditionally things are a little quieter at work, I do a bit of research into topics that interest me and that might have some bearing on our future products. This year was no exception and I decided to investigate React, Facebook’s library (framework?) for building user interfaces for the web. It’s a fascinating library to be sure (and I’ll talk more on it in another post), but there was one paradigm it uses which I haven’t really talked about before: immutability. Don’t get me wrong: sure, React components have properties and state, but the way they change (or rather are allowed to change) is very circumscribed.

From this concept of immutability, it took me back to JavaScript and how functional a language it is when used well. So, I’ll discuss some of the important aspects of functional JavaScript to begin with, and then later on, write a series of articles on React.

So, what does it mean to say that JavaScript can be thought of as a functional language? For me, there are two main aspects: functions as objects and immutability.

Functions as objects

More formally, this concept is known as higher-order functions, but basically it means that functions are not just methods, chunks of code that act on data, but that they can be passed around as data, can appear as parameters to other functions (these are usually known as callbacks), and can be returned from other functions (which leads to things like composable functions and the like). As I’ve said many times in past posts: functions are objects. I’d have to say once I really grasped this tenet, my JavaScript got better because it became more functional. The nice thing about JavaScript is that creating these functions is simplicity itself – there’s no need to worry about defining a type and then writing the function, just write the function.

Functions that merely do some processing on their input parameters and return a value with no side effects, are known as pure functions. Side effects? By that I mean that the function doesn’t do anything else apart from process the input to produce the output and no other public data structures, entities, or variables are changed or destroyed in doing so. For example, a function that processed and changed each item (say, doubling them) in an input array of numbers has a side effect: the items in the array are changed. If the function were rewritten to take in the array, and produce a second array with the doubled numbers and return it, there are no side effects: the original array is still there.

Pure functions could become more important in the near future, because they allow for certain optimizations within the interpreter/compiler. For example, if the return value from a pure function is not used, the compiler could remove the call to the function since there are no side effects. Since an attribute of pure functions is that, given the same parameters, the function will always return the same value, the compiler could apply caching or memoization techniques to avoid having to actually call the calculation code again for the same arguments.

Immutability

And that last property brings us to immutability. This is the principle that your data and data structures are immutable, that they cannot (or – a weaker proposition – will not) be changed. This is a big part of React: the properties and state will only be changed through a well-defined workflow, and therefore your component can react to those changes without any worry on your part of missing any. This principle is not tracked or restricted by the language, it’s up to you to ensure that it is followed in your code.

Immutability has a smaller scope as well: the fact that you should be writing your functions to have no side-effects.

Example

Enough of the computer science, let’s take a quick look at one simple example: memoization. Imagine we have a function that takes no arguments, does some calculations, and returns a value. Here’s one from some code I was working on over the weekend (note: it uses jQuery):

var getWhere = function () {
  var tokens = $("body").attr("data-where").split("-");
  if (tokens.length === 2) {
    return tokens[1];
  }
  return "home";
};

All it does is to find the body element of the current page, read the data-where attribute on it, parse the answer (it’ll be of the form CMS-pagetype and all I want is the pagetype part) and return the substring after the hyphen. If anything goes wrong, it returns “home” instead. So, there’s some processing here, and the way I’ve got the rest of the code structured, this function is going to be called a few times.

Now, since the answer the function is going to be returning is the same no matter how many times I call it for a given page (yes, I’m assuming here that there isn’t some code elsewhere that likes to futz with the data-where attribute on the body tag, because if that’s the case I give up with this web programming lark), I could just call it once, store the (unchanging) value somewhere, and then just use that pre-computed value. But then I would have to keep track of whether I’d called the function already (and hence the computed value is set) or whether this is the first time.

Essentially that is what I shall do, but I’m going to wrap it all in another higher-order function that takes care of all the messing around. This function will take my original function and return a new one that I shall call instead. Internally the returned function has been memoized: it will store the output value for various input values, so when the function is called again it can just return the precalculated value instead of going through the calculation again. In my example here the function takes no input parameters at all (it has zero arity as the computer science people would say), so there’s only one output value to save.

var memoize = function (fn) {
  var calcValue = undefined;
  if (fn.length !== 0) {
    return fn;
  }
  return function () {
    if (!calcValue) {
      calcValue = fn();
    }
    return calcValue;
  };
};

So, taking it statement by statement, it accepts one parameter: the function to be memoized. Then I declare the calculated value as an internal variable (yes, this function is going to be creating a closure) to be undefined. Now, if the arity of the passed-in function is not zero (that is it accepts at least one parameter), just return the function. The function will still work just as before, but no memoization will take place. Finally we return a new function. This new function checks to see if the calculated value is set, and if not calls the original function to calculate it, and finally it returns the calculated value. The first time through then, it’ll calculate the value; the second and subsequent times, it’ll just return the calculated value.

And now, here’s the slight change to the declaration of my getWhere function:

var getWhere = memoize(function () {
  // exact same code as before
});

In other words, getWhere is now the function returned from the memoizer wrapping the function that does the original work. To the callers of the function, nothing has changed: call getWhere() and it returns the correct substring. However, with the memoization the calculations are only done the once.

This is an excellent example of a higher-order function with no side-effects: it takes in a function and returns a new function. Functions are objects, remember.

Large cog wheel

Album cover for BeliefNow playing:
Innocence - Remember the Day
(from Belief)



Loading similar posts...   Loading links to posts on similar topics...

No Responses

Feel free to add a comment...

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response