深入浅出 JavaScript 柯里化:从闭包到函数式编程

50 阅读3分钟

深入浅出 JavaScript 柯里化:从闭包到函数式编程

在 JavaScript 的世界里,柯里化(Currying)  是函数式编程中一个非常重要且强大的概念。它不仅能让我们的代码更加优雅,还能提高代码的复用性和语义化程度。

一、 什么是柯里化?

简单来说,柯里化就是将一个接受多个参数的函数,转换成一系列接受单一参数(或部分参数)的函数

通常我们调用函数是这样的:add(1, 2)
而柯里化之后,调用方式变成了:add(1)(2)

1. 基础对比

我们先看一个最简单的加法例子:

// 普通函数
function add(a, b) {
    return a + b;
}
console.log(add(1, 2)); // 3

// 手动柯里化
function addCurried(a) {
    return function(b) {
        return a + b;
    }
}
console.log(addCurried(1)(2)); // 3

二、 柯里化的核心原理

柯里化的本质是利用了 闭包(Closure)  和 递归

  1. 闭包作为存储器:每一层嵌套函数都会接收并“记住”自己的参数。由于闭包的存在,这些参数(自由变量)会一直保存在内存中,不会被销毁。
  2. 参数收集:通过递归不断地收集参数,直到参数数量达到原函数的预期。
  3. 退出条件:当收集到的参数数量等于原函数定义的形参个数(即 fn.length)时,执行原函数并返回结果。

三、 实现一个通用的柯里化辅助函数

在实际开发中,我们不需要手动去写嵌套函数,而是写一个通用的 curry 工具函数:

function curry(fn) {
    // 返回一个名为 curried 的闭包函数
    return function curried(...args) {
        // 检查当前已收集的参数数量是否足够
        if (args.length >= fn.length) {
            // 退出条件:参数够了,直接执行原函数
            return fn(...args);
        }
        // 递归:参数不够,返回一个新函数继续收集
        return (...rest) => curried(...args, ...rest);
    };
}

// 测试
function add(a, b, c, d) {
    return a + b + c + d;
}

const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)(4)); // 10
console.log(curriedAdd(1, 2)(3, 4));    // 10 (非严格柯里化,支持一次传多个)

关键点解析:

  • fn.length:这是 JavaScript 函数对象的一个属性,代表该函数预期接收的参数个数。它是我们判断“参数是否收集完毕”的标尺。
  • ...args 与 ...rest:利用 ES6 的展开运算符,我们可以灵活地合并不同阶段传入的参数。

四、 柯里化的实际应用:日志系统

柯里化不仅仅是面试题,它在现实开发中非常实用,最典型的场景就是固定参数提升语义化

假设我们有一个通用的日志函数:

// 原始柯里化日志函数
const log = type => message => {
    console.log(`${type}: ${message}`);
}

// 1. 固定参数,复用逻辑
// 我们不需要每次都传 "error" 或 "info"
const errorLog = log('error');
const infoLog = log('info');

// 2. 提升语义化
// 调用时,代码的意图非常清晰
errorLog("接口异常");      // 输出: error: 接口异常
infoLog("页面加载完成");    // 输出: info: 页面加载完成

通过柯里化,我们将一个通用的 log 函数转化为了更具具体意义的 errorLog 和 infoLog。这不仅减少了重复代码的输入,还让代码读起来像句子一样自然。

五、 总结

  • 本质:闭包。利用闭包持久化参数的能力。

  • 过程:递归收集参数,直到 args.length >= fn.length

  • 优势

    • 参数复用:固定某些不常变化的参数。
    • 延迟执行:只有当参数凑齐时才会真正运行逻辑。
    • 语义化:创建出更符合业务逻辑的专用函数。

柯里化是函数式编程的基石之一,掌握它能让你在处理复杂逻辑时,拥有更灵活的拆解和组合能力。