You can see closures nearly everywhere in JavaScript, and this post will discuss closure. We’ll start from the definition, then some typical usages will be given and finally we’ll talk about some common mistakes with closure.

What is a Closure?

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions ‘remember’ the environment in which they were created.

To better understand closure, first there is something to know about lexical scope.

Lexical Scope vs. Dynamic Scope

In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined. In contrast, in languages with dynamic scope the name resolution depends upon the program state when the name is encountered which is determined by the execution context or calling context.

One topic on stackoverflow offers two vivid examples (in C language):

For lexical scope:

1
2
3
4
5
6
7
8
9
10
void fun()
{
int x = 5;
void fun2()
{
printf("%d", x);
}
fun2();
}

The inner function func2() have access to variable x defined in outer function fun().

For dynamic scope:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void fun()
{
printf("%d", x);
}
void dummy1()
{
int x = 5;
fun();
}
void dummy2()
{
int x = 10;
fun();
}

dummy1(); will print 5, and dummy2(); will print 10. Dynamic scope search value according to the calling stack.

Javascript is based on lexical scope:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function outer() {
var x = 'outer';
function inner() {
console.log(x);
}
function wrapper1() {
var x = 'wrapper1';
inner();
}
function wrapper2() {
var x = 'wrapper2';
inner();
}
inner(); // output "outer"
wrapper1(); // output "outer"
wrapper2(); // output "outer"
}
outer();

Function inner() will search variable x in the context where it is defined, rather than the execution context.

Typical Usage of Closure

Implement the Private Variable or Function

It’s very common in SPA (single page application). For example, you need to implement a button which needs to remember how many times the user clicked. You can use closure as the callback:

In the book Single Page Web Applications, closures are used nearly everywhere. IIFE (Immediately Invoked Function Expression) is used to expose public API of a module, and encapsulate the private method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spa = (function ($) {
var var1, var2;
// .. some other private variable
var privateMethod1, privateMethod2;
// .. some other private function
privateMethod1 = function() {};
privateMethod2 = function() {};
var publicMethod1, publicMethod2;
publicMethod1 = function() {};
publicMethod2 = function() {};
return {
publicMethod1: publicMethod1,
publicMethod2: publicMethod2
};
})(jQuery);

Currying

In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.

To make it simple, currying is to fill the function parameters by steps, and each time generates a more specific function, calculates the value when all the parameters are filled.

For example, we need a sum() function, which take a sequece of numbers, and return the sum of them.

1
2
3
4
5
6
7
8
9
function sum() {
var total = 0;
for (var i=0, l=arguments.length; i < l; i++) {
total += arguments[i];
}
return total;
}
sum(1,2,3,4,5) // 15

After currying it, we can evalute it as:

1
sum(1)(2)(3)(4)(5)()

Here we can use closure to help remember the already filled arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.currying = function() {
var self = this;
var args = [];
return function() {
if (arguments.length === 0) {
return self.apply(this, args);
} else {
[].push.apply(args, arguments);
return arguments.callee;
}
}
}
var sum_curried = sum.currying();
sum_curried(1)(2)(3)(4)(5)() // 15

Also The length property of a function specifies the number of arguments expected by it.

So, we can implement currying for functions with fixed number of arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Function.prototype.currying = function() {
var self = this;
var args = [];
return function() {
[].push.apply(args, arguments);
if (args.length === self.length) {
return self.apply(this, args);
} else if (args.length > self.length) {
throw new Error('Too many arguments');
}
return arguments.callee;
}
}
function foo(a, b, c) {
return a*100 + b*10 + c;
}
foo_curried = foo.currying();
foo_curried(3)(2)(1); // 321

Uncurrying

Uncurrying is the dual transformation to currying, and can be seen as a form of defunctionalization. It takes a function f whose return value is another function g, and yields a new function f′ that takes as parameters the arguments for both f and g, and returns, as a result, the application of f and subsequently, g, to those arguments. The process can be iterated.

In another sense, uncurrying is the process to make a specific function more generic: In currying, we fill part of arguments of a function and create a new more specific function; In uncurrying, we take the specific function, and unfill the already filled arguments to make it more generic. Let’s see an example.

The push, shift, and forEach methods of Array.prototype are only available on array objects. Often we borrow it from array object to help the array-like work well:

1
2
3
4
5
6
7
8
9
10
var obj = {
'length': 3,
'0': 'Apple',
'1': 'Banana',
'2': 'Orange'
};
[].push.call(obj, 'Lemon', 'Kiwi');
console.log(obj);
1
2
3
4
5
6
{ '0': 'Apple',
'1': 'Banana',
'2': 'Orange',
'3': 'Lemon',
'4': 'Kiwi',
length: 5 }

Although it works, it looks very strange, and with uncurrying we can generate a generic function whose first argument is the object (the context), thus make the whole process more intuitive:

1
2
3
4
5
6
7
8
9
10
Function.prototype.uncurrying = function() {
var self = this;
return function() {
return Function.prototype.call.apply(self, arguments);
}
}
for (var i=0, fn, ary = ['push', 'shift', 'forEach']; fn = ary[i++];) {
Array[fn] = Array.prototype[fn].uncurrying();
}

Now we can call them like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var obj = {
'length': 3,
'0': 'Apple',
'1': 'Banana',
'2': 'Orange'
};
Array.push(obj, 'Lemon', 'Kiwi');
console.log(obj);
console.log('\n\n');
var fruit = Array.shift(obj);
console.log(fruit);
console.log(obj);
console.log('\n\n');
Array.forEach(obj, function(fruit) {
console.log(fruit);
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{ '0': 'Apple',
'1': 'Banana',
'2': 'Orange',
'3': 'Lemon',
'4': 'Kiwi',
length: 5 }
Apple
{ '0': 'Banana',
'1': 'Orange',
'2': 'Lemon',
'3': 'Kiwi',
length: 4 }
Banana
Orange
Lemon
Kiwi

Throttling

Browser Javascript is event-drived, and the frequency of some event is too high, e.g, window resize and mouse move event. If the callbacks of these events are too time-consuming, the browser will get stuck. We can use closure to limit the frequency, and that’s throttling.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var throttle = function(fn, interval) {
var __self = fn,
timer;
return function() {
var args = arguments,
__me = this;
if (timer) {
return false;
}
__self.apply(__me, args);
timer = setTimeout(function() {
timer = undefined;
}, interval || 500);
return true;
}
}

The trick is whether the timeoutID returned by setTimeout is set. If it’s set, it means there is one pending execution, and we should wait. In the callback of setTimeout, we clear the timeoutID to manifest that the work is done.

You can paste the following code snippet into your browser’s console and play with it:

1
2
3
window.onresize = throttle(function() {
console.log('resize.');
}, 500);

Execution in chunks

Imagine you are implementing a chat application to talk to your Facebook friends and you have over 1000 friends online. If you load them at the same time, too much DOM operation will make the web page slow or even dead. Here is the point, we can separate all your friends into chunks, and add one chunk every second:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var timeChunk = function(ary, fn, chunkSize, deltaTime) {
var obj,
t;
var len = ary.length;
var start = function() {
for (var i = 0; i < Math.min(chunkSize || 1, ary.length); ++i) {
obj = ary.shift();
fn(obj);
}
};
return function() {
t = setInterval(function() {
if (ary.length === 0) {
return clearInterval(t);
}
start();
}, deltaTime || 200);
};
}

The following code snippet print 2 numbers every second:

1
2
3
4
5
6
7
8
9
10
11
var ary = [];
for (var i=1; i<=10; ++i) {
ary.push(i);
}
var printElement = function(e) {
console.log(e);
}
var trunkPrintElements = timeChunk(ary, printElement, 2, 1000);
trunkPrintElements();

Some Gotchas

There are still some common mistakes you’ll meet, even though closure is powerful.

value of loop variable

JavaScript don’t have a block scope, so after the loop, the i will be 5, and each function in fArr will print 5:

1
2
3
4
5
6
var fArr = new Array;
for (var i =0; i<5; ++i) {
fArr.push(function() {console.log(i);});
}
console.log(i) // 5
fArr[3]() // 5

One way to sovle this problem is to create a closure in each iteration of the loop:

1
2
3
4
5
6
7
var fArr = new Array;
for (var i =0; i<5; ++i) {
(function(i) {
fArr.push(function() {console.log(i);});
})(i);
}
fArr[3]()

Another solution is to use the let keyword in es 6, and in every iteration a new local variable i is created:

1
2
3
4
5
var fArr = new Array;
for (let i =0; i<5; ++i) {
fArr.push(function() {console.log(i);});
}
fArr[3]()

this issue of setTimeout and setInterval

In non-strict mode, this in callbacks of setTimeout and setInterval points to the window variable, and it’s undefined in strict mode. Look at the example below, we need make the bird tweak for 3 times at given frequency.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Bird(sound) {
this.sound = sound;
}
(function() {
this.keepTweeking = function() {
var cnt = 0;
var tid = setInterval(function() {
console.log(this.getSound());
++cnt;
if (cnt == 3) clearInterval(tid);
}, 1000);
};
this.getSound = function() {
return this.sound;
};
}).call(Bird.prototype);
var bird = new Bird('Jiujiu~');
bird.keepTweeking()

It failed because this in the callback function of setTimeout is window, one solution to this is to use bind to remember this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Bird(sound) {
this.sound = sound;
}
(function() {
this.keepTweeking = function() {
var cnt = 0;
var tid = setInterval(function() {
console.log(this.getSound());
++cnt;
if (cnt == 3) clearInterval(tid);
}.bind(this), 1000);
};
this.getSound = function() {
return this.sound;
};
}).call(Bird.prototype);
var bird = new Bird('Jiujiu~');
bird.keepTweeking()

Though it’s not a problem directly related to closure, we can use closure to sovle it. Just keep this in variable self, and the callback of setInterval is a closure thus can visit self:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Bird(sound) {
this.sound = sound;
}
(function() {
this.keepTweeking = function() {
var cnt = 0;
var self = this;
var tid = setInterval(function() {
console.log(self.getSound());
++cnt;
if (cnt == 3) clearInterval(tid);
}, 1000);
};
this.getSound = function() {
return this.sound;
};
}).call(Bird.prototype);
var bird = new Bird('Jiujiu~');
bird.keepTweeking()

Conclusion

This post discusses JavaScript closure thoroughly. We first compares lexical scope and dynamic scope to better understand JavaScript closure, then several typical usages are given:

  1. encapsulate private variable or function
  2. currying: fill arguments by steps
  3. uncurrying: create a more generic function
  4. throttling: control the frequency of calling a function
  5. execution in chunks: separate a big task into small parts

And finally some gotchas and their solutions are discussed: the loop variable and this in the callbacks of setTimeout and setInterval.

One more thing needs to be mentioned here: although closure is powerful, it did face some efficiency issue, e.g. the memory leak and creating new functions each time compared to the object-oriented paradigm. Also, too many levels of nesting is hard to understand and maintain, as the zen of Python puts it:

Flat is better than nested.

It’s better to think twice before wielding closures.