Understanding Closing in Javascript

I am 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 to use closure to create private variables, but I do not understand.

Can anyone enlighten the benefits of coding as follows?

+7
javascript closures
source share
8 answers

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

The example you provided demonstrates this quite well. I added inline comments to explain the environment.

 // 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 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); it starts, a new closure is created; that is, you now have a new instance of the function along with the environment in which it was created. Therefore, your new function has a reference to the variable 'message' in the specified environment, although no one else does.

Further reading: SICP Ch 3.2 . Although he focuses on the scheme, ideas coincide. If you understand this chapter well, you will have a good idea of ​​how the surroundings and lexical scope work.

Mozilla also has a page dedicated to explaining closures .

+23
source share

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

Without the use of closures, your functions will look like Swiss cheese, there will be holes in them. Closing closes these holes, so the method is independent of variables higher in the scope chain.

Now, up to this point, my answer was simply about organizing your code and style. So take this simple example. In the comment line, I call the function and the value of the variable a is fixed 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 do you need this? Well, here is a practical example. Consider the following code that uses jQuery to add 5 links to a document. When you click on a link, you expect it to be an alert number associated with the link, so the first one you think of will be warning 0, etc. But, this is not so, each link will be alert value of 5. This is due to the fact that the function I define depends on the variable i , which changes outside the context of the function. The function that I pass to 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 fix this by creating a closure so that each link has 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'); } 
+8
source share

I do not think this is a good example for private variables, because there are no real variables. The closing part is that the greet function can see message (which is not visible to the external, therefore private), but it (or anyone else) does not change it, so it is more constant.

What about the following example?

 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 
+4
source share

A better example might 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 return function, you add 1. Internal objects are encapsulated.

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

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

+2
source share

Once you β€œreceive,” you will wonder why you need to understand this for so long. This is the way I somehow felt.

I think that the scope of functions in Javascript can be expressed quite briefly.

The body of the function will have access to any variables that were visible in the lexical environment of the function declaration, as well as any variables created by calling the function, i.e. any variables declared locally, passed as arguments or otherwise provided in the language (for example, this or arguments ).

+2
source share

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

 function makeThresholdFunction(threshold) { return function(param) { return (param > threshold); } } var goodEnough = makeThresholdFunction(0.5); ... if (goodEnough(calculatedPrecision)) { ... } 

With closure, you can also use all tricks with features such as their composition:

 function compose(f1, f2) { return function(arg) { return f1(f2(arg)); } } var squareIncremented = compose(square, inc); squareIncremented(5); // 36 

More information on the design and use of closure can be found on SICP .

+2
source share

I found this pretty useful article.

When is a function not a function?

+1
source share
 //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 is the main function statement in Javascript, which returns an array from [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 sequentially as the loop repeats, but will return an array from [undefined, undefined, undefined], the main reason is that we do not press the actual value of i, we just print it, so the javascript mechanism at each iteration 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]()); 

It's a little complicated what you expect from the exit, will it be [10,20,30]? There are no answers. Let's see how this happens. First, a global execution context is created, when we create dn, we also have the generatecash () function. Now we see that as the for loop iterates through it, it creates three anonymous function objects, it may be tempting to think that console.log inside the push function also works, but this is actually not the case. We launched the call generateCash (), so the push function simply creates three anonymous function objects, this does not call the function. At the end of the iteration, the current local context is set from the execution stack and leaves the state i: 40 and arr: [functionobj0 (), functionob1 (), functionobj2 ()]. A.

So, when we start to execute the last three statements, all of them output 40, since it cannot get the value i from the current area, it rises to the chain of areas and discovers that the value i was the set value 40. The reason that all of of them will work, equal to 40, since each component of dn is in the same execution context, and they all can not find the value i in their current scope, will increase the chain of areas and find that I am set to 40 and display it accordingly

+1
source share

All Articles