簡體   English   中英

范圍和評估說明

[英]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中的范圍和上下文但我無法解釋這里的行為:

  1. 為什么我需要在“那個”上調用eval? 根據互聯網上的許多消息來源,全球定義功能的背景是最全球化的背景。 (這里應該是窗口)。 通過eval評估的代碼應該在調用eval函數的上下文中執行。

  2. 假設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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM