高阶函数
高阶函数是指满足下列条件之一的函数:
- 函数可以作为参数被传递
- 函数可以作为返回值输出
常见内置高阶函数
ES6新增的数组方法:map/reduce, fliter, sort排序等
高阶函数其他应用场景
- 高阶函数实现AOP
AOP面向切面编程:主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些无关模块通常包括日志统计,安全控制,异常处理等,然后再将这些支撑模块“动态织入”到另一个函数中去;java中通常是使用反射和动态代理模式来实现AOP,而js中可以很方便的利用高阶函数实现AOP编程
Function.prototype.before = function (beforeFn) { //假设调用的时候一般是fna.before(fnb);则这里的this是fna var self = this return function () { // 这里的this是装饰之后的函数调用的上下文,例子上f(3)调用时,没有显式的上下文,因此此时是window // console.log('inner:', this); // arguments即真正调用的时候传入的参数,此时beforeFn与self传入的是同一个参数,在例子中就是3 beforeFn.apply(this, arguments) 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 } } function fna (a) { console.log(1+a) } function fnb (a) { console.log(2+a) } var f = fna.before(fnb) f(3)
- 函数柯里化(currying)
函数柯里化curring又称为部分求值,一个currying的函数会先接受一些参数,接收了这些参数以后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存,待函数真正需要求值的时候,之前传入的所有参数都会被一次性的用于求值。
var currying = function (fn) { var args = [] return function () { if (arguments.length >= 1) { [].push.apply(args, arguments) // 用来存储前几次调用传入的参数 //其实这里有没有返回值不是必须的 //return arguments.callee } else { return fn.apply(this, args) } } } function cost () { var money = 0 for (var i=0; i<arguments.length; i++) { money += arguments[i] } console.log(money) return money } var cost = currying(cost) cost(200, 300) //未真正求值 cost(400) //未真正求值 cost() //进行真正求值
- 函数节流
针对一些被频繁调用的函数,如onresize, mousemove等,它们共同的特征是函数被触发的频率太高了,事实上可能并不需要以这么高的频率调用
var throttle = function (callback, interval = 1000) { let timer let firstTime = true return function () { if (firstTime) { // 第一次不延迟执行 callback.apply(this, arguments) } if (timer) { return false } timer = setTimeout(function () { // 清除定时器 clearTimeout(timer) timer = null fn.apply(this, arguments) }, interval) } }
- 分时函数
页面短时间内进行大量的DOM操作会造成页面卡主的情况,要循环在页面上新增1000个DOM节点,一种解决方案是下面的timeChunk函数,让原本1s钟创建1000个节点的操作,改为每200ms创建8个节点
var timeChunk = function (ary, fn, count) { var timer return function () { var operation = function () { for (var i = 0; i < Math.min(count || 1, ary.length); i++) { var curData = ary.shift() fn(curData) } } timer = setInterval(function () { if (ary.length <= 0) { clearInterval(timer) timer = null return } operation() }, 200) } }