110.JavaScript高阶函数和偏函数
1.高阶函数
所谓高阶函数是指可以把函数作为参数,或者是可以将函数作为返回值的函数(我们见得闭包函数就是高阶函数)。
function foo(x){
return function(){
return x;
}
}
对于程序的编写,高阶函数比普通函数要灵活的多,除了通常意义的函数调用返回外,还形成了一种后续传递风格的结果接收方式,而非单一的返回值形式,后续传递风格的程序编写将函数的业务重点从返回值转移到了回调函数中:
function(x,bar){
return bar(x);
}
以上的代码为例,对于相同的foo()函数,传入的bar的参数不同,则可以得到不同的结果。结合Node提供的最基本的事件模块可以看到,事件的处理方式就是基于高阶函数的特性来完成的。
高阶函数在JS中的应用比比皆是,其中ECMAScript5中提供的一些数组方法就是典型的高阶函数,比如:forEach()、map()、reduce()、reduceRight()、filter()、every()、some()等。
2.偏函数
2.1定义
偏函数通过指定部分参数来产生一个新制定的函数的函数。
偏函数是指创建一个调用另一个部分——参数或变量已经预置的的函数——的函数的用法。
2.2解释
偏函数应用是一个过程,它传给某个函数其中一部分参数,然后返回一个新的函数,该函数等待接受后续参数。
偏函数应用是一个函数,它接受另一个函数为参数,这个作为参数的函数本身接受多个参数,它返回一个函数,这个函数与它的参数函数相比,接受更少的参数。
偏函数应用提前赋予一部分参数,而返回的函数则等待调用时传入剩余的参数。
偏函数应用通过闭包作用域来提前赋予参数。
2.3示例:
你可以实现一个通用的函数来赋予指定的函数部分参数,它看起来如下:
partialApply(targetFunction: Function, …fixedArgs: Any[]) =>
functionWithFewerParams(…remainingArgs: Any[])
如果你要更进一步理解上面的形式,你可以看这里。
partialApply 接受一个多参数的函数,以及一串我们想要提前赋给这个函数的参数,它返回一个新的函数,这个函数将接受剩余的参数。
下面给一个例子来说明,假设你有一个函数,求两个数的和:
const add = (a, b) => a + b;
现在你想要得到一个函数,它能够对任何传给它的参数都加 10,我们可以将它命名为 add10()。add10(5) 的结果应该是 15。我们的 partialApply() 函数可以做到这个:
const add10 = partialApply(add, 10);
add10(5);
在这个例子里,参数 10 通过闭包作用域被提前赋予 add(),从而让我们获得 add10()。
现在让我们看一下如何实现 partialApply():
// Generic Partial Application Function
// https://jsbin.com/biyupu/edit?html,js,output
// https://gist.github.com/ericelliott/f0a8fd662111ea2f569e
// partialApply(targetFunction: Function, …fixedArgs: Any[]) =>
// functionWithFewerParams(…remainingArgs: Any[])
const partialApply = (fn, …fixedArgs) => {
return function (…remainingArgs) {
return fn.apply(this, fixedArgs.concat(remainingArgs));
};
};
test(“add10”, (assert) => {
const msg = “partialApply() should partially apply functions”;
const add = (a, b) => a + b;
const add10 = partialApply(add, 10);
const actual = add10(5);
const expected = 15;
assert.equal(actual, expected, msg);
});
如你所见,它只是简单地返回一个函数,这个函数通过闭包访问了传给 partialApply() 函数的 fixedArgs 参数。
2.4 普通函数和偏函数对比
普通方法:
var toString = object.prototype.toString;
var isString = function (obj) {
return toString.call(obj) == ‘[object String]’;
};
var isFunction = function (obj) {
return toString.call(obj) == ‘[object Function]’;
};
偏函数方法:
var isType = function (type) {
return function (obj) {
return tostring.call(obj) == ‘[object ‘ + type + ‘ ]’;
}
}
上面的例子中,用偏函数方法去除了冗余代码,解决了重复定义的问题。这种通过指定部分参数来产生一个新制定的函数的形式就是偏函数。
偏函数应用在异步编程中也十分常见,著名的类库Underscore提供的after()方法既是偏函数应用,其定义如下:
_.after = function (times, func) {
if (times <= 0) return func();
return function () {
if (—times < 1) {
return func.apply(this, arguments)
};
}
}
这个函数可以根据传入的times参数和具体的方法,生成一个需要调用多次才能真正执行实际函数的函数。