Introduction to JavaScript anonymous functions and closures

  • 2020-05-27 04:15:26
  • OfStack

Anonymous functions: functions without names;
Closure: a function that accesses a variable in the scope of a function.

1 anonymous function


//  Common function 
  function box(){            //  The function name is box;
    return 'Lee';           
  }
  box();                // =>Lee;  Call a function ;
//  Anonymous functions 
  function(){              //  Anonymous functions , complains ;
    return 'Lee';
  }
//  It executes itself through an expression 
  (function(name){
    console.log(name);        // =>Lee;
  })("Lee");              // "()" Represents an execution function , And you can send arguments ;
//  Assign an anonymous function to a variable 
  var box = function(){        //  Assigns an anonymous function to a variable ;
    return 'Lee';
  };
  console.log(box());         //  The call is similar to a function call ;
//  An anonymous function inside a function 
  function box(){
    return function(name){      //  An anonymous function inside a function , Produce closures ;
      return name;
    };
  };
  console.log(box()("Lee"));      //  function box() Calling anonymous functions , And the reference ;

2 closure

Closure: a function that has access to a variable in another function scope;
A common way to create closures is to create another function inside a function. Access the local variable of this function through another function;


//  Local variables can be returned through closures 
  function box(){
    var user = 'Lee';
    return function(){        //  Returns via anonymous functions box() Local variable of user;
      return user;
    };
  }
  console.log(box()());        // =>Lee;  Direct call box()() To get the return value of the anonymous function ;

  var b = box();
  console.log(b());          // =>Lee;  On the other 1 A way to call anonymous functions ;

//  advantages : You can keep local variables in memory , You can avoid using global variables ; 
// ( Global variable pollution results in unpredictability of the application , Every module that can be called is a recipe for disaster ; So private is recommended , Encapsulated local variables );

//  disadvantages :
//  It's accumulated by global variables 
  var age = 100;            //  The global variable ;
  function box(){
    age++;              //  Global variables can be invoked at the module level , Then sum ;
  };
  box();                //  Executive function , cumulative 1 time ;
  console.log(age);           // =>101;  Output global variable ;
  box();                //  Executive function , cumulative 1 time ;
  console.log(age);           // =>102;  Output global variable ;
//  Accumulation cannot be achieved through local variables 
  function box(){
    var age = 100;
    age++;              //  Implementation accumulative ;
    return age;
  }
  console.log(box());          // =>101;
  console.log(box());          // =>101;  Can't add up , Because the first 2 The next time the function is called , Internal function variable age It's initialized again ;

//  Local variables can be accumulated by means of closures 
  function box(){
    var age = 100;
    return function(){        //  Anonymous function inside the implementation of accumulation ;
      age++;
      return age;          //  And return the accumulated variable ; 
    };                //  At this time box() A local variable of a function age Has been modified to the cumulative value ;
  }
  var b = box();            //  to box() A function is assigned to a variable ;
  console.log(b());           // =>101;  Calling anonymous functions , cumulative 1 time ;
  console.log(b());           // =>102;  The first 2 The anonymous function is called again , Accumulative twice ;

// PS: Local variable resources returned by scope in closures are not immediately destroyed and recycled , So it might take up more memory ; So overuse of closures can lead to performance degradation ;( The closure is referred to in the " Private scope " In can realize the variable destruction )
//  The scoping chain mechanism causes 1 A question , Any variable obtained by an anonymous function in a loop is the last 1 A value ; ?

//  The loop contains anonymous functions 
  function box(){
    var arr = [];
    for(var i=0; i<5; i++){     //  When variables are declared i=5 when , Cycle to stop ; And the variables in the loop i==5; 
      arr[i] = function(){    // arr[i] You get only anonymous functions that are not executed function(){};
        return i;        
      };
    };
    return arr;           // arr = [function,function,function,function,function];
  }
  var b = box();           // =>[function,function,function,function,function];  Get function box() Returned array arr;
  console.log(b.length);       // =>5;  You get the length of the array of functions ;
  for(var i=0; i<b.length; i++){
    console.log(box()[i]());    // =>5,5,5,5,5;  Output the value of each function , Is the last 1 A value ;
  }
  //  The output of the above example is 5, That's the maximum you get after you loop i value ;
  //  because b[i] An anonymous function is called , Anonymous functions are not self-executing , Wait until it's called ,box() Completed execution ,i Has become 5;

