2011-08-03 101 views
1

我有一个Ajax调用,我将JavaScript作为字符串取回。在onSuccess方法中,我想要评估此代码。在JavaScript代码中有函数声明。所有这些功能都应该在eval之后可用。范围和评估说明

我做了一个尽可能小的例子。 (这个例子中的onFailure方法正在进行,因为在JFiddle中我无法成功实现Ajax调用)。

你可以在这里找到实例:http://jsfiddle.net/ubXAV/6/

你看到所有的浏览器工作的例子(不幸的是,这不会的jsfiddle在IE浏览器)。我标记了一些涉及以下问题的线条。下面的代码再次:​​

function evalScript(script) 
{ 
    that.eval(script); //1. 
} 

var that = this; 

// AJAX-Call - GadgetActionServlet 
new Ajax.Request("THISWILLFAIL.com", { 
    method: 'post', 
    onSuccess: function(ajaxResponse) { 
      alert("success"); 
    }, 
    onFailure: function(){ 
     var script = "{function sayHello(){alert('Hello');}}"; 
     //that.eval(script); //not working in IE 2. 
     evalScript(script); //working in all browsers 
    } 
}); 

我在关于Java的范围和背景的互联网读了很多,但我只是无法解释此行为:

  1. 为什么我需要调用EVAL在“那”?根据互联网上的许多消息来源,全球定义功能的背景是最全球化的背景。 (这里应该是窗口)。并且通过eval评估的代码应该在调用eval函数的上下文中执行。

  2. 假设Ajax调用有一个新的全局上下文(为什么?)为什么我可以访问evalScript函数但不直接在这里评估脚本。

我的整体问题是:哪些特定规则适用于eval的使用?我的职能在哪里关注上下文?并且:示例中的Ajax调用是否具有其自己的全局对象?

+1

实际上,您可以在jsFiddle中成功完成AJAX调用,请参阅此[参考页](http://doc.jsfiddle.net/use/echo.html)。 –

+0

单词'I'大写英文。 –

回答

4

第一关:如果你能避免使用eval,避免使用eval。您的代码是否有POST回来?因为如果你愿意使用GET相反,你可以在脚本元素只是追加到页面:

var script = document.createElement('script'); 
script.src = "http://example.com" + 
       "?" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param1value") + 
       "&" + encodeURIComponent("param1name") + "=" + encodeURIComponent("param2value"); 
var parent = document.body 
      || document.documentElement 
      || document.getElementsByTagName('head')[0]; 
parent.appendChild(script); 

完成。

或者如果它必须是POST,是否真的必须是实际的脚本代码?难道这是根据页面上的代码解释了的数据吗?如果你可以这样做,JSON是一种有用的数据格式。

但如果POST,并返回给你是相对于实际数据脚本代码,那么我们将不得不做一些像eval。 :-)

eval本身非常非常特别。它在它所使用的范围内工作,即使它看起来有点像一个函数,并不是函数的工作方式。所以在全球范围内实际评估脚本代码是很困难的,除非eval调用实际上是在全局范围(不在任何函数调用中),当然你不能在这里做到这一点  —你必须从你的ajax回调中触发这个,所以根据定义,这发生在一个函数内。 (编辑:我只是想到了一个办法,在全球范围内实际使用eval,在一个函数中看到更新的答案的结束,但它的邪恶和恐怖的和错误的。)

原因你可能看到建议说使用window.eval是许多现代浏览器提供window.eval(而不是eval),它在全局范围内评估给定的代码。但它并不适用于所有的浏览器,当然不是老的。

虽然有解决方法。 IE家族提供的execScript非常类似类似于其他浏览器提供的window.eval,在最坏的情况下,您可以使用script元素。下面是工作在几乎所有全球eval函数:

window.evalInGlobalScope = (function() { 
    var fname, scr; 

    // Get a unique function name 
    do { 
     fname = "__eval_in_global_test_" + Math.floor(Math.random() * 100000); 
    } 
    while (typeof window[fname] !== 'undefined'); 

    // Create test script 
    scr = "function " + fname + "() { }"; 

    // Return the first function that works: 
    return test(evalInGlobalScope_execScript) || 
      test(evalInGlobalScope_windowEval) || 
      test(evalInGlobalScope_theHardWay) || 
      evalInGlobalScope_fail; 

    function test(f) { 
     try { 
      f(scr); 
      if (typeof window[fname] === 'function') { 
       return f; 
      } 
     } 
     catch (e) { 
      return false; 
     } 
     finally { 
      try { delete window[fname]; } catch (e) { window[fname] = undefined; } 
     } 
    } 
    function evalInGlobalScope_execScript(str) { 
     window.execScript(str); 
    } 
    function evalInGlobalScope_windowEval(str) { 
     window.eval(str); 
    } 
    function evalInGlobalScope_theHardWay(str) { 
     var parent, script, d = document; 

     parent = d.body || d.documentElement || d.getElementsByTagName('head')[0]; 
     if (parent) { 
      script = d.createElement('script'); 
      script.appendChild(d.createTextNode(str)); 
      parent.appendChild(script); 
     } 
    } 
    function evalInGlobalScope_fail() { 
     throw "evalInGlobalScope: Unable to determine how to do global eval in this environment"; 
    } 
})(); 

..和here's a live example of using it

请注意,所有代码只能运行一次的代码;被选中的功能被分配到window上的evalInGlobalScope属性。

另请注意,我没有给它任何返回值。那是因为“硬路”版本基本上不能返回任何返回值,所以最安全的是它们都没有。请注意,我不确定哪些浏览器仍然需要“困难的方式”  —现在几乎所有东西都有execScript和/或window.eval


更新:我上面说你不能在全局范围内使用eval在一个函数中。从技术上讲,这是真的,但我想到一种方法来解决这个问题。这是邪恶和恐怖的和错误的,但它的工作:使用setTimeout代替,并给它的0超时:

setTimeout("your code here", 0); 

当你给setTimeout一个字符串,它在超时后执行就可以了  —的eval,全球范围内的

再一次,它是邪恶的,可怕的和错误的,它有一个额外的缺点,即它是异步的(而我们的evalInGlobalScope函数,eval同步发生),但它确实......排序......工作。 (Live copy)我不要推荐它。

+0

非常感谢您的回答!这解释了我偶然发现的所有问题! – Chris