面试题:实现基于闭包保留状态的JavaScript柯里化加法函数
基于闭包保留状态的JavaScript柯里化加法函数实现
需求说明
需要实现一个支持柯里化的加法函数add,通过闭包持续保留累计求和状态,满足以下调用场景:
add(1, 2, 3)(4)(5, 6);add(7, 8);add(9)(10);add();
最终调用add()时需输出55,累计逻辑如下:
add(1, 2, 3)(4)(5, 6)→ 累计总和为21add(7, 8)→ 21 + 15 = 36add(9)(10)→ 36 + 19 = 55add()→ 输出最终累计值55
原代码问题分析
你提供的代码无法保留累计状态,核心原因是finalOutput定义在add函数内部,每次调用add都会重新初始化该变量为0,且递归调用add(finalOutput)会创建新的函数上下文,导致之前的累计值完全丢失。
function add(...arg) { let finalOutput = 0; // 每次调用add都会重置为0 if (arg.length === 0) { return finalOutput; } return function (...newArg) { if (newArg.length) { let argsArr = [...arg, ...newArg]; finalOutput = argsArr.reduce((acc, currentValue) => { return acc + currentValue; }); return add(finalOutput); // 递归调用add,重新创建上下文,丢失之前的finalOutput } else { return finalOutput; } }; }
解决方案代码
通过立即执行函数表达式(IIFE)创建闭包,将累计总和变量封装在独立作用域中,确保所有add调用共享同一个状态:
const add = (function() { // 闭包内的变量,仅初始化一次,持续保留累计状态 let total = 0; return function(...args) { // 无参数调用时,返回当前累计值并重置状态(按需选择是否重置) if (args.length === 0) { const result = total; total = 0; // 如果需要每次调用add()后重置累计,保留此行;否则移除 return result; } // 累加本次传入的所有参数到total total += args.reduce((acc, num) => acc + num, 0); // 返回自身,支持柯里化链式调用 return add; }; })();
代码验证
执行以下调用即可得到预期结果:
add(1, 2, 3)(4)(5, 6); // 累计21 add(7, 8); // 累计36 add(9)(10); // 累计55 add(); // 输出55
逻辑解释
- 闭包状态保留:IIFE内部的
total变量不会被外部访问,且会被返回的add函数持续引用,因此不会被垃圾回收,实现状态持久化。 - 柯里化支持:每次传入参数后,函数返回自身,因此可以链式调用
add(a)(b,c)这类形式。 - 终止调用:当无参数调用
add()时,返回当前累计值,同时可选择重置total以支持下一轮累计。
内容的提问来源于stack exchange,提问作者amit chowdhary
相关产品推荐
相关产品推荐

