6

Let me ask one question. It's about closures in JavaScript, but not about how they work.

David Flanagan in his "JavaScript The Definitive Guide 6th Edition" wrote:

...Technically, all JavaScript functions are closures: they are objects, and they have a scope chain associated with them....

Is this correct? Can I call every function (function object + it's scope) a "closure"?

And stacks' tag "closures" says:

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.

In JavaScript every function refers to variables from the scope in which it was defined. So, It's still valid.

The question is: why do so many developers think otherwise? Is there something wrong with this theory? Can't it be used as general definition?

Ivan
  • 1,487
  • 1
  • 16
  • 27
  • Yes the definition is correct, look at this answer http://stackoverflow.com/questions/36636/what-is-a-closure – frhack Jun 26 '15 at 22:53
  • Function is a type, where *closure* is how you are using as. – Derek 朕會功夫 Jun 26 '15 at 23:33
  • Function != closure. Note the difference between declaring a function, which creates *one* object that is that function, and calling that function multiple times, which creates *multiple* closures. – nnnnnn Jun 27 '15 at 00:26

4 Answers4

2

Technically, all functions are closures. But if the function doesn't reference any free variables, the environment of the closure is empty. The distinction between function and closure is only interesting if there are closed variables that need to be saved along with the function code. So it's common to refer to functions that don't access any free variables as functions, and those that do as closures, so that you know about this distinction.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • *"Technically, all functions are closures."* - No, the closures are created when the (containing) function is *called*. One function called ten times would result in ten closures. – nnnnnn Jun 27 '15 at 00:21
  • No, In C language we have functions that aren't closures, just to cite an example. – frhack Jun 27 '15 at 05:19
  • @frhack My answer is only intended in the context of Javascript, this is not a language-agnostic question or answer. – Barmar Jun 29 '15 at 01:48
  • @nnnnnn The function itself isn't created until the containing function is called. When that happens, the function is created, and it's a closure. – Barmar Jun 29 '15 at 01:48
  • But then the closure applies to the invocation of the containing function, doesn't it? Because if the containing function has, say, three inner functions they all all have access to the containing function's variables, so is that one closure for the containing function, or three closures? – nnnnnn Jun 29 '15 at 03:19
  • @nnnnnn The containing function is one closure, and the inner functions are 3 more closures. – Barmar Jun 29 '15 at 03:28
1

It's a tricky term to pin down. A function that's simply declared is just a function. What makes a closure is calling the function. By calling a function, space is allocated for the parameters passed and for local variables declared.

If a function simply returns some value, and that value is just something simple (like, nothing at all, or just a number or a string), then the closure goes away and there's really nothing interesting about it. However, if some references to parameters or local variables (which, mostly, are the same) "escape" the function, then the closure — that space allocated for local variables, along with the chain of parent spaces — sticks around.

Here's a way that some references could "escape" from a function:

function escape(x, y) {
  return {
    x: x,
    y: y,
    sum: function() { return x + y; }
  };
}

var foo = escape(10, 20);
alert(foo.sum()); // 30

That object returned from the function and saved in "foo" will maintain references to those two parameters. Here's a more interesting example:

function counter(start, increment) {
  var current = start;
  return function() {
    var returnValue = current;
    current += increment;
    return returnValue;
  };
}

var evenNumbers = counter(0, 2);
alert(evenNumbers()); // 0
alert(evenNumbers()); // 2
alert(evenNumbers()); // 4

In that one, the returned value is itself a function. That function involves code that makes reference to the parameter "increment" and a local variable, "current".

I would take some issue with conflating the concept of a closure and the concept of functions being first-class objects. Those two things really are separate, though they're synergistic.

As a caveat, I'm not a formalist by basic personality and I'm really awful with terminology so this should probably be showered with downvotes.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • So, function with it's scope can't be define as "closure" as it is, no matter what? Does this function need to return another fuynction "to be interesting"? Flanagan says about every function. So, I am confused. – Ivan Jun 26 '15 at 23:00
  • 1
    @Ivan Like I said I'm terrible with definitions. To me, a function that isn't called really isn't a closure, because nothing has happened: no memory has been allocated, nothing is initialized, nothing is returned, no side-effects, etc. It's the act of *calling* a function that causes those things to (potentially) happen. – Pointy Jun 26 '15 at 23:06
  • A super-simple function that just returns a scalar *technically* creates a closure, but since it goes away it's kind-of like quantum matter-antimatter pairs that pop into existence. They're there, but it doesn't really matter other than theoretically. – Pointy Jun 26 '15 at 23:07
  • I does matter for me theoretically... It's like Holy War for me now. lol I just need to know it and get some arguments against people who think otherwise. I just failed this question on job interview yeasterday. I was so shocked since I was fully confident about closures, I couldn't even say "wait, let me explain..." and say about allocation, free variables and show some examples, he just started another question. So, I was wondering if it's me with wrong thoughts about closures or is it interviewer knowing less than me. It's like butthurt :D – Ivan Jun 26 '15 at 23:51
  • 1
    I'm not really sure what you mean by, "think otherwise". What other definition are you struggling against? What else would a "closure" be? It's a term not specific to JavaScript. – Pointy Jun 26 '15 at 23:58
  • It's mostly "can simple function create closure or not?" or "is that Flanagan quote correct?". – Ivan Jun 27 '15 at 00:05
  • @Ivan OK, well *every* function call results in a closure being created. The interesting part is whether anything can *detect* that fact. If nothing from "inside" leaks out, then the closure is created and destroyed like a stack frame in C or C++. – Pointy Jun 27 '15 at 00:08
  • *"That object returned from the function and saved in "foo" will maintain references to those two parameters."* - No it won't. The returned object retains the *values* from the two parameters, but it doesn't retain references to the actual parameters themselves. Why would it? – nnnnnn Jun 27 '15 at 00:16
  • @nnnnnn oh yes of course you're right. Let me think of a way to de-stupidize that example. Thanks. *edit* OK done I think. – Pointy Jun 27 '15 at 00:17
  • That's better. This is also the only answer (so far) that makes the vital distinction between functions that have been declared and functions that have actually been called. – nnnnnn Jun 27 '15 at 00:20
1

I would try to answer your question knowing you were asked about what closures are during the interview (read it from the comments above).

First, I think you should be more specific with "think otherwise". How exactly?

Probably we can say something about this noop function's closure:

function() {}

But it seems it has no sense since there are no variables would bound on it's scope.

I think even this example is also not very good to consider:

function closureDemo() {
    var localVar = true;
}
closureDemo();

Since its variable would be freed as there is no possibility to access it after this function call, so there is no difference between JavaScript and let's say C language.

Once again, since you said you have asked about what closures are on the interview, I suppose it would be much better to show the example where you can access some local variables via an external function you get after closureDemo() call, first. Like

function closureDemo() {
    var localVar = true;
    window.externalFunc = function() {
        localVar = !localVar;  // this local variable is still alive
        console.log(localVar); // despite function has been already run,
                               // that is it was closed over the scope
    }
}
closureDemo();
externalFunc();
externalFunc();

Then to comment about other cases and then derive the most common definition as it more likely to get the interviewer to agree with you rather than to quote Flanagan and instantly try to find the page where you've read it as a better proof of your statement or something. Probably your interviewer just thought you don't actually know about what closures are and just read the definition from the book. Anyhow I wish you good luck next time.

ivkremer
  • 1,234
  • 3
  • 23
  • 42
  • Instruction is unclear. Eneded up telling people that "Earth" isn't planet, but place where we live. :D How can I know when to start from global definition and come to "interesting case" and otherwise? It seems like my definition was correct and this is just explanation. I could do like you say. But... couldn't it mean interviewer just doesn't know more abstract definition and probably about concept of 'function working with scope it defined in, instead of scope where it is was called'? – Ivan Jun 27 '15 at 10:35
  • "Probably your interviewer just thought you don't actually know about what closures are and just read the definition from the book." So, reading books is fail nowadays? It can't be minus anyway. It's more lika advanced knowledge compared to "closure is this... look at my example". And if he would know this defintion and would doubt my knowledges, he would ask something more specific or asked for example, or maybe give me some exercises to solve. I still be he didn't know it. – Ivan Jun 27 '15 at 11:38
  • @Ivan Probably he didn't and probably he was extremely impatient to listen for explanation. In this case it's a good reason not to accept their offer because of wilful team leader/manager. Otherwise it's not too difficult to prove these definitions with code snippets. – ivkremer Jun 27 '15 at 12:12
0

The definition is correct. The closure keeps the scope where it was born

Consider this simple code:

getLabelPrinter = function( label) {
  var labelPrinter = function( value) {
      document.write(label+": "+value);
  }
  return labelPrinter; // this returns a function
}

priceLabelPrinter = getLabelPrinter('The price is');
quantityLabelPrinter = getLabelPrinter('The quantity is');

priceLabelPrinter(100);

quantityLabelPrinter(200);

//output:
//The price is: 100 The quantity is: 200  

https://jsfiddle.net/twqgeyuq/

frhack
  • 4,862
  • 2
  • 28
  • 25