為什麼不建議使用eval和with?
假裝被面試
面試官:為什麼不建議使用eval和with?
因為影響效能、減低程式碼的安全性、程式碼更加難於閱讀。
那為什麼會影響效能?、為何會減低安全性?、怎麼就讓程式碼更加難於閱讀?
這個些問題主要是考察Js開發人對詞法作用域的理解,如果你和我一樣一臉矇蔽那就跟著我一起來看看這其中的"奧秘"吧!
先了解一下什麼是詞法作用域
簡單地來說,詞法作用域就是定義在詞法階段的作用域。詞法作用域是由你在寫程式碼時將變數和塊作用域寫在哪了來決定的,因此當詞法分析器處理程式碼時會儲存作用域不變(大部分情況下是這樣)
下面用一張圖幫助理解作用域:
來自《你不知道的JavaScript上卷》
(1)、包含著整個全域性作用域,其中只有一個識別符號:foo
(2)、包含著foo所建立的作用域,其中有三個識別符號: a、b、 bar
(3)、包含著bar所建立的作用域,其中只有一個識別符號:c
從上面那張圖片可以看到,作用域是逐級巢狀的。在執行console.log(a, b, c)
時,引擎會從最內部的作用域(3)開始查詢,如果沒有找到,就逐層往外找。作用域查詢會在找到第一個匹配的識別符號時停止
。
下面迴歸正題,為什麼會影響效能?
這裡就要提到“欺騙詞法(程式碼在執行的時候"修改"詞法作用域)”
這個詞, JavaScript引擎在編譯階段有一些效能上的最佳化是依賴於能夠根據程式碼的詞法進行靜態分析,並預先確定所有變數和函式的定義位置,才能在執行過程中快速的找到識別符號。
但如果引擎在程式碼中發現了eval或with,它只能簡單地假設關於識別符號位置但判斷都是無效的,因為無法在詞法分析階段明確的知道eval會接收到什麼程式碼,這些程式碼是如何對作用域進行修改,因此最簡單的做法就是完全不做任何最佳化。如果程式碼中大量使用eval和with,導致引擎沒有對這些進行最佳化。那麼程式碼執行起來一定會變得更慢。
程式碼安全問題
我們都知道eval接收一個字串,然後解釋為一段可執行的程式碼,在傳遞進來的字元為不可預知的情況,這是多麼危險的行為。在JavaScript中有類似功能,還有: setTimeout
、setInterval
、new Function
,我們應該儘量避免這樣使用它們。
說到with,它會在你不知的情況下把一些內部作用域宣告的函式或者變數洩露到其他作用域,例如洩露到全域性:
function a() { console.log('hello') }function foo(obj) { with(obj) { a = function() { console.log("hi") } } }var obj = { b: 3} a(); // hellofoo(obj)console.log(obj.a) // undefineda(); // hi
在obj建立了作用域沒有找到a,然後在foo()作用域找,也沒有找到、最後在全域性作用域中找到了,然後就把它給改了。
程式碼更加難於閱讀
這個就不難說明,如果傳遞給它們的引數都是不可預知的變數。那肯定難於閱讀,因為你根本不知道程式碼下一步執行會不會改變這個變數。
總結
with和eval的本意是好,但它們阻斷了變數名的詞法作用域繫結,導致的副作用遠遠大於它的使用價值,所以我們應該在開發中避免使用它們。
參考資料
《你不知道的Javascript》上卷
作者:內孤
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2236/viewspace-2813444/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼不建議使用gotoGo
- 為什麼 Android 中不建議使用 EnumsAndroid
- 為什麼不建議使用免費的IP代理?
- 為什麼不建議在 MySQL 中使用 UTF-8?MySql
- Spring中為什麼不建議使用欄位注入Spring
- 為什麼不建議使用自定義Object作為HashMap的key?ObjectHashMap
- Java面試題:為什麼HashMap不建議使用物件作為Key?Java面試題HashMap物件
- Oracle RAC - Oracle為什麼不建議使用交叉線作為心跳線Oracle
- 為什麼不建議在for迴圈中使用"+"進行字串拼接字串
- 為什麼阿里巴巴不建議MySQL使用Text型別?阿里MySql型別
- Python 為什麼說 Eval 要慎用?使用 Eval 帶來的潛在風險?什麼情況下使用 Eval?Python
- 為什麼不建議函式有太多引數?函式
- 為什麼idea建議使用“+”拼接字串Idea字串
- 為什麼建議使用命令列工具?命令列
- 為什麼判斷物件是否相等, 不建議用 equals ?物件
- 談一談全棧,為什麼不建議初學者去做全棧
- 2024年 為什麼不建議新人學習ABAP
- 為什麼不再建議使用GOPATH以及如何使用Go ModulesGo
- 為什麼我不建議你通過 Python 去找工作?Python
- 為什麼不建議把資料庫部署在docker容器內?資料庫Docker
- 為什麼阿里巴巴不建議在for迴圈中使用"+"進行字串拼接阿里字串
- 為什麼阿里巴巴不建議在for迴圈中使用”+”進行字串拼接阿里字串
- 入行IT,為什麼建議你學Java?Java
- 為什麼現在連Date類都不建議使用了?
- 什麼是eval()?eval是用來幹什麼的?
- 知乎萬贊:為什麼我不建議你轉行學python?Python
- 為什麼不建議給MySQL設定Null值?《死磕MySQL系列 十八》MySqlNull
- 為什麼不建議在非同步階段注入 Vue 3.0 的生命週期非同步Vue
- 為什麼建議你常閱讀原始碼?原始碼
- 為什麼MOBA類和“吃雞”遊戲不推薦用tcp協議遊戲TCP協議
- 為什麼不建議你用 MongoDB 這類產品替代時序資料庫?MongoDB資料庫
- 為什麼建議將安全性構建到系統中?
- 為什麼java不推薦使用vectorJava
- 為什麼我牆裂建議大家使用列舉來實現單例。單例
- Python中eval如何使用?其作用是什麼?Python
- Python中eval函式是什麼?如何使用?Python函式
- 為什麼 JakeWharton 建議:App 只要用到一個 Activity ?APP
- 程式語言這麼多,為什麼建議選擇Python?Python