JavaScript學(xué)習(xí)小結(jié)之被嫌棄的eval函數(shù)和with語句實例詳解
前面的話
eval和with經(jīng)常被嫌棄,好像它們的存在就是錯誤。在CSS中,表格被嫌棄,在網(wǎng)頁中只是用表格來展示數(shù)據(jù),而不是做布局,都可能被斥為不規(guī)范,矯枉過正。那關(guān)于eval和with到底是什么情況呢?本文將詳細(xì)介紹eval()函數(shù)和with語句
eval
定義
eval()是一個全局函數(shù),javascript通過eval()來解釋運行由javascript源代碼組成的字符串
var result = eval('3+2'); console.log(result,typeof result);//5 'number'
用法
eval()只有一個參數(shù),如果傳入的參數(shù)不是字符串,它直接返回這個參數(shù)。如果參數(shù)是字符串,它會把字符串當(dāng)成javascript代碼進(jìn)行編譯。如果編譯失敗則拋出一個語法錯誤(syntaxError)異常。如果編譯成功,則開始執(zhí)行這段代碼,并返回字符串中的最后一個表達(dá)式或語句的值,如果最后一個表達(dá)式或語句沒有值,則最終返回undefined。如果字符串拋出一個異常,這個異常將把該調(diào)用傳遞給eval()
var num = 1; var str = 'test'; console.log(eval(num));//1 console.log(eval(str));//ReferenceError: test is not defined var strLong1 = 'var x = 1;var y = 2;'; console.log(eval(strLong1),x,y);//undefined 1 2 var strLong2 = 'var x = 1; x++;'; console.log(eval(strLong2),x);//1 2
作用域
eval()使用了調(diào)用它的變量作用域環(huán)境。也就是說,它查找變量的值和定義新變量和函數(shù)的操作和局部作用域中的代碼完全一樣
var b = 2; function foo(str,a){ eval(str); console.log(a,b); } foo('var b = 3;',1);//1 3
別名
當(dāng)通過別名調(diào)用時,eval()會將其字符串當(dāng)做頂層的全局代碼來執(zhí)行。執(zhí)行的代碼可能會定義新的全局變量和全局函數(shù),或者給全局變量賦值,但卻不能使用或修改函數(shù)中的局部變量
var geval = eval; var x = 'global',y = 'global'; function f(){ var x = 'local'; eval('x += "changed";'); return x; } function g(){ var y = 'local'; geval('y += "changed";'); return y; } console.log(f(),x);//localchanged global console.log(g(),y);//local globalchanged
[注意]IE8-瀏覽器通過別名調(diào)用eval()和正常調(diào)用eval()的結(jié)果相同
副作用
javascript解釋器進(jìn)行了大量的代碼分析和優(yōu)化。而eval()的問題在于,用于動態(tài)執(zhí)行的代碼通常不能分析,于是解釋器也無法對其進(jìn)行優(yōu)化,這會導(dǎo)致性能下降
與eval()類似的有setTimeout()、setInterval()、new Function()等,這些函數(shù)都可以以字符串作為參數(shù),在程序運行時動態(tài)執(zhí)行。這種執(zhí)行機(jī)制帶來的好處無法抵消其性能上的損失,所以應(yīng)該盡量避免使用
嚴(yán)格模式
由于eval()函數(shù)過于強(qiáng)大,嚴(yán)格模式對其進(jìn)行了嚴(yán)格的限制
【1】不能通過eval()函數(shù)來創(chuàng)建變量或函數(shù),但可以查詢和更改其值
'use strict'; eval('var x = 1;'); console.log(x);//ReferenceError: x is not defined 'use strict'; var x = 1; eval('x = 2;'); console.log(x);//2
【2】禁止使用eval作為標(biāo)識符
'use strict'; var eval = 10;//SyntaxError: Unexpected eval or arguments in strict mode
with
定義with語句的目的主要是為了簡化多次編寫同一對象的工作
with語句將object添加到作用域鏈的頭部,然后執(zhí)行statement,最后把作用域鏈恢復(fù)到原始狀態(tài)
with(object){ statement; }
作用
在對象嵌套層次很深的時候通常會使用with語句來簡化代碼編寫。而本質(zhì)上是通過將一個對象的引用當(dāng)作作用域來處理,將對象的屬性當(dāng)作作用域中的標(biāo)識符來處理,從而創(chuàng)建了一個新的詞法作用域
在客戶端javascript中,可能會使用類似下面這種表達(dá)式來訪問一個HTML表單中的元素
document.forms[0].address.value
如果這種表達(dá)式在代碼中多次出現(xiàn),則可以使用with語句將form對象添加到作用域鏈的頂層
with(document.forms[0]){ name.value = ''; address.value = ''; emai.value = ''; }
這種方法減少了大量的輸入,不用再為每個屬性名添加document.forms[0]前綴。這個對象臨時掛載在作用域鏈上,當(dāng)javascript需要解析諸如address的標(biāo)識符時,就會自動在這個對象中查找
[注意]with語句提供了一種讀取對象的屬性的快捷方式,但它并不能創(chuàng)建對象的屬性
如果對象o有一個屬性x,那么下面代碼給這個屬性賦值為1
var o = {x:0}; with(o) x = 1; console.log(o.x);//1
如果o中沒有定義屬性x,下面代碼和不使用with語句的代碼x=1是一模一樣的。這是因為對變量x進(jìn)行了LHS查詢,并將1賦值給它
var o = {}; with(o) x = 1; console.log(o.x);//undefined console.log(x);//1
副作用
與eval類似,with語句的javascript代碼非常難于優(yōu)化,同時也會給調(diào)試代碼造成困難,并且同沒有使用with語句的代碼相比,它運算得更慢
而且,如果with語句不當(dāng),還有可能造成變量泄漏,污染全局作用域的情況
var x = 1; var o = {}; with(o){ x = 2; } console.log(x);//2 console.log(o.x);//undefined
嚴(yán)格模式
嚴(yán)格模式下,禁止使用with語句
//SyntaxError: Strict mode code may not include a with statement 'use strict'; var o = {}; with(o){ x = 2; }
最后
使用eval和with會使得引擎無法在編譯時對作用域查找進(jìn)行優(yōu)化,從而導(dǎo)致性能下降,代碼運行變慢。因為eval和with在實際工作中很少使用,所以嚴(yán)格模式下的限制,對我們來說影響不大。就像比如外交部某一天發(fā)布公告,我國不再發(fā)放去牙買加的簽證,牙買加雖然都聽過,但大多數(shù)人這輩子都可能不去一回,所以,無所謂了。同樣地,eval和with被嫌棄不嫌棄的,也是無所謂了
以上所述是小編給大家介紹的JavaScript學(xué)習(xí)小結(jié)之被嫌棄的eval函數(shù)和with語句實例詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
javascript IFrame 強(qiáng)制刷新代碼
經(jīng)常會使用多個iframe來展示領(lǐng)域模型主子關(guān)系(主/子單),測試發(fā)現(xiàn)iframe是有cache功能的2009-07-07JS的函數(shù)調(diào)用棧stack size的計算方法
本篇文章給大家分享了關(guān)于JS的函數(shù)調(diào)用棧stack size的計算方法的相關(guān)知識點,有興趣的朋友參考學(xué)習(xí)下。2018-06-06Easy.Ajax 部分源代碼 支持文件上傳功能, 兼容所有主流瀏覽器
下面是Easy.Ajax類的初稿,如須發(fā)表,在代碼上還要修改以達(dá)到最簡,但API是不會變了2011-02-02script標(biāo)簽中的defer和async使用技巧說明
這篇文章主要介紹了script標(biāo)簽中的defer和async使用技巧,包含他們的下載順序和執(zhí)行順序,以及使用場景需要的朋友可以參考下2023-02-02JS插件amCharts實現(xiàn)繪制柱形圖默認(rèn)顯示數(shù)值功能示例
這篇文章主要介紹了JS插件amCharts實現(xiàn)繪制柱形圖默認(rèn)顯示數(shù)值功能,結(jié)合實例形式分析了amCharts插件繪制柱形圖并顯示數(shù)值的相關(guān)操作技巧,需要的朋友可以參考下2019-11-11