標籤:

被嫌棄的eval和with

被嫌棄的eval和with ×

目錄

[1]eval [2]with前面的話

  eval和with經常被嫌棄,好像它們的存在就是錯誤。在CSS中,表格被嫌棄,在網頁中只是用表格來展示數據,而不是做布局,都可能被斥為不規範,矯枉過正。那關於eval和with到底是什麼情況呢?本文將詳細介紹eval()函數和with語句

eval定義

  eval()是一個全局函數,javascript通過eval()來解釋運行由javascript源代碼組成的字元串

var result = eval("3+2");console.log(result,typeof result);//5 "number"

用法

  eval()只有一個參數,如果傳入的參數不是字元串,它直接返回這個參數。如果參數是字元串,它會把字元串當成javascript代碼進行編譯。如果編譯失敗則拋出一個語法錯誤(syntaxError)異常。如果編譯成功,則開始執行這段代碼,並返回字元串中的最後一個表達式或語句的值,如果最後一個表達式或語句沒有值,則最終返回undefined。如果字元串拋出一個異常,這個異常將把該調用傳遞給eval()

var num = 1;var str = "test";console.log(eval(num));//1console.log(eval(str));//ReferenceError: test is not defined

var strLong1 = "var x = 1;var y = 2;";console.log(eval(strLong1),x,y);//undefined 1 2var strLong2 = "var x = 1; x++;";console.log(eval(strLong2),x);//1 2

作用域

  eval()使用了調用它的變數作用域環境。也就是說,它查找變數的值和定義新變數和函數的操作和局部作用域中的代碼完全一樣

var b = 2;function foo(str,a){ eval(str); console.log(a,b);}foo("var b = 3;",1);//1 3

別名

  當通過別名調用時,eval()會將其字元串當做頂層的全局代碼來執行。執行的代碼可能會定義新的全局變數和全局函數,或者給全局變數賦值,但卻不能使用或修改函數中的局部變數

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 globalconsole.log(g(),y);//local globalchanged

  [注意]IE8-瀏覽器通過別名調用eval()和正常調用eval()的結果相同

副作用

  javascript解釋器進行了大量的代碼分析和優化。而eval()的問題在於,用於動態執行的代碼通常不能分析,於是解釋器也無法對其進行優化,這會導致性能下降

  與eval()類似的有setTimeout()、setInterval()、new Function()等,這些函數都可以以字元串作為參數,在程序運行時動態執行。這種執行機制帶來的好處無法抵消其性能上的損失,所以應該盡量避免使用

嚴格模式

  由於eval()函數過於強大,嚴格模式對其進行了嚴格的限制

  【1】不能通過eval()函數來創建變數或函數,但可以查詢和更改其值

"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作為標識符

"use strict";var eval = 10;//SyntaxError: Unexpected eval or arguments in strict mode

with

  定義with語句的目的主要是為了簡化多次編寫同一對象的工作

  with語句將object添加到作用域鏈的頭部,然後執行statement,最後把作用域鏈恢復到原始狀態

with(object){  statement;}

作用

  在對象嵌套層次很深的時候通常會使用with語句來簡化代碼編寫。而本質上是通過將一個對象的引用當作作用域來處理,將對象的屬性當作作用域中的標識符來處理,從而創建了一個新的詞法作用域

  在客戶端javascript中,可能會使用類似下面這種表達式來訪問一個HTML表單中的元素

document.forms[0].address.value

  如果這種表達式在代碼中多次出現,則可以使用with語句將form對象添加到作用域鏈的頂層

with(document.forms[0]){ name.value = ""; address.value = ""; emai.value = "";}

  這種方法減少了大量的輸入,不用再為每個屬性名添加document.forms[0]前綴。這個對象臨時掛載在作用域鏈上,當javascript需要解析諸如address的標識符時,就會自動在這個對象中查找

  [注意]with語句提供了一種讀取對象的屬性的快捷方式,但它並不能創建對象的屬性

  如果對象o有一個屬性x,那麼下面代碼給這個屬性賦值為1

var o = {x:0};with(o) x = 1;console.log(o.x);//1

  如果o中沒有定義屬性x,下面代碼和不使用with語句的代碼x=1是一模一樣的。這是因為對變數x進行了LHS查詢,並將1賦值給它

var o = {};with(o) x = 1;console.log(o.x);//undefinedconsole.log(x);//1

副作用

  與eval類似,with語句的javascript代碼非常難於優化,同時也會給調試代碼造成困難,並且同沒有使用with語句的代碼相比,它運算得更慢

  而且,如果with語句不當,還有可能造成變數泄漏,污染全局作用域的情況

var x = 1;var o = {};with(o){ x = 2;}console.log(x);//2console.log(o.x);//undefined

嚴格模式

  嚴格模式下,禁止使用with語句

//SyntaxError: Strict mode code may not include a with statement"use strict";var o = {};with(o){ x = 2;}

最後

  使用eval和with會使得引擎無法在編譯時對作用域查找進行優化,從而導致性能下降,代碼運行變慢。因為eval和with在實際工作中很少使用,所以嚴格模式下的限制,對我們來說影響不大。就像比如外交部某一天發布公告,我國不再發放去牙買加的簽證,牙買加雖然都聽過,但大多數人這輩子都可能不去一回,所以,無所謂了。同樣地,eval和with被嫌棄不嫌棄的,也是無所謂了

  但即使不去牙買加,也不妨礙我了解到牙買加是加勒比海的其中一個島國,它是英聯邦成員國,也就是原來是英國殖民地,後來獨立了。它的國旗上面是一個X

  類比於eval和with

  以上

好的代碼像粥一樣,都是用時間熬出來的標籤: javascript總結 好文要頂 關注我 收藏該文

小火柴的藍色理想 關注 - 94 粉絲 - 495 +加關注 1 上一篇:深入理解javascript作用域系列第五篇——一張圖理解執行環境和作用域 posted @ 2016-08-01 10:43 小火柴的藍色理想 閱讀(188) 評論(2) 編輯 收藏 評論列表 #1樓 2016-08-01 11:06 minttang 動態運行代碼有時候是非常重要的,沒有它的話,js就黯然失色.一點性能完全沒有問題.了解不多,閱有收穫!支持(0)反對(0) #2樓[樓主] 2016-08-01 11:29 小火柴的藍色理想 @minttang同意,其實性能問題以後應該不是問題。try-catch語句也有類似的性能問題,但是由於現在try-catch語句大量的用於塊作用域的模擬,所以chrome被要求專門針對try-catch語句進行性能改進
推薦閱讀:

共享出行之所以被嫌棄 是因為你被偽共享了
一對夫婦的離婚賬單[嫌棄自己配偶者必看]
孩子為什麼嫌棄你?
女人開始嫌棄你的4個信號, 你都知道嗎?
口述:每天凌晨給老公做早飯還被嫌棄|嫌棄|早飯|自私

TAG:嫌棄 | eval |