有没有办法使比较运算符成为变量? [复制]
Posted
技术标签:
【中文标题】有没有办法使比较运算符成为变量? [复制]【英文标题】:Is there a way to make a comparison operator a variable? [duplicate] 【发布时间】:2012-05-22 09:42:27 【问题描述】:类似于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
请注意,如果任何比较匹配,将执行相同的代码。
【问题讨论】:
不,你不能在 JS 中这样做 【参考方案1】:因为@Susam Pal 代码不起作用。我正在发布一个工作版本
<html>
<head>
<script>
function CompareSomething(val1, compareString, val2)
eval('if(' + val1 + ' ' + compareString + ' ' + val2 + ')conditionPassed();elseconditionFailed();');
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" /> op:<input id='txt2' type="text" /> 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>
【讨论】:
我已经在 Firefox、Linux 上的 Chrome 以及 Windows 以及 IE8 中测试了我的代码 (jsfiddle.net/YrQ4C),它适用于所有三种浏览器。当我的代码不适合您时,您使用了哪个浏览器?您在 JavaScript 控制台中遇到了什么错误? 您已编辑您的答案。你的早期版本有这个代码。试试看,告诉我这是否适用于所有浏览器。如果我看到你的编辑,我就不会发布更新版本。如果这让您感到恼火并减少投票,那么非常感谢您。 function compare(a, b, op) if (eval(a + op + b)) do_something() 如果你检查我当前的代码,它有你提到的代码if (eval(a + op + b)) doSomething();
。这与我的第一个不完整答案中的代码相同。后来,我只添加了安全检查,以确保解决方案是完整的。你还没有告诉我哪个浏览器执行失败if (eval(a + op + b)) doSomething();
。我当前解决方案中的这段代码在所有三个浏览器中执行。
@SusamPal 为简单起见,我已将您的版本和我的版本添加到一个简单的 html 页面中。对任何浏览器进行测试,并告诉我这是否仍然适合您。要么我错过了一些东西,要么你错过了一些东西。顺便说一句,您的代码在 IE、Firefox、Chrome 中不起作用
这是我在没有额外安全检查的情况下发布的第一个代码:jsfiddle.net/BCdcv。当您说它不起作用时,这一定是您所指的代码。但是,这段代码在 Firefox、Chrome 和 IE 上对我来说都很好。 :) 我会再次问同样的问题。 “不起作用”是什么意思?您在 JavaScript 控制台中是否遇到任何错误?请提供“不起作用”的完整详细信息。【参考方案2】:
假设您正在正确检查用户提供的操作数和运算符以确保它们包含您想要的数据而不是其他 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)
编辑:包含 Jesse 测试用例的演示:http://jsfiddle.net/99eP2/
【讨论】:
如果用户提供了这些值中的任何一个,他可以执行任何操作... @Jesse 你能解释一下为什么你不应该使用 eval 吗? @FelixKling 我在回复中提到过: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 ...
@Jesse 这是一个演示,我在其中提供了您指定的参数:jsfiddle.net/99eP2。 console.log 语句没有被执行。我认为您错过了这样一个事实,即我的函数也在根据运算符的白名单检查运算符参数。您提供的第二个参数与此白名单不匹配,因此该函数将返回而不做任何事情。
@Jesse 当然,在我的第一篇文章之后,我一直在改进我的答案并填写更多细节,但是我的演示 URL (jsfiddle.net/YrQ4C) 包含了安全的 compare() 函数开始。输入验证的假设也从一开始就在帖子中明确提到。我同意使用对象查找更安全、更干净、更易于维护。但我的观点是,这个小问题也可以使用 eval() 以安全的方式解决,同时满足 OP 的要求。【参考方案3】:
不,那是不可能的。但是您可以以更好的方式构建您的代码。例如,您可以有一个查找表:
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 创建的DEMO。
【讨论】:
这是一个 jsFiddle 演示:jsfiddle.net/jonypawks/Cq8Hd 谁知道?这是一个不错的、优雅的解决方案,比开关好得多。我使用类似的技术在我的应用中的视图之间切换。 这很聪明!非常感谢,我没有意识到你可以做这样的事情 - 附加一个函数作为字典值 @lightstrike:在 JavaScript 中,函数是一等公民,这意味着您可以像对待任何其他值(字符串、数字等)一样对待它们。 @FelixKling,也许有人认为您的代码块与this answer 中的代码块过于相似。只是猜测。以上是关于有没有办法使比较运算符成为变量? [复制]的主要内容,如果未能解决你的问题,请参考以下文章