Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does a (JS) Closure Require a Function Inside a Function

I'm having a little difficulty with the inherent concept of a closure. I get the basic idea, but here's the thing: I thought that, technically, there "is a closure" inside every Javascript function. To quote wikipedia:

In computer science, a closure (also lexical closure, function closure or function value) is a function together with a referencing environment for the nonlocal names (free variables) of that function. Such a function is said to be "closed over" its free variables.

So since you can define variables inside a function, they are "closed off" to the rest of your code, and so I see that as a closure. Thus, as I understand it:

(function(){var a = 1;}())

Is a (not very useful) example of a closure. Or heck, even just this:

function(){var a = 1;}

But, I think my understanding might be wrong. Others are telling me that for something to be a closure it has to persist a state, and so since nothing persists beyond that code it's not really a closure. That suggests that you need to have:

function(foo){foo.a = 1;}(bar); // bar.a = 1

or even (to ensure un-modifiability):

function(foo){var a = 1; bar.baz = function() { return a}}(bar); // bar.baz() = 1

So, technically speaking (I know several of the examples are practically speaking pointless, but) which of the above examples are actually examples of closures. And does a closure just have to be a space (ie. inside a JS function) where variables can be stored that can't be accessed form outside, or is persistence a key part of a closure's definition?

EDIT

Just noticed the wiki definition for the "closures" tag on Stack Overflow:

A closure is a first-class function that refers to (closes over) variables from the scope in which it was defined. If the closure still exists after its defining scope ends, the variables it closes over will continue to exist as well.

While the SO wiki is certainly no final authority, the first sentence does seem to correlate with my understanding of the term. The second sentence then suggests how a closure can be used, but it doesn't seem like a requirement.

EDIT #2

In case it isn't clear from the varying answers here, the wikipedia answer, and the tag answer, there does not seem to be a clear consensus on what the word "closure" even means. So while I appreciate all the answers so far, and they all make sense if you go with the author's definition of closure, what I guess I'm really looking for is ... is there any actual "authoritative" definition of the word (and then if so, how does it apply to all of the above)?

like image 785
machineghost Avatar asked Aug 17 '11 17:08

machineghost


2 Answers

You're being led astray by a wrong assumption of where the word "closure" comes from.

In a language-theoretic context, the point of a closure is that the function can refer to variables declared outside its own definition. It is immaterial whether it has internal variables, or that the internal variables are not visible from outside. In other words it is about seeing out from the function to its definition environment, not about seeing in from outside the function.

Why the weird word, then? Look at the function in your last example:

bar.baz = function() { return a }

This function contains a mention of the variable a which is not defined in the function body itself. It is a "free" variable of the function body, sort of a "hole" in the definition. We cannot execute the function without knowing, by some extraneous means, what variable the identifier a in the body refers to. Forming a closure at run-time pairs this "open" function body with a reference to the appropriate variable, thereby closing the hole in the definition. And that's where the name comes from.

(If you want the completely technical explanation, the underlying concept is that of a "closed" term in the lambda-calculus, which means one that has no free variables. Only closed term have independent meanings. A closure is then the combination of a (usually compiled) non-closed piece of source code, together with the contextual information that lets it behave like it was a closed term, and therefore be executable).

Addendum: In the common idiom

function() {
   var blah;
   // some code here
}();

the point is not to get a closure (you will get one, of course, but it doesn't do anything interesting for you), but to create a local scope for the blah variable. A local scope is conceptually quite a different thing from a closure -- in fact most C-lookalikes other than Javascript will create them at every {} block, whereas they may or may not have closures at all.

like image 129
hmakholm left over Monica Avatar answered Nov 04 '22 09:11

hmakholm left over Monica


None of your samples are closures technically speaking. (But forth sample can be classified as such in some circumstances, see below)

Closure is a data structure that combines reference to a function and non-empty list of call frames (or scopes) active at the moment of declaration.

Closure is created by executing some code that contains declaration of a function that uses variables from outer scopes. In this case runtime, while executing the code, has to create not just a reference to the function but closure structure - function reference and reference to its current environment - list of call frames that hold used outer variables.

For example in my TIScript call frames are replaced on stack - when you exit from a function its call frame that includes collection of variables it uses is purged from the stack. Closure creation in my case happens when: VM meets function declaration instruction and that function is marked (by compiler) as the one that uses outer variables. In this case current chain of call frames that hold used variables is moved from stack to the heap - converted to GCable data objects and reference to the function and its call chain is stored as a reference.

Your fourth case physically does not require closure to be created - no need to store call frames for later use - bar.baz contains just a number - not a reference to function.

But this:

function(foo){  
   var a = 1; 
   bar.baz = function() { return a; }; 
}

creates closure in bar.baz field. When you later invoke bar.baz() function code is executed and value of 'a' variable will be taken from reference to outer call frame that is stored in closure.

Hope it clears something for you.

like image 27
c-smile Avatar answered Nov 04 '22 09:11

c-smile