eval函數是強大的數位轉換引擎,字元串經eval轉換後得到一個javascript對象,
舉簡單例子:
var a = eval("5");等效于var a = 5;
var a = eval("'5'");等效于var a = '5';
var obj = eval("({name:'cat',color:'black'})");等效于 var obj = {name:'cat',color:'black'};
eval("alert('hello world!');");等效于 alert('hello world!');
js的資料類型為弱類型,可以在定義的時候指定資料類型,也可以在運算過程中強制資料類型轉換
一個對象經過eval轉換後資料類型不确定,在相加過程中自動與其他資料類型一緻
eval(str) 用來傳入一個字元串動态執行一段腳本,這個方法非常有用。當直接用eval()時,作用域為目前作用域,有時候我們需要讓它在全局作用域範圍内執行,比如 ajax傳回的腳本字元串,然而浏覽器對eval的差異可能使事情剛開始并不是那麼順利,本文通過在7種浏覽器(IE, Firefox, Chrome, Safari, Opera)環境中測試,并提出三種解決方案,使這個問題比較完美的解決。
看這一段javascript代碼:
function xx(){
var x= 1 ;
window .eval( 'var x=3;' );
document .writeln(x);
}
xx();
在你自己測試和看我接下來的分析之前,先想想,你認為輸出結果會是什麼呢?是1還是3?
根據本文的标題,可知肯定是在不同浏覽器下有不同表現的。
以下是我的實測資料:
JS代碼 | window .eval ( 'var x=3;' ); document .writeln (x); } | ||||||
---|---|---|---|---|---|---|---|
浏覽器 | IE | Firefox | Chrome | Safari | Opera | ||
版本 | 7.0 | 8.0 | 3.0.8 | 1.0 | 4.0 | 4.0.2 | 9.62 |
運作結果 | 3 |
可見各浏覽器及版本對window.eval()的作用域處理是有差異的。
IE中,window.eval()和eval()一樣隻在目前作用域生效。
Firefox,Safari,Opera中,直接調用eval()為目前作用域,window.eval()調用為全局作用域。
尤其值得注意的是,Google Chrome 的不同版本之間對于eval的處理也有差異。
如果需要在全局作用域eval()的效果,且通用于所有浏覽器,那就得好好變通一下了。
方法之一:
使用IE專有的window .execScript 。
如果你碰到這個問題不知所措,并上網搜尋,這個方法大概是最先也幾乎唯一能搜尋到的方法。
window .execScript (sExpression , sLanguage )。
比如上面那一段代碼中eval一句如果換成window .execScript( 'var x=3;' ); IE中的運作結果就是1了。
非IE核心的浏覽器并不支援window .execScript 。
IE之是以有這個window .execScript ,還和IE能夠執行其他語言的腳本有關,通過給不同的sLanguage 參數,IE這個方法除能夠執行javascript之外,還可以執行vbscript或是其他任何安裝過相應解釋引擎的腳本如perl,python等。
當需要在局部環境中執行的時候,我們就直接用eval()。
當需要在全局環境中執行的時候,我們可以封裝一個通用的函數,就像下面這樣:
//在全局環境中執行
function evalGlobal(strScript){
if( window .execScript) window .execScript( strScript );
else window . eval ( strScript );
就是将IE和非IE差別開來對待。
看起來,問題似乎圓滿解決了。但是顯然是有問題的,比如上表中的Chrome 1.0也和IE的eval()規則一緻,況且還不知道其他浏覽器其他版本是否有差異呢,是以,這種方法并不很可靠。
但是如果你有一點完美主義者的傾向,那麼事情還不能到此為止,肯定是有更好更簡潔的方法的嘛。
不知道閱讀此文的你是否有想到呢?
是否和我的想法一緻呢?
方法之二:
建立一個<script>元素裝載腳本。
這種方法常用來解決innerHTML中的腳本不能運作的問題。但用來解決eval()的作用域問題,恐怕就比較罕見了。
var a = document .createElement ("script" );
a.type= "text/javascript" ;
a.text= strScript ;
document .getElementsByTagName ("head" )[0 ].appendChild (a) ;
雖然這個方法有點變态,需要新增一個<script>元素,但優點是各種浏覽器及版本通用,比方法一要好一些了。。
但是如果你有再多一點完美主義者的傾向,那麼事情還不能到此為止,畢竟添加了一個HTML元素嘛,影響了頁面原本的DOM結構。
那麼是不是有更好更簡潔的方法的呢?答案是肯定的。經過我的研究,找到了同時具備簡潔和可靠的方法三。
方法之三:
還是eval。回歸原生态。
我們别忘了javascript裡面有一個改變上下文環境的關鍵字,強大的with .
原來事情可以更簡單更有效!
with ( window )eval (strScript) ;
看看,都這麼簡單了,我們完全可以不用封裝為函數了,直接在代碼中用。
文章最開始的代碼我們就可以這樣來了:
eval ( 'var x=1;' ); //局部變量
with ( window ){ eval ( 'var x=3;' );} //全局變量
//也可以用封裝的 evalGlobal( 'var x=3' );
document .writeln (x); //1 局部變量
document .writeln ( window .x); //3 全局變量
特别:
有時候,我們eval()要求既不是在全局執行,也不是在目前作用域執行,而是在父對象或子對象中執行,這時,用 with ( objContext )eval (strScript) 就更加是不可替代的選擇了。
總結:
讓eval()全局作用域執行的方法主要有:
(1)window .execScript + window . eval 級别:弱。 缺點:不簡潔,不可靠,不通用。
(2)document . createElement ("script" ) 級别:湊合。缺點:不簡潔,不幹淨。優點:可靠,通用。
(3)with ( objContext )eval (strScript) 級别:最佳。優點:簡潔,幹淨,可靠,通用。
N整一個表格比較清楚:
讓eval()全局作用域執行的方法 | 級别 | 缺點 | 優點 |
---|---|---|---|
(1)window .execScript + window . eval | 弱 | 不簡潔,不可靠,不通用 | - |
(2)document . createElement ("script" ) | 湊合 | 不簡潔,不幹淨 | 可靠,通用 |
(3)with ( window )eval (strScript) | 最佳 | 簡潔,幹淨,可靠,通用 |