Есть ли способ сделать оператор сравнения переменной? [Дубликат]

На этот вопрос уже есть ответ:

Возможны ли переменные операторы? 6 ответов

Похожий на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

Обратите внимание, что в случае сопоставления любого сравнения будет выполнен тот же код.

 Zoltan Toth14 мая 2012 г., 23:24
нет, вы не можете сделать это в JS

Ответы на вопрос(3)

что вы проверяете предоставленные пользователем операнды и операторы должным образом, чтобы убедиться, что они содержат данные, которые вы хотите, вместо другого исполняемого кода javascript, вы можете объединить два операнда с оператором между ними и передать ихeval() чтобы его казнили.

В настоящее время,eval() является Опасно потому что он может выполнять любой код JavaScript. Пользователь может указать исполняемый и, возможно, вредоносный код JavaScript в качестве оператора иeval() оценил бы это. Поэтому, когда вы делаете конкатенацию, вы должны сделать это после проверки того, что операнд безопасен. Чтобы подчеркнуть этот момент, я напишу один из самых важных принципов компьютерной безопасности в больших шрифтах:

Все данные злые, пока не доказано обратное.

Также обратите внимание, чтоeval() вызывает интерпретатор JavaScript для интерпретации, компиляции и исполнения вашего кода. Это медленно. Хотя вы можете не заметить каких-либо заметных проблем с производительностью, если вы просто используетеeval() время от времени вы можете заметить проблемы с производительностью, если звонитеeval() очень часто, скажем, на каждом ключевом событии.

Рассматривая эти недостаткиeval(), вы, возможно, захотите найти более подходящее решение, подобное тому, которое опубликовал Феликс Клинг. Тем не менее, также можно решить эту проблему с помощью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_Validatio для краткого обсуждения.

Вот демонстрация этого решения: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

 Felix Kling14 мая 2012 г., 23:31
Если любое из этих значений предоставлено пользователем, он может выполнить что угодно ...
 Jesse14 мая 2012 г., 23:30
Ты никогда не должен использовать eval.
 Susam Pal15 мая 2012 г., 01:51
@ Jesse Конечно, я улучшал свой ответ и заполнял больше деталей после моего первого поста, но мой демонстрационный URL (jsfiddle.net/YrQ4C) содержал функцию безопасного сравнения () с самого начала. Предположение о проверке ввода также было явно упомянуто в посте с самого начала. Я согласен с тем, что использование поиска объектов безопаснее, чище и удобнее в обслуживании. Но я хочу сказать, что эту небольшую проблему можно решить с помощью eval () также безопасным способом, выполняя требования OP.
 Susam Pal15 мая 2012 г., 00:15
@ Jesse Вот демонстрация, где я привел аргументы, которые вы указали: Jsfiddle.net / 99eP2 Оператор console.log не выполняется. Я думаю, что вы упустили тот факт, что моя функция также проверяет аргумент оператора против белого списка операторов. Второй аргумент, который вы указали, не будет соответствовать этому белому списку, и поэтому функция вернется, ничего не делая.
 Susam Pal15 мая 2012 г., 00:39
Те, кто отрицает мое решение, не могли бы вы объяснить свое отрицательное мнение, предоставив хотя бы одну действительную атаку, которая работает против моей функции?
Решение Вопроса

это невозможно. Но вы можете структурировать свой код лучше. Например, у вас может быть таблица поиска:

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 не существует в таблице.

Это также дает вам лучший контроль над разрешенными и недопустимыми операторами.

Вот DEMO создать к@ Джесси.

 Felix Kling15 мая 2012 г., 16:52
@ lightstrike: В JavaScript функции являются гражданами первого класса, это означает, что вы можете обращаться с ними как с любым другим значением (строка, число и т. д.).
 lightstrike15 мая 2012 г., 16:02
Это очень умно! Большое спасибо, я не понимал, что вы могли бы сделать что-то подобное - прикрепить функцию в качестве значения словаря
 Brendan Delumpa15 мая 2012 г., 01:25
Кто знает? Это хорошее, элегантное решение, которое работает лучше, чем коммутатор. Я использую подобную технику для переключения между представлениями в моем приложении.
 Jesse14 мая 2012 г., 23:31
Вот пример jsFiddle, демонстрирующий это: Jsfiddle.net / jonypawks / Cq8Hd
 Felix Kling15 мая 2012 г., 00:15
Почему понижатель?

С @ 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>
 Esen15 мая 2012 г., 15:01
Вы отредактировали свой ответ. ваша предыдущая версия имела этот код. Попробуйте и скажите мне, работает ли это во всех браузерах. Если бы я видел ваши изменения, я бы не опубликовал обновленную версию. Если это вас разозлило и сократило голосование, тогда большое спасибо. функция сравнения (a, b, op) {if (eval (a + op + b)) do_something ()}
 Susam Pal15 мая 2012 г., 15:42
Если вы проверите мой текущий код, он содержит код, который вы упомянулиif (eval(a + op + b)) doSomething();. Это тот же код, который присутствовал в моем первом неполном ответе. Позже я добавил только добавленные проверки безопасности, чтобы убедиться, что решение завершено. Вы все еще не сказали мне, какой браузер не удалось выполнитьif (eval(a + op + b)) doSomething();. Этот код в моем текущем решении выполняется во всех трех браузерах.
 Susam Pal15 мая 2012 г., 00:08
Я проверил свой код Jsfiddle.net / YrQ4C) в Firefox, Chrome для Linux, а также Windows, а также IE8, и он работает во всех трех браузерах. Какой браузер вы использовали, когда мой код не работал для вас? Какую ошибку вы получили в консоли JavaScript?
 Esen15 мая 2012 г., 16:56
@ SusamPal для простоты я добавил вашу версию и мою версию на простую HTML-страницу. Проверьте это на любом браузере и скажите, работает ли он для вас. Либо я что-то упустил, либо вы что-то упустили. Кстати, ваш код не работает в IE, Firefox, Chrome
 Susam Pal15 мая 2012 г., 17:27
Это был мой первый код, который я разместил без дополнительных проверок безопасности: Jsfiddle.net / BCdcv Это должен быть код, на который вы ссылаетесь, когда говорите, что он не работает. Тем не менее, этот код прекрасно работает для меня на Firefox, Chrome, а также IE. :) Я хотел бы задать тот же вопрос еще раз. Что вы подразумеваете под "не работает"? Вы получаете какие-либо ошибки в консоли JavaScript? Пожалуйста, предоставьте полную информацию о "не работает".

Ваш ответ на вопрос