5

Will the following code form a closure?

function f() {}

Does where this function is defined affect the answer?

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 1
    A closure represents an outer and inner function. The inner function could have access to local variables defined within the outer function. So a normal function declaration would not be a closure. – Blauharley Feb 21 '15 at 21:26
  • Afaik you form a closure when you reference and capture variables. You can see what the closure contains in devtools. – elclanrs Feb 21 '15 at 21:26
  • typically, you return a function from a function in order to do a closure – Ryan Feb 21 '15 at 21:29
  • Have you read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures? – j08691 Feb 21 '15 at 21:31
  • 1
    You should read [this answer](http://stackoverflow.com/a/12931785/1048572) – Bergi Feb 21 '15 at 21:39

4 Answers4

4

Yes, it forms a closure.

A closure is the combination of a function reference and the environment where the function is created. The code in the function will always have access to any variables defined in the scope where the function is created, no matter how the function is called.

Example; the function f will always use the variable x even if it is called in a scope where x isn't reachable:

function container() {

  var x = 42;

  function f() {
    document.write(x);
  }

  return f;

}

var func = container();
func(); // displays 42
//document.write(x); // would give an error as x is not in scope
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • In my example, there are no variables declared in the context within which the function has been defined. According to your answer a closure (albeit an empty one) is still present, is that correct? – Ben Aston Feb 21 '15 at 21:37
  • @BenAston: I wouldn't call an "empty" closure like your function `f` a closure any more. I even would say that a function without free variables does not - can not - form a closure. – Bergi Feb 21 '15 at 21:40
  • @BenAston: Yes, in Javascript the closure is always created. As a comparison; in strictly typed languages the closure is generally only created when the code in the function actually uses a variable from the scope, but as Javascript is dynamic it's not possible to determine what variables might be used. Also, a scope always has variables defined even if you don't create any. The global scope has a bunch of variables, and inside a function the `arguments` always exist for example. – Guffa Feb 21 '15 at 21:41
  • @Guffa: I think you're confusing terms now. Whether a language support a form of closure has nothing to do with strict typing. – Bergi Feb 21 '15 at 21:43
  • @Bergi: That's not what I said. – Guffa Feb 21 '15 at 21:45
  • Why the downvote? If you don't explain what it is that you think is wrong, it can't improve the answer. – Guffa Feb 21 '15 at 21:46
  • @Guffa: Maybe I misunderstood "*in strictly typed languages the closure is generally only created when the code in the function actually uses a variable from the scope, but as Javascript is dynamic it's not possible to determine what variables might be used*", but it seems wrong. Also, the downvote is because I disagree that `function f() {}` forms a closure. – Bergi Feb 21 '15 at 21:48
  • 1
    @Bergi Running a function creates a `LexicalEnvironment` that contains a reference to the `LexicalEnvironment` within which it is defined (thereby closing over the parent `LexicalEnvironment`). This is surely a closure and whether there are variables in the parent or grandparent LE is moot? – Ben Aston Feb 21 '15 at 21:51
  • 1
    @Bergi: I think that you are confused about what a closure is. Whether any variables are used or not doesn't change the fact that every function has an environment where it is created. – Guffa Feb 21 '15 at 21:54
  • If none of the variables in the ancestor lexical environments are used in the function, that [[scope]] reference can be optimized away (real-world engines do this). Is it a closure any more then? Imo not. Yes, ES5 specs every function creation to form a closure, but I don't think that should make us call every function a closure. – Bergi Feb 21 '15 at 22:02
  • 2
    @Bergi I am leaving this as the answer because the internal optimisations of JS VMs should not IMO affect my conceptual understanding of the language. – Ben Aston Feb 21 '15 at 22:07
  • If the function `f` had only this statement: `eval("alert(" + document.getElementById("my_input").value + ")");` and the `my_input.value` returned the value `x`, the eval'd `alert(x)` would show `42` even though `f` has no variable reference to `x` that can be determined before the function runs. This could only happen if there's a closure. Bergi's right in that things can be optimized to release non-referenced variables (when there's no `eval`), but that's an implementation detail. I wouldn't go so far as to say there's no closure since "closure" really describes a language construct. – Lye Fish Feb 21 '15 at 22:08
  • @BenAston: OK, I guess you are understanding the language concepts now having read all those linked posts :-) Imo the term "closure" becomes moot if everything is one, that's why [that answer](http://stackoverflow.com/a/12931785/1048572) makes the distinction about "interesting closures" :-) – Bergi Feb 21 '15 at 22:12
  • 1
    @Bergi actually I had a pretty good understanding of the concepts when I wrote the question, but thanks to yourself and Guffa I now have an excellent understanding. – Ben Aston Feb 21 '15 at 22:14
  • 1
    @BenAston Good, that's all that is important :-) – Bergi Feb 21 '15 at 22:15
  • ...just because a JS implementation could optimize away an entire function, we wouldn't say *"there is no function"*. – Lye Fish Feb 21 '15 at 22:15
