摘要:一旦到達(dá)頂層全局作用域,可能找到,也可能沒有找到,查找過程都必須停止。當(dāng)引擎執(zhí)行查詢時,如果查詢在所有嵌套的作用域中遍尋不到所需的變量,引擎就會拋出異常。代表作用域判別失敗相關(guān),而則代表作用域判別成功了,但是對結(jié)果的操作是非法或不合理的。
什么是作用域
對于幾乎所有編程語言,最基本的功能之一就是能夠存儲變量的值,并且能在之后對這個值進(jìn)行訪問和修改。這樣就會帶來幾個問題,這些變量存儲在哪里?程序在需要的時候又是如何找到它們的?要解決這些問題,就需要引入一套規(guī)則來存儲變量和訪問變量,這套規(guī)則就是作用域。
理解作用域在剛開始接觸 JavaScript 這門語言時,肯定會經(jīng)常接觸到?JavaScript 是動態(tài)語言,?是解釋執(zhí)行的,但事實(shí)上?JavaScript 是一門編譯語言。只不過和 Java、C# 這些傳統(tǒng)意義上的編譯語言不同,JavaScript 的編譯過程不是發(fā)生在構(gòu)建之前的。大部分情況下,JavaScript 的編譯過程發(fā)生在代碼執(zhí)行前的很短時間內(nèi)。也就是說?JavaScript 代碼在執(zhí)行前都要進(jìn)行編譯。
為了更好地理解作用域,我們需要明確下面幾個概念
引擎
從頭到尾負(fù)責(zé)整個 JavaScript 程序的編譯及執(zhí)行過程
編譯器
負(fù)責(zé)語法分析及代碼生成等臟活累活
作用域
負(fù)責(zé)收集并維護(hù)由所有聲明的標(biāo)識符(變量) 組成的一系列查詢, 并實(shí)施一套非常嚴(yán)格的規(guī)則, 確定當(dāng)前執(zhí)行的代碼對這些標(biāo)識符的訪問權(quán)限。
下面我們從引擎、編譯器和作用域的角度,分析 var a = 2?這條聲明語句,看看它們是如何協(xié)同完成工作的
遇到 var a, 編譯器會詢問作用域是否已經(jīng)有一個該名稱的變量存在于同一個作用域的集合中。 如果是, 編譯器會忽略該聲明, 繼續(xù)進(jìn)行編譯; 否則它會要求作用域在當(dāng)前作用域的集合中聲明一個新的變量, 并命名為a。
接下來編譯器會為引擎生成運(yùn)行時所需的代碼, 這些代碼被用來處理 a = 2 這個賦值操作。 引擎運(yùn)行時會首先詢問作用域, 在當(dāng)前的作用域集合中是否存在一個叫作 a 的變量。 如果是, 引擎就會使用這個變量; 如果否, 引擎會繼續(xù)查找該變量。如果引擎最終找到了 a 變量, 就會將 2 賦值給它。 否則引擎就會舉手示意并拋出一個異常!
簡單來說,變量的賦值操作會執(zhí)行兩個動作, 首先編譯器會在當(dāng)前作用域中聲明一個變量(如果之前沒有聲明過), 然后在運(yùn)行時引擎會在作用域中查找該變量, 如果能夠找到就會對它賦值,否則就會并拋出一個異常。
作用域嵌套我們知道引擎查找變量的過程在作用域中進(jìn)行的,而這個過程通常會涉及多個作用域。
當(dāng)一個塊或函數(shù)嵌套在另一個塊或函數(shù)中時, 就發(fā)生了作用域的嵌套。 因此, 在當(dāng)前作用域中無法找到某個變量時, 引擎就會在外層嵌套的作用域中繼續(xù)查找, 直到找到該變量,或抵達(dá)最外層的作用域(也就是全局作用域) 為止。
為了便于理解,可以將作用域嵌套比喻成一棟高樓,我們從一樓(當(dāng)前作用域)開始查找,如果沒有找到,就會前往上一個樓層繼續(xù)查找,以此類推。一旦到達(dá)頂層(全局作用域),可能找到,也可能沒有找到,查找過程都必須停止。
繼續(xù)上文的示例,引擎在執(zhí)行編譯器生成的代碼時,會通過查找變量 a 來判斷它是否已經(jīng)聲明過。查找的過程由作用域進(jìn)行協(xié)助, 但是引擎執(zhí)行怎樣的查找, 會影響最終的查找結(jié)果。查找過程分為兩類:LHS查詢和RHS查詢。其實(shí)很簡單,當(dāng)變量出現(xiàn)在賦值操作的左側(cè)時進(jìn)行 LHS 查詢, 出現(xiàn)在右側(cè)時進(jìn)行 RHS 查詢。
更準(zhǔn)確一點(diǎn)的講,?RHS?查詢是查找某個變量的值,而?LHS?查詢是查找變量的容器本身,從而可以對其賦值。如下面的示例:
var a = 2; // a: LHS查詢 var b = 3; // b: LHS查詢 a = b; //a: LHS查詢 b:RHS查詢
為什么區(qū)分 LHS 和 RHS 是一件重要的事情?
因?yàn)樵谧兞窟€沒有聲明(在任何作用域中都無法找到該變量) 的情況下, ?LHS?和?RHS兩種查詢的行為是不一樣的。
1.當(dāng)引擎執(zhí)行?RHS?查詢時,如果 RHS 查詢在所有嵌套的作用域中遍尋不到所需的變量, 引擎就會拋出 ReferenceError異常。?
console.log(a); //ReferenceError: a is not defined
2.當(dāng)引擎執(zhí)行 LHS 查詢時, 如果在頂層(全局作用域) 中也無法找到目標(biāo)變量,全局作用域中就會創(chuàng)建一個具有該名稱的變量, 并將其返還給引擎, 前提是程序運(yùn)行在非“嚴(yán)格模式” 下。如果在“嚴(yán)格模式”下,引擎也會拋出?ReferenceError異常。
//非嚴(yán)格模式 var a =2; b = a; console.log(b); //2
//嚴(yán)格模式 "use strict"; var a =2; b = a; console.log(b); //ReferenceError: b is not defined
另外,如果 RHS 查詢找到了一個變量, 但是你嘗試對這個變量的值進(jìn)行不合理的操作,比如試圖對一個非函數(shù)類型的值進(jìn)行函數(shù)調(diào)用, 或著引用 null 或 undefined 類型的值中的屬性, 那么引擎會拋出另外一種類型的異常, 叫作TypeError。
ReferenceError 代表作用域判別失敗相關(guān), 而 TypeError 則代表作用域判別成功了, 但是對結(jié)果的操作是非法或不合理的。
《你不知道的JavaScript》
微信公眾號:
聲明:本文為博主學(xué)習(xí)感悟總結(jié),水平有限,如果不當(dāng),歡迎指正。轉(zhuǎn)載與引用請注明作者及出處。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104559.html
摘要:前言官方文檔地址中文文檔地址是一個的第三方庫,是的優(yōu)秀實(shí)踐。初次了解是在讀林昊翻譯的設(shè)計(jì)模式與最佳實(shí)踐一書時。能力所限,已翻譯部分可能仍有字詞錯誤或語句不通順的地方,歡迎有能力的同學(xué)幫助糾正。就是其中的佼佼者。 前言 官方文檔地址: https://www.styled-components.com/ 中文文檔地址:https://github.com/hengg/styled-com...
摘要:前言官方文檔地址中文文檔地址是一個的第三方庫,是的優(yōu)秀實(shí)踐。初次了解是在讀林昊翻譯的設(shè)計(jì)模式與最佳實(shí)踐一書時。能力所限,已翻譯部分可能仍有字詞錯誤或語句不通順的地方,歡迎有能力的同學(xué)幫助糾正。就是其中的佼佼者。 前言 官方文檔地址: https://www.styled-components.com/ 中文文檔地址:https://github.com/hengg/styled-com...
摘要:我們先來看一看的官方定義展開語法可以在函數(shù)調(diào)用數(shù)組構(gòu)造時將數(shù)組表達(dá)式或者在語法層面展開還可以在構(gòu)造字面量對象時將對象表達(dá)式按的方式展開。 我們先來看一看MDN的官方定義 展開語法(Spread syntax), 可以在函數(shù)調(diào)用/數(shù)組構(gòu)造時, 將數(shù)組表達(dá)式或者string在語法層面展開;還可以在構(gòu)造字面量對象時, 將對象表達(dá)式按key-value的方式展開。(譯者注: 字面量一般指 [1...
摘要:指北詳談解構(gòu)賦值附贈練習(xí)題一何謂解構(gòu)賦值基本概念首先我們看一下給的定義解構(gòu)賦值語法是一個表達(dá)式,這使得可以將值從數(shù)組或?qū)傩詮膶ο筇崛〉讲煌淖兞恐袕亩x中,我們可以發(fā)現(xiàn)解構(gòu)賦值的作用是對變量進(jìn)行賦值主要通過兩個方面實(shí)現(xiàn)這個作用數(shù)組將數(shù)組中的 ES6指北【6】——詳談解構(gòu)賦值【附贈練習(xí)題】 一、何謂解構(gòu)賦值? 1. 基本概念 首先我們看一下MDN給的定義 解構(gòu)賦值語法是一個 Javasc...
摘要:箭頭函數(shù)基本語法函數(shù)語法具名函數(shù)匿名函數(shù)三句話第一句話聲明第二句話聲明匿名函數(shù)第三句話把匿名函數(shù)賦值給箭頭函數(shù)語法特點(diǎn)只能做賦值,不能做聲明第一種寫法完全寫法不省略參數(shù)個數(shù),不省略函數(shù)體花括號參數(shù)個數(shù)函數(shù)體內(nèi)語句個數(shù)第二種寫法省略參數(shù)括號參 1.箭頭函數(shù)基本語法 1.1 ES3 函數(shù)語法 // 具名函數(shù) function xxx(arg1, arg2) { console.lo...
閱讀 2728·2021-11-22 13:52
閱讀 1193·2021-10-14 09:43
閱讀 3648·2019-08-30 15:56
閱讀 2956·2019-08-30 13:22
閱讀 3283·2019-08-30 13:10
閱讀 1571·2019-08-26 13:45
閱讀 1106·2019-08-26 11:47
閱讀 2800·2019-08-23 18:13