《JavaScript设计模式与开发实践》基础篇(二)——闭包和高阶函数

栏目: JavaScript · 发布时间: 5年前

内容简介:如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些 跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后, 再通过“动态织入”的方式掺入业务逻辑模块中。
  • 变量的作用域

    • 如果该变量前面没有带上关键字 var,这个变量就会成为全局变量
    • 用 var 关键字在函数中声明变量,这时候的变量即是局部变量,只有在该函数内部才能访问到这个变量,在函数外面是访问不到的
      var func = function(){ 
          var a = 1;
          alert ( a ); // 输出: 1 
      };
      func();
      alert ( a ); // 输出:Uncaught ReferenceError: a is not defined
      复制代码
  • 变量的生存周期

    • 对于全局变量来说,全局变量的生存周期当然是永久的,除非我们主动销毁这个全局变量。
    • 而对于在函数内用 var 关键字声明的局部变量来说,当 退出函数 时,它们都会随着函数调用的结束而被 销毁
      var func = function(){
           var a = 1; // 退出函数后局部变量 a 将被销毁 
           alert ( a );
       }; 
       func();
      复制代码
    • 闭包可以延续变量的生存周期
      var func = function(){ 
          var a = 1;
          return function(){ 
              a++;
              alert ( a );
          } 
      };
      var f =  f(); 
      f();  // 输出:2
      f();  // 输出:3
      f();  // 输出:4
      f();  // 输出:5
      复制代码
  • 闭包的更多作用

    • 封装变量
    var mult = (function(){ 
        var cache = {};
        var calculate = function(){ // 封闭 calculate 函数
            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 ]; 
            }
            return cache[ args ] = calculate.apply( null, arguments );
        }
    })();
    alert ( mult( 1,2,3 ) ); // 输出:6 
    alert ( mult( 1,2,3 ) ); // 输出:6 
    复制代码
    • 延续局部变量的寿命
  • 闭包实现命令模式

<html> 
    <body>
        <button id="execute">点击我执行命令</button>
        <button id="undo">点击我执行命令</button> 
   <script>
    var Tv = {
        open: function(){
              console.log( '打开电视机' ); 
        },
        close: function(){
              console.log( '关上电视机' );
        } 
    };
    var createCommand = function( receiver ){ 
          var execute = function(){
               return receiver.open();// 执行命令,打开电视机
          }
          var undo = function(){ 
                return receiver.close();// 执行命令,关闭电视机
          }
          return {
                execute: execute, 
                undo: undo
         }
    };
    var setCommand = function( command ){
          document.getElementById( 'execute' ).onclick = function(){
                  command.execute(); // 输出:打开电视机 
          }
          document.getElementById( 'undo' ).onclick = function(){ 
                  command.undo(); // 输出:关闭电视机
          } 
    };
    setCommand(createCommand(Tv));
      </script> 
    </body>
</html>
复制代码
  • 闭包与内存管理

    • 可能会引起内存泄漏

如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的

高阶函数

高阶函数是指至少满足下列条件之一的函数

  • 函数可以作为参数被传递
  • 函数可以作为返回值输出
  • 函数作为参数传递

    • 回调函数
      • 异步请求
      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 );
      });
      复制代码
      • 委托
      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';
      });
      复制代码
  • 函数作为返回值输出

    • 判断数据的类型
    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( [] );     // 输出:true
    Type.isString( "str" );    // 输出:true
    复制代码
    • 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 );  // 输出:true
    复制代码
  • 高阶函数实现AOP (面向切面编程 )

AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些 跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后, 再通过“动态织入”的方式掺入业务逻辑模块中。

Function.prototype.before = function( beforefn ){
    var __self = this; // 保存原函数的引用
    return function(){ // 返回包含了原函数和新函数的"代理"函数
         beforefn.apply( this, arguments ); 
         return __self.apply( this, arguments );
    }
};
Function.prototype.after = function( afterfn ){
     var __self = this;
     return function(){
         // 执行新函数,修正 this // 执行原函数
          var ret = __self.apply( this, arguments );        
          afterfn.apply( this, arguments );
          return ret;  
     } 
};
var func = function(){ 
    console.log( 2 );
};
func = func.before(function(){ 
    console.log( 1 );
}).after(function(){ 
      console.log( 3 );
});
func();    //  1  2  3
复制代码
  • 高阶函数的其他应用

    • currying 又称部分求值。一个 currying 的函数首先会接受一些参数,接受了这些参数之后, 该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保 存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
    var currying = function( fn ){ 
        var args = [];
        return function(){
            if ( arguments.length === 0 ){
                  return fn.apply( this, args ); 
            }else{
                  [].push.apply( args, arguments );
                  return arguments.callee; 
            }
        } 
    };
    var cost = (function(){ 
        var money = 0;
        return function(){
              for ( var i = 0, l = arguments.length; i < l; i++ ){
                    money += arguments[ i ]; 
              }
              return money; 
        }
    })();
    var cost = currying( cost );  // 转化成 currying 函数
    cost( 100 ); // 未真正求值
    cost( 200 ); // 未真正求值
    cost( 300 );// 未真正求值 
    alert ( cost() ); // 求值并输出:600
    复制代码
    • uncurrying
    Function.prototype.uncurrying = function () {  
        var self = this; // self 此时是 Array.prototype.push
        return function() {
            var obj = Array.prototype.shift.call( arguments );// 相当于 Array.prototype.push.apply( obj, 2 ) };
        };
    };
    var push = Array.prototype.push.uncurrying(); 
    var obj = {
        "length": 1,
        "0": 1 
    };
    push( obj, 2 ); 
    console.log( obj );// 输出:{0: 1, 1: 2, length: 2}
    复制代码
    • 函数节流:将即将被执行的函数用 setTimeout 延迟一段时间执行。如果该次延迟执行还没有完成,则忽略接下来调用该函数的请求
    var throttle = function ( fn, interval ) {
        var __self = fn, // 保存需要被延迟执行的函数引用 timer, // 定时器
        firstTime = true; // 是否是第一次调用
        return function () {
              var args = arguments,
              __me = this;
              if ( firstTime ) { // 如果是第一次调用,不需延迟执行 
                  __self.apply(__me, args);
                  return firstTime = false;
              }
              if ( timer ) { // 如果定时器还在,说明前一次延迟执行还没有完成 
                  return false;  
              }
              timer = setTimeout(function () { // 延迟一段时间执行           
                   clearTimeout(timer);
                   timer = null;
                   __self.apply(__me, args);
              }, interval || 500 ); 
        };
    };
    window.onresize = throttle(function(){ 
        console.log( 1 );
    }, 500 );
    复制代码

以上所述就是小编给大家介绍的《《JavaScript设计模式与开发实践》基础篇(二)——闭包和高阶函数》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深度学习

深度学习

[美] 伊恩·古德费洛、[加] 约书亚·本吉奥、[加] 亚伦·库维尔 / 赵申剑、黎彧君、符天凡、李凯 / 人民邮电出版社 / 2017-7-1 / 168

《深度学习》由全球知名的三位专家Ian Goodfellow、Yoshua Bengio 和Aaron Courville撰写,是深度学习领域奠基性的经典教材。全书的内容包括3个部分:第1部分介绍基本的数学工具和机器学习的概念,它们是深度学习的预备知识;第2部分系统深入地讲解现今已成熟的深度学习方法和技术;第3部分讨论某些具有前瞻性的方向和想法,它们被公认为是深度学习未来的研究重点。 《深度......一起来看看 《深度学习》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具