最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

deeper understanding of closure in Javascript - Stack Overflow

programmeradmin4浏览0评论

I was reading the ments on an answer and saw this ment:

[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?

I was reading the ments on an answer and saw this ment:

[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?

Share Improve this question edited May 23, 2017 at 10:28 CommunityBot 11 silver badge asked Apr 4, 2013 at 2:18 mkoryakmkoryak 58k64 gold badges203 silver badges262 bronze badges 4
  • stackoverflow./a/12931785/783743 – Aadit M Shah Commented Apr 4, 2013 at 2:42
  • The second quote is not necessarily correct. An "unused" closure exists at least in theory, but it might be removed (say for optimisation) because it isn't used. ECMA-262 doesn't define implementation, only behaviour, so if a closure is never used, how do you know if it ever existed? :-) Every function in ECMAScript may create a closure to its outer execution context, at the very least to the global context. – RobG Commented Apr 4, 2013 at 2:44
  • Why was this question marked as a duplicate? No real harm since it was answered/accepted, but it really is a different question than the linked one. Not every closure question on Stack overflow can be a duplicate of "How do closures work?" And in this case the top voted answers on that question don't directly address what this question is concerned about. I expect nobody cares enough to reopen, but the closing seems hasty to me. – Ben McCormick Commented Apr 4, 2013 at 13:39
  • it wasn't marked as a duplicate - thats just a link to that answer. – mkoryak Commented Apr 4, 2013 at 17:19
Add a ment  | 

4 Answers 4

Reset to default 11

I think you're taking that ment too literally. The ment 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/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/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.

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 plicated, this type of garbage collector can more accurately establish whether a variable is used or not.

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.

    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
发布评论

评论列表(0)

  1. 暂无评论