[nodejs 內功心法][作用域與閉包系列一] js作用域是什麼?

作用域

作用域是一套規則,用於確定在何處以及如何查找變量。如果查找的目的是對變量進行賦值,那麼就會使用LHS查詢,如果目的是獲取變量的值,就會使用RHS查詢, 下面我們先了解一下 LHS 和 RHS

LHS

換句話說,當變量出現在賦值操作的左側時進行 LHS 查詢,出現在右側時進行 RHS 查詢。
LHS是要找到變量的內存地址,從而對其進行賦值

RHS

RHS查詢與簡單地查找某個變量的值別無二致, RHS就是要獲取變量的值

不多逼逼,直接上代碼吧。

function demo(a) {
	console.log(a);  // 100
}

demo(100)

上面這個例子裏面既有LHS也有RHS, 我們來分析一下哪些是LHS, 哪些是RHS。
.
最後一行demo(…)函數的調用需要進行RHS引用,意味着去“找demo的值,並把它給我”
.
這裏還有一個容易被忽略卻非常重要的細節。
.
代碼中隱式的 a=100 操作可能很容易被你忽略掉。這個操作發生在 100 被當作參數傳遞給 demo(…) 函數時,100 會被分配給參數 a。爲了給參數 a(隱式地)分配值,需要進行一次 LHS 查詢。
.
這裏還有對 a 進行的 RHS 引用,並且將得到的值傳給了 console.log(…)。console.log(…) 本身也需要一個引用才能執行,因此會對 console 對象進行 RHS 查詢,並且檢查 得到的值中是否有一個叫作 log 的方法。
.
最後,在概念上可以理解爲在 LHS 和 RHS 之間通過對值 100 進行交互來將其傳遞進 log(…) (通過變量 a 的 RHS 查詢)。假設在 log(…) 函數的原生實現中它可以接受參數,在將 100 賦值給其中第一個(也許叫作 arg1)參數之前,這個參數需要進行 LHS 引用查詢。

作用域嵌套

當一個塊或函數嵌套在另一個塊或函數中時,就發生了作用域的嵌套。因此,在當前作用 域中無法找到某個變量時,引擎就會在外層嵌套的作用域中繼續查找,直到找到該變量, 或抵達最外層的作用域(也就是全局作用域)爲止。

function demo(a) {
	console.log( a + b );
}

var b = 2
demo(2) // 4

//對 b 進行的 RHS 引用無法在函數 foo 內部完成,但可以在上一級作用域(在這個例子中就 是全局作用域)中完成。
// 下面模擬引擎和作用域的對話
//引擎:foo 的作用域兄弟,你見過 b 嗎?我需要對它進行 RHS 引用。 作用域:聽都沒聽過,走開。
// 引擎:foo 的上級作用域兄弟,咦?有眼不識泰山,原來你是全局作用域大哥, 太好了。你見過 b 嗎?我需要對它進行 RHS 引用。
// 作用域:當然了,給你吧。

遍歷嵌套作用域鏈的規則很簡單:引擎從當前的執行作用域開始查找變量,如果找不到, 就向上一級繼續查找。當抵達最外層的全局作用域時,無論找到還是沒找到,查找過程都 會停止。

爲什麼要區分LHS 和 RHS

因爲在變量還沒有申明(在任何作用域中都無法找到)的情況下,兩種查詢的行爲是不一樣的。

function demo(a) {
	console.log( a + b ); // 對b RHS查詢無法找到變量 拋出ReferenceError錯誤
	b = a
}
demo(2);

上面的例子會拋出 ReferenceError 錯誤

重點

如果 RHS 查詢在所有嵌套的作用域中遍尋不到所需的變量,引擎就會拋出 ReferenceError 異常。值得注意的是,ReferenceError 是非常重要的異常類型。

相較之下,當引擎執行 LHS 查詢時,如果在頂層(全局作用域)中也無法找到目標變量,全局作用域中就會創建一個具有該名稱的變量,並將其返還給引擎,前提是程序運行在非“ 嚴格模式”下。

作用域內心OS: “不,這個變量之前並不存在,但是我很熱心地幫你創建了一個。”

ES5 中引入了“嚴格模式”。同正常模式,或者說寬鬆 / 懶惰模式相比,嚴格模式在行爲上 有很多不同。其中一個不同的行爲是嚴格模式禁止自動或隱式地創建全局變量。因此,在 嚴格模式中 LHS 查詢失敗時,並不會創建並返回一個全局變量,引擎會拋出同 RHS 查詢 失敗時類似的 ReferenceError 異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章