定义
维基百科中对偏函数(Partial application)的定义为
In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.
翻译成中文
在计算机科学中,局部应用是指固定一个函数的一些参数,然后产生另一个 更小元的函数。什么是元,?元是指函数参数的个数。比如 一个带有两个参数的函数被称为二元函数。
举个简单的例子
function add(a, b) {
return a + b;
}
// 执行 add 函数,一次传入两个参数即可
add(1, 2) // 3
// 假设有一个 partial 函数可以做到局部应用
var addOne = partial(add, 1);
addOne(2) // 3
个人觉得翻译成“局部应用”或许 更贴切些,以下全部使用“局部应用”
柯里化与局部应用
如果看过上一篇文中,实际上你会发现这个例子和柯里化太像了,所以两者有什么区别呢?
其实也是很明显
柯理化是将一个多参数函数转换为多个单参数函数,也就是将一个n元函数转换成一个n个一元函数。
局部应用则是固定的一个或者多个参数,也就是将一个n元函数转换为一个n-x函数
如果两者有什么关系的话,引用function-programming-jargon的描述是:
Curried functions are automatically partially applied
Partial
我们今天的目的就是模仿underscore写一个partial函数,比起curry函数,这个显然简单了很多
也许你在想我们可以直接使用bind呐,举个例子
function add(a, b) {
return a + b;
}
var addOne = add.bind(null, 1);
addOne(2) // 3
第一版
根据之前的描述,我们可以尝试着写出第一版
// 第一版
// 似曾相识的代码
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function() {
var newArgs = args.concat([].slice.call(arguments));
return fn.apply(this, newArgs);
};
};
我们可以写个demo验证一下this的孩子系那个
function add(a, b) {
return a + b + this.value;
}
// var addOne = add.bind(null, 1);
var addOne = partial(add, 1);
var value = 1;
var obj = {
value: 2,
addOne: addOne
}
obj.addOne(2); // ???
// 使用 bind 时,结果为 4
// 使用 partial 时,结果为 5
第二版
然而正如curry函数可以使用占位符一样,我们希望partial函数也可以实现这一个功能,我们再来看看第二版
// 第二版
var _ = {};
function partial(fn) {
var args = [].slice.call(arguments, 1);
return function() {
var position = 0, len = args.length;
for(var i = 0; i < len; i++) {
args[i] = args[i] === _ ? arguments[position++] : args[i]
}
while(position < arguments.length) args.push(arguments[position++]);
return fn.apply(this, args);
};
};
我们来验证一下
var subtract = function(a, b) { return b - a; };
subFrom20 = partial(subtract, _, 20);
subFrom20(5);
写在最后
值得注意的是,:underscore和lodash都提供了partial函数,但只有loash提供了curry函数