函数柯里化的使用

180 阅读2分钟

函数柯里化

函数柯里化的定义

把一个接受多个参数的函数转化成一个接收单个参数的函数,并且返回一个接收剩余参数而且返回结果的新函数

举例说明:

    function sum (a + b) {
        return a + b
    }

    // 将sum函数柯里化
    function curryingSum (a) {
        return function (b) {
            return a + b    
        }
    }

    const s = curryingSum(1)
    s(2) // 3

柯里化的好处

  • 参数复用
    // 正则判断
    function isPhoneNumber (regexp, number) {
        return regexp.test(number)
    }

    // 使用
    isPhoneNumber(/\d{11}/, '34324323d')
    isPhoneNumber(/\d{11}/, '3432fdsaf4323d')

    // 每次都要写两个参数,比较繁琐,可以采用柯里化修改
    function curryingIsPhoneNumber (regexp) {
        return function (number) {
            return regexp.test(number)    
        }
    }

    const isPhoneNumber1 = curryingIsPhoneNumber(/\d{11}/)
    
    isPhoneNumber1('2132434')
    isPhoneNumber1('2132dfadsfadsf434')
  • 提前判断
    function addEvent (element, event, handler) {
        if (document.addEventListener) {   // 每次调用这个方法时都需要做一次判断
            if (element && event && handler) {
                element.addEventListener(event, handler)    
            }
        } else {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler);
            }    
        }
    }

    // 柯里化函数
    function curryingAddEvent () {
        if (document.addEventListener) {
            return function () {
                if (element && event && handler) {
                    element.addEventListener(event, handler)    
                }
            }
        } else {
            return function () {
                if (element && event && handler) {
                    element.attachEvent('on' + event, handler);
                }    
            }
        }
    }
    const addEvent1 = curryingAddEvent()
  • 延迟函数执行
    // 像我们js中经常使用的bind,实现的机制就是Currying.
    Function.prototype.bind = function (context) {
        const args = Array.prototype.slice.call(arguments, 1)
        const _self = this

        return function () {
            args.push(Array.prototype.slice.call(arguments))
                
            return _self.apply(context, args)
        }
    }

currying封装函数

前面讲解了柯里化的用处,但是存在一个问题,我们不可能对每个函数进行修改让其柯里化
但是我们可以封装一个函数来对现有的函数进行柯里化

    // 封装函数
    function processCurrying (fn) {
        const args = Array.prototype.slice.call(arguments, 1)
        
        return function () {
            const _args = Array.prototype.slice.call(arguments)
            const allArgs = args.concat(_args) // 外层的和内层的参数融合成为一个实参带到fn中进行执行

            return fn.apply(this, allArgs)
        }
    }

    // 使用
    function sum (a, b) {
        console.log(a, b)
        return a + b
    }
    
    const curryingSum = processCurrying(sum, 1)
    curryingSum(2) // 3

上面的例子并不支持链式调用,比如 curryingSum(2)(3)(13, 2)
因此对上面的例子做一个递归的处理,来支持链式调用

   function processCurrying (fn, args) {
        const allArgs = args || []
        const len = fn.length // Function.prototype.length 返回函数的形参个数
        const _this = this

        return function () {
            const _args = Array.prototype.slice.call(arguments)
            Array.prototype.push.call(allArgs, _args)

            if (allArgs.length < len) { // 传递的参数并未达到形参个数将继续收集参数
                return processCurrying.call(_this, fn, allArgs)
            }

            return fn.apply(this, allArgs)
        }
    }

    // 使用
    function sum (a, b) {
        console.log(a, b)
        return a + b
    }
    
    const curryingSum = processCurrying(sum)
    curryingSum(2)(2)(2)(2) // 8

输入图片说明