Scope, scope chain, currying, and closure of JS knowledge points

1. Scope and scope chain

Scope refers to an area that exists when js variables are used, which is divided into global scope (window) and local scope (function, setTimeout, etc. all generate local scope). When a local-scope variable name duplicates a global-scope variable name, the local variable overrides the global variable.

When using a variable in the local scope, if the corresponding variable cannot be found in its own scope, it will search for the upper-level scope until the global scope. If there is no such variable in the global scope, undefined will be reported. Conversely, variables in the local scope cannot be used in the global scope.

window.a = 1
function(){
  // Output 1, although there is no a variable locally, but there is a variable globally.
  console.log(a)
  var b = 2
}
// An error is reported, local variables cannot be used in the global.
console.log(b)

The above process of querying variables layer by layer is called the query scope chain. This structure of layers of local scopes up to the global scope is called a scope chain.

// Global scope, declares a global variable a
var a = 100

// Functions generate local scope
function acs(){
  // declare a local variable b in this local scope
    var b = 50
  // Output: 100, 50
  console.log(a, b) // Execution process: find variable a in this scope,
                                      // Can't find --> Find it in the upper scope --> Find it globally, use a in the global scope
                                      // Find variable b in this scope, found it, use b of this local variable
}()

// Output: b is not defined
console.log(a, b)

2. Closure

1. What is a closure?

A closure refers to a private variable that calls a local variable inside a function outside the function, and the local variable will not be reclaimed by the browser immediately after the call, but will always exist. To put it simply, a function returns a function.

Description in the Red Book: A closure is a function that has access to a variable in the scope of another function.

In fact, the closure is to return a function, and the inclusion relationship formed by the function's reference to the local variable is the closure.

In fact, it is to create a local variable that will not be reclaimed by GC. Because of this, closures have the risk of memory leaks and need to be cleared immediately after each use.

Closure formation: There is a reference to the parent scope in the current environment.

2. How to write closures

// Form closures with self-executing functions
var add = function(){
    let sum = 0
  return function operation(){
      return sum = sum ? sum + 1 : 1
  }
}()

// output: 1
add()
// output: 2
add()
// output: 3
add()
// output: 4
add()

// Clear closures, delete private variables
add = null
// output: null
console.log(add)
// Output: add is not function
add()

3. The role of closures

The purpose of using closures - hiding variables, accessing a variable indirectly, calling a function outside the lexical scope where the function is defined.

Closures are often used in callback functions, private properties, and function currying.

4. Use closures to implement multiple image like functions

Completed with closures, multi-picture likes are liked separately, and the number of likes of each input does not interfere with each other. In this example, 5 new independent lexical scopes are declared using closures.

<!-- * @Description: Closure realizes multi-picture likes * @Author: CY small dust s * @Date: 2021-07-28 18:39:33 * @LastEditTime: 2021-11-08 17:19:37 * @LastEditors: Please set LastEditors-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Closure realizes multi-picture likes</title>
  </head>
  <style>
    ul li {      list-style: none;      float: left;      margin: 0px 20px 20px 0px;    }    ul li img {      width: 200px;      height: 200px;    }  </style>
  <body>
    <ul>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-0.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-1.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-2.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-3.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-6.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
      <li>
        <img
          class="img"
          src="https://www.keaidian.com/uploads/allimg/181206/co1Q206121F4-0-7.jpg"
          alt="Hello"
        />
        <input type="button" class="add" value="Current number of likes (1)" />
      </li>
    </ul>

    <script>
      window.onload = function () {        // get ul
        let add = document.querySelectorAll("ul li input");        // Loop out each input and add the closure
        for (let i = 0; i < add.length; i++) {          // Add a click event to each input
          add[i].onclick = (function () {            let sum = 2;            // Return the function, complete the creation of private variables, and form a closure
            return function () {              this.value = "The current number of likes (" + sum++ + ")";            };          })();        }      };    </script>
  </body>
</html>

5. Use closures to protect private properties

Create a counter function and define a private property in it, here it is protected from direct modification by a closure.

It can be seen that in this example, we do not operate privatelyCounter directly, but operate privateCounter in the counter through the method actively exposed by makeCounter.

// create a counter
const makeCounter = function(){
    // Create private variables
    var privatelyCounter = 0
    // output private variable
    function console(){
        return privatelyCounter
    }
    // Change counter method
    function change(num){
        privatelyCounter += num
    }
    // expose public methods
    return {
        CounterAdd(num){
            change(num)
        },
        CounterSub(num){
            change(num)
        },
        CounterLog(){
            return console()
        }
    }
}
// declare two counters
const counter1 = makeCounter()
const counter2 = makeCounter()
counter1.CounterAdd(1)
counter1.CounterAdd(1)
counter2.CounterSub(-1)
counter2.CounterSub(-1)
// output: 2
console.log(counter1.CounterLog())
// output: -2
console.log(counter2.CounterLog())

Reference video explanation: into learning

3. Use closures to implement function currying

The so-called function currying is to convert a multi-argument function into a single-argument function.

// normal self-increment method
function numAdd(x, y){
    return x + y
}
console.log(numAdd(1, 2))

// Currying with Closures
function numAddCurry(x){
    return function(y){
        return x + y
    }
}
// First declare a variable to get the auto-increment method
const curry = numAddCurry(1)
// When calling this variable for auto-increment, output: 3
console.log(curry(2))
// Or directly call the auto-increment method to pass in two parameters, and the output is also: 3
console.log(numAddCurry(1)(2))

Tags: Javascript

Posted by myharshdesigner on Fri, 21 Oct 2022 15:01:17 +1030