[英]scope and eval explanation
我有一個Ajax調用,我將一些JavaScript作為String返回。 在onSuccess方法中,我想評估此代碼。 在JavaScript代碼中有函數聲明。 在eval之后,所有這些功能都應該可以訪問。
我編寫了一個盡可能小的例子。 (事情正在示例中的onFailure方法中進行,因為在JFiddle中我無法成功進行Ajax調用)。
你可以在這里找到例子: http : //jsfiddle.net/ubXAV/6/
您看到的示例適用於所有瀏覽器(不幸的是,這在IE中的JSFiddle中不起作用)。 我標記了一些引用下面問題的行。 這是代碼:
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中的范圍和上下文但我無法解釋這里的行為:
為什么我需要在“那個”上調用eval? 根據互聯網上的許多消息來源,全球定義功能的背景是最全球化的背景。 (這里應該是窗口)。 通過eval評估的代碼應該在調用eval函數的上下文中執行。
假設Ajax調用有一個新的全局上下文(是嗎?)為什么我可以訪問evalScript函數但不直接在這里評估腳本。
我的整體問題是:哪些特定規則適用於eval的使用? 關於背景,我的職能在哪里? 並且:示例中的Ajax調用原型是否有自己的全局對象?
首先:如果您可以避免使用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";
}
})();
.. 這是一個使用它的實例 。
請注意,確定使用內容的所有代碼只運行一次; 選擇的函數將分配給window
上的evalInGlobalScope
屬性。
另請注意,我沒有給它任何返回值。 那是因為“硬路”版本基本上不能返回任何返回值,所以如果它們都沒有,那么它是最安全的。 請注意,我不確定哪些瀏覽器仍然需要“艱難的方式” - 現在幾乎所有的東西都有execScript
和/或window.eval
。
更新 :我上面說過,你不能在函數中使用全局范圍的eval
。 從技術上講,這是真的,但我想到了一種繞它運行的方法。 它是邪惡的,可怕的和錯誤的,但它確實有效:使用setTimeout
代替,並給它超時0
:
setTimeout("your code here", 0);
當你給setTimeout
一個字符串時,它會對它執行一個eval
- 在超時之后, 在全局范圍內 。
再次,它是邪惡的,可怕的和錯誤的,並且它具有額外的缺點,它是異步的(而使用我們的evalInGlobalScope
函數,eval同步發生),但它確實......有點......工作。 ( 實時拷貝 )我不推薦它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.