6

我目前正在编写一个 JS 规则引擎,它有时需要使用 eval() 函数来评估布尔表达式。

首先,我构造一个等式:

var equation = "relation.relatedTrigger.previousValue" + " " + relation.operator +
        " " + "relation.value";

relationship.relatedTrigger.previousValue是我要比较的值。

relationship.operator是运算符(“==”、“!=”、<=、“<”、“>”、>=")。

relationship.value是我要比较的值。

然后我简单地将这个字符串传递给 eval 函数,它返回 true 或 false ,如下所示:

return eval(equation);

这绝对可以正常工作(使用单词和数字)或除 >= 和 <= 之外的所有运算符。例如,当评估方程时:

relation.relatedTrigger.previousValue <= 100

当 previousValue = 0,1,10,100 和所有负数时返回 true,但对于介于两者之间的所有内容返回 false。

我将非常感谢任何人帮助我回答我的问题或帮助我找到替代解决方案。

问候,

奥吉尔。

PS 我不需要关于 eval() 函数的不安全性的演讲。任何赋予relation.relatedTrigger.previousValue 的值都是预定义的。

编辑:这是完整的功能:

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);
}
}

答案:由下面的 KennyTM 提供。字符串比较不起作用。需要转换为数字。

4

3 回答 3

5

您没有显示如何relation.relatedTrigger.previousValue获得,但我猜这个变量的类型仍然是一个字符串。在这种情况下,右侧将被视为字符串。字符串比较匹配您提到的所有特征:

>>> '-213' <= '100'
true
>>> '0' <= '100'
true
>>> '1' <= '100'
true
>>> '2' <= '100'
false
>>> '10' <= '100'
true
>>> '13' <= '100'
false

你需要确保relation.relatedTrigger.previousValue是一个数字。一种解决方案是在比较中使用一元 + 运算符,例如

+relation.relatedTrigger.previousValue <= 100

这与eval. 问题是 Javascript 中过于自由的隐式转换。


编辑:顺便说一句,您可以使用函数字典代替 eval。这更快,也更安全。请参阅http://jsperf.com/eval-vs-function-map

var fmap = {
    '>=': function(a, b) { return a >= b; },
    ...
};

fmap[relation.operator](+relation.relatedTrigger.previousValue, 
                        +relation.value);
于 2012-09-21T09:26:59.947 回答
1

它是比较字符串而不是数字。

确保relation.relatedTrigger.previousValuerelation.value是数字。

"11"> "100":因为按字母顺序11排在后面。100

11 < 100 按数字顺序排列。

于 2012-09-21T09:34:32.153 回答
0
var relation = {'relatedTrigger':{'previousValue':"7"}, 'operator':'<=', 'value': "100"};

var equation = "parseFloat(relation.relatedTrigger.previousValue)" + " " + relation.operator + 
    " " + "parseFloat(relation.value)"; 

alert(equation + ", " + eval(equation));

这实际上是您最终得到的结果,并且确保数字值而不是字符串传递的额外步骤似乎有效。

于 2012-09-21T09:36:50.937 回答