元素组成的数学表达式
" />
本文介绍如何安全、可靠地验证并求值由 <p> 标签拼接而成的数学表达式,借助 math.js 实现语法校验与计算,并规避 eval() 的安全风险。
本文介绍如何安全、可靠地验证并求值由 `
` 标签拼接而成的数学表达式,借助 `math.js` 实现语法校验与计算,并规避 `eval()` 的安全风险。
在构建前端计算器时,一个常见需求是:将用户逐次点击输入的符号(如数字、运算符、括号)以 <p> 标签形式追加到容器(如 #screen)中,当点击 = 时,需自动提取所有 <p> 的文本内容,拼接为完整表达式,验证其语法合法性,并返回计算结果。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
直接使用 eval() 虽简单但存在严重安全隐患(如执行恶意代码),且无法提供清晰的错误定位;而手写递归下降解析器又过于复杂。更优解是采用成熟的数学表达式解析库——math.js。
✅ 正确实现步骤
- 统一运算符表示:HTML 中显示的 x 和 ÷ 需映射为标准 JavaScript 运算符 * 和 /(可在 data-op 属性中定义,或点击时转换);
- 提取表达式:用 Array.from(screen.querySelectorAll('p')).map(p => p.textContent.trim()).join('') 获取连续、无空格的表达式字符串;
- 安全求值与校验:调用 math.evaluate(expression),它会自动进行语法分析、类型检查和计算,非法表达式(如 2++3、1/0、未闭合括号)均抛出可捕获的 Error;
- 事件委托优化:将点击监听绑定到 <ul>,避免为每个 <li> 单独绑定事件,提升性能与可维护性。
? 示例代码(含错误处理)
<script src="https://unpkg.com/mathjs@11/lib/browser/math.js"></script>
<div id="calculator">
<div id="screen"></div>
<div>
<ul id="operationMain">
<li data-op="(">(</li>
<li data-op=")">)</li>
<li data-op="+">+</li>
<li data-op="-">−</li>
<li data-op="*">×</li>
<li data-op="/">÷</li>
<li data-op="%">%</li>
<li data-op=".">.</li>
<li data-op="0">0</li>
<li data-op="1">1</li>
<!-- 其他数字与符号同理 -->
<li class="blue" data-op="=">=</li>
</ul>
</div>
</div>const screen = document.getElementById('screen');
const ul = document.getElementById('operationMain');
const operationLogic = () => {
return Array.from(screen.querySelectorAll('p'))
.map(el => el.textContent.trim())
.join('');
};
ul.addEventListener('click', (e) => {
const li = e.target.closest('li');
if (!li) return;
const op = li.dataset.op;
if (!op) return;
const insert = document.createElement('p');
insert.textContent = op;
if (op === '=') {
const expr = operationLogic();
try {
const result = math.evaluate(expr);
insert.textContent = `${result}`; // 显示结果
screen.innerHTML = ''; // 清空屏幕(可选)
screen.appendChild(insert);
} catch (err) {
insert.textContent = `Error: ${err.message}`;
screen.appendChild(insert);
console.error('Expression invalid:', expr, err);
}
} else {
screen.appendChild(insert);
}
});⚠️ 关键注意事项
- 永远不要使用 eval():它允许执行任意 JavaScript,极易被注入攻击(如输入 alert(1) 或 fetch('/api/delete'));
- math.js 默认禁用危险函数:如 Function, import, eval 等,安全性高;如需扩展功能,请显式配置 math.create({ createUnit: true });
- 空格与格式无关紧要:math.evaluate("2 + 3 * 4") 与 "2+3*4" 结果一致,无需额外清洗空格;
- 支持高级特性:math.js 原生支持科学计数法(1e5)、常量(pi, e)、函数(sin(π/2))、甚至矩阵运算,远超基础四则运算需求。
通过以上方案,你不仅实现了表达式合法性验证与精确计算,还兼顾了代码健壮性、可读性与安全性——这才是生产级计算器应有的工程实践。


















