本篇文章給大家帶來關于JavaScript中塊級作用域的實現原理相關知識,在ES6之前,塊級作用域是不被JavaScript所支持的,JavaScript是通過什么支持了塊級作用域的呢?本文將講解塊級作用域的底層實現原理,希望對大家有幫助。
作用域與執行上下文
很多人覺得作用域與執行上下文是一個概念,這種想法是完全錯誤的!
作用域
作用域在函數聲明時就已經確定了,作用域是據名稱來查找變量的一套規則,也就是確定了當前執行代碼對變量的訪問權限。JavaScript一共支持三種類型的作用域,它們分別是:全局作用域、函數作用域、塊級作用域。
執行上下文
執行上下文是js引擎從解釋到運行中間預編譯時對執行做的準備工作,創建了當前區域的執行環境,這個執行環境就是執行上下文。
執行棧
調用棧用來裝js代碼中的各種執行上下文,是js引擎追蹤函數執行的一個機制。
以下面的代碼為例:
console.log(1); function pFn() { console.log(2); (function cFn() { console.log(3); }()); console.log(4); } pFn(); console.log(5); //輸出:1 2 3 4 5
先有全局環境下的執行上下文,調用pFn后將函數環境pFn的執行上下文壓入棧中,由于pFn中執行了cFn函數,所以繼續壓入cFn函數的執行上下文,執行完畢后依次出棧。
全局上下文只有應用程序退出前才會被銷毀,比如關閉網頁或者退出瀏覽器
javascript 是如何支持塊級作用域的
我們知道在js中由于初始設計的不規范,用var關鍵字定義變量會導致變量提升等一系列問題,但為了保持兼容性,我們也不得不對var聲明變量這種方式保留支持,那么:JavaScript是如何做到既要支持變量提升,又要支持塊級作用域的呢?
我們以下面這段代碼為例:
function foo() { var a = 1; let b = 2; { let b = 3; var c = 4; let d = 5; console.log(a); console.log(b); } console.log(b); console.log(c); console.log(d); }
首先函數內部通過var聲明的變量被存放到變量環境中,通過let聲明的變量在預編譯階段被存放到詞法環境中,當然在函數體內部塊作用域中let聲明的變量并沒有被存放到詞法環境中。
繼續執行代碼,當執行到代碼塊里面時,變量環境中的a的值已經被設置為1,詞法環境中b的值已經被設置成了2,注意用let聲明的變量b和d此時不是underfined而是uninitialized未初始化
最后當函數體內塊作用域執行結束之后,其內部變量就會從詞法環境的棧頂彈出
總結
我們可以知道上面問題的答案:
用let 聲明出來的變量中都會在詞法環境中存放,塊級作用域是通過詞法環境的棧結構來實現的,而變量提升是通過變量環境來實現的,兩者結合就同時支持變量提升和塊級作用域
以及變量的查找方式:
從詞法環境的作用域棧頂開始向下查找,如果找到了就返回值,如果找不到,就繼續去變量環境中查找