函数式编程:柯里化(Currying)
在一个函数中首先填充几个参数(然后再返回一个新函数)的技术称为柯里化(Currying)
定义
维基百科中对柯里化 (Currying) 的定义为:
In mathematics and computer science,
currying is the technique of translating the evaluation of a function
that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions,
each with a single argument.
白话:
将接受 n 个参数的 1 个函数改为只接受一个参数的 n 个互相嵌套的函数,这么说是不是有点拗口,说白了就是本来三个参数,改为嵌套三层,每次只传一个参数。
柯里化本质上是 降低通用性,提高适用性。
特点
- 在一个函数中首先填充几个参数(然后再返回一个新函数)的技术称为柯里化(Currying)。
- 柯里化又称部分求值,字面意思就是不会立刻求值,而是到了需要的时候再去求值。
- 其含义是给函数分步传递参数,每次传递参数后部分应用参数,
- 并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。
精典示例
// 实现这样的一个加法
add(2)(1, 3, 4)(2, 3)(3)(4, 6)(7, 98)() // 133
我的实现
其实以下这个
curry
的实现并不严谨,因为这个函数可以接受多个参数 (偏函数更为合适)
function sum() {
var args = [].slice.call(arguments);
return args.reduce((a, b) => a + b);
}
function curry(theFunction) {
var finalArgs = [];
var curried = function () {
var args = [].slice.call(arguments);
if (args.length > 0) {
finalArgs = finalArgs.concat(args);
return curried;
} else {
return theFunction.apply(null, finalArgs);
}
};
return curried;
}
const sumFinal = curry(sum);
用currying 的好处
- 复用参数
- 提前确认(这个有在实际中使用过): 性能
- 提前绑定好
context
,延时执行(Function.bind, nx.stubTrue, nx.stubFalse)
// 正常正则验证字符串 reg.test(txt)
// 函数封装后
function check(reg, txt) {
return reg.test(txt);
}
check(/\d+/g, "test"); //false
check(/[a-z]+/g, "test"); //true
// Currying后
function curryingCheck(reg) {
return function (txt) {
return reg.test(txt);
};
}
var hasNumber = curryingCheck(/\d+/g);
var hasLetter = curryingCheck(/[a-z]+/g);
hasNumber("test1"); // true
hasNumber("testtest"); // false
hasLetter("21212"); // false
var on = function (element, event, handler) {
if (document.addEventListener) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
} else {
if (element && event && handler) {
element.attachEvent("on" + event, handler);
}
}
};
var on = (function () {
if (document.addEventListener) {
return function (element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
};
} else {
return function (element, event, handler) {
if (element && event && handler) {
element.attachEvent("on" + event, handler);
}
};
}
})();
//换一种写法可能比较好理解一点,上面就是把isSupport这个参数给先确定下来了
var on = function (isSupport, element, event, handler) {
isSupport = isSupport || document.addEventListener;
if (isSupport) {
return element.addEventListener(event, handler, false);
} else {
return element.attachEvent("on" + event, handler);
}
};
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}