eval(「1+2」),-> 3函數
動態判斷源代碼中的字符串是一種很強大的語言特性,幾乎沒有必要在實際中應用。若是你使用了eval(),你應當仔細考慮是否真的須要使用它。佈局
1、eval()是一個函數仍是一個運算符優化
eval()是一個函數,但因爲它已經被當成運算符來對待了。。JavaScript語言的早期版本定義了eval函數,現代JavaScript解釋器進行了大量的代碼分析和優化。而eval的問題在於,用於動態執行的代碼一般來說不能分析,換句話說,若是一個函數調用了eval,那麼解釋器將沒法對這個函數作進一步優化,而將eval定義爲函數的另外一個問題是,它能夠被賦予其餘的名字,var f=eval;那麼解釋器就沒法放心的優化任何調用了f()的函數。而當eval是一個運算符的時候,就能夠避免這些問題。spa
2、eval().net
eval()只有一個參數。若是傳入的參數不是字符串,它直接返回這個函數。若是參數是字符串,它會把字符串當成JavaScript代碼進行編譯,若是編譯失敗者拋出一個語法錯誤異常。若是編譯成功,則開始執行這一段代碼,並返回字符串中的最後一個表達式會或語句的值,若是最後一個表達式或語句沒有值,則最終返回undefined。若是字符串拋出一個異常,這個異常將把該調用傳遞給eval()。code
關於eval最重要的是,它使用了調用它的變量做用域環境。也就是說,它查找變量的值和定義新變量和函數的操做和局部做用域中的代碼徹底同樣。若是一個函數定義了一個局部變量x,而後調用eval(「x」),它會返回局部變量的值。若是它調用eval(「x=1」),它會改變局部變量的值。若是函數調用了eval(「var y=2;」),它聲明瞭一個新的局部變量y,一樣地,一個函數能夠經過以下代碼聲明一個局部變量:htm
eval(「function f(){return x+1;}」);對象
若是在最頂層的代碼中調用eval,固然,它會做用於全局變量和全局函數。blog
須要注意的是,傳遞給eval的字符串必須在語法上將的通,不能經過eval往函數中任意粘貼代碼片斷,好比:eval(「return ;」)是沒有意義的,由於return只有在函數中才起到做用,而且事實上,eval的字符串執行時的上下文環境和調用函數的上下文環境是同樣的,這不能使其做爲函數的一部分來運行。若是字符串做爲一個單獨的腳本是有語義的,那麼將其傳遞給eval做參數是徹底沒有問題的,不然,eval會拋出語法錯誤異常。ip
3、全局eval()
eval()具備更改佈局變量的能力,這對於JavaScript優化器來講是一個很大的問題。然而做爲一種權宜之計,JavaScript解釋器針對那些調用了eval的函數所作的優化並很少。但當腳本定義了eval的一個別名,且用另外一個名稱調用它,JavaScript解釋器又會如何工做呢?爲了讓JavaScript解釋器的實現更加簡化,ECMAScript3標準規定了任何解釋器都不容許對eval賦予別名。若是eval函數經過別名調用的話,則會拋出一個EavlError異常。
實際上,大多數的實現並非這麼作的。當經過別名調用時,eval會將其字符串當成頂層的全局代碼來執行。執行的代碼可能會定義新的全局變量和全局函數,或者給全局變量賦值,但卻不能使用或者修改主調函數中的局部變量,所以,這不會影響到函數內的代碼優化。
ECMAScript5是反對使用EavlError的,而且規範了eval的行爲,「直接的eval」,當直接使用非限定的「eval」名稱來調用eval()函數時,一般稱爲「直接eval」。直接調用eval()時,它老是在調用它的上下文做用域內執行。其餘的間接調用則使用全局對象做爲其上下文做用域,而且沒法讀、寫、定義局部變量和函數。下面有一段示例代碼:
var geval=eval; //使用別名調用evla將是全局eval var x="global",y="global"; //兩個全局變量 function f(){ //函數內執行的是局部eval var x="local"; //定義局部變量 eval("x += ' chenged';");//直接使用eval改變的局部變量的值 return x; //返回更改後的局部變量 } Function g(){ //這個函數內執行了全局eval var y="local"; geval("y += ' changed';"); //直接調用改變了全局變量的值 return y; } console.log(f(),x); //改變了佈局變了,輸出 「local changed global」 console.log(g(),y); //改變了全局變量,輸出 「local global changed」
全局的eval的這些行爲不只僅是處於代碼優化其的須要而做出的一種折中方案,它其實是一種很是有用的特性,它容許咱們執行那些對上下文沒有任何依賴的全局腳本代碼段。真正須要eval來執行代碼段的場景並很少見。但當你真的意識到它的必要性的時候,你更可能會使用全局eval而不是局部eval。
4、嚴格eval()
ECMAScript5嚴格模式對eval()函數的行爲施加了更多的限制,甚至對標識符eval的使用也施加了限制。當在嚴格模式下調用eval時,或者eval執行的代碼段以「Use strict」 指令開始,這裏的eval是私有上下文環境中的局部eval。也就是說,在嚴格模式下,eval執行的代碼段能夠查詢或更改局部變量,但不能在局部做用域中定義新的變量或函數。
此外,嚴格模式將「eval」列爲保留字,這讓eval()更像一個運算符。不能用一個別名覆蓋eval()函數。而且變量名,函數名。函數參數或者異常捕獲的參數都不能取名爲eval。
俗話說的好:寶劍鋒從磨礪出,梅花香自苦寒來。