Details of function nesting and closures in js

Details of function nesting and closures in js

Preface:

Today I will talk to you about my understanding of closures. Before discussing this issue, let's first understand the domain of variables.
In js, variable definition scopes include global scope and local scope. The new variable declaration keyword in es6 is introduced to solve the confusion of some variable scopes. The global scope is not discussed here. Mainly talk about the scope of the function.

1. Scope

To put it simply, the scope of a function is the space inside the curly braces of the function. Let's look at two examples first, which may help you understand this concept better.

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

function f2(){
  let n = 999
}
alert(n); // error message

2. Function return value

Before talking about closures, I have to talk about function return values. Regarding the return value of the function, the editor only had a deeper understanding at the beginning of the year. A function without a return value will return undefined after execution, and a function with a return value will become the corresponding return value after execution. Just like this

// Function without return value function f1(){
  alert(666)
}
console.log(f1()) // After the pop-up window appears, output undefined in the console

// There is a return value function f2(){
  alert(666)
  return 'over'
}
console.log(f2()) // After the pop-up window appears, output over in the console. Of course, you can return a string, a Bealon, or 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 do this. The so-called code nesting means that there is a function declaration inside a function.

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 before. In actual projects, it is necessary to access the variables inside the function from outside the function. At this time, the problem of local variable scope should be addressed. It seems impossible, but 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 do this:

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


So far, accessing local variables within global functions has been resolved. But on the way home, I was thinking, in order to realize this function, can I avoid this trouble? I can also meet the needs through such a function.

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

console.log(outer()) // lilei  


Indeed, the code above is the same as what is output to the console through closure, so why introduce closure? It took me nearly a week to figure it out. It's like variable->function->class. Each level up is a gradual improvement process. More logic can be implemented through functions, such as data processing, which cannot be achieved by variables alone.

5. Practical Application of Closures

The editor introduced closures above, so what are their applications in actual projects? Let’s look at the following code first:

1. Hide internal variable names and function execution pause

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. setTimeout function passes parameters

The default setTimeout is this:

I have also tried this before.

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

If you want to pass parameters to a function through delay, the role of closure will become apparent.

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

3. Callback

Define a behavior and associate it with a user event (click or keypress). Code is usually bound to an event as a callback (a function that is 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="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="size-12">12</a>
    <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="size-20">20</a>
    <a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" 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 n seconds, the timing is restarted.

The key to the implementation lies in the setTimeout function. Since a variable is needed to save the timing, in order to maintain global purity, it can be implemented with the help of closures. Like this:

/*
* fn [function] the function that needs anti-shake* delay [number] milliseconds, anti-shake deadline value*/
function debounce(fn,delay){
    let timer = null //With closure return function() {
        if(timer){
            clearTimeout(timer) //Entering this branch statement indicates that a timing process is currently in progress and the same event is triggered again. So to cancel the current timing and restart the timing timer = setTimeOut(fn,delay) 
        }else{
            timer = setTimeOut(fn,delay) // Entering this branch means that there is no timing currently, so start a timing}
    }
}

6. Use classes to implement functions similar to hiding internal variables in closures

The above is a practical application of closures. When I couldn’t sleep at night, I thought of the same need. Can it be implemented through classes? Finally, after a lot of trouble, the answer is yes, like this:

class Adder{
    constructor(c){
        this._c = c
    }
    increase(){
        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 articles:

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

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

https://developer.mozilla.org...

You may also be interested in:
  • Function nesting in JavaScript
  • Learn about JavaScript closure functions in one article
  • JavaScript Closures Explained
  • Javascript scope and closure details
  • JS Difficulties Synchronous and Asynchronous and Scope and Closure and Detailed Explanation of Prototype and Prototype Chain
  • Avoiding Problems Caused by Closures in JavaScript
  • Detailed explanation of JavaScript closure issues
  • Detailed explanation of JavaScript function usage [function definition, parameters, binding, scope, closure, etc.]

<<:  Teach you 10 ways to center horizontally and vertically in CSS (summary)

>>:  Navigation Design and Information Architecture

Recommend

The main idea of ​​​​dynamically setting routing permissions in Vue

I have seen some dynamic routing settings on the ...

A brief discussion on the magic of parseInt() in JavaScript

cause The reason for writing this blog is that I ...

What does mysql database do?

MySQL is a relational database management system....

Example of using nested html pages (frameset usage)

Copy code The code is as follows: <!DOCTYPE ht...

Implementation code of short video (douyin) watermark removal tool

Table of contents 1. Get the first link first 2. ...

Use native js to simulate the scrolling effect of live bullet screen

Table of contents 1. Basic principles 2. Specific...

The difference between animation and transition

The difference between CSS3 animation and JS anim...

How to use bar charts in Vue and modify the configuration yourself

1. Import echart in HTML file <!-- Import echa...

Detailed explanation of the usage of DECIMAL in MySQL data type

Detailed explanation of the usage of DECIMAL in M...

Semantic web pages XHTML semantic markup

Another important aspect of separating structure ...

Docker installs and runs the rabbitmq example code

Pull the image: [mall@VM_0_7_centos ~]$ sudo dock...

Modularity in Node.js, npm package manager explained

Table of contents The basic concept of modularity...

Solve the pitfall of storing boolean type values ​​in localstorage

LocalStorage stores Boolean values Today, when I ...