//  The loop contains anonymous functions - change 1, Self-executing anonymous functions 
  function box(){
    var arr = [];
    for(var i=0; i<5; i++){
      arr[i] = (function(num){  // arr[i] Get the result value after the anonymous function is executed 0-4;
        return num; 
      })(i);           //  Self-executing and referrals ;
    }
    return arr; 
  }
  var b = box();           // =>[0,1,2,3,4];  At this time b On behalf of box() Returned array ;
  for (var i = 0; i < b.length; i++) {
    console.log(b[i]);       // 0 1 2 3 4;  This is a number ;
  };
  //  In the example , We let anonymous functions execute themselves , Result in the final return to a[i] It's an array instead of a function ; Eventually lead to b[0]-b[4] Retained in the 0,1,2,3,4 The value of the ;

//  The loop contains anonymous functions - change 2, Let's do another anonymous function inside the anonymous function ;
  function box(){
    var arr = []; 
    for(var i=0; i<5; i++){
      arr[i] = (function(num){
        return function(){   //  Returns the function ;
          return num;      
        }
      })(i);
    }
    return arr;           // arr = [function,function,function,function,function];
  }
  var b = box();
  for (var i = 0; i < b.length; i++) {
    console.log(b[i]());      // 0,1,2,3,4; 
  };

//  change 1 And change 2 In the , We execute ourselves through anonymous functions , Assign the result to immediately arr[i];
//  every 1 a i, Is passed by the caller by value , So everything you end up returning is incrementally specified i; Rather than box() Variables in a function i;

3 this object


//  Used in closures this The object may cause 1 Some problems ;this Objects are bound at runtime based on the execution environment of the function ;
//  if this Globally it's pointing window, If you're inside an object, you're pointing to that object ;
//  Closures, on the other hand, point at runtime window the , Because closures do not belong to the properties or methods of this object ; 
  var user = 'Window';
  var obj = {
    user:'Object',
    getUserFunction:function(){
      return function(){            //  Closures do not belong obj, The inside of the this Point to the window;
        return this.user;
      };
    }
  };
  console.log(obj.getUserFunction()());      // =>Window;

  //  You can force an object to point to 
  console.log(obj.getUserFunction().call(obj));  // =>Object;

  //  You can also go from the top 1 Get object in scope 
  getUserFunction:function(){
    var that = this;               //  From the method of the object this; At this time that Point to the obj object ;
    return function(){
      return that.user;
    }
  }
  console.log(obj.getUserFunction()());      // =>Object;

4 memory leak


//  Due to the IE the JScript The objects and DOM Objects use different garbage collection methods , So the closure is in IE Can lead to memory leak problems , That is, you cannot destroy elements that reside in memory ;
  function box(){
    var oDiv = document.getElementById('oDiv'); // oDiv After finished 1 It resides directly in memory ;
    oDiv.onclick = function(){
      alert(oDiv.innerHTML);          //  Here with oDiv Cause memory leaks ;
    };
    oDiv = null;                 //  Remove references ;
  }
  box();
  //  The anonymous function is saved 1 A for box() A reference to an active object , So you can't reduce it oDiv The reference number ;
  //  As long as the anonymous function exists ,oDiv At least the number of references 1; So the memory it consumes will never be recycled ;
  // PS: If no dereferencing is used , Wait until the browser closes to release it ;

5 mimic block-level scope (define and immediately call an anonymous function)


// JS There is no concept of block-level scopes ;
//  This means in block statements (for statements /if statements ) The variables defined in , It is actually created in the include function rather than in the statement ;
  function box(count){
    for(var i=0; i<count; i++){}        // box(2); => count=2; i=2 Time loop stop , At this time i=2;
    console.log(i);               // =>2; i Not because I left for Block is the failure ;
  }
  box(2);

  function box(count){
    for(var i=0; i<count; i++){}
    var i;                   //  Even if you redeclare , It also doesn't override the previous values ;
    console.log(i);
  }
  box(2);
