close
在 Ajax 橫行的時代,我們常常可以碰到一種需求,那就是用 Ajax 讀入另一個 js 檔的內容然後執行執行他。
 
但是用 Ajax 讀進來的程式碼已經變成字串了,如何再讓字串變回程式碼呢?對 Javascript 有一定經驗的人馬上就能想到的是 eval() 這個 function,看以下的範例:
 
(請注意!以下的範例小弟因為偷懶所以直接用字串來取代 Ajax 讀入的片段)
 
範例一:
    <html>
        <script>
            ttt = "function show() {alert('hello');}";
            eval (ttt);
        </script>
        <body>
            <input type="button" value="run test()" onclick="test()">
            <input type="button" value="run show()" onclick="show()">
        </body>
    </html>

 
當按下「run show()」之後,會彈出小視窗顯示 hello 字串,這表示 eval() 發生作用,字串變成了程式碼。但是若是將範例一的 script 部份改成以下的寫法:
 
範例二:
    <script>
        function test() {
            ttt = "function show() {alert('hello');}";
            eval (ttt);
            show();
        }
    </script>

 
這時先按下「run test()」,此時會彈出小視窗顯示 hello 字串,表示在 test() 中的 eval() 發生作用,接下來再按下「run show()」,此時你會發現瀏覽器丟出了「找不到物件」的錯誤。
 
這是為什麼呢?在 test() 中呼叫 show() 是正常的,但是在 test() 外呼叫 show() 卻會發生錯誤!原來這全都是 Scope 搞得鬼。
 
在 test() 中,eval() 之後的 show() function 的範圍只存在於 test() 之內,所以在 test() 之內呼叫 show() 是 ok 的,但是在 test() 之外呼叫 show() 的話,會因為 show() 僅存活於 test() 之中而呼叫不到 (這個就是全域變數和區域變數的問題)。
 
後來小弟在 Internet 上找到了這篇文章:http://blog.roodo.com/rocksaying/archives/2741057.html。上面是說用 window.eval() 來取代 eval() 即可,於是小弟依樣葫蘆之後發現這個方法在 Firefox 是可行的,但是在 IE 上仍然是沒有作用。後來在找了幾篇文章之後得知在 IE 上可以用 window.execScript() 來替代 eval(),因此若是將範例二改成下列的寫法:
 
範例三:
    <script>
        function test() {
            ttt = "function show() {alert('hello');}";
            if (window.execScript) {
                window.execScript(ttt); 
            } else {
                window.eval(ttt);
            }
            show();
        }
    </script>
 
如此就可以在 IE 和 Firefox 上執行。不過這樣的寫法還要多一道判斷的語法,總覺得不大漂亮,因此小弟再根據 Internet 上的這篇 (http://www.javaeye.com/topic/17227) 討論內容(註),直接去更改 show() 這個 function 的宣告方式,讓 show() 一被宣告就是全域的物件。
 
範例四:
    <script>
        function test() {
            ttt = "show = new function() {alert('hello');}";
            eval (ttt);
            show();
        }
    </script>

 
如此一來不但可以通吃兩大瀏覽器,而且還不用像範例三那樣要多一些判斷的語法,應該可以說是最好的解決方式!
 
註:在該篇(http://www.javaeye.com/topic/17227)討論中,是建議使用 window.show = new function() {alert('hello');} 的方式來宣告讓 show() function 變成全域物件,但經小弟的測試發現,即使不加 window 宣告出來的 show() 也是全域變數,所以在範例四中小弟是使用 show = new function()... 而不是使用 window.show = new function()...。
arrow
arrow
    全站熱搜

    大笨鳥 發表在 痞客邦 留言(0) 人氣()