高阶函数

2016-10-12 曹强 更多博文 » 博客 » GitHub »

javascript

原文链接 https://ronghuaxueleng.github.io/2016/10/12/JavaScript%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5-3%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。



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

  • 函数可以作为参数被传递
  • 函数可以作为返回值输出
    (js这么好的语言中的函数当然满足 ^^)_

函数作为参数传递

把函数当作参数传递,可以抽离出一部分容易变化的业务逻辑,把这部分业务逻辑放在函数中,可以分离业务代码中变与不变的部分。

  • 回调函数,ajax异步,callback

    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.user); })

高阶函数实现AOP

AOP(面向切面编程),把一些跟核心业务逻辑模块无关的功能抽离出来(通常包括日志统计,安全控制,异常处理等)

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和打印3的函数通过AOP的方式动态植入func函数,于是执行时候顺利返回1,2,3

函数节流

js函数大多是用户触发,大多不会遇到跟性能相关的问题,但是少数情况触发不被用户控制的。
例如:

  • window.onresize事件

  • mousemove事件

  • 上传进度

以上函数触发频率太高,比如我们对onresize事件绑定了打印事件,当拖动窗口时,可能会一秒打印十次,这太累了,因此要采取一点措施(聪明的机智的你一定想到了setTimeout)

主要实现原理:当即将被执行的函数用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);