在JavaScript中使用`eval`时处理`return false`

时间:2011-10-04 04:39:44

标签: javascript eval

我正在处理一种情况,我需要将jQuery事件绑定到页面以处理通过JSF生成的UI更新。唉,JSF糟透了,它坚持在所有事情上点击活动,这会抢占我的任何jQuery工作。

感谢SO的优秀人员,我找到了解决方案:

mixing my jQuery click events with existing object's onclick attribute

逻辑是:

  • 在页面加载时,抓取所有onclick属性并将它们存储在变量中。
  • 绑定我的jQuery事件
  • 在我自己的jQuery事件之后,我可以eval原始的onclick:eval(onclickValueVariable)

这在我的所有虚拟onclick事件测试中都有用。

但是那个实时JSF页面失败了。问题是所有的onclick都以'return false'结束,这导致了这个错误:

return not in function

例如:

<div class="uglyJSFcreatedTag" onclick="console.log('hey');return false">

jQuery会解雇它:

var $jsfTag = $('.uglyJSFcreatedTag');
var cacheOnclick = $jsfTag.attr(onclick);
$jsfTag.removeAttr('onclick');

...bunch of logic here to decide if the inline onclick should fire and, if so...

eval(cacheOnclick)

问题是return false。看起来在射击eval时无法返回任何内容。

有解决方案吗?我想我可以将值作为字符串并进行字符串解析以删除所有返回false,然后从脚本本身调用它。但这听起来有点混乱。有更优雅的解决方案吗?

如果没有,我应该在调用eval之前过滤掉哪些特定的JS语句?

2 个答案:

答案 0 :(得分:6)

两个选项:

1。使用当前的方法,只需在评估之前用函数包装onclick字符串。存储结果,并将其作为函数调用。请务必使用相应的this上下文调用它:

var f = eval("(function(){ "+cacheOnclick+"})");
f.call($jsfTag[0]);

注意:函数声明周围的括号()在eval中是 required 。这使得声明成为一个表达式(从语法上讲),从而使它在eval中合法化。

2。而不是抓取onclick 属性,从dom元素本身获取实际函数。另外,除非你需要对你的代码中的jsf处理函数做一些特别的事情,我建议你直接将JSF函数添加为jquery click处理程序,而不是从你的代码中明确地调用它:

var $jsfTag = $('.uglyJSFcreatedTag');
$jsfTag.bind('click', $jsfTag[0].onclick);
$jsfTag.removeAttr('onclick');

就个人而言,我会采用方法#2,但任何一方都应该工作。


更新:以下是选项#2的附加说明:

var $jsfTag = $('.uglyJSFcreatedTag');

这是你的例子 - 我们使用jquery来检索一个包含所有带有类名'uglyJSFcreatedTag'的元素的集合。

$jsfTag.bind('click', $jsfTag[0].onclick);

这将从集合($jsfTag[0])中获取第一个元素,并获取该元素对象的onclick属性。 .onclick是一个javascript属性,包含对浏览器根据“onclick”属性的字符串内容生成的已编译函数的引用。现在,由于我们有处理函数,我们可以使用jquery bind() function将它直接绑定到jquery click事件。

$jsfTag.removeAttr('onclick');

最后,我们只删除该属性。这没关系,因为我们已经通过jquery绑定了这个函数。如果我们不将它从“旧式”onclick中删除,那么它将被调用两次。

注意:您可能已经注意到上述代码仅适用于所选集合中的第一个元素。对于你的集合包含多个元素的极有可能的情况,你需要循环遍历集合并分别处理每个元素。以下是您将如何做到这一点:

var $jsfTag = $('.uglyJSFcreatedTag');
$jsfTag.each( function(idx, element) {
    $(element).bind('click', element.onclick).removeAttr("onclick");
});

如果你想跳过某些元素的jsf处理程序,那么在“each loop”中插入逻辑来测试它,并跳过调用以相应地绑定。


如果您必须继续从您的点击处理程序中调用jsf处理程序,那么至少考虑使用element.onclick而不是$(element).attr('onclick')。后者需要eval,而前者则不需要。

答案 1 :(得分:4)

我认为将代码包装在匿名函数中并立即调用它应该比过滤掉return语句更容易。

evalCode = "function() {" + evalCode + "}()";