7

I'm trying to wrap my head around closures in Javascript.

Here is an example from a tutorial:

function greeter(name, age) {
  var message = name + ", who is " + age + " years old, says hi!";

  return function greet() {
    console.log(message);
  };
}

// Generate the closure
var bobGreeter = greeter("Bob", 47);

// Use the closure
bobGreeter();

The author said that this is an effective way of using closure to make private variables, but I don't get the point.

Could someone enlighten the benefits of coding like this?

never_had_a_name
  • 80,383
  • 96
  • 257
  • 374
  • possible duplicate of ["var functionName = function() {}" vs. "function functionName() {}" in Javascript](http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname-in-javascript) – BrunoLM Oct 11 '10 at 01:56
  • 2
    @BrunoLM: I think that is a different question. – Thilo Oct 11 '10 at 02:01
  • "return function greet()": Does this compile? – Thilo Oct 11 '10 at 02:04
  • I've just written a [blog post](http://skilldrick.co.uk/2010/11/a-brief-introduction-to-closures/) that explains exactly how you'd use a closure to create a private variable. – Skilldrick Nov 23 '10 at 14:49
  • still, a good example that helps explain closure! – bouncingHippo Nov 05 '12 at 20:21

8 Answers8

24

A closure is a pair of a function and the environment in which it was defined (assuming lexical scoping, which JavaScript uses). Thus, a closure's function can access variables in its environment; if no other function has access to that environment, then all of the variables in it are effectively private and only accessible through the closure's function.

The example you provided demonstrates this reasonably well. I've added inline comments to explain the environments.

// Outside, we begin in the global environment.
function greeter(name, age) {
  // When greeter is *invoked* and we're running the code here, a new
  // environment is created. Within this environment, the function's arguments
  // are bound to the variables `name' and `age'.

  // Within this environment, another new variable called `message' is created.
  var message = name + ", who is " + age + " years old, says hi!";

  // Within the same environment (the one we're currently executing in), a
  // function is defined, which creates a new closure that references this
  // environment. Thus, this function can access the variables `message', `name',
  // and `age' within this environment, as well as all variables within any
  // parent environments (which is just the global environment in this example).
  return function greet() { console.log(message); };
}

When var bobGreeter = greeter("Bob", 47); is run, a new closure is created; that is, you've now got a new function instance along with the environment in which it was created. Therefore, your new function has a reference to the `message' variable within said environment, although no one else does.

Extra reading: SICP Ch 3.2. Although it focuses on Scheme, the ideas are the same. If you understand this chapter well, you'll have a good foundation of how environments and lexical scoping work.

Mozilla also has a page dedicated to explaining closures.

