Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 325
mkoryak Avatar asked Apr 04 '13 02:04

mkoryak


People also ask

What is the benefit of closure in JavaScript?

Advantages of closures Variables in closures can help you maintain a state that you can use later. They provide data encapsulation. They help remove redundant code. They help maintain modular code.

Why is it called closure JavaScript?

Let's understand what the closure is. Closure means that an inner function always has access to the vars and parameters of its outer function, even after the outer function has returned. You have learned that we can create nested functions in JavaScript.

What is closure in JavaScript interview questions?

A JavaScript closure is when an inner function has access to its outer enclosing function's variables and properties. In the code above, the following line of code: setTimeout(function() { alert(i); }, 1000 + i); uses a variable i which is declared outside of itself.


2 Answers

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.

like image 102
Ben McCormick Avatar answered Sep 21 '22 23:09

Ben McCormick


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.

like image 33
Ja͢ck Avatar answered Sep 22 '22 23:09

Ja͢ck