如何在JavaScript中不使用eval()解析嵌套函数调用字符串
解决方案:解析嵌套SUM/PRODUCT函数字符串(禁用eval)
先把题目里给的基础函数放出来:
const SUM = (...args) => args.reduce((a, b) => a + b); const PRODUCT = (...args) => args.reduce((a, b) => a * b);
接下来是核心的evaluateString函数实现,我用栈结构来处理嵌套调用——毕竟嵌套函数是从最内层往外层算的,栈的「后进先出」特性刚好适配这个逻辑:
function evaluateString(expr) { const stack = []; let currentFunc = null; let currentArgs = []; let currentToken = ''; // 逐个字符遍历表达式 for (let i = 0; i < expr.length; i++) { const char = expr[i]; // 碰到左括号:说明当前拼好的token是函数名,把当前上下文压栈,开始处理新函数 if (char === '(') { currentFunc = currentToken.trim(); stack.push({ func: currentFunc, args: currentArgs }); currentArgs = []; currentToken = ''; } // 碰到右括号:计算当前函数的结果,把结果传给外层函数当参数 else if (char === ')') { // 先把最后一个参数塞进列表 if (currentToken.trim()) { currentArgs.push(Number(currentToken.trim())); currentToken = ''; } // 调用对应函数算出结果 const result = window[currentFunc](...currentArgs); // 弹出栈顶的外层函数上下文,继续处理 const prevContext = stack.pop(); currentFunc = prevContext?.func || null; currentArgs = prevContext?.args || []; // 把当前结果加入外层函数的参数列表 currentArgs.push(result); } // 碰到逗号:分割参数,把当前token转成数字塞进参数列表 else if (char === ',') { if (currentToken.trim()) { currentArgs.push(Number(currentToken.trim())); currentToken = ''; } } // 其他字符:拼接成token(要么是函数名,要么是数字参数) else { currentToken += char; } } // 遍历完整个表达式后,参数列表里的唯一元素就是最终结果 return currentArgs[0]; }
测试验证
拿题目里的两个例子试试:
console.log(evaluateString("PRODUCT(SUM(PRODUCT(2,2),2),3)")); // 输出 18 console.log(evaluateString("SUM(12,PRODUCT(1,2))")); // 输出 14
思路碎碎念
为啥用栈?因为嵌套函数的执行顺序是从最内层往外层算,栈刚好能帮我们暂存还没处理完的外层函数信息——比如当我们遇到SUM(PRODUCT(2,2),2)里的PRODUCT(时,先把SUM的上下文压进栈,专心处理PRODUCT,等PRODUCT算完出结果了,再把结果塞回SUM的参数列表里继续计算。
整个过程就是一步步拆嵌套、算内层、拼外层,完全不用eval,也能处理任意深度的嵌套调用。
内容的提问来源于stack exchange,提问作者i_abhilash
相关产品推荐
相关产品推荐

