函数柯里化

148 阅读1分钟

在实际应用中可能有类似如下方式的函数调用方式:

func(1)(2)(3)

这就是函数柯里化的表现形式(当然并不定有此形式的就是柯里化的函数),下面进行一下简单介绍:

柯里化又称部分求值,一个柯里化的函数首先会接受一些传参,接受了这些传参之后,函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数内形成的闭包中被保存起来,到参数被真正求值的时候,之前传入的参数会被一次性用于求值。

// 字符串的拼接

const concat_string = (a, b, c) => {
    console.log('root_func', a + b + c)
    return a + b + c
}
// 简单的柯里化包装器
const createCurry = (f) => {
    return (a) => {
        return (b) => {
            return f(a, b)
        }
    }
}

// “高级的” 柯里化包装器 缺点是包装后的柯里化函数调用的次数与原始函数的参数的个数相关
function advCreateCurry(func) {
    // console.log('a', func, func.length)
        // func.length 指的是 被包装的函数里面传参的个数

    return function curried(...args) {

        console.log('b', args, args.length)

        if(args.length >= func.length) {
            return func.apply(this, args)
        } else {
            return function(...args2) {
                
                console.log('c', args2)
                return curried.apply(this, args.concat(args2))
            }
        }
    }
}

// 包装调用
const curry = createCurry(concat_string)
// 包装调用
const advCurry = advCreateCurry(concat_string)

curry('a')('bc')
advCurry('a')('b')('c')
advCurry('bc', 'a')
advCurry('b', 'c')('a')

// 无限拼接字符串
function infiniteCurry(string) {
    let ret = Array.prototype.slice.call(arguments).join(', ')
    let temp = function(string) {
        console.log('temp_arguments', arguments)
        ret = [ret, Array.prototype.slice.call(arguments).join(', ')].join(', ')
        return temp
    }

    temp.toString = function() {
        console.log('temp_ret', ret)
        return ret
    }
    console.log('arguments', arguments);
    console.log('ret', ret)
    console.log('temp', temp)
    
    return temp
}

var tempFunc = infiniteCurry('rich', "xiu")('yu')('xu')

console.log(tempFunc.toString())