JavaScript欺騙詞法的eval、with與catch及其效能問題
正常來說,執行期上下文的作用域鍊是不會改變的
JavaScript中的詞法作用域並不是一成不變的
(詞法作用域/靜態作用域:作用域由書寫程式碼時函數宣告位置決定)
有幾種機制是可以欺騙詞法的
它們是with()、eval()還有try-catch語句的catch子句
其中with和eval我們不應該去使用(會產生很多問題)
欺騙詞法的意思就是欺騙詞法作用域
也就是說,它們在運行時改變了作用域鏈
下面我就來談談這些可以欺騙詞法的機制
eval
eval()函數接受一個字串作為參數,並且解析字串產生程式碼
var a = 123;eval('console.log(a)');// 123
於是控制台列印了123
執行了eval函數之後
js引擎並不知道這段程式碼時動態插入的,並且修改了作用域鏈
引擎還會像往常一樣查找作用域鏈
看下面的程式碼
var a = 1;function demo(){ eval('var a = 2;');//欺骗词法 console.log(a);// 2} demo();
當eval函數執行時,在demo函數執行環境的最頂端作用域添加了變數a
這個局部環境中的a「遮蔽」了全域環境的a
最終導致程式列印2
eval()函數不僅可以修改它目前所處的作用域,甚至可以修改全域作用域
無論怎樣,它都可以在運行期間修改詞法作用域
ES5的嚴格模式對這個函數加了一些限制,我把上面的程式碼加上局部嚴格模式
var a = 1;function demo(){ 'use strict'; eval('var a = 2;'); console.log(a);// 1} demo();
我們發現這回控制台印了1
這是因為在嚴格模式下, eval()運行時擁有自己獨立的詞法作用域(省的它給執行環境的作用域鏈搗亂)
這樣其中的聲明就無法修改它所在的作用域了
這種可以動態產生程式碼的還有兩個和它很像
計時器setTimeout()和setInterval()第一個參數可以是程式碼字串
還有函式建構器new Function()的最後一個參數同樣接受程式碼字串
和eval()一樣,不要使用這種用法,這會帶來嚴重的效能問題,這個問題一會兒再說
with
另一個不建議使用的欺騙詞法的語法就是這個with關鍵字
with通常用作重複引用某個物件的多個屬性的捷徑
好處是可以不需要重複的引用物件本身
例如我想重複使用console物件
console.log(1);console.info(2);console.warn(3);
使用with關鍵字
with(console){ log(1); info(2); warn(3); }
#看起來with好像沒什麼問題,但看下面
function demo(obj){ with(obj){ a = 5; } }var obj1 = {a:1};var obj2 = {b:2}; demo(obj1); console.log(obj1.a);// 5demo(obj2); console.log(obj2.a);// undefinedconsole.log(a);//5 -->变量a居然泄漏到了全局环境
我們發現使用with關鍵字修改了obj1的a
但是它不僅沒有在obj2上增加a,反而產生副作用洩漏到了全局
這是因為with可以把一個物件處理為一個完全隔離的詞法作用域(放到作用域鏈的最前面)
所以在它內部產生執行a = 5;
它會向下查找作用域鏈,但沒有找到,於是在全域創建了一個a變數(沒有var 的聲明)
注意:雖然with產生了一個詞法作用域,但是with內部的正常var聲明不會被限制在這個區塊作用域中
也就是說聲明在with外部的作用域
像這樣
function demo(){ var obj = {}; with(obj){ var b = 1; console.log(b); // 1 } console.log(b); // 1} demo(); console.log(b);// Uncaught ReferenceError: b is not defined
而且with關鍵字在ES5的嚴格模式乾脆就不讓用
如果你嘗試使用你會看到這樣的錯誤:
catch
除了eval與with之外,try-catch語句中的catch子句同樣可以修改執行環境的作用域鏈
當try程式碼區塊內發生錯誤,執行流立即跳到catch子句
隨後把異常物件推入一個可變物件並且放到作用域鏈最前面,這和with很像
一旦catch子句執行完畢,作用域鏈就會恢復原樣
但是和eval和with不同,try-catch還是相對有用,不用完全拋棄(雖然我沒用過)
性能
欺騙詞法會產生效能問題
js引擎在編譯階段會進行效能最佳化,許多最佳化依賴於能夠根據程式碼詞法進行靜態分析
預先確定了變數和函數的定義位置,才能快速找到標識符
但是eval或with無法判斷標識符位置(存在於程式碼執行過程中,無法靜態分析)
也就是說:在eval和with面前,js引擎所有的最佳化沒有任何意義(簡直酷炫)
既然沒意義,js引擎乾脆就不優化了
這樣就導致程式運行變慢了
對於with,它還有自己獨特的效能問題…
產生了作用域,就會導致它所在的函數的所有局部變數處於第二個作用鏈物件
存取代價更高了
對於try-catch語句,如果我們想要使用,可以這樣做
try{ ...}catch(e){ handleError(e); }
在catch語句中只執行了一段程式碼,委託給一個函數用於處理錯誤
這樣沒有局部變數的存取
作用域鏈的臨時改變就不會影響效能
總結
總結重點
#詞法作用域意味著作用域是書寫程式碼時函數宣告的位置來決定
編譯時詞法分析階段能知道所有標識符在哪裡及如何宣告eval可以對程式碼字串進行演算,藉此在執行時修改了詞法作用域
with透過將一個物件引用當作作用域來處理,藉此在運行時創建了詞法作用域
#eval在嚴格模式下會產生獨立詞法作用域,無法修改所在作用域
with在嚴格模式下禁止使用
eval與with(還有catch)可以欺騙詞法,在執行時修改作用域鏈
eval與with致使js引擎無法在編譯階段優化作用域查找(無法靜態分析),導致程式變慢
說了這麼多,就是要告訴大家不要使用with關鍵字與eval函數~( ̄0 ̄)/
以上就是JavaScript欺騙詞法的eval、with與catch及其效能問題的內容,更多相關內容請關注PHP中文網(www.php.cn )!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

隨著Vue的使用越來越廣泛,Vue的開發者也需要考慮如何優化Vue應用程式的效能和記憶體佔用。本文將討論Vue開發的一些注意事項,幫助開發者避免常見的記憶體佔用和效能問題。避免無限循環當一個元件不斷更新自己的狀態,或一個元件不斷渲染它自己的子元件時,可能會導致無限循環。這種情況下,Vue將會耗盡記憶體並且使應用程式非常緩慢。為了避免這種情況,Vue提供了一

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。
