I am currently writing a JS rules engine which at one point needs to evaluate boolean expressions using the eval() function.
Firstly I construct an equation as such:
var equation = "relation.relatedTrigger.previousValue" + " " + relation.operator +
" " + "relation.value";
relation.relatedTrigger.previousValue is the value I want to compare.
relation.operator is the operator (either "==", "!=", <=, "<", ">", >=").
relation.value is the value I want to compare with.
I then simply pass this string to the eval function and it returns true or false as such:
return eval(equation);
This works absolutely fine (with words and numbers) or all of the operators except for >= and <=. E.g. When evaluating the equation:
relation.relatedTrigger.previousValue <= 100
It returns true when previousValue = 0,1,10,100 & all negative numbers but false for everything in between.
I would greatly appreciate the help of anyone to either answer my question or to help me find an alternative solution.
Regards,
Augier.
P.S. I don't need a speech on the insecurities of the eval() function. Any value given to relation.relatedTrigger.previousValue is predefined.
edit: Here is the full function:
function evaluateRelation(relation)
{
console.log("Evaluating relation")
var currentValue;
//if multiple values
if(relation.value.indexOf(";") != -1)
{
var values = relation.value.split(";");
for (x in values)
{
var equation = "relation.relatedTrigger.previousValue" + " " + relation.operator +
" " + "values[x]";
currentValue = eval(equation);
if (currentValue)
return true;
}
return false;
}
//if single value
else
{
//Evaluate the relation and get boolean
var equation = "relation.relatedTrigger.previousValue" + " " + relation.operator +
" " + "relation.value";
console.log("relation.relatedTrigger.previousValue " + relation.relatedTrigger.previousValue);
console.log(equation);
return eval(equation);
}
}
Answer: Provided by KennyTM below. A string comparison doesn't work. Converting to a numerical was needed.
eval() is a dangerous function, which executes the code it's passed with the privileges of the caller. If you run eval() with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension.
Malicious code : invoking eval can crash a computer. For example: if you use eval server-side and a mischievous user decides to use an infinite loop as their username. Terribly slow : the JavaScript language is designed to use the full gamut of JavaScript types (numbers, functions, objects, etc)… Not just strings!
An alternative to eval is Function() . Just like eval() , Function() takes some expression as a string for execution, except, rather than outputting the result directly, it returns an anonymous function to you that you can call. `Function() is a faster and more secure alternative to eval().
The eval server command has been deprecated since MongoDB 3.0 and is definitely not recommendable for performance or security reasons.
You didn't show how relation.relatedTrigger.previousValue
is obtained, but I guess the type of this variable is still a string. In this case, the right hand side will be treated as a string instead. A string comparison matches all characteristics you mentioned:
>>> '-213' <= '100'
true
>>> '0' <= '100'
true
>>> '1' <= '100'
true
>>> '2' <= '100'
false
>>> '10' <= '100'
true
>>> '13' <= '100'
false
You need to make sure relation.relatedTrigger.previousValue
is a number. One solution is use the unary + operator in the comparison, e.g.
+relation.relatedTrigger.previousValue <= 100
This has nothing to do with eval
. The problem is the overly liberal implicit conversion in Javascript.
Edit: By the way, instead of eval, you could use a dictionary of functions instead. This is faster and also safer. See http://jsperf.com/eval-vs-function-map.
var fmap = {
'>=': function(a, b) { return a >= b; },
...
};
fmap[relation.operator](+relation.relatedTrigger.previousValue,
+relation.value);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With