从多参到链式:JS 柯里化通关课

17 阅读2分钟

 柯里化介绍

首先来看一个简单的场景,计算 a + b + c。正常写法是 add(1,2,3),但柯里化会把它变成 add(1)(2)(3)——把多参数的函数,拆成一系列单参数函数的链式调用,每次调用只传部分参数,直到传完所有参数才执行最终计算。」

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

// 柯里化后的函数
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}
console.log(curriedAdd(1)(2)(3)); // 6(链式调用,分步传参)

手写柯里化

要实现通用的柯里化函数,必须抓住 3 个核心点:

  1. 收集参数:用闭包保存每次传入的参数,直到收集够「原函数需要的参数个数」;
  2. 判断触发执行:每次传参后,判断已收集的参数个数是否 >= 原函数的形参个数,够了就执行原函数,不够就返回新函数继续收集;
  3. 保持原函数的 this 指向和参数传递:确保执行原函数时,this 指向正确,且能接收剩余参数。

我们要写一个 curry 函数,接收「原函数」作为参数,返回「柯里化后的函数」。用法:const curriedFn = curry(原函数)

首先,curry 函数接收原函数 fn,返回一个新函数 curried。用闭包保存已收集的参数 args

function curry(fn) {
  // 用闭包收集每次传入的参数
  const args = [];

  // 返回柯里化后的函数,每次调用时接收部分参数
  return function curried(...rest) {
    // 把本次传入的参数加入 args(收集参数)
    args.push(...rest);

    // 核心判断:已收集的参数个数 >= 原函数的形参个数?
    if (args.length >= fn.length) {
      // 够了,执行原函数,返回结果
      return fn(...args);
    } else {
      // 不够,返回 curried 函数,继续收集参数
      return curried;
    }
  };
}

测试结果

// 原函数:3个形参
function add(a, b, c) {
  return a + b + c;
}

// 柯里化处理
 curriedAdd = curry(add);

// 测试1:分步传参(每次1个)
console.log(curriedAdd(1)(2)(3)); // 6(符合预期)

// 测试2:部分批量传参
console.log(curriedAdd(1, 2)(3)); // 6(符合预期)
console.log(curriedAdd(1)(2, 3)); // 6(符合预期)

// 测试3:一次性传参(和原函数用法一致)
console.log(curriedAdd(1, 2, 3)); // 6(符合预期)