目錄
eval
with
catch
性能
總結
首頁 web前端 js教程 JavaScript欺騙詞法的eval、with與catch及其效能問題

JavaScript欺騙詞法的eval、with與catch及其效能問題

Feb 28, 2017 pm 02:58 PM

正常來說,執行期上下文的作用域鍊是不會改變的 

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);
}
登入後複製

JavaScript欺騙詞法的eval、with與catch及其效能問題

#看起來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的嚴格模式乾脆就不讓用
如果你嘗試使用你會看到這樣的錯誤:

JavaScript欺騙詞法的eval、with與catch及其效能問題

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 )!


#
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

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

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

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

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

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

Vue開發注意事項:避免常見的記憶體佔用和效能問題 Vue開發注意事項:避免常見的記憶體佔用和效能問題 Nov 22, 2023 pm 02:38 PM

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

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

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

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

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

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

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

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

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

See all articles