跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

基础语法综合练习:实现一个简单的计算器核心逻辑

应禁用eval(),改用安全解析器或Function构造器;手写解析器需分三步:正则提取、双栈按优先级计算、清空剩余运算符;数字转换推荐Number()并校验NaN。 怎么用
eval()
安全地算四则表达式 直接用
eval()
解析用户输入的算式最省事,但也是最大风险点——它会执行任意代码。真实场景里,你几乎不该让它碰原始输入。 只在输入已严格过滤后使用:比如正则提前筛掉
;
、
__
、
import
、
exec
等字符或关键字 更稳妥的做法是禁用
eval()
,改用
Function
构造器限制作用域:
const calc = new Function('a', 'b', 'op', 'return a op b');
但注意这只能处理单个二元运算,复杂表达式仍需解析 常见错误现象:
eval("2 + 3 * 4")
得到 20(符合数学优先级),但
eval("1 + 2 + 3")
没问题,
eval("1++")
就报
SyntaxError
——说明它认的是 JS 语法,不是纯数学表达式 手写简易表达式解析器的关键三步 不依赖第三方库时,核心是把字符串拆成“数字+运算符”再按优先级合并。不用递归下降,也能靠两个栈搞定。 第一步:用正则提取所有数字和运算符,例如
"3 + 4 * 2"
→ 数组
["3", "+", "4", "*", "2"]
;注意负号要和减号区分,
"-5 + 3"
的开头
-
是符号,不是运算符 第二步:维护一个数字栈和一个运算符栈;遇到乘除,立刻弹出前一个数字和运算符计算,结果压回数字栈;加减则先入栈,等最后统一算 第三步:遍历完后,把剩余运算符逐个处理。漏掉这步会导致
"1 + 2 + 3"
只算到
1 + 2 = 3
就停了,最后结果变成 3 而不是 6
parseFloat()
和
Number()
在数字转换时的区别 用户输
" 12.3abc "
或
"0x1F"
,两种方法行为完全不同,选错会悄悄引入 bug。
parseFloat(" 12.3abc ")
返回
12.3
,它从左扫到第一个非法字符就停;
Number(" 12.3abc ")
返回
NaN
,要求整个字符串可转为有效数字
parseFloat("0x1F")
返回
0
(因为
x
不合法),而
Number("0x1F")
返回
31
(支持十六进制) 计算器场景建议用
Number()
,配合
isNaN()
显式判断失败;若用
parseFloat()
,必须额外检查输入是否被截断,比如比对原字符串长度和转换后字符串长度 为什么别在按钮点击里反复绑定
onclick
每次点击都重新
element.onclick = handleCalc
,表面能用,但会覆盖上一次绑定,导致历史事件监听器丢失,调试时找不到为什么某次计算没响应。 正确做法是只绑一次,在初始化时设置:
document.getElementById('calc-btn').onclick = handleCalc;
如果逻辑需要动态更新(比如切换加减模式),不要重绑事件,而是改内部状态变量,让
handleCalc
自己读取当前模式 容易踩的坑:在循环里给多个按钮绑事件时写成
for (let i = 0; i console.log(i); }
,结果全输出
btns.length
——这是闭包和变量提升的老问题,得用
let
声明循环变量,或用
forEach
真正难的不是算对 2 + 2,而是当用户粘贴进
"1e5 + 0.1e-3 * 2"
或连续点
+
十几次时,你的解析逻辑是否还稳得住。边界情况比主流程更花时间。

相关文章