詳解JS作用域(一)

2022-04-05 16:32:49 字數 2397 閱讀 4475

儲存和訪問變數,是任何一種程式語言最基本的功能之一,變數存在**?程式需要時如何找到它?這些問題需要一套良好的規則來規範,這套規則,就成為作用域。

js通常歸類為解釋語言,但它其實是編譯語言,和傳統編譯語言不同,它不是提前編譯,編譯結果也不能在分布式系統中進行移植。js引擎進行編譯的步驟和傳統的編譯語言非常相似,傳統編譯語言,程式中的一段原始碼在執行之前會經歷三個步驟,統稱為「編譯」。

2.1 分詞/詞法分析

這個過程會講由字元組成的祖父穿分解成有意義的**塊。這些**塊叫詞法單元。例如:var a=2;會分解成以下這些詞法單元:

var、a、=、2、;

空格是否會被當做詞法單元,取決於空格在這門語言中是否具有意義。

2.2 解析/詞法分析

這個過程是將詞法單元流轉成乙個由元素逐級巢狀所組成的代表了程式語法結構的樹,這個樹叫做抽象語法樹(ast)

var a=2; 的抽象語法數中可能會有乙個叫做variabledeclaration的頂級節點,接下來是乙個叫做identifier(它的值是a)的節點,以及乙個叫做assignmentexpression的子節點,assignmentexpression節點有乙個叫做numericliteral(它的值是2)的子節點。

2.3 **生成

將ast轉換成可執行**的過程叫做**生成,簡單來說就是有某種方法可以講var a=2 ;的ast轉化成一組機器指令,用來建立乙個叫做a的變數(包括分配記憶體等),並將乙個值存在a中。

比起那些編譯過程只要三個步驟的語言編譯器,js引擎要複雜得多,例如,在語法分析和**生成階段有特定的步驟來對執行效能進行優化,包括對冗餘元素進行優化等。簡單來說,任何js**片段在執行前都要進行編譯(通常就在執行前),因此js編譯器首先會對var a=2;這段程式進行編譯,然後做好執行他的準備,並且通常馬上就會執行它。

3.1 參與到var a=2;進行處理的過程中的演員們

引擎:從頭到尾負責整個js程式的編譯和執行過程

編譯器:引擎的好朋友,負責詞法分析以及**生成等髒活累活。

作用域:引擎的另外乙個朋友,負責收集並維護由所有宣告的識別符號(變數)組成的一系列查詢,並實施一套非常嚴格的規則,確定當前執行的**對這些識別符號的訪問許可權。

3.2 對話

看看var a=2;的執行過程。

編譯器首先會將這段**分解成詞法單元,然後將詞法單元解析成乙個樹結構,但是當編譯器進行**生成時,他對這段程式的處理方式和預期的有所不同。可以合理地假設編譯器所產生的**能夠用下面的偽**進行概括:「為乙個變數分配記憶體,將其命名為a,然後將值2儲存在這個變數」,然而,這並不完全正確。

事實上編譯器會進行如下處理:

遇到var a,編譯器會詢問作用域是否已經有乙個該名稱的變數存在於同乙個作用域的集合中,如果是,編譯器會忽略該宣告,繼續進行編譯,否則他會要求作用域在當前作用域的集合中宣告乙個新的變數,命名為a。

接下來編譯器會為引擎聲稱執行時所需的**,這些**備用處理a=2這個賦值操作。引擎執行時會首先詢問作用域,在當前的作用域集合中是否存在乙個叫做a的變數,如果是,引擎會使用這個變數,否則,引擎會繼續查詢變數。

如果引擎最終找到了a變數,就會將2賦值給它,否則引擎會舉手示意丟擲乙個異常。

所以,變數的複製操作會執行兩個動作,首先編譯器會在當前作用域中宣告乙個變數(如果之前沒有宣告過),然後再執行時引擎會在作用域中查詢這個變數,如果能夠找到就會對他賦值。

3.3 編譯器有話說

編譯器在編譯過程的第二步中生成了**,引擎執行它時,會通過查詢變數a來判斷是否已宣告過,查詢的過程由作用域協助,但是引擎執行怎麼樣的查詢,會影響最終的查詢結果。

引擎為會a進行lhs查詢,另外乙個查詢的型別叫做rhs。

當變數出現在賦值操作的左側時,進行lhs查詢,出現在右側時進行rhs查詢。

console.log(a); //對a的引用是乙個rhs引用

a=2;//對a的引用是lhs引用

當乙個塊或者函式巢狀在另外乙個塊或者函式中時,就發生了作用域巢狀,在當前作用域中無法找到這個變數時,引擎就會在外層巢狀的作用域中繼續找,直到找到該變數,或抵擋最外層的作用域位置。

function foo(a)

var b=2;

foo(2);

引擎:foo作用域兄弟,你見過b嗎?我需要對它進行rhs引用。

作用域:沒有

引擎:foo的上級作用域兄弟,你見過b沒?我需要對它進行rhs引用。

作用域:當然了,給你!

作用域是一套規則,用於確定在何處以及如何查詢變數,如果查詢的目的是對變數賦值,那麼就使用lhs查詢,如果目的是獲取變數的值,就用rhs查詢,

JS作用域和作用域鏈

什麼是js作用域?js作用域也就是js識別變數的範圍 1 全域性作用域 2 區域性作用域 3 e6的塊級作用域 全域性作用域 也就是定義在window下的變數範圍,在任何地方都可以訪問 區域性作用域 是只在函式內部定義的變數範圍 塊級作用域 簡單來說就是用let和const在任意的 塊中定義的變數都...

JavaScript 作用域,作用域鏈詳解

前言 es5缺少區域性作用域的概念,而es6已經補充了es6的概念。一 作用域 把作用域比作乙個個封閉的方塊,在相同乙個封閉方塊中的物體可以相互接觸,但是無法和別的封閉方塊中的物體直接接觸。二 全域性作用域 這個就是簡單的全域性作用域。全域性作用域相當於乙個最大的封閉空間,他裡面還有乙個個小的封閉空...

js中的作用域和作用域

作用域是在執行時 中的某些特定部分中變數,函式和物件的可訪問性 簡單的說就好似變數能起到作用的範圍 區域性作用域 也可以叫做函式作用域 一般只在固定的 片段內可訪問到,最常見的例如函式內部 如下 在我們在函式中用var關鍵字宣告乙個 變數 a 在函式外輸出a的值 function scope con...