-1

I have a string expression like this 10/3*4-7 and I want to know if there is some type of javascript method that can convert the string into an actual expression so that I can get the answer . I have a function that randomly generates numbers and operators, and I want to get the result from the equation. However, the function that I created to get the result only does the calculation from left to right. It does not go by a operator priority, where * and / get calculated first and stuff like that. Is there something in javascript that can do that or would I have to create a function to do something like that?

black_yurizan
  • 407
  • 2
  • 7
  • 19

3 Answers3

3

I'd recommend using a library such as Math.js as this will parse the math expression using a regular expression. This will avoid opening the application up to Cross-site scripting (XSS) attacks.

var answer = math.eval('10/3*4-7');
console.log(answer);
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.6.0/math.min.js"></script>
Graham Walters
  • 2,054
  • 2
  • 19
  • 30
0

This function takes either a string expression, or an array of characters that create an expression.

function calculate(expression) {
  "strict mode";
 if(Array.isArray(expression))
  expression = expression.join("");
  var allowedChars = "1234567890%^*()-+/. ";
  for (var i = 0; i < expression.length; i++)
    if (allowedChars.indexOf(expression.charAt(i)) < 0)
      throw new Error("Invalid expression: unexpected '" + expression.charAt(i) + "' in '"+expression+"'");
  return eval(expression);
}

try{
 alert(calculate("4+4"));
 alert(calculate([7,"+",9,"/",34]));
 alert(calculate("45/3"));
 alert(calculate("100 * cheeseburger"));
}catch(e){
 alert(e.message);
}

Here's why this is safe:

  1. Improper use of eval opens up your code for injection attacks
    • In strict mode eval is not able to introduce new variables to the surrounding scope. (As it's at the end of it's own function, nothing else is happening in that scope anyway.)
    • The function will throw an error if any character is present which is not part of a mathematical expression, making injection impossible.
  2. With eval, debugging can be more challenging (no line numbers, etc.)
    • In this case the function throws an Error, which includes a line number. The eval'd code is only so a single line, so this is not relevant.
  3. eval'd code executes more slowly (no opportunity to compile/cache eval'd code)
    • In this case there is nothing to compile/cache, so this is not an issue.
I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116
-1

There is quite a discussion here on why you should not use eval() unless there are no clear alternatives. Using eval() in this case is completely unnecessary as shown in the example below:

var expression = "10/3*4-7";
var foo = Function('"use strict"; return '+expression);

console.log(foo());
Community
  • 1
  • 1
Tibrogargan
  • 4,508
  • 3
  • 19
  • 38
  • I don't know about "all broswers", but this mechanism has been in JavaScript for at least 19 years (since ECMA 1.0). I'd be surprised if there were any mainstream browsers that didn't support it – Tibrogargan Nov 04 '16 at 04:00
  • Function is JS standard and is supported in all browers. However it is insecure for literally the exact same reason as eval. There is no benefit to this over eval whatsoever. – I wrestled a bear once. Nov 04 '16 at 04:02
  • @Iwrestledabearonce using eval() will disable compiler optimization. – Tibrogargan Nov 04 '16 at 04:03
  • Compiler optimization? what are talking about? references, please. – I wrestled a bear once. Nov 04 '16 at 04:05
  • Oh I get it. You're parroting the selected answer in the question you linked to. I guess you thought `Function` would use magic instead of the interpreter to evaluate the string.. – I wrestled a bear once. Nov 04 '16 at 04:11
  • @Iwrestledabearonce. Actually, it's was from a discussion on another question that I've been trying to track down. I think I'll skip it, since you have all the answers – Tibrogargan Nov 04 '16 at 04:20
  • So is this method is just as dangerous as eval? – black_yurizan Nov 04 '16 at 04:34
  • As it turns out, not quite. But effectively yes. Found the reference I was looking for [here](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval). `eval()` (along with `Function()`, :/) cause the JS Engine to not do optimization of any code because it can't trust the results. `Function()` is marginally better because it's not lexically scoped. – Tibrogargan Nov 04 '16 at 04:38
  • @Iwrestledabearonce. `eval()` has access to the local scope and can modify local variables. `Function()` cannot, it's globally scoped not lexically scoped. – Tibrogargan Nov 04 '16 at 04:50
  • ok, i guess that's a point, though i'm not sure how relevant it is when one could simply put it in a closure and give it it's own scope.] – I wrestled a bear once. Nov 04 '16 at 04:59
  • Looks like math.js uses `Function()`, At least you should be guaranteed of reasonably clean expression. – Tibrogargan Nov 04 '16 at 05:04
  • @Iwrestledabearonce. It comes down to: Does putting `eval()` anywhere in your JS turn off the JS Engine optimizations for *everything*, or just the local scope? If it's just the local scope then sure - put it in a closure and you're good. If it's the entire file then use `Function()` – Tibrogargan Nov 04 '16 at 05:06
  • @Tibrogargan - I appreciate your argument because I'm learning things, however you should take a closer look at the article you linked to a few lines up. These "optimizations" are about bookmarking points in the code where there are variables, etc, for easy reference. They are not "compiler" optimizations as JS is script and is not compiled. Both Function and eval disable these "optimizations." And finally, none of these "optimizations" apply to the use-case at hand. No variables are being created, so there is no optimizations to be done anyway. – I wrestled a bear once. Nov 04 '16 at 12:56