JavaScript自定义公式求值器嵌套函数实现遇阻,寻求技术帮助
问题分析与解决方案
核心问题
你的代码最大的问题在于参数拆分逻辑错误:直接用split(',')分割函数参数时,无法识别嵌套函数内部的逗号,导致参数被错误切割。比如公式SUM(AVERAGE(1,3),3)的参数字符串会被拆成"AVERAGE(1"、"3)"、"3",前两个子串无法被正确解析为数字或函数,最终返回NaN——这就是为什么你必须在sum里加isNaN判断来规避错误的原因。
修复步骤
1. 实现正确的参数解析函数
写一个能识别括号层级的参数拆分函数,只有当逗号处于最外层括号时才作为参数分隔符:
function parseArgs(argsStr) { const args = []; let currentArg = ''; let bracketDepth = 0; for (const char of argsStr) { if (char === '(') bracketDepth++; else if (char === ')') bracketDepth--; else if (char === ',' && bracketDepth === 0) { args.push(currentArg.trim()); currentArg = ''; continue; } currentArg += char; } if (currentArg.trim()) args.push(currentArg.trim()); return args; }
2. 修正evaluate函数逻辑
替换掉原有的split(','),改用上面的parseArgs,同时加入参数有效性过滤,避免无效值干扰计算:
function evaluate(formula) { formula = formula.trim(); const match = /^(\w+)\((.*)\)$/.exec(formula); if (!match) { const num = parseFloat(formula); return isNaN(num) ? NaN : num; } let [, func, argsStr] = match; const args = parseArgs(argsStr).map(arg => evaluate(arg)); const validArgs = args.filter(arg => !isNaN(arg)); switch (func.toUpperCase()) { // 支持大小写不敏感的函数名 case 'SUM': return validArgs.reduce((acc, num) => acc + num, 0); case 'MIN': return validArgs.length ? Math.min(...validArgs) : NaN; case 'AVERAGE': return validArgs.length ? validArgs.reduce((a,b)=>a+b,0)/validArgs.length : NaN; default: return NaN; } }
3. 简化计算函数
因为已经在evaluate里过滤了无效参数,原有的计算函数可以大幅简化:
// 现在可以完全移除sum里的isNaN判断 function sum(...args) { return args.reduce((acc, num) => acc + num, 0); } // 甚至可以直接把sum的逻辑整合到evaluate里,不需要单独函数
测试验证
- 测试公式
AVERAGE(SUM(1, 2), 4):先递归计算SUM(1,2)得到3,再计算AVERAGE(3,4)返回3.5 - 测试公式
SUM(AVERAGE(1,3),3):AVERAGE(1,3)返回2,SUM(2,3)返回5,无需额外判断即可正确计算 - 测试嵌套多层函数
MIN(SUM(1, AVERAGE(5,7)), 4):先算AVERAGE(5,7)=6,再算SUM(1,6)=7,最后MIN(7,4)=4
额外优化建议
- 加入语法错误提示:比如当解析到不存在的函数时,返回
"未知函数: XXX"而非NaN - 处理空输入或无效格式:比如输入空字符串时返回
"请输入合法公式" - 支持更多函数:比如
MAX、COUNT等,只需在switch里新增分支即可
内容的提问来源于stack exchange,提问作者J M
相关产品推荐
相关产品推荐

