JavaScript -高阶函数

时间:2021-2-20 作者:admin

高阶函数的应用

函数作为参数传递

  • 回调函数
let getUserInfo = function ( userId, callback ) {
    $ajax('http://xxx.com/getUserInfo?id=userId', function (data){
          if(typeof callback==='function'){
            callback(data)
        }  
    })
}
  • Array.prototype.sort

    // 从小到大
    
    [1,4,3]sort( function ( a , b ) {
      return a - b;
    });
    // 输出 [1,3,4]
    
    // 从大到小
    
    [1,4,3]sort( function ( a , b ) {
      return b - a;
    });
    // 输出 [4,3,1]
    
    

    函数作为返回值输出

  • 判断数据的类型

     let Type = {};
     for (let 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([]);
     Type.isString( "S" )
    
    
  • getSingle

    // 这只是单例模式的例子
    let getSingle = function ( fn ) {
        let ret;
      return function () {
          return ret || ( ret = fn.apply( this , arguments ) )
      };
    };
    
    // 此函数既把函数当作参数传递,又让函数执行后返回了另外一个函数。下面是执行效果
    
    let getScript = getSingle(function(){
        return document.creatElement( 'script' );
    });
    let script1 = getScript();      
    let script2 = getScript();
    
    alert(script1 === script2); 
    // 输出 true
    
    

高阶函数实现AOP

AOP的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计,安全控制,异常处理等。把这些功能抽离出来后,再通过“动态织入”的方式掺入业务逻辑中。这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次是可以很方便的复用日志统计等功能模块。

在JavaScript中实现AOP,都是指把一个函数“动态织入”到另外一个函数之中,具体的技术很多。本例通过扩展Function.prototype来做到这点。

Function.prototype.before = function( beforefn ){
    var __self = this; // 保存原函数的引用
    return function(){ // 返回包含了原函数和新函数的"代理"函数
        beforefn.apply( this, arguments ); // 执行新函数,修正this
        return __self.apply( this, arguments ); // 执行原函数
    }
};

Function.prototype.after = function( afterfn ){
    var __self = this;
    return function(){
        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

高阶函数的其他应用

  • curring

curring又称 部分求值。一个curring函数首先会接受一些参数,接受参数之后并不会立即执求值,二是继续返回另外一个函数,刚才传入的参数在函数形成的 闭包中保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
例子:

// 计算每个月开销
var monthlyCost = 0;
var cost = function( money ){
    monthlyCost += money;
};

cost( 100 ); // 第1 天开销
cost( 200 ); // 第2 天开销
cost( 300 ); // 第3 天开销
//cost( 700 ); // 第30 天开销
alert ( monthlyCost ); // 输出:600

我们可以看到每天花掉的钱,但是我们的目的是到月底看到一共花了多少钱,所以只需要月底计算一次。

var cost = (function(){
    var args = [];
    return function(){
        if ( arguments.length === 0 ){
            var money = 0;
            for ( var i = 0, l = args.length; i < l; i++ ){
                money += args[ i ];
            }
            return money;
        }else{
            [].push.apply( args, arguments );
        }
    }
})();

cost( 100 ); // 未真正求值
cost( 200 ); // 未真正求值
cost( 300 ); // 未真正求值
console.log( cost() ); // 求值并输出:600

但这还不是完整的curring。接下来我们写一个通用的function curring(){},接受一个参数,即将要被curring的函数。这个例子里,这个函数的作用是遍历本月每天的开销并求出她们的总和。代码如下:

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
  • 函数节流

原理:将即将被执行的函数用setTimeout延迟执行。如果该次延迟执行还没有完成,那么则忽略接下来调用该函数的请求。throttle函数接收两个参数,第一个参数为需要被延迟执行的函数,第二个为延迟执行的时间。具体代码:

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 );
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。