Evil Eval的替代方案 - 关系运算符

mai*_*man 6 javascript eval

作为输入验证的一种形式,我需要强制一个字符串'9>6'来评估一个布尔值.

除了评估字符串,我似乎无法找到解决方法.

我一直都听说过eval的邪恶(特别是因为我正在验证表单输入),关于它可以评估任何脚本和性能问题的事实.

但....

我的案例中是否有任何替代方案(处理关系运算符)?

var arr = ['<9', '>2'];

var check = function (a) {

    return arr.every(function (x) {
            var string = '';

            string += a + x;

            try {
                return eval(string);
            } catch (e) {
                return false;
            }
        });
    };

console.log(check('3'))
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 2

我可以看到三件事需要改进:

  • a您应该直接引用变量,以便可以与值的真实形式进行比较,而不是对值进行字符串化并将其连接到表达式a。否则你可能会出现奇怪的行为。

    return eval("a " + x);
    
    Run Code Online (Sandbox Code Playgroud)
  • 由于您可能会check多次使用,因此您不应eval每次都调用(甚至每次调用多次)。您可以将字符串组成一个大&&表达式,甚至更好的是,您可以预先将条件编译为单个函数,这样您就根本不必eval从内部调用check

  • 您应该考虑使用Function构造函数而不是eval.

有了这些,您的代码可能如下所示:

var arr = ['<9', '>2'];

var check = new Function("a", "return "+arr.map(function(x) {
    return "a"+x;
}).join(" && ")+";");
console.log(check.toString()); // function anonymous(a) { return a<9 && a>2; }
console.log(check('3'));
Run Code Online (Sandbox Code Playgroud)

或这个:

var arr = ['<9', '>2'];
var fns = arr.map(function(x) {
    return new Function("a", "return a "+x+";");
});
function check(a) {
    return fns.every(function(f) {
        return f(a);
    });
}
console.log(check('3'));
Run Code Online (Sandbox Code Playgroud)

当然,我希望这arr不是由用户控制的(或者更糟糕的是,不是当前用户控制的);如果您希望用户输入这些条件,您应该确保明确将它们列入白名单,或者立即使用更复杂的表达式语法/解析器/评估器。
除非是这种情况,eval(或者就此而言,Function)并不完全是邪恶的,它只是缩短(并可能简化)您的代码。您也可以编写出成熟的函数(如 Nit 和 peterh 建议的那样)。