closure

  • Scope of a variable

    • If the variable is not preceded by the keyword var, it becomes a global variable
    • When you use the var keyword to declare a variable in a function, the variable is a local variable, which can be accessed only inside the function, not outside the function
      var func = function(){ var a = 1; alert ( a ); // Output: 1}; func(); alert ( a ); Uncaught ReferenceError: A is not definedCopy the code
  • The lifetime of a variable

    • For global variables, the lifetime of a global variable is, of course, permanent, unless we actively destroy the global variable.
    • For local variables declared in functions with the var keyword, whenExit functionWhen the function call endsThe destruction
       var func = function(){ var a = 1; // The local variable a will be destroyed after exiting the function alert (a); }; func();Copy the code
    • Closures can extend the lifetime of a variable
      var func = function(){ 
          var a = 1;
          return function(){ a++; alert ( a ); }}; var f = func(); f(); // output :2 f(); // output :3 f(); // output :4 f(); / / output: 5Copy the code
  • More on closures

    • Encapsulation variable
    var mult = (function(){ 
        var cache = {};
        var calculate = functionCalculate (){var a = 1;for(var i = 0, l = arguments.length; i < l; i++ ){
                  a = a * arguments[i];
            };
            return a; 
        }
    
       return function(){
            var args = Array.prototype.join.call( arguments, ', ' ); 
            if ( args in cache ){
                return cache[ args ]; 
            }
            returncache[ args ] = calculate.apply( null, arguments ); }}) (); Alert (mult(1,2,3)); // output :6 alert (mult(1,2,3)); / / output: 6Copy the code
    • Extends the life of local variables
  • Closures implement command mode

 <html> 
    <body>
        <button id="execute"<button id= <button id="undo"</button> <script> var Tv = {open:function(){
              console.log( 'Turn on the TV' ); 
        },
        close: function(){
              console.log( 'Turn off the TV'); }}; var createCommand =function( receiver ){ 
          var execute = function() {returnreceiver.open(); // Execute the command to turn on the TV} var undo =function() {returnreceiver.close(); // Execute the command to turn off the TV}return {
                execute: execute, 
                undo: undo
         }
    };
    var setCommand = function( command ){
          document.getElementById( 'execute' ).onclick = function(){ command.execute(); // Output: turn on the TV} document.getelementbyId ('undo' ).onclick = function(){ command.undo(); // Output: turn off the TV}};setCommand(createCommand(Tv));
      </script> 
    </body>
</html>
Copy the code
  • Closures and memory management

    • Memory leaks may occur

If a circular reference is formed between two objects, neither object can be reclaimed, but the memory leak caused by a circular reference is not caused by a closure per se

Higher-order functions

A higher-order function is one that satisfies at least one of the following conditions

  • Functions can be passed as arguments
  • The function can be output as a return value
  • Functions are passed as arguments

    • The callback function
      • An asynchronous request
      var getUserInfo = function( userId, callback ){
          $.ajax( 'http://xxx.com/getUserInfo?' + userId, function( data ){
                if ( typeof callback === 'function'){ callback( data ); }}); } getUserInfo( 13157,function( data ){ 
          alert ( data.userName );
      });
      Copy the code
      • entrust
      var appendDiv = function( callback ){ 
          for ( var i = 0; i < 100; i++ ){
                var div = document.createElement( 'div' ); div.innerHTML = i;             
                document.body.appendChild( div );
                if ( typeof callback === 'function'){ callback( div ); }}; }; appendDiv(function( node ){ 
          node.style.display = 'none';
      });
      Copy the code
  • Function is output as the return value

    • Determine the type of data
    var Type = {};
    for ( var i = 0, type; type = [ 'String'.'Array'.'Number' ][ i++ ]; ){
         (function( type ){
             Type[ 'is' + type ] = function( obj ){
                   return Object.prototype.toString.call( obj ) === '[object '+ type +'] ';
             }
         })(type)}; Type.isArray( [] ); / / output:true
    Type.isString( "str"); / / output:true
    Copy the code
    • getSingle
     var getSingle = function ( fn ) {
         var ret;
         return function () {
             return ret || ( ret = fn.apply( this, arguments ) );
         };
      };
     var getScript = getSingle(function() {return document.createElement( 'script'); }); var script1 = getScript(); var script2 = getScript(); alert ( script1 === script2 ); / / output:true
    Copy the code
  • High-order function implementation AOP (Aspect oriented Programming)

The main role of AOP(aspect oriented programming) is to extract functions that are not related to the core business logic module, such as log statistics, security control, exception handling, and so on. After these functions are extracted, they are incorporated into the business logic module through “dynamic weaving”.

Function.prototype.before = function( beforefn ){ var __self = this; // Save a reference to the original functionreturn function(){// returns a function containing the original and the new function"Agent"Function beforefn.apply(this, arguments);return__self.apply( this, arguments ); }}; Function.prototype.after =function( afterfn ){
     var __self = this;
     return functionVar ret = __self.apply(this, arguments); var ret = __self.apply(this, arguments); afterfn.apply( this, arguments );returnret; }}; var func =function(){ 
    console.log( 2 );
};
func = func.before(function(){ 
    console.log( 1 );
}).after(function(){ console.log( 3 ); }); func(); / / 1 2 3Copy the code
  • Other applications of higher order functions

    • Currying is also called partial evaluation. A function that curries will first take some arguments. After taking these arguments, the function will not immediately evaluate, but will continue to return another function, and the arguments that were passed will be stored in the closure formed by the function. When the function is actually asked for a value, all the arguments passed in before are used to evaluate it at once.
    var currying = function( fn ){ 
        var args = [];
        return function() {if ( arguments.length === 0 ){
                  return fn.apply( this, args ); 
            }else{
                  [].push.apply( args, arguments );
                  returnarguments.callee; }}}; var cost = (function(){ 
        var money = 0;
        return function() {for ( var i = 0, l = arguments.length; i < l; i++ ){
                    money += arguments[ i ]; 
              }
              returnmoney; }}) (); var cost = currying( cost ); // Convert this function to cost(100); // Cost (200) is not evaluated; // Cost (300); // not really evaluated alert (cost()); // Evaluate and print :600Copy the code
    • uncurrying
    Function.prototype.uncurrying = function() { var self = this; // self is array.prototype.pushreturn function() { var obj = Array.prototype.shift.call( arguments ); / / equivalent to the Array. The prototype. Push. Apply (obj, 2)}; }; }; var push = Array.prototype.push.uncurrying(); var obj = {"length": 1,
        "0": 1}; push( obj, 2 ); console.log( obj ); // Output :{0: 1, 1: 2, length: 2}Copy the code
    • Function throttling: Delay the execution of an upcoming function with setTimeout. If the delay is not complete, subsequent calls to the function are ignored
    var throttle = function(fn, interval) {var __self = fn, // save the function to be delayed by the reference timer, // timer firstTime =true; // is the first callreturn function () {
              var args = arguments,
              __me = this;
              if(firstTime) {// If this is the first call, there is no delay in executing __self.apply(__me, args);return firstTime = false;
              }
              if(timer) {// If the timer is still running, the previous delay has not been completedreturn false;  
              }
              timer = setTimeout(function() {// Delay executing clearTimeout(timer) for some time; timer = null; __self.apply(__me, args); }, interval || 500 ); }; }; window.onresize = throttle(function(){ console.log( 1 ); }, 500);Copy the code

Series of articles:

JavaScript Design Patterns and Development Practices