js之高阶函数

概念

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

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

高阶函数的应用场景

高阶函数主要用于抽离出项目中容易变化的业务逻辑,并对这部分业务逻辑进行封装,从而分离业务代码中变化与不变化的部分。以下为高阶函数比较常见的应用场景。

回调函数

比如在ajax异步请求中,由于网络请求时间的不固定性,我们不能确定请求完成的具体时间,那么解决的办法就是传递一个处理函数作为参数到请求数据的方法中,请求完成后执行回调函数。

1
2
3
4
5
var getData = function(url, callback) {
$.get(url, function(data){
callback(data);
});
};

Array对象方法

在Array对象中,有很多方法都可以接受函数作为参数,然后对数组进行一些处理。例如map()sort()filter()等等:

1
2
3
4
5
6
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);

实现AOP

AOP(面向切面编程)原本是JAVA 的Spring框架的一个重要内容。其主要作用是把一些跟核心业务无关的功能抽离出来,再通过“动态织入”的方式掺入业务逻辑模块中。通常,在JavaScript中实现AOP,主要是通过apply()或者call()把一个函数“动态织入”到另一个函数中。

在Spring的框架中有before(前置通知,在目标函数的前面执行一些前置操作)、after(后置通知,在目标函数的后面面执行一些后置操作)、around(环绕通知)。 以下为用JavaScript实现前置通知和后置通知方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//前置通知
Function.prototype._before = function(func){
var __self = this;
return function(){
func.apply(__self, arguments);
return __self.apply(__self, arguments);
}
}

function a(){
console.log('I\'m a');
}

a = a._before(function(){
console.log('before');
});

a();
// 结果:
// before
// I'm a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//后置通知
Function.prototype._after = function(func){
var __self = this;
return function(){
var ret = __self.apply(__self, arguments);
func.apply(__self, arguments);
return ret;
}
}

function b(){
console.log('I\'m b');
}

b = b._after(function(){
console.log('after');
});

b();
// 结果:
// I'm b
// after

柯里化

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

来实现一个柯里化求和函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var currying = function(fn){
var args = [];
return function(){
if(!!arguments.length) {
[].push.apply(args, arguments);
return arguments.callee;
} else {
return fn.apply(this, args);
}
}
}
var sum = (function(num){
var ret = 0;
return function(){
for(var i = 0, len = arguments.length; i < len; i++) {
ret += arguments[i];
}
return ret;
}
})();
var newSum = currying(sum);
newSum(1)(2)(3)(4)() // 10

参考文章