//  in JavaScript In the , variable i Is defined in the box() Of the active object , So let's start with it being defined , You can access it anywhere inside the function ;
//  These two examples , instructions JavaScript There is no scope for block-level statements ,if(){}/for(){} Wait is not scoped ;
//  If there is scope , Out of this range i They should be destroyed ;

// JavaScript Does not remind whether or not multiple declarations are made 1 A variable ; In this situation , It will simply ignore subsequent statements ( If it's initialized and assigned , It will still be implemented );

//  Model block-level scopes ( Private scope )
  (function(){
    //  Here is the block-level scope ;
  })();
  //  The above code is defined and called immediately 1 Three anonymous functions ; Include the function declaration in 1 Put the parentheses in , Which means that it actually is 1 Function expression ;

//  Use block-level scopes ( Private scope ) rewrite 
  function box(count){
    (function(){
      for(var i=0; i<count; i++){}
    })();
    console.log(i);                //  An error , Don't have access to ; variable i In a private scope , Out of the private scope is destroyed .
  }
  box(2);
//  After using block-level scopes , Any variable defined in an anonymous function , Will be destroyed at the end of the execution ;(i Can only be used in loops , It is destroyed after use );
//  Private scopes have access to variables count, Because the anonymous function is 1 A closure , He has access to all variables in the containing scope ;
//  This technique is often used outside of functions in the global scope , This limits the number of variables and functions that can be added to the global scope ;
// 1 Generally speaking , We should all add as few variables and functions to the global scope as possible ; Too many global variables and functions can easily lead to naming conflicts ;
//  Use block-level scopes , Each developer can use their own variables , You don't have to worry about messing up the global scope ;
  (function(){
    var box = [1,2,3,4];
    console.log(box);              // =>[1,2,3,4]; box Come out and be unrecognized ;
  })();                      //  Destroys variables in anonymous functions ;
  console.log(box);                // =>box is not defined;
  //  Using block-level scopes in global scopes can reduce the memory footprint of closures ; Because there is no reference to an anonymous function 
  //  Once the function is done , You can immediately destroy its scope chain ;

6 private variables


// JavaScript No notion of private properties ; All properties are common ;
//  But there are 1 The concept of private variables : A variable defined in any function , You can think of it as a private variable , Because you can't access these variables outside of the function ;
//  Private variables include the parameters of a function / Local variables and other functions defined within functions ;
  function box(){
    var age = 100;                 //  Private variables , Externally inaccessible ;
  }

//  It's created internally 1 A closure , Then the closure can access these variables through its own scope chain ;
//  And the use of this 1 point , You can create public methods to access private variables ; Privilege method ;
  function Box(){                  //  The constructor ;
    var age = 100;                 //  Private variables ;
    function run(){                //  Private functions ;
      return ' In the operation of the ...';
    };
    this.get = function(){             //  Public privileged methods ;
      return age+run();             //  Assign the closure to a variable ;
    };
  }
  var box = new Box();
  console.log(box.get());

//  You can access private variables through constructor arguments 
  function Person(name){
    var user = name;              //  This sentence can be omitted ;
    this.getUser = function(){
      return user;
    };
    this.setUser = function(name){
      user = name;
    }
  }
  var p = new Person('Lee');
  console.log(p.getUser());            // =>Lee;
  console.log(p.setUser('Jack'));
  console.log(p.getUser());            // =>Jack;
  //  but , The disadvantage of the constructor pattern is that the same is created for each instance 1 Set of new methods ; Using static private variables to implement privileged methods can avoid this problem ;

7 static private variables


//  Through block-level scopes ( Private scope ) Defines a private variable or function in , You can also create privileged methods that are publicly available ;
  (function(){                  //  Create a private scope ;
    var age = 100;               //  Static private variable ;
    function run(){
      return ' In the operation of the ...';
    };
    Box = function(){};             //  Use functional expressions to define constructors ;
    Box.prototype.go = function(){       //  public ( privilege ) methods ; Defined on a prototype ;
      return age+run();
    };
  })();
  var box = new Box();
  console.log(box.go());             // 100 In the operation of the ...;
