preface

I believe that many front-end partners in the work and study, will more or less contact with and understand anonymous functions and closures. Be troubled by these two knowledge points, also went to the Internet to search a lot of information, check information and explanation have their own words, and even some explanation itself is incorrect, this is more headache. Today we’re going to talk about anonymous functions and closures, and how they relate to each other. Important).

What are anonymous functions

The opposite of an anonymous function is a named function, and a named function is very simple: function myFn(){}, that’s a named function and the name of that function is myFn. You can test it:

function myFn(){
}
cosnole.log(myFn.name);//myFn
Copy the code

Specifically, in the ES6 version, referential function expressions can also be considered named functions. For example, var myFn1 = function(){}, print myfn1. name, also get myFn1.

And anonymous functions, when you use an anonymous function, you’re going to execute it immediately. Often called self-executing or self-calling anonymous functions. Commonly used to build sandbox mode, the role is to open up the closed variable scope environment, in the joint work of many people, after merging JS code, there will be no conflict of the same variables. There are many ways to write an immediate anonymous function. The most common are the following:

(function(){ 
  console.log("I'm Anonymous 1."); }) ();// I am anonymous

(function(){ 
  console.log("I'm Anonymous 2"); } ());// I am anonymous

console.log((function(){}).name);/ / "name is empty
Copy the code

The difference between the two is that the initiating parentheses are outside the anonymous function parentheses, and the initiating parentheses are inside the anonymous function parentheses. Personally, I recommend the first writing method in practice. This writing method is more consistent with the call mechanism, and the parameters of the call are obvious, as follows:

(function(i,j,k){ 
  console.log(i+j+k); }) (1.3.5);
/ / 9
Copy the code

There are other ways to write self-executing anonymous functions:

-function(){ 
  console.log("I'm anonymous X."); } ();console.log(-function(){}.name);/ / - 0
+function(){ 
  console.log("I'm anonymous X."); } ();console.log(+function(){}.name);/ / 0
~function(){ 
  console.log("I'm anonymous X."); } ();console.log(~function(){}.name);/ / 1
!function(){ 
  console.log("I'm anonymous X."); } ();console.log(!function(){}.name);//true
void function(){ 
  console.log("I'm anonymous X."); } ();console.log(void function(){}.name);//undefined
Copy the code

These operators, which sometimes affect the type of results, are not recommended, but you can look them up to see the difference between them. Named functions can also be executed immediately, without too much stretching here (the main purpose of this article is to illustrate the relationship between anonymous functions and closures).

In fact, an immediate anonymous function is not a function because it has already been executed, so it is a result, except that the result can be a string, a number, or null/false/true, or an object, an array, or a function (both objects and arrays can contain functions). The result depends on what the function returns when it completes.

How are closures defined and understood

The definition of closure itself is abstract, and MDN’s official interpretation is: A closure is the combination of a function and the lexical environment within which that function was declared. A closure is a combination of a function and the lexical context in which the function is defined. Lots of places to see a way: each function is a closure in js, such understanding is also no problem, but will increase the difficulty of understanding of the closure, here don’t understand, so can according to the role of closure to make sense of it: is external to a function to carry out the function of the definition of internal method, and access the function of the definition of internal variables.

Here’s a classic example of using closures to access local variables inside a function from outside:

function box(){
  var a = 10;
  function inner(){
    return a;
  }
  return inner;
}
var outer = box();
console.log(outer());/ / 10
Copy the code

Normally, after the box executes, it is reclaimed by the recycling mechanism, including its internal defined local variables. If the inner variable is referenced by the outer variable, it will not be recycled. If the inner variable is referenced by the outer variable, it will not be recycled.

But if I look at this, I still have a face, where do I use closures? Outer = box(); outer = box();

  • The closure used in this example is actually the lexical context in which inner and inner are defined. This closure is returned and referenced by the outer, so that the inner can be executed outside the box, and the inner can read the variable A inside the box.

  • The purpose of using this closure is to access A from outside the box by executing outer().

Implement closures with anonymous functions

In the example above is a named function inside the box inner implemented using a named function closures, that how to use anonymous functions to achieve closure, is simple:

// The first step is to change the inner named function to an anonymous function and return it
function box(){
  var a = 10;
  return function(){
    console.log(a) ; }}var outer = box();
