7

类似于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

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

4

3 回答 3

16

No that is not possible. But you can structure your code in a better way. For example you can have a lookup table:

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

and later:

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

Of course you should also handle the case when user_comparison does not exist in the table.

These also gives you a better control over allowed and not allowed operators.

Here is a DEMO create by @Jesse.

于 2012-05-14T21:29:25.783 回答
5

Assuming that you are checking the user provided operands and operators properly to ensure that they contain the data you want instead of other javascript executable code, you can concatenate the two operands with the operator in between and feed it to eval() to get it executed.

Now, eval() is dangerous because it can execute any JavaScript code. The user can feed executable and possibly malicious JavaScript code as the operator and eval() would evaluate it. Therefore, when you do the concatenation, you should do it after validating that the operand is safe. To stress this point, I'll write one of the most important tenets of computer security in large fonts:

All input is evil until proven otherwise.

Also, note that eval() calls the JavaScript interpreter to interpret, compile and execute your code. This is slow. While you may not notice any observable performance issue if you are just using eval() once in a while, you may notice performance issues if you are calling eval() very frequently, say, on every keyevent.

Considering these drawbacks of eval(), you might want to go for a neater solution like the one posted by Felix Kling. However, it is also possible to solve this problem using eval() in a safe manner as shown below:

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

Note that validating the input against a whitelist is almost always a better idea than validating it against a blacklist. See https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#White_List_Input_Validation for a brief discussion on it.

Here is a demonstration of this solution: http://jsfiddle.net/YrQ4C/ (Code also reproduced below):

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)

Edit: Demo with Jesse's test case included: http://jsfiddle.net/99eP2/

于 2012-05-14T21:27:47.893 回答
-2

由于@Susam Pal 代码不起作用。我正在发布一个工作版本

<html>
  <head>
   <script>
       function CompareSomething(val1, compareString, val2) {  
           eval('if(' + val1 + ' ' + compareString + ' ' + val2 + '){conditionPassed();}else{conditionFailed();}'); 
  }
  function compare(a, op, b) { 
      if (eval(a + op + b))
          conditionPassed();
      else
         conditionFailed();
  }
  function conditionPassed() {
      alert('condition passed');
  }
  function conditionFailed() {
      alert('condition failed');
  }
    </script>
  </head> 
<body>
a:<input id='txt1' type="text" />&nbsp;op:<input id='txt2' type="text" />&nbsp;b:<input id='txt3' type="text" /><br/>
<button id='compare'  onclick='CompareSomething(document.getElementById("txt1").value,document.getElementById("txt2").value,document.getElementById("txt3").value)'>Compare Esen Method</button><br/>
<button id='compare'  onclick='Compare(document.getElementById("txt1").value,document.getElementById("txt2").value,document.getElementById("txt3").value)'>Compare Susam Method</button>
  </body>
 </html>
于 2012-05-14T21:37:42.523 回答