函数的柯里化

看了不少大佬的文章,终于对柯里化有了初步的理解,简单总结一下。
什么是柯里化?
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
看了概念还是一头雾水,用代码解释一下。
例如有一个简单的加法运算:

function add(a,b,c){
    return a+b+c
}
add(1,2,3);   //这是接受多个参数的函数

现在把它变换成接受单一参数的柯里化函数

function add(a){
  return function(b){
    return function(c){
       return a+b+c
    }
  }
}
add(1)(2)(3);   //接受单一参数

柯里化函数结合了闭包的用法,不了解闭包的先学习闭包噢
柯里化把简单的问题复杂化了,同时把复杂的问题自由化了,来看这么一个例子:

// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4,5) = 15;

这个题目的难点在于参数的不确定,所以要封装一个函数来运算。

function add(){
	//debugger;
    var args = [].slice.call(arguments);
    var fn = function(){
        var newArgs = args.concat([].slice.call(arguments));
        return add.apply(null,newArgs);   //null表示window
    } 
    fn.toString = function(){     //toString()重写函数
        return args.reduce(function(a, b) {   
        //reduce() 方法接收一个函数作为累加器
            return a + b;
        })
    }
    return fn ;
}
 add(1)(2)(3);    //f 6
 add(1, 2, 3)(4);   //f 10
 add(1)(2)(3)(4,5) ;  //f 15
 add(1)(2)(3).toString();   //6

函数有些难理解,建议debugger在浏览器看运行步骤。

柯里化的应用场景
手机号、邮箱的验证,我们一般会写一个通用的函数,将用于验证的正则和将要被验证的字符串作为参数传入。

function check(reg,targetString){
    return reg.test(targetString);
}

这样使用会有点冗余,每次都要重复写正则表达式

check(/^1[34578]\d{9}$/, '14900000088');
check(/^1[34578]\d{9}$/, '13714357188');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]');
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]');

柯里化函数的运行过程其实是一个参数的收集过程,我们将每一次传入的参数收集起来,并在最里层处理,所以可以借助这个思路来封装一下。

function createCurry(func, args) {
    var arity = func.length;    //2      check函数形参的长度
    var args = args || [];
    return function() {
        var newArgs = [].slice.call(arguments);
        [].push.apply(newArgs, args);   //args参数push进newArgs
       // 如果参数个数小于最初的func.length,则递归调用,继续收集参数
        if (newArgs .length < arity) {
            return createCurry.call(this, func, newArgs);
        }
        // 参数收集完毕,则执行func
        return func.apply(this, newArgs );
    }
}
var checkPhone = createCurry(check)(/^1[34578]\d{9}$/);
var checkEmail =  createCurry(check)(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);

最后调用就会更加简洁了。

checkPhone('14900000088');
checkPhone('13714357188');
checkEmail('[email protected]');

参考资料:https://www.jianshu.com/p/5e1899fe7d6b

猜你喜欢

转载自blog.csdn.net/qq_37012533/article/details/84974543