Function nesting and closure in js

Keywords: Javascript Front-end Vue.js

Today, let's talk about closures I understand. Before we talk about this, let's first understand the definition domain of variables.
In js, the variable definition domain includes global scope and local scope. The new variable declaration keyword in es6 is introduced to solve the confusion of the scope of some variables. The global scope is not discussed here. Mainly about the scope of functions.
1, Scope
To put it simply, the scope of a function is inside the curly braces of a function. Look at two examples first, maybe you can understand this concept better

function f1(){
  let n = 999
  console.log(n)
}
f1() // 999

function f2(){
  let n = 999
}
alert(n); // report errors

2, Return value of function
Before I talk about closures, I have to talk about the return value of a function. On the return value of the function, Xiaobian only had a deeper understanding at the beginning of the year. A function without a return value will return undefined after execution. A function with a return value will become the corresponding return value after execution. Like this

// Function with no return value
function f1(){
  alert(666)
}
console.log(f1()) // After the pop-up window appears, output undefind on the console

// Return value exists
function f2(){
  alert(666)
  return 'over'
}
console.log(f2()) // After the pop-up window appears, output over on the console. Of course, you can return a string, you can also return a bean, and you can also return a function.

3, Function nesting
In refactoring - improving the design of existing code, it is proposed that js syntax allows functions to be nested inside functions, but not all programming languages can. The so-called code nesting means that there are function declarations inside functions, like this:

function outer(){
  let name = 'lilei'
  function inner(){
    console.log(name)
  }
}  

4, Closure
The problem of local variable scope in js has been explained earlier. In actual projects, it is necessary to access variables outside the function and inside the function. At this time, the problem of local variable scope is followed. It seems impossible that the emergence of closures solves this problem.

function outer(){
  let name = 'lilei'
  function inner(){
    return name
  }
  return inner
}

The above is a typical closure function. When using this closure function, we can:

let g = outer()
console.log(g()) // lilei

So far, the local variable in the global access function has been solved. However, Xiaobian was thinking on his way home that in order to realize this function, I can meet the needs through such a function.

function outer(){
  let name = 'lilei'
  return name
}

console.log(outer()) // lilei  

Indeed, the above code is the same as the final output on the console through closures, so why introduce closures? Xiaobian also thought about it for nearly a week to understand, which is like variable - > function - > class. Each layer is a process of gradual improvement. More logic can be realized through functions, such as data processing, which can not be realized only by variables.
5, Practical application of closure
The above small series introduces closures, so what are their applications in actual projects? First look at the following code:
1. Hide internal variable names and function execution pauses

function outer() {
    let name = 1
    function inner() {
        return name ++
    }
    return inner
}
let g = outer()
console.log(g()) // 2
console.log(g()) // 3
console.log(g()) // 4
console.log(g()) // 5

2. The setTimeout function passes parameters

The default setTimeout is like this

Xiaobian has tried this before

function f1(p) {
    console.log(p)
}
setTimeout(f1(666),3000) // No delay, direct output 666

If you want to pass parameters to the function through delay, the function of closure will appear.

function f1(a) {
    function f2() {
        console.log(a);
    }
    return f2;
}
var fun = f1(1);
setTimeout(fun,1000); // Print out 1 in a second

3. Callback
Define the behavior and then associate it with a user event (click or key). The code is usually bound to the event as a callback (the function called when the event is triggered). Like the following code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <a href="#" id="size-12">12</a>
    <a href="#" id="size-20">20</a>
    <a href="#" id="size-30">30</a>

    <script type="text/javascript">
        function changeSize(size){
            return function(){
                document.body.style.fontSize = size + 'px';
            };
        }

        var size12 = changeSize(12);
        var size14 = changeSize(20);
        var size16 = changeSize(30);

        document.getElementById('size-12').onclick = size12;
        document.getElementById('size-20').onclick = size14;
        document.getElementById('size-30').onclick = size16;
</script>
</body>
</html>

4. Function anti shake

The callback is executed n seconds after the event is triggered. If it is triggered again within this n seconds, the timing will be re timed.

The key to implementation lies in the setTimeout function. Since a variable is needed to save the timing and consider maintaining global purity, it can be implemented with the help of closed packets. As follows:

/*
* fn [function] Functions requiring anti shake
* delay [number] MS, anti shake duration value
*/
function debounce(fn,delay){
    let timer = null    //With closures
    return function() {
        if(timer){
            clearTimeout(timer) //Entering the branch statement indicates that the current timing process is in progress and the same event is triggered. So cancel the current timing and restart the timing
            timer = setTimeOut(fn,delay) 
        }else{
            timer = setTimeOut(fn,delay) // Entering this branch indicates that there is no timing at present, so start a timing
        }
    }
}

6, Use class to realize the function of hiding internal variables in similar closures
The above is a practical application of closures. When Xiaobian can't sleep at night, he thinks of the same requirements. Can he also implement them through classes? Finally, after a toss, the answer is yes, like this:

class Adder{
    constructor(c){
        this._c = c
    }
    increace(){
        this._c ++ 
    }
    decreace(){
        this._c --
    }
    get finalNum(){
        return this._c
    }
}
let c = new Adder(1)
c.increace()
console.log(c.finalNum) // 2
c.increace()
console.log(c.finalNum) // 3
c.increace()
console.log(c.finalNum) // 4
c.decreace()
console.log(c.finalNum) // 3

Reference article: https://www.cnblogs.com/gg-qq...

https://www.cnblogs.com/pikac...

https://developer.mozilla.org...
You can also scan the two-dimensional code, pay attention to my WeChat official account, snail stack.

Posted by totof06 on Wed, 10 Nov 2021 04:17:19 -0800