The cliche of closures

Many points of view refer to “What you Don’t know about JavaScript”, “JavaScript Ninja secrets”, private letter to me, can be power book ah. Enter the text:

Maybe you don’t know what closures are, but they’re everywhere in your code! You may not think you need closures, but you have to prepare them for every interview! You may not find this useful, but a lot of frameworks are based on closures!

Let’s focus on the following questions to understand closures:

  • Lexical scope
  • Closure formation
  • The concept of closures
  • A common form of closure
  • What closures do

Closures and lexical scope

There’s a quote in the Book JavaScript You Don’t Know: Closures are the natural result of writing code based on lexical scope. So before you know about closures, you have to understand what a lexical scope is. This was covered in the previous article: Understanding the lexical scope of JavaScript (check it out a bit). If you don’t want to see it, that’s fine. Let’s examine a piece of code to understand what a lexical scope is and how closures are formed.

var a = 100

function foo() {
  var a = 10 
  function test() {
    var b = 9
    console.log(a + b)
  }
  return test
}

var func = foo()
func()
Copy the code

Scope analysis

In the figure above we clearly reflect scope nesting.

  • The global variable func is a reference to test.
  • The test definition runs in global scope, although it is defined in the scope of the foo wrapper.
  • When a + b is executed in test, the value of a is equal to 10 instead of 100. Indicate that the lookup for a variable has nothing to do with where test is executed.
  • This is the lexical scope, and the scope nesting is determined at the writing stage, regardless of where the function is run.

Closure formation

After scoping the appellate code, it is not difficult to conclude that wherever the test function is executed, it always belongs to an identifier in the foo scope, so test always has access to the foo scope.

Normally, after foo is executed, the js garbage collection mechanism will destroy the scope of the foo function. But since the test function holds a reference to foo’s scope, you never know where test will be called as long as the program is running. Whenever test is executed, it accesses the a variable in the foo scope. Therefore, the garbage collection mechanism does not destroy the scope of foo after the completion of foo. This forms a closure

A common form of closure

Above we have analyzed how closures are formed. A typical closure code is also analyzed. We said in the prologue that you may not know what closures are, but they’re everywhere in your code. Next, let’s examine the common form of closures.

Even if you don’t know about closures, you’ve written the following code. Similar:

computed: {
  add() {
    return function(num) {
      return num + 1
    }
  }
},
Copy the code

The calculated property of the acceptable parameters in VUE

function init() {
    $(.name).click(function handleClickBtn() {
        alert('click btn')
    })
}
Copy the code

Use jQ binding events in initialization functions

$.ajax({url:"/api/getName",success:function(result){
    console.log(result)
}});
Copy the code

Ajax request data

window.addEventListener('click', function() {
        
})
Copy the code

Native Registration Event

You can see that closures form when functions are passed as values. JavaScript you Don’t Know concludes: If you treat functions (accessing their respective lexical scopes) as if they were first-level value types and pass them around, you’ll see closures applied to those functions. When you use callbacks in timers, event listeners, Ajax requests, cross-window communications, Web Workers, or any other asynchronous (or synchronous) task, you’re actually using closures!

What closures do

One useful use of closures is the callback function. Another function is to encapsulate private variables. There’s a section in JavaScript Ninja Lore that explains this in detail. Let’s see how closures encapsulate private variables

Private variable encapsulation

Scenario: You have a function foo that counts the number of times it has been called

var num = 0

function foo() {
  // Add one
  num = num + 1
  return num
}

foo()
foo()
foo()

console.log(num)
Copy the code

The global variable num counts the number of calls to foo. The biggest downside is that you don’t know when the value of num has been tampered with. It would be nice if the NUM variable could be privatized so that it could not be changed externally.

function baz() {
  var num = 0

  return function() {
    num++
    return num
  }
}

var foo = baz()
foo()
foo()
let fooNum = foo()

console.log(fooNum)
Copy the code

In the baz scope, you cannot change the value of num under baz while the program is running.

summary

  • Closures are a natural consequence of writing code based on lexical scope
  • Closures are common in our code, and the most common is callback functions
  • Closures do a lot of things, callbacks, privatizing variables, and so on