Today I would like to talk with you about my understanding of closures. Before we get to that, let’s look at the domain of variables. In JS, variable scope has global scope and local scope. The new variable declaration keyword in ES6 was introduced to solve part of the variable scope confusion. Global scope is out of the question here. Let’s talk about the scope of the function.

The scope of a function is the inside of the curly braces of a function. Let’s look at two examples to get a better understanding of this concept. You can also follow my wechat public number, Snail Quanzhan.

function f1(){  
    let n = 999;  
    console.log(n);
}
f1(); / / 999
function f2(){  
    let n = 999;
}
alert(n); / / an error
Copy the code

Before I talk about closures, I need to say a few words about the return value of a function. It was only earlier this year that I had a deeper understanding of the return value of a function. A function with no return value returns undefined, and a function with a return value returns the corresponding value. Like this

// A function with no return value
function f1(){  
    alert(Awesome!);
}
console.log(f1()); // Output undefind on the console after the popover
// Return value exists
function f2(){  
    alert(Awesome!);return 'over';
}
console.log(f2()); // After the popover appears, print over on the console. You can return a string, you can return a Bealon, you can return a function.
Copy the code

In refactoring – Improving the Design of existing Code, it is proposed that the JS syntax allows functions to be nested within a function, but not all programming languages can. The so-called code nesting is a function declaration inside a function, like this:

function outer(){  
    let name = 'lilei';
    function inner(){    
        console.log(name); }}Copy the code

In the actual project, it is necessary to access the variables inside the function outside, at this time, according to the local variable scope problem. It seems impossible, but the advent of closures solves this problem.

function outer(){  
    let name = 'lilei';
    function inner(){    
        return name;  
    }  
    return inner;
}
Copy the code

Here is a typical closure function. When using this closure function, we can do something like this:

let g = outer();
console.log(g()); // lilei
Copy the code

At this point, you have solved the problem of local variables within global access functions. But xiaobian on the way home, in order to achieve this function, is not the trouble, I through such a function, but also can meet the demand.

function outer(){  
    let name = 'lilei';  
    return name;
}
console.log(outer()); // lilei
Copy the code

It is true that the above code is the same as the final output from the console via closures, so why introduce closures? This is like variables -> function -> class, each layer is a process of gradual improvement, through the function can achieve more logic, such as data processing, only by variables can not be achieved.

Closures: What is the application of closures in real projects? 1. Hide the internal variable name and pause the function execution

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
Copy the code

2. The setTimeout function passes arguments

The default setTimeout looks like this

Xiaobian has also done this experiment

function f1(p) {    
    console.log(p);
}
setTimeout(f1(Awesome!),3000); // Output 666 directly without delay
Copy the code

This is where closure comes into play when you want to delay passing parameters to a function.

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

3, the callback

Define the behavior and then associate it with a user event (click or button). Code is typically bound to an event as a callback (the function that is called when the event fires). Like the following code

<! DOCTYPEhtml>
<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>
Copy the code

4, function shake proof

The callback is executed n seconds after the event is triggered, and if it is triggered again within n seconds, the timer is reset.

The key to the implementation is the setTimeout function. Since you still need a variable to hold timing, consider maintaining global purity, which can be achieved with closures. Like this:

/** fn [function] delay [number] delay */
function debounce(fn,delay){    
 let timer = null    // with closure
 return function() {        
     if(timer){            
         clearTimeout(timer) // Enter the branch statement, indicating that a timing process is currently underway and the same event is triggered again. So cancel the current timer and start the timer again
         timer = setTimeOut(fn,delay)         
     }else{            
         timer = setTimeOut(fn,delay) // Enter the branch to indicate that no time is currently being timed, so start a timer}}}Copy the code

This is a practical application about closures. When I can’t sleep at night, I think of the same requirement. Is it possible to use a class to achieve it? Finally, after a bit of agonizing, the answer was 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
Copy the code

Reference article: www.cnblogs.com/gg-qq/p/113… www.cnblogs.com/pikachuworl… Developer.mozilla.org/zh-CN/docs/…