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 }
  • 相关阅读:
    mysql 主从配置
    doGet和doPost的区别
    我的第一个MVC项目
    c3p0xml配置详解
    c3p0连接数据库
    java加载资源文件
    Windows上部署Python
    Windows上部署Python
    NagiosQL安装
    Nagios Windows客户端NSClient++ 0.4.x安装配置
  • 原文地址:https://www.cnblogs.com/kinthon/p/4948680.html
Copyright © 2011-2022 走看看