outer();/ / 10
Var outer = box(); var outer = box()
var outer = (function(){
  var a=10;
  return function(){
    console.log(a);
  }
})();
//outer as a receipt of the result of the immediate execution of the anonymous function, which is the closure, outer equals the closure.
Outer executes the closure of the return inside the anonymous function
// This closure can access the private variable A inside the anonymous function, so print 10
outer();/ / 10
Copy the code

This rewrites the closure implemented by an anonymous function. The real closure used is the inner function that is returned and the context in which the function is defined. Closures are not directly related to whether a function is anonymous. Closures can be created for both anonymous and named functions.

For loop problems and solutions

Another confusing problem we often encounter in work and school is in the for loop:

for(var i = 0; i<5; i++){ setTimeout(function(){
    console.log(i);
  },100*i);
}
Copy the code

We wanted to print out 0,1,2,3,4, and instead we print out 5 5’s, which is embarrassing. What caused the problem? This is because the setTimeout callback is not executed immediately but is timed and executed until the end of the loop (no extension to the runtime mechanism here). The point to make is that js functions only hold references to variables until they are executed, and do not actually get or save the values of variables. So by the end of the loop, the value of I is already 5, so executing the timer callback will print five 5’s.

1) How to solve this problem? The most common solution is to add an immediate anonymous function to the timer and pass the current loop’s I as an argument to the immediate anonymous function. As follows:

for(var i = 0; i<5; i++){ (function(i){
    setTimeout(function(){
      console.log(i);
    },100*i);
  })(i);
}
Copy the code

The expected result can be obtained: 0,1,2,3,4. At this time, many people think that the anonymous function that executes immediately is a closure, which is actually wrong, and then expand many cases on the wrong understanding, causing others to be confused after reading it. Attached is a screenshot of a student’s answer on Stack Overflow, which I think makes a lot of sense:

Stackoverflow.com/questions/8…

2) What is the closure of this for loop, and what does the self-executing anonymous function do? We can test the result by rewriting the anonymous function to a named function:

for(var i = 0; i<5; i++){function hasNameFn(i){
    setTimeout(function(){
      console.log(i);
    },100*i);
  };
  hasNameFn(i);
}
Copy the code

You can see that the result is the same as the result of using anonymous functions, so it is also clear that closures are not directly related to anonymous functions.

The closure of this for loop and the use of self-executing anonymous functions:

  • The for loop actually generates the closure when it executes the timer’s callbacks, which are window, similar to the global outer that references inner, and the anonymous function equivalent to the box function.

  • Each time we create a private lexical environment for the loop, we pass in the I of the current loop and store it in the lexical environment. This I is similar to the local variable a declared by var in the box function.

  • A self-executing anonymous function can retrieve the value of the current variable I because it is executed. The timer callback is therefore executed with a specified value for the I referenced.

  • Maybe we could rewrite it to make it a little bit clearer:

for(var i = 0; i<5; i++){ (function(j){
    var _i = j;
    setTimeout(function(){
      console.log(_i);
    },100*_i);
  })(i);
}
Copy the code

The rewritten anonymous function parameter is denoted by j and internally defines a local variable _i=j. When the anonymous function is executed, it passes in the I of the loop, and the _i printed in the timer is actually J. The anonymous function is executed immediately, and the value of j will also be determined. So each time the timer callback prints the same value that the anonymous function has determined.

3) Other solutions to the problem of the for loop are how to make the timer callback refer to the current I instead of the I at the end of the loop.

The simplest way is to use an ES6 let, which can create block-level scopes for variables:

for(let i = 0; i<5; i++){ setTimeout(function(){
    console.log(i);
  },100*i);
}
// Write it this way to make more sense
for(var i = 0; i<5; i++){let j = i;
  setTimeout(function(){
    console.log(j);
  },100*j);
}
Copy the code

You can also bind the current I to the timer callback (bind actually implements a Currified closure for the caller and saves the arguments passed to the caller during execution) :

for(var i = 0; i<5; i++){ setTimeout(function(i){
    console.log(i);
  }.bind(this,i),100*i);
}
Copy the code

Anonymous functions have the same effect as immediate functions, so there is no relationship between anonymous functions and closures, but many times when anonymous functions are used to solve problems, they happen to form a closure, causing many people to confuse the relationship between anonymous functions and closures.

At this point, about the relationship between anonymous functions and closures, but also about the chat, I hope to give those who are confused about anonymous functions and closures some help, at the same time, there are deficiencies in the article, also ask everyone to point out, learn and progress together!