Simple JS Calculator to implement code _JAVASCRIPT skills

Source: Internet
Author: User
Tags mul numeric value tagname function calculator

Look at the calculator in your phone and divide it into a general calculator and a science calculator

Think that the head is not big enough to achieve a normal version of the bar (support positive and negative subtraction, such as basic continuous operations, does not provide parentheses function)

Look at the diagram effect:

I. Knowledge PREPARATION

1+1 =?

Normally, we see this expression knowing how to do it, knowing the result of the operation.

But the computer is not the same, the computer cannot recognize this string of expressions, it can only recognize a specific rule: prefix expression + 1 1 or suffix expression 1 1 +

Give me a chestnut.

(3 + 4) x5-6 is an infix expression
-x+ 3 4 5 6 prefix expression
3 4 + 5x6-suffix expression

So in order to realize the automatic operation of the program, we need to convert the input data into a prefix or suffix expression.

The concept of prefix, infix, suffix expressions and the methods of mutual conversion here's a little bit more to say, this blog post is more clear.

Therefore, in the implementation of this calculator, the implementation of the suffix expression, refer to the above article, focus on these two algorithms:

Similar to the conversion to a prefix expression, follow these steps:
(1) Initialize two stacks: operator stack S1 and stack S2 for storing intermediate results;
(2) Scan infix expression from left to right;
(3) When the operation number is encountered, it is pressed into the S2;
(4) When the operator is encountered, compare its priority with the S1 stack-top operator:
(4-1) If the S1 is empty, or the top operator of the stack is a left parenthesis "("), the operator is put directly into the stack;
(4-2) Otherwise, if the precedence is higher than the stack top operator, the operator is also pressed into the S1 (note that the conversion to the prefix expression is higher or the same, and here does not include the same situation);
(4-3) Otherwise, the operator at the top of the S1 stack is ejected and pressed into the S2, and then again to (4-1) compared to the new stack-top operator in S1;
(5) When the parentheses are encountered:
(5-1) If the opening parenthesis is "("), it is directly pressed into the S1;
(5-2) If the closing parenthesis ")", then pops the S1 stack top operator and presses into the S2 until the opening parenthesis is encountered, discarding the pair of parentheses at this time;
(6) Repeat steps (2) to (5) until the far right of the expression;
(7) The remaining operators in the S1 are ejected and pressed into the S2 in turn;
(8) in turn, pop-up elements in the S2 and output, the result of the reverse is the infix expression corresponding to the suffix expression (when converting to the prefix expression without reverse order).

Similar to prefix expressions, only the order is left to right:
Scans the expression from left to right, and when it encounters a number, it presses the number onto the stack, when an operator is encountered, the top two numbers of the pop-up stack are computed with the operator (the top element of the top element op stack), and the result is repeated to the right end of the expression, and the resulting value is the result of the expression.
For example suffix expression "3 4 + 5x6-":
(1) scan from left to right to push 3 and 4 into the stack;
(2) encountered the + operator, so pop-up 4 and 3 (4 for the top of the stack element, 3 for the second top element, pay attention to the prefix expression to do comparison), calculate the value of 3+4, get 7, and then 7 into the stack;
(3) 5 into the stack;
(4) Next is the x operator, so pop 5 and 7, calculate the 7x5=35, 35 into the stack;
(5) 6 into the stack;
(6) The last is the-operator, which calculates the value of 35-6, that is, 29, to derive the final result.

Second, the implementation process

The first step, of course, is to build a calculator page structure, not a scientific calculator, only provides the basic operation function, but also can be real-time operation, display the complete infix expression, after the operation to save a record of the operation.

To say first: Originally want to achieve the decimal point function, but the existence of the decimal point of data storage and data display to achieve a pressure, the realization process is really brain, simply cancel this function first.

1. Page structure:

   

2. Combine a little style:

