在 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()...。
- Apr 25 Fri 2008 18:20
字串變程式碼~ eval() 的限制與解決之道
close
全站熱搜
留言列表
發表留言