Improve Closures explanation in JS

Look at this issue about improving the closure explanation in JS. It’s not yet been worked on, but I’m willing to now, and I’d love to see your ideas on how we could improve the closures explanation in JS.

An issue I was wondering about is this section: if I’m right, isn’t this a block? Why, then, does the explanation speak about a function-scoped variable and a nested lexical scope (there is no nesting as I see it)? Perhaps it assumes some global “function” in which the block is nested?


Function-scope

The var keyword defines a function-scoped variable. This means that variables defined by var are available anywhere in the function where they are defined and any nested lexical scope (either function or block).

{
  var five = 5;
}

// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;

Other open ideas from the GH issue include having an advanced explanation with a function being returned and dropping the block example (if I understood @SleeplessByte’s comment correctly). Do you agree with these, and if so, how exactly would we go about implementing them, e.g. what would we have instead of the block example?

There is a lot of confusion around what closures are. I believe this is because people tend to talk only about the ‘interesting’ cases. The nature of closures is actually very simple.

Or, more precisely:

Simple examples:

function hello() {
  return 'Goodbye, Mars!';
}

function world() {
  Console.log('Hello, World!';)
}

function add5(x) {
  return x + 5;
}

Here, hello references the string 'Goodbye, Mars!', which was not given to it as an argument, and therefore is a closure. More precisely: this function contains said string literal as a free variable.

Likewise, in world the literal 'Hello, World!' and the identifier Console.log are not parameters and therefore free variables, so this function is a closure as well.

add5 does have a parameter, but it also contains the literal 5 as a free variable, so it too is a closure.

Terminology: one says a closure closes over its free variables. That is, the above hello closes over 'Goodbye, Mars!', world closes over Console.log and 'Hello, World!', and add5 closes over 5 (and possibly + if that is not a primitive in the language) but not over x.

The concept of closures originates from the lambda calculus (or so I suspect).

Functions that are not closures (i.e. use only parameters) are called combinators. These are quite rare. Most by far of the functions one typically uses in programming are closures.


Now for an ‘interesting’ example:

function f() {  // closes over `0` and `1`.
  var x = 0;
  function g() {  // closes over `x` and `1`.
    x += 1;
    return x;
  }
  return g;
}

Dealing with g, a language implementer might worry: what is x? Where in memory should I look? Quickly they might come up with concepts such as scope and environment.

However, these need not concern you, the language user. As far as you are concerned, x is just a value somewhere, just like 1 and Console.log. It’ll get garbage collected (I guess) at some point when it’s no longer needed, whatever, but while you need it it’ll always be there for you.

Variables that are closed over aren’t any weirder than global variables. In fact, global variables themselves are closed over: by the global scope all functions that use them.

1 Like

While I find all relevant words, I’m not quite sure if the explanation is 100% right. Just see this comment, which makes it clear (functional programming - What exactly does "closing over" mean? - Stack Overflow).

Functions that are not closures (i.e. use only parameters) are called combinators . These are quite rare. Most by far of the functions one typically uses in programming are closures.

Comes that from a wrong definition of closures? Closures are definitely not so often used than normal functions (sure, can depend on style and programming language).

@MatthijsBlom thanks for the explanation! How could we relate this to the Concept explanation and the exercise?

The Closures is one of the topics that needs a lot of work to make it accessible to beginners. Scoping also needs to be explained properly. The article mentions the global scope but neglects to mention the module/file scope and how it differs from the global scope. Some explanation about hoisting is also needed since code that looks like this x++; var x; is valid.

A discussion in the forum is likely not going to be enough.

Wikipedia says,

In computer programming, the term free variable refers to variables used in a function that are neither local variables nor parameters of that function. The term non-local variable is often a synonym in this context.

In your example, you say string literals are free variables. Are string literals variables?

I do not see any disagreement with my post in there. Can you point it out?

Yes, they are. It’s just that non-PLT folk (i.e. most people) only start using the term once things get interesting – typically when free variables are mutated.


I did make another mistake; I’ll correct it shortly.


Do you find the above explanation inaccessible to beginners?

Is scoping in JavaScript not very easy? It’s just lexical, no?


For our purposes: yes, they are, though perhaps this word is not ideal.

Literals are names used to refer to certain values. In that sense they are identifiers. Above I use the term variable loosely; of course they are not actual variables, as they cannot vary: instead they should perhaps be called constants. But for the purpose of discussing closures we might as well call them ‘variables’, just like constants and parameters.

Local function variables don’t make a function a closure. As soon as you can access variables from an outer function scope, it’s a closure.

Rust even has a special syntax for closures, which makes it absolutely clear. But JavaScript (or Go, my main language), don’t have a very specific syntax for closures. Just they are usually anonymous.

Correct; I glossed over local bindings.