柯里化
柯里化:是一种函数的转化,它是指将接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术
简单地说,就是固定一个参数,返回一个接受剩余参数的函数,实质上就是使用闭包返回一个延迟执行函数
看下面这个例子:
| 12
 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函数。
柯里化优点
参数复用,或者说是固定参数,避免重复传参
比如说我们用正则验证一个手机号。
| 12
 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);
 
 | 
提前返回,或者说是提前确认,避免重复判断 和 延迟执行
再做一个拓展,我们需要对一个正确的手机号做一系列不同步的操作(同步的话就没有意义了)
| 12
 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);
 
 | 
动态创建函数
| 12
 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));
 };
 }
 })();
 
 | 
手写实现
| 12
 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)
看完这个,你还不懂函数柯里化?