计算器项目替换eval()函数实现计算功能的技术咨询
替换计算器中的eval()函数方案
要替换eval()同时保留计算功能,核心是避免执行任意代码的安全风险,同时正确解析数学表达式。下面提供两种可行的实现方式:
方案一:手动实现四则运算解析(推荐,安全可控)
手动解析表达式能完全掌控输入逻辑,彻底规避代码注入风险。以下是支持加减乘除取模且遵循运算符优先级的实现:
首先添加一个解析计算的函数:
function calculateExpression(expression) { // 过滤非法字符 const sanitized = expression.replace(/[^0-9+\-*/% .]/g, ''); // 校验表达式首尾是否为运算符 if (/^[+\-*/%]/.test(sanitized) || /[+\-*/%]$/.test(sanitized)) { throw new Error('Invalid expression'); } // 拆分数字和运算符为数组 const tokens = sanitized.match(/(\d+\.?\d*|[+\-*/%])/g); if (!tokens) throw new Error('Invalid expression'); // 第一步:处理乘、除、取模(优先级更高) let i = 0; while (i < tokens.length) { const token = tokens[i]; if (token === '*' || token === '/' || token === '%') { const left = parseFloat(tokens[i-1]); const right = parseFloat(tokens[i+1]); let result; switch(token) { case '*': result = left * right; break; case '/': if (right === 0) throw new Error('Division by zero'); result = left / right; break; case '%': result = left % right; break; } // 替换运算的三个元素为计算结果 tokens.splice(i-1, 3, result.toString()); i -= 1; // 回退索引,重新检查当前位置 } else { i++; } } // 第二步:处理加、减 let result = parseFloat(tokens[0]); for (let i = 1; i < tokens.length; i += 2) { const operator = tokens[i]; const num = parseFloat(tokens[i+1]); switch(operator) { case '+': result += num; break; case '-': result -= num; break; } } return result; }
然后修改你的calBtn点击事件:
calBtn.addEventListener('click',()=>{ try{ console.log("Input value:", userInput.value); const result = calculateExpression(userInput.value); userOutput.value = isNaN(result) ? 'Invalid selection' : result; } catch(e){ userOutput.value='Invalid selection'; } });
方案二:使用Function构造函数(简单但需严格校验)
如果不想手动解析,可以用Function替代eval,但必须做严格的输入过滤,仅允许合法的数字和运算符:
calBtn.addEventListener('click',()=>{ try{ console.log("Input value:", userInput.value); // 只保留数字、运算符、小数点和空格 const sanitizedInput = userInput.value.replace(/[^0-9+\-*/% .]/g, ''); // 额外校验:禁止开头/结尾是运算符、禁止连续运算符 if (/^[+\-*/%]/.test(sanitizedInput) || /[+\-*/%]{2,}/.test(sanitizedInput) || /[+\-*/%]$/.test(sanitizedInput)) { throw new Error('Invalid expression'); } // 创建函数并执行计算 const calculate = new Function(`return ${sanitizedInput}`); const result = calculate(); userOutput.value = isNaN(result) ? 'Invalid selection' : result; } catch(e){ userOutput.value='Invalid selection'; } });
额外优化建议
- 输入实时校验:在按钮点击时就拦截非法输入,比如不允许连续点击运算符,避免用户输入无效格式
- 补充小数点按钮:添加小数点按钮并设置
data-type="number",完善计算器功能 - 处理精度问题:浮点数计算可能存在精度误差,可以用
toFixed(n)控制结果显示的小数位数
内容的提问来源于stack exchange,提问作者Adarsh tripathi
相关产品推荐
相关产品推荐

