柯里化
柯里化:是一种函数的转化,它是指将接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术
简单地说,就是固定一个参数,返回一个接受剩余参数的函数,实质上就是使用闭包返回一个延迟执行函数
看下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function curry(f) { return function(a) { return function(b) { return f(a,b) }; }; }
function sum(a,b) { return a+b; }
let curriedSum = curry(sum);
let res = curriedSum(1)(2);
|
curry的实现如上面代码所示,十分简单:只要有两个包装器(wrapper)
curry(func)
的结果就是一个包装器 function(a)
。
- 当它被像
curriedSum(1)
这样调用时,它的参数会被保存在词法环境中,然后返回一个新的包装器 function(b)
。
- 然后这个包装器被以
2
为参数调用,并且,它将该调用传递给原始的 sum
函数。
柯里化优点
参数复用,或者说是固定参数,避免重复传参
比如说我们用正则验证一个手机号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function curry(fn, ...args) { return (...callbackArgs) => { const currentArgs = [...args, ...callbackArgs]; return callbackArgs.length === 0 || currentArgs.length === fn.length ? fn(...currentArgs) : curry(fn, ...currentArgs); } }
const phoneReg = /^1[3-9]\d{9}$/;
function _checkPhone(reg, phone) { return reg.test(phone); }
console.log(_checkPhone(phoneReg, 19956526362));
const checkPhone = curry(_checkPhone)(phoneReg); checkPhone(19956526362); checkPhone(16956526362);
|
提前返回,或者说是提前确认,避免重复判断 和 延迟执行
再做一个拓展,我们需要对一个正确的手机号做一系列不同步的操作(同步的话就没有意义了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function doSomething1(reg, phone, callback) { reg.test(phone) && callback(); }
function doSomething2(reg, phone, callback) { reg.test(phone) && callback(); }
doSomething1(phoneReg, 19956526362,callback1); doSomething2(phoneReg, 19956526362,callback2);
function _doSomething(reg, phone, callback) { reg.test(phone) && callback(); }
const doSomething = curry(_doSomething)(19956526362); doSomething(callback1); doSomething(callback2);
|
动态创建函数
1 2 3 4 5 6 7 8 9 10 11
| const addEvent = (function () { if (window.addEventListener) { return (elem, type, fn, capture) => { elem.addEventListener(type, (e) => fn.call(elem, e), capture); }; } else { return (elem, type, fn, capture) => { elem.attachEvent('on' + type, (e) => fn.call(elem, e)); }; } })();
|
手写实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function myCurry(func, ...args) { return function() { args = [...args, ...arguments]; if (args.length < func.length) { return myCurry(func, ...args); } else { return func(...args); } }; };
function sum(a,b,c) { return a+b+c; }
let sumCurried = myCurry(sum); console.log(sumCurried(1)(2)(3));
let sumCurried = myCurry(sum); console.log(sumCurried(1,2)(3));
let sumCurried = myCurry(sum); console.log(sumCurried(1)(2,3));
|
参考
柯里化(Currying)
看完这个,你还不懂函数柯里化?