Closures

  1. Access to outer variables
  2. Nested functions
  3. Closures
    1. Mutability of LexicalEnvironment
    2. The notorious closure loop
    3. [[Scope]] for new Function
  4. Summary

From the previous article, we know that a variable is a property of the LexicalEnvironment object.

Here we discuss access to outer variables and nested functions. In-depth understanding of closures follows automatically.

Access to outer variables

What if a variable is accessed, but it isn’t local? Like here:

var a = 5

function f() {
  alert(a)
}

In this case, the the interpreter finds the variable in the outer LexicalEnvironment object.

The process consists of two steps:

  1. First, when a function f is created, it is not created in an empty space.

    There is a current LexicalEnvironment object. In the case above, it’s window (a is undefined at the time of function creation).

    When a function is created, it gets a hidden property, named [[Scope]], which references current LexicalEnvironment.

  2. Later, when the function runs, it creates it’s own LexicalEnvironment and links it with [[Scope]].

    So when a variable is not found in the local LexicalEnvironment, it is searched outside:

If a variable is read, but can not be found anywhere, the error is generated.

function f() {
  alert(x) // reading x gives error, no x
}

Certain language constructs block the error, for example typeof x works if there is no x (and returns undefined), but that’s an exception.

If a variable is set, but not found anywhere, then it is created in the outmost LexicalEnvironment, which is window.

function f() {
  x = 5 // writing x puts it into window
}

Nested functions

Functions can be nested one inside another, forming a chain of LexicalEnvironments which can also be called a scope chain.

var a = 1
function f() {

  function g() {
*!*
    alert(a) 
*/!*
  }

  return g  
}

var func = f()
func() // 1

LexicalEnvironments form a chain (from inside out):

// LexicalEnvironment = window = {a:1, f: function}
var a = 1
function f() {
  // LexicalEnvironment = {g:function}

  function g() {
    // LexicalEnvironment = {}
    alert(a) 
  }

  return g  
}

So, function g has access to g, a and f.

Create a function sum that will work like that: sum(a)(b) = a+b.

Yes, the syntax is dual brackets. Funny, isn’t it? For instance:

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

Open solution
Solution

The idea is that sum should return a function which knows a and will take care about next argument.

Can be done like this:

function sum(a) {

  return function(b) { // takes a from outer LexicalEnvironment
    return a+b
  }

}

alert( sum(1)(2) )
alert( sum(5)(-1) )

Create a function sum that will work like that: sum(a)(b) = a+b and accepts any number of brackets.

For instance:

sum(1)(2) == 3
sum(5)(-1)(2) == 6
sum(6)(-1)(-2)(-3) == 0
sum(0)(1)(2)(3)(4)(5) == 15

Open hint 1
Hint 1
Open solution
Solution

To make sum(1) callable as sum(1)(2), it must return a function.

The function can be either called or converted to a number with valueOf.

The solution is really self-explanatory:

function sum(a) {
  
  var sum = a 
  
  function f(b) {
    sum += b
    return f
  }
  
  f.toString = function() { return sum }
  
  return f
}

alert( sum(1)(2) )  // 3
alert( sum(5)(-1)(2) )  // 6
alert( sum(6)(-1)(-2)(-3) )  // 0
alert( sum(0)(1)(2)(3)(4)(5) )  // 15

Closures

Nested function may continue to live after the outer function has finished:

function User(name) {
	
  this.say = function(phrase) {  
    alert(name + ' says: ' + phrase)
  }

}

var user = new User('John')

Marking up LexicalEnvironments:

Note, the this context is not related to scopes and variables. It does not participate here.

As we see, this.say is a property in the user object, so it continues to live after User completed.

And if you remember, when this.say is created, it (as every function) gets an internal reference this.say.[[Scope]] to current LexicalEnvironment. So, the LexicalEnvironment of the current User execution stays in memory. All variables of User also are it’s properties, so they are also carefully kept, not junked as usually.

The whole point is to ensure that if the inner function wants to access an outer variable in the future, it is able to do so.

  • The inner function keeps a reference to the outer LexicalEnvironment.
  • The inner function may access variables from it any time even if the outer function is finished.
  • The browser keeps the LexicalEnvironment and all it’s properties(variables) in memory until there is an inner function which references it.

This is called a closure.

Mutability of LexicalEnvironment

Several function may share same outer LexicalEnvironment. In this case they can modify it’s properties.

