2011-08-03 102 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