中高级前端面试高频题之函数柯里化

这是我参与更文挑战的21天,活动详情查看 更文挑战

函数柯里化是一种编程方式,它提供了把一个抽象函数作为参数送给另一个函数的方法,以此来做到调用和实现的分离,简单讲就是:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数,所以表现形式上通常有着多次接受参数的特点。

让我们假定一个carry函数为柯里化方法,用以下例子来展示柯里化函数效果:

var fn = curry(function(a, b, c) {
    console.log(a + b + c)
})
fn(1,2,3) // 6
fn(1)(2)(3) // 6
fn(1, 2)(3) // 6
fn(1)(2, 3) // 6
复制代码

在经过柯里化之后的函数fn,无论使用以上哪种方式调用,最后返回的结果都一样。我们不难看出柯里化的函数有个应用特点:多次传递参数,参数未处理完则返回函数。

常见面试题:实现一个函数让 fn(1)(2) === 3

function curry(fn, arg = []) {
    return function() {
        const _args = arg.slice(0)
        for(let i = 0; i < arguments.length; i++) {
            _args.push(arguments[i]) // 每次把函数参数组合传递给下次调用使用
        }
        if(_args.length < fn.length) { // Currying传入的参数少于接收参数的数量,继续接受参数的函数
            return curry.call(this, fn, _args)
        } else {
            return fn.apply(this, _args) // 最后返回计算结果
        }
    }
}

const fn = curry(function(a, b) {
    return a + b
})

console.log(fn(1)(2) === 3) // true
复制代码

以上解题步骤使用到了call、apply、递归、数组拷贝,可视为对这些基础知识的运用考察。

浅显地来看,柯里化的一个关键点在于传递参数没有达到定义函数的数量则不会停下来返回结果,所以通常可以想到的应用场景如下:

// 假设如下一段代码
fn(a, b, c) {
  // ... TODO
}
const a = fn('head', 'foot', 'content111')
const b = fn('head', 'foot', 'content222')
复制代码
// 利用柯里化就可以“缓存”相同的变量赋值:
const fn = curry((a, b, c) => {
  // ... TODO
})
const x = fn('head', 'foot')
const a = x('content111')
const b = x('content222')
复制代码

emm…但是实际开发中这种场景应该有其它更好的写法,这样做只是充分利用到了函数式编程方式,个人认为实际应用的场景真的并不多见吧。

我们看到柯里化也是函数中返回一个函数,很像闭包,那么利用闭包缓存参数,就可以做些有趣的事情,比如下面这个“延迟”执行函数。

假设有如下函数:

// reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
const add = (...args) => args.reduce((a, b) => {
    return a + b 
});
console.log( add(6,6,6) ); // 立即输出结果 18
复制代码

改造此函数:

function delayCurry(func) {
    let args = [];
    return function result(...a) {
        if (arguments.length === 0){ return func(...args) } // 直到没有参数时才返回结果
        args = args.concat([].slice.apply(arguments))
        return result;
    }
}

const sum = delayCurry(add);

sum(6)(3)(3);
sum(6);
console.log( sum() ); // 此时输出结果 18
复制代码

我对柯里化的探究也只能止步于此,最常见还是在面试当中,而在实际应用下可能还是取决于函数式编程的功底罢。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享