deeper understanding of closure in Javascript

I was reading the comments on an answer and saw this comment:

[the closure] doesn't persist the state of foo so much as creates a special scope containing (1) the returned function and (2) all the external variables referenced at the time of the return. This special scope is called a closure.

OK, so far so good. Now here is the interesting part that I didn't know about:

Case in point... if you had another var defined in foo that was not referenced in the return function, it would not exist in the closure scope.

I guess that makes sense, but what implications does this have other than memory use / perfomance?

Question -- If all variables in scope were included in the closure, what would that allow me to do that I cannot do with the current model?

Answers:

Answer

I think you're taking that comment too literally. The comment is just saying that you can't access it outside the function scope (it's not publicly accessible), not that its not available at all within the function. The returned function will have access to all of the outer functions scope no matter what. You just can't access that scope outside the outer function if the inner function doesn't provide a way of accessing it.

For instance, this expression evaluates to 4:

function testClosure(){
 var x = 2;
    return function(y){
        alert(eval(y));
    }

}

var closure = testClosure();

closure("x+2");  //4

http://jsfiddle.net/dmRcH/

So x is available despite not being directly referenced

Further research

It appears that chrome and firefox at least do attempt to optimize this in the sense that if you're not providing ANY way to reference the x variable, it doesn't show up as being available in the debugger. Running this with a breakpoint inside a closure shows x as unavailable on Chrome 26 and Firefox 18.

http://jsfiddle.net/FgekX/1/

But thats just a memory management detail, not a relevant property of the language. If there is any possible way that you could reference the variable, it is passed, and my suspicion is that other browsers may not optimize this in the same way. Its always better to code to the spec than to an implementation. In this case though the rule really is: "if there's any possible way for you to access it, it will be available". And also, don't use eval because it really will keep your code from optimizing anything.

Answer

if you had another var defined in foo that was not referenced in the return function, it would not exist in the closure scope.

This is not entirely accurate; the variable is part of the closure scope, even though it may not be directly referenced inside the function itself (by looking at the function code). The difference is how the engines optimize unused variables.

For instance, unused variables in the closure scope are known to cause memory leaks (on certain engines) when you're working with DOM elements. Take this classical example for instance:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

Source

In above code, memory is leaked (in both IE and Mozilla at least) because el is part of the closure scope for the click handler function, even though it's not referenced; this causes a cyclic reference which can't be removed because their garbage collection is based on reference counting.

Chrome, on the other hand, uses a different garbage collector:

In V8, the object heap is segmented into two parts: new space where objects are created, and old space to which objects surviving a garbage collection cycle are promoted. If an object is moved in a garbage collection cycle, V8 updates all pointers to the object.

This is also referred to as a generational or ephemeral garbage collector. Albeit more complicated, this type of garbage collector can more accurately establish whether a variable is used or not.

Answer

JavaScript has no inherent sense of privacy so we use function scope (closure) to simulate this functionality.

The SO answer you reference is an example of the Module pattern which Addy Osmani does a great job explaining the importance of in Learning JavaScript Design Patterns:

The Module pattern encapsulates "privacy", state and organization using closures. It provides a way of wrapping a mix of public and private methods and variables, protecting pieces from leaking into the global scope and accidentally colliding with another developer's interface. With this pattern, only a public API is returned, keeping everything else within the closure private.

Answer
    Please have a look below code:

    for(var i=0; i< 5; i++){            
                setTimeout(function(){
                    console.log(i);
                },1000);                        
            }

   Here what will be output? 0,1,2,3,4 not that will be 5,5,5,5,5 because of closure

   So how it will solve? Answer is below:

   for(var i=0; i< 5; i++){
            (function(j){     //using IIFE           
                setTimeout(function(){
                    console.log(j);
                },1000);
            })(i);          
        }

    Let me simple explain, when a function created nothing happen until it called so for loop in 1st code called 5 times but not called immediately so when it called i.e after 1 second and also this is asynchronous so before this for loop finished and store value 5 in var i and finally execute setTimeout function five time and print 5,5,5,5,5

Here how it solve using IIFE i.e Immediate Invoking Function Expression

   (function(j){  //i is passed here           
                setTimeout(function(){
                    console.log(j);
                },1000);
            })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

For more, please understand execution context to understand closure.

- There is one more solution to solve this using let (ES6 feature) but under the hood above function is worked

 for(let i=0; i< 5; i++){           
                setTimeout(function(){
                    console.log(i);
                },1000);                        
            }

Output: 0,1,2,3,4

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.