In the example below, this.fixName changes name, which is used by this.say:

function User(name) {
	
  this.fixName = function() {
    name = 'Mr.' + name.toUpperCase()
  }

  this.say = function(phrase) {  
    alert(name + ' says: ' + phrase)
  }

}

var user = new User('John')
// (1)
user.fixName()
// (2)
user.say("I'm alive!") // Mr.JOHN says: I'm alive!

Here user.fixName.[[Scope]] and user.say.[[Scope]] reference same LexicalEnvironment, which corresponds to new User run.

From (1) to (2), the LexicalEnvironment.name is updated, so both functions see the variable change.

Variables in outer LexicalEnvironment may change.

Inner functions always see the last value.

The notorious closure loop

The task below contains interesting tricks, best demonstrated by an example. Please, glance at the solution, or, much better, try to solve it.

Here is a function to create an army of shooters:

function makeArmy() {

  var shooters = []

  for(var i=0; i<10; i++) {
    var shooter = function() { // a shooter is a function
      alert(i) // which should alert it's number
    }
    shooters.push(shooter)    
  }

  return shooters 
}

var army = makeArmy()

var shooter = army[0] // first shooter
shooter() // alerts 10, should be 0

shooter = army[5] // 5th shooter
shooter() // alerts 10, should be 5

// all shooters alert same: 10 instead of 1,2,3...10.

Why all shooters alert the same? How to make each shooter output it’s number?

Open solution
Solution

Note that the shooter function. Does not have a variable named i.

So, when it is called, the interpreter takes i from the outer LexicalEnvironment.

The problem is that at the time when shooters are run, function makeArmy has already finished the execution.

The loop has finished and the variable i is now 10.

There are two possible solutions.

The first one is to put the correct value into the shooting function itself.

function makeArmy() {

  var shooters = []

  for(var i=0; i<10; i++) {

*!*
    var shooter = function() {
      alert( arguments.callee.i ) 
    }
    shooter.i = i
*/!*

    shooters.push(shooter)    
  }

  return shooters 
}

var army = makeArmy()

army[0]() // 0
army[1]() // 1

Another, more advanced solution is to use an extra function to trap the current value of i:

function makeArmy() {

  var shooters = []

  for(var i=0; i<10; i++) {

*!*
    var shooter = function(i) {

      return function() {
        alert( i ) 
      }

    }(i)

*/!*
    shooters.push(shooter)    
  }

  return shooters 
}

var army = makeArmy()

army[0]() // 0
army[1]() // 1

Let’s consider the highlighted fragment more thoroughly.

var shooter = function(i) {
  return function() {
    alert( i ) 
  }
}(i)

Here, the actual shooting function is created as the result of an anonymous function(i) which is created and executed in one place.

So, when it comes to executing alert(i), it will be taken from LexicalEnvironment of the anonymous function.

So, the anonymous function traps current i into it’s LexicalEnvironment and allows the shooter to access it.

The last way is to wrap the whole loop into temporary function. Sometimes that’s more readable:

function makeArmy() {

  var shooters = []

*!*
  for(var i=0; i<10; i++) (function(i) {

    var shooter = function() {
      alert( i ) 
    }
    
    shooters.push(shooter) 
   
  })(i)
*/!*

  return shooters 
}

var army = makeArmy()

army[0]() // 0
army[1]() // 1

The (function(i) { ... }) definition is wrapped into brackets to make sure the interpreter treats that as expression.

[[Scope]] for new Function

There is an exception to general scope binding rule. When you create a function using new Function, it’s [[Scope]] points to window, not to current LexicalEnvironment.

The following example demonstrates how a function, created with new Function ignores local variable a and outputs the global variable.

The regular behavior:

window.a = 1;
function getFunc() {
  var a = 2;
 
  var func = function() { alert(a) }

  return func; 
}

getFunc()() // 2, from LexicalEnvironemnt of getFunc

And now the function, created by new Function:

window.a = 1
function getFunc() {
  var a = 2
 
  var func = new Function('', 'alert(a)')  
  return func
}

getFunc()() // 1, from window

Summary

We discussed the following topics:

  • How variables are handled in JavaScript.
  • How scopes work.
  • What is a closure and how to use it.
  • Possible pitfalls and subtles in working with closures.

Closures in JavaScript is like a salt. You can live without it, but not very long. Usually people put it everywhere…

See also:

Tutorial

Donate

Donate to this project