zoukankan      html  css  js  c++  java
  • JS 之简单计算器

    要求:

    响应用户对数字和算术操作符按钮的操作,记录并显示用户通过按钮输入的算术表达式(50分)响应用户功能按钮的操作

    用户按下“←”按钮,删除当前算术表达式最后一个字符,并更新显示

    用户按下“CE”按钮,清除当前算术表达式(20分)用户按下“=”按钮,计算当前表达式的结果并显示

    如果,算术表达式非法,弹出警告框提醒用户,并终止计算

    效果图:

    代码链接:https://github.com/sysuKinthon/Web2.0/tree/master/Web2.0/calculator

    经验:

    1)其实代码实现不难,而且用了已经不大推崇的eval函数,这个函数会带来代码注入的问题;

    2)实现过程中主要想说的是一种思维,因为之前一直都不怎么接触事件处理机制,一直都是用c,c++,java来打代码,所以在写这个的时候有一个致命的思维误区:

        //if input the symbol, the reslut should be clear;
        for(i = 0; i < symbolList.length; ++i) {
            symbolList[i].onclick = function(event) {  //不能使用i来索引对象,因为当Onclick事件发生时,i已经都是20了。
                if(flag == true) {
                    expression.value = "";
                    flag = false;
                }
                var content = event.target.innerText;
                expression.value = expression.value + content;
            }
        }

    一开始在for循环里面,一上手就想用sybmolList[i]来引用innerText;也就是:

    var content = event.target.innerText;
    换成
    var content = symbolList[i].innerText;

    发现我一点击事件就出现越界行为,输出查看i,i的值都是同一个数,这个数决定于window.onload回调函数结束后的i值。要清楚,这是闭包导致的,当我们的DOM加装完毕后,window.onload事件就发动了,并调用事件处理;好像一切都没有问题,但是想想看,当我们点击事件,并触发了symbolList中的对象时,回调了我们设置的函数,此时它引用i的值的话,必然是symbolList.length,因为onload事件已经执行了,但由于闭包,如果我们的点击函数中有引用外部的变量的话,是可以访问到的,在javascript中是采用了垃圾处理机制,闭包包含了外部的活动对象,所以这个对象还没有被销毁,可以被引用。所以我们在程序中是不能直接调用 i来索引事件源的,要使用event.target

    拓展:

    毕竟利用eval来实现计算会导致一些意想不到的问题,所以就用算法实现了下中缀表达式的计算:参考

    关于考虑运算符优先级的问题,也就是什么时候栈里面的运算符应该出栈,主要考虑一个方面就可以了,就是运算符的栈始终要保持栈顶的元素优先级最高,相同优先级的后面进入的优先级高,同时需要考虑对于")"来说,当在遇到"("时,它的优先级是最高的,遇到后,就是最低的了(也就是不要入栈)。

    主要的函数代码如下:

     1 // calculator the postfix expression
     2 function calculate(postfix) {
     3     var i, item, result;
     4     var num = [];
     5     for(i = 0; i < postfix.length; i++) {
     6         item = parseFloat(postfix[i]);
     7         if(!isNaN(item)) {
     8             num.push(item);
     9         } else {
    10             second = num.pop();
    11             first = num.pop();
    12             switch(postfix[i]) {
    13                 case '+':
    14                     result = first + second;
    15                     num.push(result);
    16                     break;
    17                 case '-':
    18                     result = first - second;
    19                     num.push(result);
    20                     break;
    21                 case '/':
    22                     result = first / second;
    23                     num.push(result);
    24                     break;
    25                 case '*':
    26                     result = first * second;
    27                     num.push(result);
    28                     break;
    29             }
    30             //console.log(result);
    31         }
    32     }
    33     result = num.pop();
    34     result = parseFloat(result.toFixed(8), 10);
    35     return result;
    36 }
    37 
    38 
    39 // translate the infix expression to the postfix expression
    40 function toPostfix(infix) {
    41     //split the input to the token
    42     var regex = /((|)|/|*|-|+)/;
    43     var array= infix.split(regex);
    44     var i;
    45     var postfix = [];
    46     var symbol = [];
    47     // remove the empty item
    48     for(i = 0; i < array.length; i++) {
    49         if(array[i] == "")
    50             array.splice(i, 1);
    51     }
    52 
    53     for(i = 0; i < array.length; i++) {
    54         var item = array[i];
    55         if(!isNaN(parseFloat(item))) {
    56             postfix.push(item);
    57         } else {
    58             while(symbol.length) {
    59                 if(compare(item, symbol[symbol.length-1])) { //if the item is greater
    60                     break;
    61                 } else {
    62                     postfix.push(symbol.pop());
    63                     /*if(postfix[postfix.length-1] == "(")
    64                         console.log(1);*/
    65                 }
    66             }
    67             if(item == ")") {
    68                 symbol.pop(); //pop "("
    69             } else { 
    70                 symbol.push(item);
    71             }
    72         }
    73     }
    74     while(symbol.length) {
    75         if(symbol) {
    76             postfix.push(symbol.pop());
    77         }
    78     }
    79     return postfix;
    80 }
    81 
    82 function compare(item, top) {
    83     if(item.match(/)/) && top.match(/(/))
    84         return true;
    85     if(item.match(/(/) || top.match(/(/)) {
    86         return true;
    87     }
    88     if(item.match(/*|//) && top.match(/+|-/)) {
    89         return true;
    90     }
    91     //console.log(item);
    92     return false;
    93 }
  • 相关阅读:
    思念
    空白
    curl json string with variable All In One
    virtual scroll list All In One
    corejs & RegExp error All In One
    socket.io All In One
    vue camelCase vs PascalCase vs kebabcase All In One
    element ui 表单校验,非必填字段校验 All In One
    github 定时任务 UTC 时间不准确 bug All In One
    input range & color picker All In One
  • 原文地址:https://www.cnblogs.com/kinthon/p/4948680.html
Copyright © 2011-2022 走看看