You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

闭包/柯里化棘手问题求解:sum()空调用场景的函数实现

实现支持无末尾调用的柯里化sum函数

要实现这个需求,核心是利用JavaScript中函数作为对象可以重写toString/valueOf方法的特性——当alert这类操作需要获取函数的原始值时,会自动调用toString方法,我们可以在这里返回当前的累加总和;同时让函数本身支持链式调用,每次接收参数后返回一个新的累加函数(或更新自身状态)。

方案实现(纯函数版,无副作用)

function sum() {
  // 工厂函数,创建带累加值的函数
  function createAccumulator(total) {
    // 定义累加函数
    function accumulator(num) {
      // 每次调用返回新的累加器,携带更新后的总和
      return createAccumulator(total + num);
    }
    // 重写toString,返回当前总和的字符串形式
    accumulator.toString = function() {
      return String(total);
    };
    return accumulator;
  }
  // 初始总和为0,返回第一个累加器
  return createAccumulator(0);
}

验证场景

const s = sum();
alert(s); // 弹出0
alert(s(1)); // 弹出1
alert(s(1)(2)); // 弹出3
alert(sum()(3)(4)(5)); // 弹出12

原理说明

  1. 柯里化逻辑:createAccumulator 是一个工厂函数,每次接收当前总和 total,返回一个新的 accumulator 函数。当调用 accumulator(num) 时,会创建并返回一个携带 total + num 总和的新累加器,实现链式调用。
  2. 隐式类型转换:当 alert 函数尝试输出 accumulator 时,会触发隐式类型转换,调用我们重写的 toString 方法,返回当前的累加总和,而非默认的函数代码字符串。
  3. 无副作用:每个累加器的总和都是独立维护的,修改一个累加器不会影响其他实例,比如 s 本身始终保持初始总和0,而 s(1) 返回的是一个新的总和为1的累加器。

另一种简洁实现(共享状态版)

如果不需要严格的纯函数,也可以用闭包共享同一个状态,代码更轻便:

function sum() {
  let total = 0;
  function accumulator(num) {
    if (typeof num === 'number') {
      total += num;
    }
    return accumulator;
  }
  accumulator.toString = () => String(total);
  return accumulator;
}

这种实现下,同一个累加器实例的状态会被修改,比如调用 s(1) 后,再alert s 会弹出1,而非初始的0。如果你的场景不需要保留初始状态,这个版本更简洁。

内容的提问来源于stack exchange,提问作者Roma Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:55:20