The history of closures

Closure is a translation of the English word closure, a difficult word to translate, and in the computer world it has three distinct meanings:

  • In compilation principles, it is a step in dealing with syntax production;
  • In computational geometry, it represents a convex polygon (translated as convex hull) enclosing a set of plane points.
  • In programming languages, it represents a function.

The concept of closures first appeared in The Computer Journal in 1964, P. J. Landin put forward The concepts of Applicative Expression and closure in The Mechanical Evaluation of Expressions.

In the 1960s, the dominant programming language was functional programming based on lambda calculus, so this initial closure definition used a lot of functional terminology. A less precise description is “a λ expression with a series of information”. A λ expression is a function in a functional language.

We can be so simple to understand that the closure is just a binding the execution environment function, the function is not a simple expression of printed books, closure and common function, is the difference between it carries the execution environment, like people need to bring in the alien oxygen equipment, this function also with the environment in the process.

In this classical definition of a closure, there are two parts to a closure.

  • Part of the environment
    • The environment
    • Identifier list
  • Expression part

Closures in JavaScript

Let’s look at the definition of closures:

MDN: A combination of a function bound (or surrounded by) references to its surrounding state (lexical environment) is a closure. That is, closures allow you to access the scope of an outer function within an inner function. In JavaScript, whenever a function is created, the closure is created at the same time the function is created.

Closures are generated when a function can remember and access its lexical scope, even if the function is executed outside the current lexical scope. Closures are a natural consequence of writing code based on lexical scope, and you don’t even need to consciously create closures in order to take advantage of them.

JavaScript Advanced Programming edition 4: Closures are functions that reference variables in the scope of another function, usually implemented in nested functions.

From this we can know:

The essence of JavaScript closures comes from two things, lexical scopes and functions passed as values.

Lexical scope, that is, the way the code is written, an inner function can access variables outside the function. The engine represents a function through data structures and algorithms that allow access to peripheral variables that are registered in the corresponding data structure in accordance with the rules of lexical scope during code interpretation execution.

Functions are passed as values, known as first class objects. A function can be assigned as a value, passed as an argument to another function, or a function can be returned as a value. A function is returned as a value, also is equivalent to return to a channel, the channel access to this function the lexical scope of variables, namely the function required by the data structure is preserved, the values in the data structure in execution is created when the outer function, when the outer function has been completed for destruction, but due to the internal function as a value back out, These are worth preserving. And you can’t access it directly, you have to go through the returned function. This is also called private sex.

Here’s an example to remember:

function foo() {
    var myName = " JavaScript "
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName: function () {
            console.log(test1)
            return myName
        },
        setName: function (newName) {
            myName = newName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName(" CSS ")
bar.getName()
console.log(bar.getName())
Copy the code

First let’s look at what happens when the stack is called by executing the innerBar line inside foo:

As you can see from the code above, the innerBar is an object that contains two methods, getName and setName. As you can see, both methods are defined inside foo, and both use myName and test1 variables inside.

By the rules of lexical scope, the inner functions getName and setName always have access to variables in their outer function foo, so when the innerBar object is returned to the global variable bar, even though foo is finished executing, But the getName and setName functions can still use the myName and test1 variables in foo. So when foo completes, its entire stack looks like this:

As you can see from the figure above, the execution context of foo is popped off the top of the stack, but the setName and getName methods returned use the myName and test1 variables inside foo, so they remain in memory. This is much like the setName and getName methods, which carry the foo function’s own backpack wherever they are called.

It is a specific backpack because it is inaccessible from anywhere except the setName and getName functions, so we can call the backpack the closure of the foo function.

Ok, now we can finally give closure a formal definition. ** In JavaScript, according to the rules of lexical scope, an inner function can always access the variables declared in its outer function. When an inner function is returned by calling an outer function, the variables referenced by the inner function are kept in memory even after the outer function has finished executing. Let’s call this set of variables a closure. ** If the external function is foo, then the set of variables is called the closure of foo.

So how do these closures work? When executing myName = “CSS” in the bar.setName method, the JavaScript engine looks for the myName variable in the order “current execution context — > foo function closure — > global execution context.” You can refer to the following call stack state diagram:

As you can see from the figure, there is no myName variable in the execution context of setName. Foo’s closure contains the variable myName, so calling setName changes the value of myName variable in foo’s closure.

Similarly, when bar.getName is called, the variable myName is called in the foo function closure.

You can also use developer Tools to see how closures work. Open Developer Tools in Chrome, hit a breakpoint anywhere in the bar function, and refresh the page to see something like this:

When bar.getName is called, the Scope item on the right represents the Scope chain:

  • Local is the current onegetNameFunction scope;
  • Closure(foo) refers tofooClosure of a function;
  • Global at the bottom means Global scope;

From “Local — > Closure(foo) — > Global” there is a complete chain of scopes.

In the future, you can also use Scope to see the Scope chain of the actual code, which will be easier to debug the code.

The role of closures

  1. The first thing closures do is give us access to variables inside a function outside of it. By using closures, you can create private variables by calling the closure function externally, thereby accessing the variables inside the function externally.
  2. Another purpose of a closure is to keep a variable object in the context of a function that has already run out of memory. Because the closure retains a reference to the variable object, the variable object is not reclaimed.

Closure application scenarios

Currie,

Currization: Transform a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function).

// Before currization
const getVolume = (l, w, h) = > l * w * h
const volume1 = getVolume(100.200.100)
const volume2 = getVolume(100.200.300)

// After currified
const getVolume = l= > w= > h= > l * w * h
const getVolumeWithDefaultLW = getVolume(100) (200)
const volume1 = getVolumeWithDefaultLW(100)
const volume2 = getVolumeWithDefaultLW(300)
Copy the code

modular

Used to encapsulate the internal implementation and expose only the external interface, common in tool library development.

var counter = (function() {
  var privateCounter = 0
  function changeBy(val) {
    privateCounter += val
  }
  return {
    increment: function() {
      changeBy(1)},decrement: function() {
      changeBy(-1)},value: function() {
      return privateCounter
    }
  }
})()
Copy the code

Reference:

MDN

You don’t know JavaScript scroll up

JavaScript Advanced Programming version 4

Scope and closure – implementation principles and functions of closures

(2021) (2021) (2021)

What is a closure?