ide
  • 17,118
  • 4
  • 56
  • 101
  • 1
    +1 for linking to [Mozilla's Closure page](https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures) - it's the best, most concise explanation of Closure basics and practical applications that I've found. Highly recommended – mjmoody383 Mar 09 '13 at 03:16
  • Thank you, I was going to post a question about how a code I did can work with closure because I didn't understand well this feature. Now I understand it! Your example it's the same thing I was trying to do! – Aker666 Apr 11 '19 at 10:27
8

The purpose of a closure is so that the variables you use inside a given function are guaranteed to be "closed" which means they do not depend on external variables - they only depend on and use their arguments. This makes your Javascript methods closer to a pure function, that is, one that returns the same value for the same given arguments.

Without using closures, your functions will be like Swiss cheese, they will have holes in them. A closure plugs up those holes so the method doesn't depend on variables higher in the scope chain.

Now, up until this point, my answer has been simply about organizing your code and style. So take this simple example. At the line with the comment, I invoke a function and the value of the variable a is captured for future use.

var a = "before";
var f = function(value) {
    return function()
    {
      alert(value);
    }
} (a); //here I am creating a closure, which makes my inner function no longer depend on this global variable
a = "after";

f(); //prints "before"

Now, why would you need to do this? Well, here's a practical example. Consider the following code that uses jQuery to add 5 links to the document. When you click a link, you would expect it to alert the number associated with the link, so clicking the first you would think would alert 0, and so on. But, this is not the case, each link will alert the value of 5. This is because the function I define depends on the variable i which is being modified outside the context of the function. The function I pass into bind is a Swiss cheese function.

for (var i = 0; i < 5; i++)
{
    var a = $('<a>test link</a>').bind('click', function(){
        alert(i);
    });
    $(a).appendTo('body');
}

Now, let's fix this by creating a closure so each link will alert its correct number.

for (var i = 0; i < 5; i++)
{
    var fn = function (value) {
        return function() {
            alert(value);
        };
    } (i); //boom, closure
    var a = $('<a>test link</a>').bind('click', fn);
    $(a).appendTo('body');
}
wsanville
  • 36,053
  • 7
  • 69
  • 99
  • 1
    Kudos for providing a REAL-WORLD example... first one I've seen – Yarin Nov 17 '10 at 17:17
  • I am not an expert in JS, and wanted to understand why Closure is not required in the function below... it alerts how I would expect it to. for (var i = 0; i < 5; i++) { var a = function(){ alert(i); }(); } – Rahul Soni Apr 18 '15 at 03:28
4

I don't think this is a good example for private variables, because there are no real variables. The closure part is that the function greet can see message (which is not visible to the outside, hence private), but it (or anyone else) is not changing it, so it is more of a constant.

How about the following example instead?

function make_counter(){
    var i =0;
    return function(){
        return ++i;
    }
}

var a = make_counter();
console.log(a());  // 1
console.log(a());  // 2
var b = make_counter();
console.log(b());  // 1
console.log(a());  // 3
Thilo
  • 241,635
  • 91
  • 474
  • 626
  • Great example. Now I understand what closure is for. To close (hide) the outer function's variables. This is correct? – never_had_a_name Oct 11 '10 at 02:05
  • Sorry if my example is similar to yours, I was typing it and testing it first before I posted and hadn't seen yours. – alex Oct 11 '10 at 02:07
  • To close around the outer scope's variables, yes. Does not mean hiding. Means your scope gets extended to include everything it references. I guess the term comes from things like "transitive closures" in mathematics. – Thilo Oct 11 '10 at 02:07
2

A better example may be

function add(start, increment) {
  return function() {
      return start += increment;
  }
}

var add1 = add(10, 1);

alert(add1()); // 11
alert(add1()); // 12

Here, every time you call the returned function, you add 1. The internals are encapsulated.

The returned function still has access to its parents variables (in this case, start and increment).

On a lower level of thinking, I think it means that the function's stack is not destroyed when it returns.

alex
  • 438,662
  • 188
  • 837
  • 957
2

Once you "get it" you will wonder why it took you so long to understand it. That's the way way I felt anyways.

I think function scope in Javascript can be expressed fairly concisely.

The function body will have access to any variables that were visible in the lexical environment of the function declaration, and also any variables created via the function's invocation -- that is, any variables declared locally, passed through as arguments or otherwise provided by the language (such as this or arguments).

Cristian Sanchez
  • 27,279
  • 10
  • 53
  • 59
2

It's called "closures" because they are "closed" around free variables, and there are much more ways to use it then only hiding state. For example, in functional programming, where closures came from, they are often used to reduce parameters number or set some constant for a function. Let's say you need function goodEnough() that will test if some result is better then some threshold. You can use function of 2 variables - result and threshold. But you can also "enclose" your constant inside function:

function makeThresholdFunction(threshold) {
    return function(param) {
        return (param > threshold);
    }

}

var goodEnough = makeThresholdFunction(0.5);
...
if (goodEnough(calculatedPrecision)) {
   ...
}

With closures you can also use all the tricks with functions such as their composition:

function compose(f1, f2) {
    return function(arg) {
        return f1(f2(arg));
    }
}

var squareIncremented = compose(square, inc);
squareIncremented(5); // 36

More on closure design and usage can be found at SICP.

ffriend
  • 24,834
  • 13
  • 81
  • 125
1
//Lets start with a basic Javascript snippet
function generateCash() {
    var denomination = [];
    for (var i = 10; i < 40; i += 10) {
        denomination.push(i);
    }
    return denomination;
}

This a basic function statement in Javascript that returns an array of [10,20,30]

//--Lets go  a step further

function generateCash() {
    var denomination = [];
    for (var i = 10; i < 40; i += 10) {
        denomination.push(console.log(i));
    }
    return denomination;
}

This will print 10, 20 ,30 sequentialy as the loop iterates, but will return an array of [undefined, undefined, undefined], the major reason being we are not pushing the actual value of i, we are just printing it out, hence on every iteration the javascript engine will set it to undefined.

//--Lets dive into closures

function generateCash() {
    var denomination = [];
    for (var i = 10; i < 40; i += 10) {
        denomination.push(function() {
            console.log(i)
        });
    }
    return denomination;
}

var dn = generateCash();
console.log(dn[0]());
console.log(dn[1]());
console.log(dn[2]());

This is a little tricky, what do you expect the output will be, will it be [10,20,30]? The answers is no, Lets see how this happens. First a Global execution context is created when we create dn, also we have the generatecash() function. Now we see that as the for loop iterates, it creates three anonymous function objects, it might be tempting to think that the console.log within the push function is getting fired too, but in reality it is not. We haved invoked generateCash(), so the push function is just creating three anonymous function objects, it does not trigger the function. At the end of the iteration, the current local context is popped from the execution stack and it leaves the state of i : 40 and arr:[functionobj0(), functionob1(), functionobj2()].

So when we start executing the last three statements, all of them output 40, since it is not able to get the value of i from the current scope, it goes up the scope chain and finds that the value of i has been set to 40. The reason all of them will fire 40 is beacause every single component of dn lies in the same execution context and all of them on being not able to find the value of i in their current scope will go up the scope chain and find i set as 40 and output it respectively

Arijit Basu
  • 93
  • 1
  • 3
1

I found this a pretty helpful article.

When is a function not a function?

Simon_Weaver
  • 120,240
  • 73
  • 577
  • 618