body {padding:20px;
font-family:arial;
  }. calc-wrap {width:300px;
  border:1px solid #ddd;
border-radius:3px;
  }. calc-operation {width:100%;
Border-collapse:collapse;
  }. calc-in-out {width:100%;
  padding:10px 20px;
  Text-align:right;
  Box-sizing:border-box;
Background-color:rgba (250, 250, 250,. 9);
  }. calc-in-out p {overflow:hidden;
  margin:5px;
width:100%;
  }. calc-history {margin-left: -20px;
  font-size:18px;
  Color: #bbb;
  border-bottom:1px dotted #ddf;
min-height:23px;
  }. calc-in, calc-out {font-size:20px;
  Color: #888;
  line-height:39px;
min-height:39px;

}. calc-in {color: #888; calc-out {color: #ccc;}
  . calc-in.active,. calc-out.active {font-size:34px;
Color: #666;
  }. calc-operation td {padding:10px;
  width:25%;
  Text-align:center;
  border:1px solid #ddd;
  font-size:26px;
  Color: #888;
Cursor:pointer;

}. calc-operation td:active {background-color: #ddd;} . calc-operation. cls {color: #ee8956;}
 

So the static calculator on the Rough ~ ~

3. JS Logic

This part is the point, step by step

The first is the monitoring of the calculator, that is, this form, you can use the way the event delegate, the parent node listening processing

    Binding event
    Bindevent:function () {
      var = this;

      $operation. On (' click ', Function (e) {
        e = e | | window.event;
        var elem = E.target | | E.srcelement,
          Val,
          action;

        if (Elem.tagname = = ' TD ') {
          val = elem.getattribute (' data-val ') | | elem.getattribute (' DATA-AC ');  

Listen to data, get only a page of a value/operator, so you need to store the data to form infix, and then by infix conversion to suffix, and finally through the suffix of the calculation

    infix expression
    this.infix = [];
    Suffix expression
    this.suffix = [];
    Suffix expression operation result set
    This.result = [];

According to the algorithm steps to achieve, here is not used to parentheses, if the actual need, can be modified in the corresponding position to judge the conditions can ~

/infix expression suffix infix2suffix:function () {var temp = [];

      This.suffix = []; for (var i = 0; i < this.infix.length i++) {//numeric value, direct pressure into if (!this.isop (this.infix[i)) {thi
        S.suffix.push (This.infix[i]);
          } else {if (!temp.length) {Temp.push (this.infix[i]);
            else {var optop = temp[temp.length-1]; Loops determine the precedence of operators, and push the operator higher into the suffix expression if (!this.priorhigher (Optop, This.infix[i]) {while Temp.length &
                amp;&!this.priorhigher (Optop, This.infix[i])) {This.suffix.push (Temp.pop ());
              Optop = Temp[temp.length-1];
          The current operator is also pressed into the suffix expression temp.push (this.infix[i]);
      The remaining operation symbol is pressed into while (temp.length) {This.suffix.push (Temp.pop ()); }
    },

 The suffix expression evaluates to
    Calcsuffix:function () {
      this.result = [];

      for (var i = 0; i < this.suffix.length i++) {
        //numeric value, direct pressure into result set
        if (!this.isop (this.suffix[i)) {
          this.result. Push (This.suffix[i]);
        }
        Operator, takes two items out of the result set, and sets the result of the operation into the result set
        else {
          This.result.push (This.opcalc this.result.pop (), this.suffix[i), This.result.pop ()));
        }
      At this point, there is only one value in the result set, that is, return
       this.result[0];
    }

In fact, in the implementation of the time will find that infix, suffix is just a difficult point, more complex place is the whole calculator state changes (or data changes)

In this simple calculator, there are numbers (0-9), operators (+-*/), operations (remove delete), pre operation (percent semicolon squared), decimal point, real-time operation and other data and operations

It's even more complicated if it's a science calculator, so it's critical to sort out how to control these things, and the most important one is the construction and storage of infix expressions.

When the continuous click + number, is not in line with the actual operation, so need a variable lastval to record the previous value, as the operation and update, and then pass judgment, prevent the program error

After clicking the = number, we can continue to use this result for operation, or restart the operation

Constructs infix expression
    buildinfix:function (Val, type) {
      //Direct click equals operation,
      if (this.calcdone) {
        This.calcdone = False ;
        Click the number again to proceed with the new Operation
        if (!this.isop (val)) {
          this.resetdata ();
        }
        Then click the operator to continue the operation with the current result value
        else {
          var re = this.result[0];
          This.resetdata ();
          This.infix.push (re);
        }

      var newval;
       ...

Click Delete, delete a number, not directly delete a number, and then update the value of infix expression

      Delete operation
      if (type = = ' del ') {
        newval = This.infix.pop ();
        Delete the end of a number
        newval = Math.floor (NEWVAL/10);
        if (newval) {
          this.infix.push (newval);
        }

        This.lastval = this.infix[this.infix.length-1];
        return this.infix;
      }  

Adding operations, you need to consider more, such as continuous continuous operators, consecutive numbers, operators +-the number of positive negative, access to the decimal point of the connection and so on

      Add operations, you first have to determine whether the operator repeats
      else if (type = = ' Add ') {
        ///Two consecutive operators
        if (This.isop (val) && This.isop ( This.lastval)) {return
          this.infix;
        }
        Two consecutive numbers
        else if (!this.isop (val) &&!this.isop (This.lastval)) {
          newval = This.lastval * + val;
          This.infix.pop ();
          This.infix.push (this.lastval = newval);

          return this.infix;
        }
        First digital positive negative
        if (!this.isop (val) && this.infix.length = 1 && (This.lastval = = ' + ' | | this.lastval = = = '-') {
          newval = This.lastval = = ' + '? val:0-Val;
          This.infix.pop ();
          This.infix.push (this.lastval = newval);

          return this.infix;
        }


        This.infix.push (This.lastval = val);
        return this.infix;
      }

In many cases, the calculator needs to be done in real time, to simplify the code, can be encapsulated into a method, in the appropriate position to call

    Immediate Operation
    Calculate:function (type) {
      this.infix2suffix ();
      var suffixre = This.calcsuffix ();

      if (suffixre) {this
        . $out. Text (' = ' + suffixre)
          . attr (' title ', Suffixre)
          . Removeclass (' active ');

        If it is shown directly to be equal to operation if
        (type = = ' eq ') {this
          . $in. Removeclass (' active ');
          this. $out. addclass (' active ');
          Set tag: Calculation is currently displayed
          This.calcdone = true;
          This.lastval = suffixre;
          Set History
          var history = This.infix.join (') + ' = ' + suffixre;
          this. $history. Text (History). attr (' title ', history);
        }

      }
    ,

The remaining is the processing process after the click, that is, all kinds of call processing transfer data-> construction infix processing data-> infix suffix-> suffix operation display

Like clicking on a number

    Number: 0-9
          if (!isnan (parseint (val)) {
            //build infix expression and display
            var infixre = That.buildinfix (parseint (Val, 10), ' Add ');
            That $in. Text (Infixre.join (")). AddClass (' active ');

            That.calculate ();

            return;
          }

Like a couple of operations, but they're pretty much the same.

       Pre-operation: percent, decimal, squared
          else if ([' per ', ' dot ', ' sq '].indexof (action)!==-1) {
            if!that.infix.length | | that.isop (THA T.lastval)) {return
              ;
            }

            if (action = = ' per ') {
              that.lastval/=
            } else if (action = = ' sq ') {
              that.lastval *= that.lastval;
            else if (action = = ' dot ') {
              //That.curdot = true;
            }

            Re-construct infix expression
            var infixre = That.buildinfix (that.lastval, ' change ');
            That $in. Text (Infixre.join (")). AddClass (' active ');

            That.calculate ();
          }

The above is the implementation of this simple calculator steps, too much change does not guarantee that there will be no mistakes

The basic logic is so, if you want to add the decimal point operation, parentheses operation, sine and other scientific calculator functions, or to achieve it yourself. Brain big AH.

$ (function () {function Calculator ($dom) {this. $dom = $ ($dom);
    Historical operations this. $history = this. $dom. Find (' calc-history ');
    Input area this. $in = this. $dom. Find (' calc-in ');
    Output area this. $out = this. $dom. Find (' calc-out ');

    this. $operation =-$dom. Find (' calc-operation ');
    Operator mappings This.op = {' Plus ': ' + ', ' minus ': '-', ' mul ': ' * ', ' div ': '/'};

    This.oparr = [' + ', '-', ' * ', '/'];
    infix expression this.infix = [];
    Suffix expression this.suffix = [];
    Suffix expression operation result set This.result = [];
    Store the nearest value This.lastval = 0;
    is currently calculated equal to completion this.calcdone = FALSE;

    The correction This.curdot = False that the decimal point (.) correlation value is currently being performed;
  This.init ();
    } Calculator.prototype = {constructor:calculator,//Initialize Init:function () {this.bindevent ();

      },//Binding event Bindevent:function () {var = this;
        $operation. On (' click ', Function (e) {e = e | | window.event; var elem = E.target | |

        E.srcelement, Val, action;
          if (Elem.tagname = = ' TD ') {val = Elem.getattribute (' data-val ') | | elem.getattribute (' DATA-AC '); Number: 0-9 if (!isnan (parseint (Val, 10)) {//build infix expression and display var infixre = That.buildinfix (P
            Arseint (Val, N), ' Add ');

            That $in. Text (Infixre.join (")). AddClass (' active ');

            That.calculate ();
          Return

          action = Val;
              Action: Purge, delete, compute equals if ([' CLS ', ' del ', ' EQ '].indexof (Action)!==-1) {if (!that.infix.length) {
            Return }//Empty data if action = = ' CLS ' | | (Action = = ' del ' && That.calcdone)]
              {that. $in. Text (");

              that. $out. Text (");
            That.resetdata (); }//Clear else if (action = = ' del ') {//re-construct infix expression var infixre = that.b Uildinfix(That.op[action], ' del ');

              That $in. Text (Infixre.join (")). AddClass (' active ');

            That.calculate ();

            }//Equals else if (action = = ' eq ') {that.calculate (' eq ');  }//Pre-operation: percent, decimal, squared else if ([' per ', ' dot ', ' sq '].indexof (action)!==-1) {if (!that.infix.length | | that.isop (THAT.LASTVAL))
            {return;
            } if (action = = ' per ') {that.lastval/= 100;
            else if (action = = ' sq ') {that.lastval *= that.lastval;
            else if (action = = ' dot ') {//That.curdot = true;
            //re-construct infix expression var infixre = That.buildinfix (that.lastval, ' change ');

            That $in. Text (Infixre.join (")). AddClass (' active ');
          That.calculate (); }//Operator: +-*/else if (That.isop (That.op[action])) {if (!tHat.infix.length && (that.op[action] = = = ' * ' | | | that.op[action] = = = '/') {return;
            var infixre = That.buildinfix (That.op[action], ' add ');
          That $in. Text (Infixre.join (")). AddClass (' active ');
    }
        }
      });
      }, Resetdata:function () {this.infix = [];
      This.suffix = [];
      This.result = [];
      This.lastval = 0;
    This.curdot = false; },//build infix expression buildinfix:function (val, type) {//Direct click equals operation, if (This.calcdone) {this.cal
        Cdone = false;
        Click the number again to proceed with the new operation if (!this.isop (val)) {this.resetdata ();
          //Click operator, then continue with the current result value else {var re = this.result[0];
          This.resetdata ();
        This.infix.push (re);

      } var newval;
        Delete operation if (type = = ' del ') {newval = This.infix.pop ();
   Delete the end of a number newval = Math.floor (NEWVAL/10);     if (newval) {This.infix.push (newval);
        } this.lastval = this.infix[this.infix.length-1];
      return this.infix; }//Add operation, first to determine whether operator repeats else if (type = = ' Add ') {//two consecutive operators if (This.isop (val) && th
        Is.isop (This.lastval)) {return this.infix; }///two consecutive number else if (!this.isop (val) &&!this.isop (This.lastval)) {newval = This.lastv
          Al * + val;
          This.infix.pop ();

          This.infix.push (this.lastval = newval);
        return this.infix; }//First digit positive negative if (!this.isop (val) && this.infix.length = 1 && (This.lastval = = ' + ' | | th
          Is.lastval = = ")" {newval = This.lastval = = ' + '? val:0-Val;
          This.infix.pop ();

          This.infix.push (this.lastval = newval);
        return this.infix; }//TODO: decimal Arithmetic//if (This.isop (val)) {//This.curdot = False;
      ////decimal point//if (THIS.CURDOT) {//var Dotlen = 0;
      newval = This.infix.pop ();
      Dotlen = Newval.tostring (). Split ('. '); Dotlen = dotlen[1]?

      dotlen[1].length:0;
      newval + = Val/math.pow (Dotlen + 1);

      Fixed decimal point operation exact value//newval = parsefloat (newval.tofixed (Dotlen + 1));
      This.infix.push (this.lastval = newval);
      return this.infix;
        } this.infix.push (This.lastval = val);
      return this.infix;
        }//change operations, such as% of the pre-operation else if (type = = ' changes ') {This.infix.pop ();

        This.infix.push (This.lastval = val);
      return this.infix;
    },//Determine if Operator isop:function (OP) {return op && this.opArr.indexOf (OP)!==-1; Priorhigher:function (A, B) {return (a = = = ' + ' | | a = = = ') && (b = = ' * '
    '/'); },//Operator Operations opCalc:function (b, op, a) {return op = = ' + '? A + B:op = = '-'? A-b: op = = ' *'
        ? A * B:op = = '/'?
    A/b: 0;
      },//Immediate operation Calculate:function (type) {This.infix2suffix ();

      var suffixre = This.calcsuffix (); if (suffixre) {this. $out. Text (' = ' + suffixre). attr (' title ', Suffixre). Removeclass (' active ')

        ;
          If it is shown directly to be equal to operation if (type = = ' eq ') {this. $in. Removeclass (' active ');
          this. $out. addclass (' active ');
          Set tag: Calculation is currently displayed This.calcdone = true;
          This.lastval = Suffixre;
          Set history var history = This.infix.join (') + ' = ' + suffixre;
        this. $history. Text (History). attr (' title ', history);
      }},//infix expression suffix infix2suffix:function () {var temp = [];

      This.suffix = [];
 for (var i = 0; i < this.infix.length; i++) {       Numerical value, direct pressure into the if (!this.isop (this.infix[i))) {This.suffix.push (this.infix[i]);
          } else {if (!temp.length) {Temp.push (this.infix[i]);
            else {var optop = temp[temp.length-1]; Loops determine the precedence of operators, and push the operator higher into the suffix expression if (!this.priorhigher (Optop, This.infix[i]) {while Temp.length &
                amp;&!this.priorhigher (Optop, This.infix[i])) {This.suffix.push (Temp.pop ());
              Optop = Temp[temp.length-1];
          The current operator is also pressed into the suffix expression temp.push (this.infix[i]);
      The remaining operation symbol is pressed into while (temp.length) {This.suffix.push (Temp.pop ());

      }},//suffix expression evaluates calcsuffix:function () {this.result = [];
          for (var i = 0; i < this.suffix.length i++) {//numeric value, direct pressure into result set if (!this.isop (this.suffix[i)) { This.result.push (thIs.suffix[i]); The//operator, take two items out of the result set, and place the result of the operation in the result set else {This.result.push (This.opcalc (This.result.pop), this.
        Suffix[i], This.result.pop ());
    There is only one value in the result set at this time, that is, return this.result[0 for the result;

  }
  };
New Calculator ('. Calc-wrap ');
 });

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.