2012-05-14 4 views
5

python: make a variable equal an operator (+,/,*,-)Есть ли способ сделать оператор сравнения переменной?

У меня есть код, в котором пользователь может выбрать тип сравнения для запуска и значение для сравнения. Я хотел бы знать, есть ли способ в 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 

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

+0

Нет, вы не можете сделать это в JS –

ответ

10

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

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 создатель: @Jesse.

+2

Вот jsFiddle, демонстрирующий это: http://jsfiddle.net/jonypawks/Cq8Hd/ – Jesse

+0

Почему downvote? –

+0

Кто знает? Это приятное, элегантное решение, которое работает лучше, чем коммутатор. Я использую подобный метод переключения между представлениями в моем приложении. –

4

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

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

Весь вход злой, пока не будет доказано обратное.

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

Учитывая эти недостатки 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) 

Edit: Demo с тестом Джесси включены: http://jsfiddle.net/99eP2/

+0

Вы никогда не должны использовать eval. – Jesse

+0

Если какое-либо из этих значений предоставлено пользователем, он может выполнить все ... –

+0

@ Джесс, пожалуйста, объясните, почему вы не должны использовать eval? – Esen

-1

Поскольку код @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> 
+1

Я протестировал свой код (http://jsfiddle.net/YrQ4C/) в Firefox, Chrome на Linux, а также на Windows, а также на IE8, и работает на всех трех браузерах. Какой браузер вы использовали, когда мой код не работал для вас? Какую ошибку вы получили в консоли JavaScript? –

+0

вы отредактировали свой ответ. ваша предыдущая версия имела этот код. Попробуйте и скажите, работает ли это во всех браузерах. Если бы я видел ваше редактирование, я бы не опубликовал обновленную версию. Если это вас раздражало и уменьшило голос, то большое вам спасибо. Функция сравнения (a, b, op) { if (eval (a + op + b)) do_something() } – Esen

+1

Если вы проверите мой текущий код, у него есть код, который вы указываете 'if (eval (a + op + b)) doSomething(); '. Это тот же код, который присутствовал в моем первом неполном ответе. Позже я добавил только добавленные проверки безопасности, чтобы убедиться, что решение завершено. Вы все еще не сказали мне, какой браузер не смог выполнить 'if (eval (a + op + b)) doSomething();'. Этот код в моем текущем решении выполняется во всех трех браузерах. –

Смежные вопросы