iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
自我挑戰組

每日一杯 JavaScript 特調系列 第 6

作用域 Scope、作用域鏈 Scope Chain

在初學階段,還蠻常碰到明明定義好的變數卻回報 error,可能是因為對 Scope 的觀念沒有理解。

什麼是 Scope ?

我習慣稱 Scope 為作用域,有人稱為範疇,是一個用來查找、訪問變數及函式的規則。
在 ES6 的 let、const 出現之前,我們只有函式作用域 ( var ),但 ES6 後多了區塊作用域,主要是定義了 let、const 作用範圍 。

簡單來說,作用域表示變數或者函式有作用的地方。

function sayHi(){
	var guy = 'Lisa'
	function greet(){...}
  console.log(guy)
}

console.log(guy)
greet()

上面程式碼,我們在全域宣告了一個函式 sayHi ,函式裡面宣告變數 guy 以及函式 greet,但當我們想從全域取用 guy 跟 greet 就會報錯,因為這兩者的作用域在 sayHi 裡面。

但為什麼下面的例子,我們可以訪問函式以外的變數?

var idol = 'Rose'

function sing(){
  console.log(idol)
}

sing()

idol 宣告在全域環境,卻能在 sing 函式裡呼叫,這是靠作用域鏈 Scope Chain 查找的結果。

前幾篇講執行環境 Execution context 的時候,我們提到 JS 遇到函式調用時會創建一個屬於該函式的執行環境,每個函式內部有自己的 [[scope]],調用函式時的執行環境會把 [[scope]] 跟 Scope Chain 連結。

當全域執行環境建立時,創造階段初始化了全域的 variable object 以及 scope chain。

globalExecutionContext:{
	VO:{
		idol:undefined,
		sing:function
	},
	ScopeChain:{
		globalExecutionContext.VO
	}
}

// 並且宣告 sing 函式時,sing 的作用域會參考由全域給的 scopechain 的內容
sing.[[scope]] = globalExecutionContext.ScopeChain

接著 sing() 被調用,因著 sing 的 scope 可以透過 scoope chain 取得外部全域的變數

此外,若無使用宣告定義變數的話,則 JS 會視為全域變數 ( 這是不好的習慣哦~ )

var idol = 'Rose'

function sing(){
  fruit = 'grape'
}

console.log(fruit)

上一篇
JS 題:將變數宣告在全域環境是否為好習慣?
下一篇
IIFEs 立即函式:不需呼叫即可執行
系列文
每日一杯 JavaScript 特調7

尚未有邦友留言

立即登入留言