Before we start talking about closures, we need to take a look at scope and lexical scope, for example, scope, lexical scope, scope Chain, lexical Environment, and Execution Context

Closure (Closure)

Lexical scope allows us to statically access variables in outer scope

function outerFunc() {	
  // --- start lexical scope 
  let outerVar = 'I am outside! ';
    
  // start closure
  function innerFunc() {	
    console.log(outerVar); // => logs "I am outside!"
  }									
  // end closure

  return innerFunc;
  // --- end lexical scope 
}

const myInnerFunc = outerFunc();
myInnerFunc();
Copy the code

MyInnerFunc () still prints ‘I am outside! ‘, here are some important points:

  • Although innerFunc is executed outside of its lexical scope, it can still access the variable outerVar in the Outer scope
  • In other words, innerFunc() captures the variable outerVar defined in outerFunc() from its lexical scope (an important feature of closures)

Conclusion:

A closure is a function that can access its lexical scope even if the function is executed outside of its lexical scope. In other words, a closure is a function that remembers (or captures) variables from where they were defined, even if the function is executed outside its lexical scope

Application scenarios for closures

Event handler

let countClicked = 0;

myButton.addEventListener('click'.function handleClick() {
  countClicked++;
  myText.innerText = `You clicked ${countClicked} times`;
});

Copy the code

Callback

Case 1:

const message = 'Hello, World! ';

setTimeout(function callback() {
  console.log(message); // logs "Hello, World!"
}, 1000);
Copy the code

Example 2:

let countEven = 0;
const items = [1.5.100.10];

items.forEach(function iterator(number) {
  if (number % 2= = =0) { countEven++; }}); countEven;/ / = > 2
Copy the code

Functional Programming

function multiply(a) {
  return function executeMultiply(b) {
    returna * b; }}const double = multiply(2);
double(3); / / = > 6
double(5); / / = > 10

const triple = multiply(3);
triple(4); / / = > 12
Copy the code

stale closure

function createIncrement(incBy) {
  let value = 0;

  function increment() {
    value += incBy;
    console.log(value);
  }

  const message = `Current value is ${value}`;
  function log() {
    console.log(message);
  }
  
  return [increment, log];
}

const [increment, log] = createIncrement(1);
increment(); // logs 1
increment(); // logs 2
increment(); // logs 3
// Does not work!
log();       // logs "Current value is 0"
Copy the code

Log () increments Current value is 0, increment value = 3, log() increments Current value is 0.

Since log() is a stale closure, its value is outdated(0), so no matter how many times increment() is executed, it prints 0

How to fix this problem?

function log() {
	const message = `Current value is ${value}`;
  console.log(message)
}
Copy the code

As shown above, you simply retrieve the value of value every time you call log()

Stale Closure: this closure captures a outdated value

reference

  • simple-explanation-of-javascript-closures/
  • react hooks stale closures
  • JavaScript you Don’t Know, vol. 1