js高级进阶之函数柯里化

函数柯里化是所有编程语言推崇的函数优化方式,js的函数柯里化是你写出优雅函数的基础。

概念

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
例如:我们求(a+b)*c 如果普通方法实现 f(a,b,c),用柯里化方法:f(a)(b)©这种调用格式获取。

实现原理

  • 闭包来保存参数;
  • 高阶函数实现运算;

例如最简单的例子:求 (15+3)*4的值

let calcu = (a, b, c) => (a+b)*c;
        function curry(fn, args){
            let len = fn.length;
            let _this = this;
            let _args = args || [];
            return function(){
                let args = Array.prototype.slice.apply(arguments);
                args = Array.prototype.concat.call(_args, args);
                // 当接收到的参数小于fn所需参数个数时,继续接收参数
                if(args.length < len){
                    return curry.call(_this, fn, args);
                }
                return fn.apply(this, args);
            }
        }
        let add = curry(calcu);
        console.log(add(15)(3)(5)); //72

在上面的代码中,我们使用curry函数它可以不用一次性接收三个参数,而是慢慢接收,当发现接收到的参数达到3个之后再返回结果。这就是参数复用(通过例子我们可以看到,实现这个特点主要原因是利用了闭包,将接收到的参数存于_args中,由于闭包的原因这些参数在函数执行完之后并不会被释放掉。

上面的curry方法,将每次调用fn时读入的参数用args来保存,并将本次读入的参数args与当前一共拥有的所有参数_args用concat方法连接起来,当参数个数符合fn的参数个数要求时,则调用fn。

特点

  • 参数复用: 就是利用闭包的原理,让我们前面传输过来的参数不要被释放掉。
  • 提前确认: 利用柯里化特性对某些全局方法进行改写,这样其实就是提前确定了会走哪一个方法,避免每次都进行判断。
  • 延迟运行:利用闭包将函数的定义和执行环境分开。

参数复用案例:

// 正常正则验证字符串 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(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)
    }
}

柯里化函数的最佳实现

函数柯里化是一个比较难以应用的方法,最主要是能够理解其原理使你阅读源码无障碍,下面给出一个柯里化的最佳实现方法,背过他可以救急

// 支持多参数传递
function progressCurrying(fn, args) {
    var _this = this
    var len = fn.length;
    var args = args || [];

    return function() {
        var _args = Array.prototype.slice.call(arguments);
        Array.prototype.push.apply(args, _args);

        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (_args.length < len) {
            return progressCurrying.call(_this, fn, _args);
        }

        // 参数收集完毕,则执行fn
        return fn.apply(this, _args);
    }
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值