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

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

内容简介:如果两个对象之间形成了循环引用,那么这两个对象都无法被回收,但循环引用造成的内存泄露在本质上也不是闭包造成的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设计模式与开发实践》基础篇(二)——闭包和高阶函数》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

RESTful Web Services Cookbook

RESTful Web Services Cookbook

Subbu Allamaraju / Yahoo Press / 2010-3-11 / USD 39.99

While the REST design philosophy has captured the imagination of web and enterprise developers alike, using this approach to develop real web services is no picnic. This cookbook includes more than 10......一起来看看 《RESTful Web Services Cookbook》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换