Evaluate the equation in Javascript, without eval ()

I have a bunch of fields on a web page (150+) that must have equations on them to get the result.

I am currently saving the equation as follows:

<input name="F7" type="text" class="numeric" data-formula="([C7]-[D7])/[E7]" readonly /> 

When the input is blurry, I use the jQuery selector to iterate over all the inputs with the data-formula attribute, accept the formula, and use the regular expression to replace the pointers ( [C7] in the equation) with their corresponding values.

After that, I will eval() equation to get the result, and put it in the correct input. This works fine, but very slow and causes the webpage to hang for a few seconds, which is bad if it happens every time the input is blurred.

Is there a way to evaluate an equation like "(1-2) / 4" without using eval() ? These equations can also have functions like the square root (which makes eval() nice, as I can just put Math.sqrt() in the formula), and the numbers can be decimal.

Note. This application should work on IE7 and 8, so I do not believe that I can use Webworkers or something like that. I also only considered running this code after clicking the "Save" button, but I would prefer the user interface to update live if possible

+4
source share
6 answers

I really know only two alternatives: you need to use a script element that is dynamically written to the page, for example:

 function evaluate(formula) { var script = document.createElement("script"); script.type = "text/javascript"; script.text = "window.__lr = " + formula + ";"; document.body.appendChild(script); document.body.removeChild(script); var r = window.__lr; return r; } 

Another would be to use new Function(...) :

 function evaluate3(formula) { var func = new Function("return " + formula); return func(); } 

But I don’t think you will find something that gives similar performance with eval : http://jsperf.com/alternative-evaluation

The performance of eval depends on browsers and platforms, do you have a specific browser / platform combination? New javascript engines in improved browsers will offer optimized eval :

Test results

This is just a limited test suite for several UAs, but it should give you an idea of ​​how it works in different environments.

+3
source

Is there a way to evaluate an equation such as "(1-2) / 4" without using eval() ?

Well, you can tokenize the expression and write your own evaluator that mimics what eval does. But although this may be useful in terms of limiting side effects (since eval is a very large hammer), it is extremely unlikely to work better than eval .

However, you can make the cache the result of evaluating all the other inputs so that you only evaluate the actual fuzzy input. It must be really effective.

For example, suppose you have this global object:

 var values = { A7: /* initial value for A7 */, B7: /* initial value for B7 */, C7: /* initial value for C7 */, D7: /* initial value for D7 */, E7: /* initial value for E7 */, F7: /* initial value for F7 */, /* etc */ }; 

... and then bind this blur handler to all inputs:

 $("input").blur(function() { values[this.id] = this.value; // Or parseInt(this.value, 10), or parseFloat(this.value), etc. doTheEvaluation(); }); 

... where doTheEvaluation used the values ​​from values , rather than recounting all of them each time.

If this.value can reference other fields, you can do a recursive evaluation of this - but without evaluating all of your inputs.

+4
source

Validation: I would write a strong regular expression to validate input, and then use eval to evaluate it if it is safe.

Evaluation: Regarding the speed of eval: if this is a big problem, you can queue all the equations (save them in an array) and evaluate them all at once:

 var equations = ['1+1', '2+2', '...']; //<-- Input from your fields var toBeEvald = '[' + equations.join(',') + '];'; var results = eval(toBeEvald); // result[0] = 2 // result[1] = 4, etc 
+1
source

I would modify your code to execute only one eval.

 var expressions = [] // for each field // expressions.push("id:" + parsedExpression); var members = expressions.join(","); var resultObj = eval("({" + members + "})"); // for each field document.getElementById(id).value = resultObj[id]; 
+1
source

If you have a reliable Internet connection, you can connect to Google and use your services to evaluate your expression. Google has a pretty powerful server, and all you have to do is send a request with the queue, which is the equation, and get it. Of course, it can be slower or faster depending on the speed of the Internet / speed of the browser.

Or you can write your own equation evaluator. This is quite complicated and probably won't be more efficient than eval. You will also have to go through a huge PEMDAS order issue.

I suggest you combine the equations together in one line, and eval that all at once, and get the results all at once.

0
source

You can use new Function to evaluate your expressions.

0
source

All Articles