0

Yes, it always defines a closure no matter where it is defined. This tutorial has a few illustrative examples.

Loic Dachary
  • 1,034
  • 1
  • 10
  • 24
0

You create a closure when the function has references to variables in its lexical scope:

var a = 'foo'
function f() {} // no closure
function f() {return a} // closure

If you place a debugger statement inside the function you can see what the closure contains in Chrome devtools. You'll see the first example has nothing, while the second will show a: 'foo'

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • @elclanrs This is at odds with the answer here http://stackoverflow.com/questions/12930272/javascript-closures-vs-anonymous-functions/12931785#12931785 – Ben Aston Feb 21 '15 at 21:42
  • @BenAston: That answer there says "*If F has no free variables then it cannot be a closure.*" which matches elclanrs description – Bergi Feb 21 '15 at 21:46
  • @Bergi That answer states "All functions in JavaScript are closures as explained in this post..." – Ben Aston Feb 21 '15 at 21:48
  • @BenAston: Ok ok, but that's too generalised imho. I think the following sentence from the "Myth 3" section of that post covers the issue well: "*its important to note that the closure creation process is identical for every function*". However those functions that *dont use* this closure feature are no closures to me (it might be nitpicking, but matches [the definition](https://en.wikipedia.org/wiki/Closure_(computer_programming)) best, and in fact it is what actual JS engines do). So "every function *can be* a closure", but not all of them are. – Bergi Feb 21 '15 at 21:56
  • @Bergi: All functions in Javascript create a closure. If the closure isn't used, then you can think of them as not having one if you like, but they still do. – Guffa Feb 21 '15 at 22:00
  • @Bergi Actual engines create a `LexicalEnvironment` that points to `LexicalEnvironment` within which the function was declared. There is no separate closure object, but the `LexicalEnvironment` is always created together with a link to the parent LE. Given this, can you help me understand your comment "... [this] is what actual JS engines do". Thanks :) – Ben Aston Feb 21 '15 at 22:00
  • @Bergi, OK thanks for your clarification as a comment on another answer here. – Ben Aston Feb 21 '15 at 22:07
  • @BenAston: function objects have [[scope]] properties, lexical environments have an "outer" reference. However, those [lexical environments are garbage collected when no more needed](http://stackoverflow.com/q/8665781/1048572), and a function might never become a closure when it has no free variables. Static analysis does lots of things :-) – Bergi Feb 21 '15 at 22:08
  • @Bergi is the "outer" reference a copy of the reference to the `[[Scope]]` of the function? Is the outer reference a property on the LE? – Ben Aston Feb 21 '15 at 22:18
  • @BenAston: [Yes](http://es5.github.io/#outer-environment-reference), [exactly](http://es5.github.io/#x10.4.3) – Bergi Feb 21 '15 at 22:19
-1

Because javascript is a special language (see scope, hoisting and more recently the TDZ), depending on how specific you are in your question you might get different answers.

Is it a javascript closure? No. See definition by Mozilla https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

Is it captured in a closure (or does it form a closure - the original question)? Depends on optimizations. But most likely yes. See http://dmitrysoshnikov.com/ecmascript/chapter-6-closures/ and more importantly https://en.wikipedia.org/wiki/Closure_%28computer_programming%29

The closure term is used by javascript "evangelists" to identify those functions that would not work correctly if they weren't captured in actual closures - this is the correct way of saying it from a fundamentally operational point of view. And the reason is probably due to a lack of a better term rather than anything else.

bug-a-lot
  • 2,446
  • 1
  • 22
  • 27