//  The object declaration above , USES a Box = function(){} Rather than functiong Box(){}; And in the declaration Box When not in use var The keyword 
//  Lead to : Initializes an undeclared variable , Always create 1 Global variables ; so ,Box became 1 Global variables , Can be accessed outside the private scope ;
//  Because if you define a constructor with a function declaration , So it becomes a private function , Could not be accessed globally , So you use a functional definition of the constructor ;
  (function(){
    var user = "";
    Person = function(value){          //  Defined here Person It's a global variable ;
      user = value;              //  The constructor here has access to private variables name;
    };
    Person.prototype.getUser = function(){
      return user;
    };
    Person.prototype.setUser = function(value){
      user = value;
    }
  })();
  var person = new Person();
  person.setUser('Lee');
  console.log(person.getUser());          // =>Lee;
//  Using the prototype Causes methods to be Shared , while user It becomes a static property ;
//  So static properties : Properties that are Shared among different objects ;?

8 module mode


//  In a nutshell , If you have to create 1 Object and initialize it with some data , And also to be public 1 Methods that can access this private data , Then you can use the module pattern ;
//  Previously, we used constructors to create private variables and privileged methods ;
//  Object literals are then created in module mode ;
  var box = {                   //  Literal object , It's also a singleton : only 1 Object of two instances ;
    age:100,                   //  This is a public property , It's going to be private ;
    run:function(){
      return ' In the operation of the ...';
    };
  };

//  Module patterns privatize variables and functions :
  var box = function(){
    var age = 100;
    function run(){
      return ' In the operation of the ...';
    }
    return {                   //  will 1 Two literal objects are returned as the value of a function ;
      go:function(){              //  The returned object literal contains only the properties and methods that can be exposed ;
        return age+run();          //  Because this object is defined inside an anonymous function , So its public methods have access to private variables and functions ;
      }                  
    };                      //  essentially , This object literal defines the singleton's public interface ;
  }();
//  This pattern requires some initialization of the singleton , This is useful when you need to maintain its private variables at the same time ; 

//  The example above returns the object directly , Or you could write it this way :
  var box = function(){
    var age = 100;
    function run(){
      return ' In the operation of the ...';
    }
    var obj = {                  //  Create literal objects ;
      go:function(){
        return age+run();
      }
    };
    return obj;                  //  Returns the object you just created ;
  }();

//  Object declarations for literals , You can think of it in design patterns 1 Kind of singleton pattern ;
//  The singleton pattern , It is the only thing that keeps the object forever 1 An instance ;

//  Enhanced module pattern : Suitable for returning custom objects , That's the constructor ;
  function Desk(){};
  var box = function(){
    var age = 100;
    function run(){
      return ' In the operation of the ...';
    };
    var desk = new Desk();
    desk.go = function(){
      return age+run();
    };
    return desk;
  }();
  console.log(box.go());              // =>100 In the operation of the ;

9 subtotal

In JavaScript programming, functional expressions are a very useful technique; Dynamic programming can be realized by using function expressions without naming functions.

1. Function expression

Function expressions are different from function declarations; Function declarations require names, but function expressions do not;
Function expressions without names are called anonymous functions; 2. The closure
A closure is created when other functions are defined inside the function. The principle is as follows:
In the background execution environment, the scope chain of the closure contains its own scope, the scope of the containing function, and the global scope.
Typically, the scope of a function and all its variables are destroyed after the function is executed.
However, when the function returns a closure, the scope of the function is kept in memory until the closure does not exist. 3. Block-level scopes
You can use closures to mimic block-level scopes in JavaScript (JavaScript itself has no notion of block-level scopes). The main points are as follows:
Create and immediately call a function so that you can execute the code without leaving a reference to the function in memory.
The result is that all variables inside the function are destroyed immediately -- unless some variable is assigned to a variable that contains a scope (that is, an external scope). 4. Private variables
Closures can also be used to create private variables in objects, as follows:
Even though there is no real concept of private object properties in JavaScript, you can use closures to implement public methods that access variables that contain scope definitions.
You can use the constructor pattern, the prototype pattern to implement the privilege method of the custom type, or you can use the module pattern to implement the privilege method of the singleton.


Related articles: