[JavaScript] detailed explanation of the relationship between closures and anonymous functions

preface

This article is about the relationship between JavaScript closures and anonymous functions, from the concept of anonymous functions to immediate execution functions, and finally to closures. Let's take a look at the article analysis. I hope you will like it.

In the previous article on adding setTimeout output to the for loop, we used a closure, but it can also be said to be an anonymous function. Is there a relationship between anonymous functions and closures?
[the answer is that there is no relationship between them]

Anonymous function

Anonymous function, as the name suggests, is a function without a name. The corresponding function is a named function, also known as a named function.

//Anonymous function
function (){
    console.log('Anonymous function');
}
//named function 
function myFn(){
    console.log('named function ');
}
//The variable a is the name of the anonymous function
var a = function(){
    console.log('a Is the name of the anonymous function');
}

If we directly run the anonymous function in the console, we will find an error and cannot execute it. Anonymous functions cannot be executed. Generally, anonymous functions are executed immediately when they are used. They are also called self executing anonymous functions or self calling anonymous functions. Generally, they are called immediate execution functions.

Execute function now

Common immediate execution functions are as follows:

;(function(){
    console.log('caibaojian.com');
})()

;(function(){
    console.log('caibaojian.com');
}());

The above two methods are typical writing methods of immediate execution functions. The difference between them is that one execution is outside the brackets of anonymous functions and the other execution initiated brackets are inside anonymous functions. The first method is more common. The parentheses are outside the parentheses of anonymous functions. See the figure below:

Step decomposition:

  1. First declare an anonymous function(){alert('I am an anonymous function ')}.
  2. The anonymous function is then called with a pair of parentheses () after the anonymous function.

Then why wrap it in parentheses? In fact, it is to be compatible with JS syntax. If we don't add parentheses, we can write it directly

function (){alert('I'm an anonymous function')}()

The browser will report syntax errors. If you want to pass the syntax check of the browser, you must add some small things, such as the following. See more: Drill down javascript: function expressions called immediately

(function(){alert('I'm an anonymous function')} ()) // Wrap the entire expression in parentheses
(function(){alert('I'm an anonymous function')}) () //Wrap the function in parentheses
!function(){alert('I'm an anonymous function')}() // On the contrary, we don't care what the value is, we just want to pass the syntax check.
+function(){alert('I'm an anonymous function')}()
-function(){alert('I'm an anonymous function')}()
~function(){alert('I'm an anonymous function')}()
void function(){alert('I'm an anonymous function')}()
new function(){alert('I'm an anonymous function')}()

In fact, the immediate execution function has only one function: to create an independent scope, which can not be accessed outside, so as to avoid variable pollution.
For example, in our previous article, we talked about a topic in the third parameter of setTimeout.

for (var i = 0; i < 6; i++) {
    setTimeout(function () {
        console.log(i); //Why does it always output 6 instead of 0,1,2,3,4,5
    }, i * 1000);
}

We found that the above timer always outputs 6, because the execution function in setTimeout is asynchronous. During execution, the value of i runs through the whole scope, rather than assigning an i to each timer alone. After running, the value of for is 6, and the output is always 6. How to solve it? Create an independent scope for each timer with the immediate execution function.

for (var i = 0; i < 6; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j);
        }, j * 1000);
    })(i);
}

When the for loop executes, the immediate execution of the function has the result. The j value in each immediate execution function is an independent one and will not be affected later. Therefore, the timer will be executed 5 times respectively.

//First immediate execution function
(function(0){
    setTimeout(function(){
        console.log(0);
    })
})(0);
//The second immediate execution function
(function(1){
    setTimeout(function(){
        console.log(1);
    })
})(1);
//......
//Sixth immediate execution function
(function(5){
    setTimeout(function(){
        console.log(5);
    })
})(5);

The value of i changes from 0 to 5, corresponding to 6 immediate execution functions. j "in these 6 immediate execution functions are 0, 1, 2, 3, 4 and 5 respectively. i believe you have a clear understanding of the two concepts of anonymous functions and immediate execution functions. Does closure have anything to do with anonymous functions?

closure

js closures refer to functions that have access to variables in the scope of another function. Personally, I think the greatest use of js closures is to prevent pollution to the global scope. The most magical thing about closures is that they can access local variables in functions outside a function. Putting these variables in functions in the form of closures can avoid pollution.
More about: On closures in JavaScript
We can isolate the first immediate execution function above

function box(i) {
    setTimeout(function () {
        console.log(i);
    }, i * 1000);
}
box(1);

//Or so
function box(i) {
    function inner() {
        console.log(i);
    }
    return inner;
}
var outer = box(1);
outer();

conclusion

Obviously, this is a closure. Then we look at our first anonymous function code and immediate execution function code. We can see that there is no relationship between anonymous function and closure. Closures can be used in both anonymous and named functions.

How to understand the closure in the for loop and the role of self executing anonymous functions: the closure generated by the for loop is actually the callback function of the timer. The execution environment of these callback functions is window, similar to the execution environment of the global outer referencing inner in the example just now, and the anonymous function is equivalent to the box function in the example just now. A question on the Stackoverflow website is similar to what we analyzed today. One answer is good.

The closure mechanism applies to all JavaScript functions, whether anonymous or not. I think the confusion between these two concepts comes from the use of the term "closure", in which the author has said "the following code creates a closure", and then gives an example of exactly using anonymous functions. In this case, closure mechanism is usually an important factor to make a specific code segment work as expected, and using anonymous functions instead of named functions is just a convenient way to encode it. People who read these examples and see "closure" for the first time then misunderstand the term and continue to use it incorrectly in their own Stack Overflow or blog posts, so confusion spreads.

At first, I thought that the anonymous function has something to do with closures. That's because the timer happens to use closures and anonymous functions, which makes us mistakenly think that there is a relationship between the two. In fact, there are many ways to solve this problem, such as what we said before The third parameter of setTimeout , you can also get the same effect as using the immediate execution function. Therefore, there is no relationship between anonymous functions and closures, but a closure happens to be formed when anonymous functions are used to solve problems, which leads to many people's confusion about the relationship between anonymous functions and closures.

Keywords: Javascript

Added by pthurmond on Mon, 04 Oct 2021 01:46:23 +0300