1.原理

  • 构建图形界面,实现数字按钮,和运算符号(+,-,/,*,=)
  • 算式的显示界面可以设置为一个文本框,文本框的设置readonly
  • 在点击了相应的按钮后,value的值执行字符串拼接,最后=使用eval函数

2.重构eval函数实现字符串运算

参考网址:波兰表达式 http://blog.haoji.me/postfix-notation.html

例:str = ‘2+(5+2(5+2))+510’

一般按照我们运算习惯都是先运算括号里面,但是怎么让机器知道这些呢
目标 [5,2,+] => 5+2
分析:这个是最里面的一层表达式,如果要实现这样的效果,那么下一步应该是
[5,2,2,+,] = 5+22
将5+2的结果再入栈操作,这里就直接可以看做是从左到右的执行顺序了

第一步:先将符号的运算确定好

规则:

  1. 建立一个栈,然后从左至右的遍历中缀表达式;
  2. 碰到数字直接输出,碰到操作符则需要进行优先级的比较,如果栈为空或者栈顶的操作符的优先级比当前的低,则将当前的操作符Push入栈,如果栈顶操作符的优先级大于等于当前的操作符,则POP栈顶操作符并输出,直到出现前一种情况为止;
  3. 括号需要特殊处理,如果是(则直接入栈,如果是),则需要等到找到对应的(为止,并且当两者同时出现时则同时删除。

    1. // demo '2+(5+2*(5+2))+5*10'
    2. function houzhui(str) {
    3. //这里使用 /(\d*)/ 可以匹配并记住数字,并且在没有数字的时候匹配空
    4. let input = str.split(/(\d*)/), output = [], temp = []; // output表示输出,temp表示临时存放操作符的堆栈
    5. input = input.filter( value => value !== ''); // 清除空格
    6. let yxj = {'+': 1, '-': 1, '*': 2, '/': 2}; // 优先级
    7. input.forEach(current => {
    8. if(/\d/g.test(current)){
    9. output.push(current); // 如果是数字,直接放入输出栈
    10. }
    11. else if(current === '('){
    12. temp.push(current); // 如果左括号,放入堆栈
    13. }
    14. else if(current === ')') { // 如果是右括号,循环输出,直至匹配到左括号才停止
    15. while(temp.length > 0) {
    16. let op = temp.pop();
    17. if(op === '(') break;
    18. output.push(op);
    19. }
    20. } else { // 否则,如果是加减乘除,需要针对优先级做不同处理
    21. while(temp.length >= 0) {
    22. let op = temp[temp.length-1];
    23. // 如果堆栈为空,或者上一个操作符是(,或者当前操作符优先级比栈顶操作符优先级要高
    24. if(!temp.length || op === '(' || yxj[current] > yxj[op]) {
    25. temp.push(current);
    26. break;
    27. } else output.push(temp.pop());
    28. }
    29. }
    30. });
    31. // 输入循环结束后,如果操作符堆栈不为空,还要循环输出
    32. while(temp.length > 0) output.push(temp.pop());
    33. return output;
    34. }

第二步:调用函数,将每一个结果重新入栈

  1. function countHouzhui(input) {
  2. let output = [];
  3. input.forEach(item => {
  4. if(/\d/g.test(item)) output.push(item);
  5. else {
  6. let n2 = output.pop();
  7. let n1 = output.pop();
  8. output.push(count(n1, n2, item));
  9. }
  10. });
  11. function count(n1, n2, op) {
  12. [n1,n2] = [n1,n2].map(Number);
  13. // 使用状态模式节约开销
  14. let state = {
  15. '*' :function (left,right) {
  16. return left * right;
  17. },
  18. '/' :function (left,right) {
  19. return left / right;
  20. },
  21. '%' :function (left,right) {
  22. return left % right;
  23. },
  24. '+' :function (left,right) {
  25. return left + right;
  26. },
  27. '-' :function (left,right) {
  28. return left - right;
  29. },
  30. };
  31. console.log(n1, n2, op);
  32. return state[op](n1, n2)
  33. }
  34. return output[0];
  35. }
  36. console.log(countHouzhui(houzhui('2+(5+2*(5+2))+5*10'))); // 输出 71