Javascript Closures

How Many Ways Are There to Add 1?

Christmas Eve, 2015

Today I'd like to investigate javascript closures. My first encounter with functional programming made my head spin, but since then, I have seen the power, elegance and utility of this programming paradigm.

First, there are many good discussions of javascript closures on the Web. This discussion does not pretend to trump any of them, but I had to learn it from my own angle. Here I will show some nuances I have encountered. There are many other related subjects here that I will not get into, like lexical scope, strict mode, silent failures or object oriented javascript.

Buckle Up

There are some failed examples shown here, to show some pitfalls one should avoid. Obvserve closeley.

Or Not

If you don't want to read through this to get the best version (on this page) of "add_one" click here

What Is a Closure?

To over simplify (and lose some accuracy), a closure is a function enclosed within another function. The heart of functional programming is being able to pass around functions as values to be executed at will. This is great for event driven applications. Let's dive right in with the first example.

Example 1: add one, version 1

// add one, version one
function add_v1 (init) {
  var val = init;
  return function () {
    val = val + 1;
    console.log("val is " + val);
  }
}

This is the most basic example I can come up with to implement a closure that adds 1.  It doesn't do much and is not very useful, but it will add one to the initial value if you use it correctly.  The outer function is named, but the inner function is anonymous, or not named.  The inner function is the return value for add_v1.  Let's "kick the tires".

var a = add_v1

Notice there are no parenthasis () in this line of code. Let's compare a to b, below. What is a?
a = function add_v1 (init) { var val = init; return function () { val = val + 1; console.log("val is " + val);}}

var b = add_v1(3);// b is a closure
What is b?
b = function () { val = val + 1; console.log("val is " + val); }

We can run b by itself, we don't need the variable a or the adder function. Here we have executed the adder function and assigned the result to b. Now we can run b at will separately from another variable, say c shown below. Then each of b and c can retain different values even though they run the same function.

b()

Our "add one version one" closure is used for the first time, but doesn't do much, not even write to the console. This demonstrates our first pitfall: our adder does not initialize the internal variable "val", or rather, initializes it to undefined, which will, in turn, give us a NaN when we try to manipulate it numerically, which is garbage for what we want to do.

var c = add_v1(4);
c();// run it, the internal variable "val" is now 5

The value of "val" in c and b now have different values. They were each initialized with different values and run once.

b = add_v1(3);// initialize

Here we started over and gave an initial value. The add_v1 function runs, but the internal anoymous function does not. Therefore, nothing is logged to the console once again. The value of the internal variable val is 3 after executing this line of code, but you can't see it unless you use your debugger.

a(3)();// original function with an initial value and execute the internal function

console -> val is 4

Finally, we have executed both functions - a and its closure - and text is written to the console -> val is 4.  b and a are quite different.

a()();// bad, don't do this

console -> val is NaN

Pitfall. This code initializes val to undefined and then tries to add 1. val is then NaN.

a()(7);// bad, don't do this

console -> val is NaN

Pitfall. Almost the same as above, except we provide an argument to the closure, which it promptly ignores. The closure takes no arguments.

a("fred")();// bad, don't do this (unless that's what you really wanted)

console -> val is fred1

Pitfall. This is what you get when you try to add a string and a number. The function will take the argument, but javascript is weakly typed. This has strengths and weaknesses.

Example 2: add one, version 2

// add one, version two
function add_v2 (init) {
  var val = init;
  return function () {
    val += 1;
    console.log("val is " + val);
    return val;
  }
}

Here is a modified example from the previous in that the closure returns a value. It's a small difference in code with substantive implications.

var c = add_v2(21);
c();// val is 22
c();// val is 23

console -> val is 22
console -> val is 23

Now we can use our adder. What just happened? It's a bit different than the previous example. Now that we're returning a value, the return value can be used. When we execut c(), we are actually executing the closure function within its environment. What is c equal to? c = function () {val += 1;console.log("val is " + val);return val;} but we can't execute that function unless we know what the value of val is. This is the major difference between a function and a closure. The closure can be executed outside its original scope. The javascript engine will make a reference to the environment in which it was initiated and the value of val will be known.

Example 3: add one, version 3

// add one, version three
function add_v3 (init) {
  var val = init;
  return function () {
    val += 1;
    return val;
  }
}

This one is not functionally different, I just left out the console logging

Example 4: add one, version 4

// add one, version four
var add_v4 = (function (init) {
  var counter = init;
  return function () {
    counter += 1;
    console.log("counter is " + counter);
    return counter;
  }
})(93);// invoke / initialize (this is possible one time only)

console -> counter is 94

Here, instead of naming the function, I assigned the closure to the variable add_v4. It works much the same way as the previous example, except it can only be initiated once (unless you write the entire code block again) since the name of the outer function is nowhere to be found. It is an anonymous function. Since it was initialized to 93 and immediately executed, the first console log shows the counter to be 94. Now what happens if we execute this line?

add_v4(98);
The 98 is promptly ignored. 98 is not the initialization value, but the closure is executed, and the counter value is 95.

Example 5: add one, version 5

// add one, version five
function add_v5 (init_val) {
  var innerNum = init_val;
  function addOne () {
    innerNum += 1;
    return innerNum;
  }
}

Here I have named the inner function, but the adder function does not return anything. That's why I'm not calling this one a closure - it's just a private function. This is a pitfall you need avoid when coding. You'll run into all sorts of errors if you don't return a value when you need to.

var g = add_v5(99);// undefined
g();//error - trying to execute a variable that is not a function

Example 6: add one, version 6

// add one, version six
function add_v6 (init_val) {
  var innerNum = init_val;
  return function addOne () {
    innerNum += 1;
    return innerNum;
  }
}

This is the most useful version for this set of exercises.


var h = add_v6(101);
h();//102
h();//103

Example 7: add one, version 7

// add one, version seven
var add_v7 = function (init) {
  this.counter = init,
  function () {
    counter += 1;
    console.log("counter is " + counter);
    return counter;
  },
  function () {
    counter += 2;
    console.log("counter is " + counter);
    return counter;
  }
};

An exercise left to the reader.