一、概念
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
要点:
将多参数的函数进行变换,让其变成每次只接受1个参数
返回一个新函数,此函数可以接受余下的参数,并且返回结果
柯里化是一个逐步接收参数的过程。
为啥要柯里化?
Function.protoype.bind
就是一个柯里化的实现
二、实现
形参定长:
Copy function curry(fn){
let allArgs = [];
return function next(...args){
allArgs = allArgs.concat(...args)
if(fn.length === allArgs.length){
const result = fn(...allArgs);
allArgs = []; // 结果计算完后要清空参数容器,避免柯里化后的函数再次调用后受影响
return result
}else{
return next
}
}
}
function add(a, b, c){
return a+ b+c
}
console.log(add(1,2,3))
let curryingAdd = curry(add);
console.log(curryingAdd(1,2,3));
console.log(curryingAdd(1)(2,3));
console.log(curryingAdd(1)(2)(3));
形参不定长:
(待补充,目前没有看到比较完美实现)
难点:不确定函数什么时候调用结束,所以,柯里化内部实现的时候,无法判断是直接返回结果还是继续返回函数。
一种思路是通过改写toString或valueOf,但验证并不可行。
Copy function curry(fn){
let allArgs = [];
function next(){
allArgs = allArgs.concat(...arguments)
return next
}
next.toString = next.valueOf = function(){
return fn(allArgs)
}
return next
}
三、应用
1、参数复用
常规实现:
Copy function check(reg, text) {
return reg.test(text)
}
console.log(check(/\d+/g, 'test'));
console.log(check(/[a-z]+/g, 'test'));
柯里化实现:
Copy function curryingCheck(reg) {
return function (text) {
return reg.test(text)
}
}
let check = curryingCheck(/\d+/g)
let checkLetter = curryingCheck(/[a-z]+/g)
console.log(checkNumber('test'));
console.log(checkLetter('test123'));
2、兼容逻辑提前确认
常规实现:
Copy const on = function (ele, eventName, handler) {
if (document.addEventListener) {
ele.addEventListener(eventName, handler, false);
} else {
ele.attachEvent("on" + eventName, handler);
}
};
on(document.querySelector(".demoe"), "click", () => console.log("clicked"));
柯里化实现:只需要做一次兼容判断,无需每次调用都判断
Copy const curry = function () {
if (document.addEventListener) {
return (ele, eventName, handler) => ele.addEventListener(eventName, handler, false);
} else {
return (ele, eventName, handler) => ele.attachEvent("on" + eventName, handler);
}
};
const curringOn = curry();
curringOn(document.querySelector(".demoe"), "click", () => console.log("clicked"));
3、延迟执行
Copy Function.prototype.myBind = function(context){
let _this = this;
return function(...args){
return _this.apply(context, args)
}
}
function sum(x, y, z){
return x + y + z
}
let newSum = sum.myBind(null)
console.log(newSum(1, 2, 3))
参考: