元素组成的数学表达式
" />
本文介绍如何安全地提取页面中 <div id="screen"> 内所有 <p> 标签的文本内容,拼接为合法数学表达式,并使用 math.js 进行语法校验与求值,避免 eval() 风险。
本文介绍如何安全地提取页面中 `
` 标签的文本内容,拼接为合法数学表达式,并使用 `math.js` 进行语法校验与求值,避免 `eval()` 风险。
在构建 Web 计算器时,一个常见需求是:将用户逐次点击输入的符号(数字、运算符、括号等)以 <p> 元素形式追加到显示区域(如 <div id="screen">),并在点击 = 时自动识别这些 <p> 的组合是否构成有效数学表达式,并返回计算结果。直接拼接字符串后调用 eval() 存在严重安全风险(XSS)且无法精准报错;而手动实现完整数学表达式解析器则过于复杂。推荐采用成熟数学计算库(如 math.js)进行健壮解析与求值。
✅ 正确实现步骤
- 统一运算符表示:HTML 中的 x 和 ÷ 不是 JavaScript/math.js 支持的运算符,需映射为 * 和 /(可通过 data-op 属性或预处理逻辑实现,本例采用简化方式:前端按钮直接使用 * /);
- 提取并拼接表达式:使用 Array.from(screen.querySelectorAll('p')).map(p => p.textContent.trim()).join('') 获取所有 <p> 的纯净文本,按顺序连接成单个字符串;
- 安全求值与错误捕获:调用 math.evaluate(expression) —— 它能自动校验语法、类型、括号匹配、除零等,并抛出可读性高的错误;
- 事件委托优化:将点击监听绑定到 <ul> 上,利用 event.target.closest('li') 提升性能与可维护性,避免为每个按钮重复绑定。
? 示例代码(含关键注释)
<script src="https://unpkg.com/mathjs/lib/browser/math.js"></script>
<div id="calculator">
<div id="screen"></div>
<div>
<ul id="operationMain">
<li class="operatorColor">(</li>
<li class="operatorColor">)</li>
<li class="operatorColor">+</li>
<li class="operatorColor">-</li>
<li class="operatorColor">*</li>
<li class="operatorColor">/</li>
<li class="operatorColor">%</li>
<li class="operatorColor">.</li>
<li class="blue">=</li>
<li>0</li><li>1</li><li>2</li><li>3</li><li>4</li>
<li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>00</li>
</ul>
</div>
</div>const screen = document.getElementById('screen');
const ul = document.getElementById('operationMain');
// 构建表达式字符串:提取所有 <p> 文本并去除首尾空格
const getExpression = () => {
return Array.from(screen.querySelectorAll('p'))
.map(p => p.textContent.trim())
.filter(text => text !== '') // 过滤空内容(防误操作)
.join('');
};
// 主逻辑:点击时处理输入或计算
ul.addEventListener('click', (event) => {
const tgt = event.target.closest('li');
if (!tgt) return;
const value = tgt.textContent.trim();
// 创建新 <p> 元素并插入屏幕
const insert = document.createElement('p');
insert.textContent = value;
screen.appendChild(insert);
// 点击 "=" 时执行计算
if (value === '=') {
const expression = getExpression();
console.log('Evaluating:', expression);
try {
const result = math.evaluate(expression);
// 清空屏幕并显示结果(可选:保留原表达式 + 结果)
screen.innerHTML = '';
const resultEl = document.createElement('p');
resultEl.textContent = `= ${result}`;
screen.appendChild(resultEl);
} catch (err) {
// 友好提示语法错误(如 "Unexpected operator"、"Parentheses not balanced")
alert(`表达式错误:${err.message}`);
// 可选:高亮错误位置或清空非法输入
screen.innerHTML = '<p style="color:red">❌ 表达式无效</p>';
}
}
});⚠️ 注意事项与最佳实践
- 禁止使用 eval():eval() 会执行任意代码,若用户输入恶意脚本(如 alert(1)),将导致 XSS 漏洞;
- 运算符标准化:若必须保留 x/÷ 显示,建议用 data-op="*" 属性存储真实运算符,textContent 仅用于展示;
- 空格与连续符号处理:math.js 对空格不敏感,但多个连续运算符(如 ++、2..3)会报错,可在 getExpression() 中加入简单预校验(如正则 /[\+\-\*\/%]{2,}/);
- 精度与大数:math.js 默认支持高精度计算,如需整数运算可配合 math.round() 或 math.bignumber();
- 用户体验增强:可添加退格(Backspace)功能、括号自动配对、表达式历史记录等。
通过引入 math.js 并采用事件委托+表达式拼接+异常捕获的组合方案,你既能获得工业级的数学解析能力,又能写出清晰、安全、易维护的计算器逻辑。

















