如何在没有 eval 的 javascript 中编写计算器
Posted
技术标签:
【中文标题】如何在没有 eval 的 javascript 中编写计算器【英文标题】:How to code a calculator in javascript without eval 【发布时间】:2015-11-24 08:46:26 【问题描述】:所以,我到处搜索,但找不到答案。我已经尝试了大约 3 次,并通过基本上将输入作为字符串存储在数组中,解析数字,然后打开运算符来计算整数,从而得到了一个基本的,但我有一个真的很难弄清楚链接逻辑。有没有人有什么建议?甚至可能只是伪代码?我真的不想使用 eval。非常感谢
【问题讨论】:
你打算如何使用计算器?你想要一个主要的计算器函数并将表达式作为字符串传递给它吗?像这样:calculate("1 + 2 / 9")
我会采取任何有效的方法,在这一点上。这不是我的意图,因为我认为像这样在最后评估所有操作员可能会更加痛苦,因为我必须考虑操作顺序,但如果你知道一种方法,我如果你愿意分享,我会很高兴。我打算做一些事情,如果用户输入1+3*5-10%
,脚本过程将评估1+3,然后存储它,然后是5*5,存储它,然后是25-10,存储它,然后输出0.15 .
是的。不过,必须有某种逻辑才能知道在哪里拆分表达式。
*** 上的一个类似问题,但有更多答案,可在here 获得。
【参考方案1】:
对于只有 5 个运算符(^、*、/、+、-)且没有括号的简单计算器,您可以这样做。首先,将字符串转换为数字和运算符的数组很方便。然后,我们遍历数组,按优先顺序查找每个运算符,并将运算符应用于它之前和之后的数字。
function tokenize(s)
// --- Parse a calculation string into an array of numbers and operators
const r = [];
let token = '';
for (const character of s)
if ('^*/+-'.indexOf(character) > -1)
if (token === '' && character === '-')
token = '-';
else
r.push(parseFloat(token), character);
token = '';
else
token += character;
if (token !== '')
r.push(parseFloat(token));
return r;
function calculate(tokens)
// --- Perform a calculation expressed as an array of operators and numbers
const operatorPrecedence = ['^': (a, b) => Math.pow(a, b),
'*': (a, b) => a * b, '/': (a, b) => a / b,
'+': (a, b) => a + b, '-': (a, b) => a - b];
let operator;
for (const operators of operatorPrecedence)
const newTokens = [];
for (const token of tokens)
if (token in operators)
operator = operators[token];
else if (operator)
newTokens[newTokens.length - 1] =
operator(newTokens[newTokens.length - 1], token);
operator = null;
else
newTokens.push(token);
tokens = newTokens;
if (tokens.length > 1)
console.log('Error: unable to resolve calculation');
return tokens;
else
return tokens[0];
const calculateButton = document.getElementById('calculate');
const userInput = document.getElementById('userInput');
const result = document.getElementById('result');
calculateButton.addEventListener('click', function()
result.innerhtml = "The answer is " + calculate(tokenize(userInput.value));
);
<input type="text" id="userInput" />
<input type="button" value="Calculate" id="calculate" />
<div id="result"></div>
(jsfiddle)。要允许括号,您可以告诉calculate
函数在开始查找任何其他运算符之前检查括号,然后在每组括号内的表达式上递归调用自身。解析功能也可以改进,例如删除任何空白并处理错误。
【讨论】:
我注意到一个错误:当你尝试计算这样的东西时:10.01 - 11
你会得到0.9900000000000002
这是错误的。
@TomSki 这是 JS 和大多数语言 ***.com/questions/1458633/… 中十进制计算的普遍问题。它可以使用像decimal.js github.com/MikeMcl/decimal.js这样的库来处理,就像这个计算器的更新版本jsfiddle.net/10wn7bun/2
谢谢,最近几天我一直在寻找解决这个问题的方法,但我找不到任何简单的方法。似乎 decimal.js 对我来说是最好的选择。
@Ghos3t |这是一个很晚的回应,但数学家通常使用 BIDMAS。括号、索引、除法、乘法、加法、减法,具体按此顺序。它不是从左到右或从右到左,而是使用 BIDMAS。
@Tigerrrrr Ghos3t 的评论是对早期版本答案中的错误的回应,该版本已修复。运算确实按照 (1) 指数 (2) 乘法/除法 (3) 加法/减法的顺序从左到右进行。例如 40-5+6 = (40-5)+6 而不是 40-(5+6) - 首先完成最左边的操作。加法不一定在减法之前完成,BIDMAS 等在这方面可能会令人困惑。 en.m.wikipedia.org/wiki/Order_of_operations以上是关于如何在没有 eval 的 javascript 中编写计算器的主要内容,如果未能解决你的问题,请参考以下文章
Javascript:从字符串调用以匿名函数编写的函数,函数名称没有eval?
JavaScript中,为什么eval和with会有性能问题?
是否仍然值得在移动 JavaScript 上使用 eval 来提高性能?