有没有办法使比较运算符成为变量

Is there a way to make a comparison operator a variable?

本文关键字:变量 运算符 比较 有没有      更新时间:2023-09-26

类似于python:使变量等于运算符(+,/,*,-(

我有一些代码,用户可以在其中选择要运行的比较类型,以及要比较的值。我很想知道Javascript中是否有任何方法可以将用户提供的比较值转换为实际的比较,从而允许我执行以下操作:

if (user_val user_comparison other_val) {
    do_something();
}

而不必执行以下操作:

if (user_comparison = '<') {
    if (user_val < other_val) {
        do_something();
    }
else if (user_comparison = '<=') {
    if (user_val <= other_val) {
        do_something();
    }
....etc

请注意,如果匹配任何比较,将执行相同的代码。

不,这是不可能的。但是你可以用更好的方式构建你的代码。例如,您可以有一个查找表:

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

后来:

if(operator_table[user_comparison](user_val, other_val)) {
    // do something
}

当然,当表中不存在user_comparison时,您也应该处理这种情况。

这些还使您能够更好地控制允许和不允许的运算符。

这是@Jesse创建的演示

假设您正在正确检查用户提供的操作数和运算符,以确保它们包含您想要的数据而不是其他 javascript 可执行代码,您可以将这两个操作数与中间的运算符连接起来,并将其提供给eval()以使其执行。

现在,eval()危险,因为它可以执行任何JavaScript代码。用户可以作为操作员提供可执行的和可能的恶意JavaScript代码,eval()会对其进行评估。因此,在执行串联时,应在验证操作数是否安全后执行此操作。为了强调这一点,我将用大字体写下计算机安全最重要的原则之一:

所有输入都是邪恶的,除非另有证明。

另外,请注意,eval()调用 JavaScript 解释器来解释、编译和执行您的代码。这很慢。虽然如果您只是偶尔使用 eval(),您可能不会注意到任何可观察到的性能问题,但如果您非常频繁地调用eval(),例如,在每个 keyevent 上,您可能会注意到性能问题。

考虑到eval()的这些缺点,您可能希望选择更整洁的解决方案,例如Felix Kling发布的解决方案。但是,也可以使用eval()以安全的方式解决此问题,如下所示:

function compare(a, op, b)
{
  // Check that we have two numbers and an operator fed as a string.
  if (typeof a != 'number' || typeof b != 'number' || typeof op != 'string')
    return
  // Make sure that the string doesn't contain any executable code by checking
  // it against a whitelist of allowed comparison operators.
  if (['<', '>', '<=', '>=', '==', '!='].indexOf(op) == -1)
    return
  // If we have reached here, we are sure that a and b are two integers and
  // op contains a valid comparison operator. It is now safe to concatenate
  // them and make a JavaScript executable code.
  if (eval(a + op + b))
    doSomething();
}

请注意,根据白名单验证输入几乎总是比根据黑名单验证输入更好的主意。有关它的简要讨论,请参阅 https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#White_List_Input_Validation。

以下是此解决方案的演示: http://jsfiddle.net/YrQ4C/(下面还复制了代码(:

function doSomething()
{
  alert('done something!')
}
function compare(a, op, b)
{
  if (typeof a != 'number' || typeof b != 'number' || typeof op != 'string')
    return
  if (['<', '>', '<=', '>=', '==', '!='].indexOf(op) == -1)
    return
  if (eval(a + op + b))
    doSomething();
}
// Positive test cases
compare(2, '<', 3)
compare(2, '<=', 3)
// Negative test cases
compare(2, '>', 3)
compare(2, '>=', 3)
// Attack tests
compare('alert(', '"attack!"', ')')
// Edit: Adding a new attack test case given by Jesse
// in the comments below. This function prevents this
// attack successfully because the whitelist validation
// for the second argument would fail.
compare(1, ';console.log("executed code");2==', 2)

编辑:杰西测试用例的演示包括:http://jsfiddle.net/99eP2/