當我們學會了 Javascript 的 Function 怎麼使用後,有沒有常常因爲參數、變數、全域變數傻傻分不清楚的問題呢?今天我們就來聊聊 Javascript 的 Function Scope 吧!
HIHI~😍 如果你是第一次來的話,『Chan-Chan-Dev』是一個專門用簡單的圖文與故事講解網路程式技術的網站。
若你也喜歡用這種方式學習的話,歡迎加入 Chan-Chan-Dev Facebook 的粉絲團,在發佈的時候就有比較多機會收到通知喔!😍
Function 前情提要
在上一篇 Javascript Function 超基礎入門!老司機勿入! 提到 Function 的最基礎用法,若錯過的朋友可以先花個簡單的幾分鐘瀏覽一下喔 😀
Function Scope 函數作用域
什麼是 Function Scope 函數作用域呢?
在回答這個問題之前,讓我們一樣來個小故事吧 😆
從前從前從前在一塊元古的大陸上,這塊大陸上有著好幾個大大小小的原始的部落。
這些部落裡中有個不成文且流傳已久的奇怪規定,就是『任何一個從這個部落出生的人,終其一生都不可以跨越邊界』
,因此每個部落的首領下令用粗壯的樹幹圍出部落的邊界
,並且禁止部落的人到外頭去。
小明是出生在部落 A
的小孩,因此你在部落 A
呼喊『小明』的名字,你就可以找到部落 A
的小明。
相反地,如果你在部落 A
以外的地方呼喚『小明』的名字,部落 A
以外的人就會對你黑人問號,不知道你在找誰,跟你說這裏沒有這個人啦 😵
我們把鏡頭還給棚內 !
我們可以把整個 <script>....</script>
之間的區域假想爲一塊大陸
,在實際宣告 function 的時候也會因爲那一對 {}
圍出一個 區域
,而這個區域就叫做 Scope 作用域
。就像是圍出一個個不同的部落
。
function 所圍出的邊界
就像是 電網
一樣,因此若是在這個區域
裏面出生的孩子(例如:宣告的變數、參數)都被告知絕對不可以走出這個區域以外
的地方 😭
也因為他們只能活在這對{}
所形成的區域內,因此被稱爲 區域變數 Local Variables
。
簡單地來看一下這段程式範例:
1 | function a() { |
在執行過後,就會發現 Console 印出:
部落 A 小明 👈 由第 3 行印出
Uncaught ReferenceError: min is not defined 👈 執行第 6 行發生錯誤
在第二行的 min
是在 a
function 裏面宣告的,因此它的 scope (作用域 / 生存範圍)
就只能在第 2 ~ 3 之間。
也因為如此,當我們在 a
function {}
以外的範圍,試圖地取用 min
這個變數時,就會像是在部落 A
外頭呼叫小明的名字一樣,因為沒有人認識,所以就會得到 min is not defined
的錯誤囉 😆
避免命名衝突
另一個 function 的區域變數同名的狀況
就是這麼巧,因為小明
是一個菜市場名!
在另外一個部落 B
剛好也有一個小明,如果在部落 A
裡呼喚小明的話,你只會找到部落 A
裡的小明,你不會找到部落 B
的小明,因為部落 B
的小明根本不在部落 A
阿!
反之,在部落 B
的話,是只會找到部落 B
的小明的,不會找錯找到部落 A
的小明。
1 | function a(){ |
因此,function 有像是部落的邊界作爲隔絕的話,就可以像上述一樣避免命名衝突的問題了。
我們可以看到 a
、b
有一樣命名的變數 min
,但是因爲是在不同的 function 內存取,因此就不會有互相撞名衝突的問題囉!
function 外的同名變數狀況
小明因爲太菜市場名了!出現了一個出生在大陸上的小明,他不屬於任何部落
,就自己漂流在這片大陸上,那。。那會發生什麼事情呢?
1 | <script> |
相較於宣告在 function 的區域變數
,若他不是宣告在 function 內的話,則會稱作全域變數
,就像是上面宣告在最外層的 min
變數一樣。
如果我們一樣在部落 A
的呼喊『小明』的名字,因爲部落 A
的人只認識部落 A
的小明,因此你還是可以找到部落 A
的小明。
1 | const min = "漂流大陸的小明"; |
如果這時候你在部落 A
以外的地方呼喊『小明』的名字,大陸上的居民只認識漂流大陸
的小明,因此你就可以找到漂流大陸
的小明,你不會找到任何一個部落
裡的小明。
1 | const min = "漂流大陸的小明"; |
如果部落裡沒有這個人…
如果今天後山的部落 C 根本沒有小明
這個人,但是我們卻在部落 C
呼喊『小明』的名字,我們會找的到小明嗎?就算有找到的話會找到哪一個小明呢?
尋人的步驟是這個樣子的:
若部落
裡有你要找的人,你就可以找到的到這個人。
但如果發現沒有你要找的這個人,就會派渡鴉到部落以外一層
去尋找你要找的人囉。
因爲部落 C
建立在大陸上,因此你在部落 C
呼喊『小明』的名字,部落沒有小明這個人的話,就會往外找到漂流大陸
的小明囉!
1 | const min = "漂流大陸的小明"; |
巢狀 function 狀況
我們把上述的程式碼稍微調整一下,改爲以下:
1 | function a(){ |
若把 c
function 改放進 a
function 內的話,這時候的 min
變數會是誰呢?
還記得這個尋人邏輯嗎?
若部落
裡有你要找的人,你就可以找到的到這個人。
但如果發現沒有你要找的這個人,就會派渡鴉到部落以外一層
去尋找你要找的人囉。
可以稍微用上面的尋人邏輯去想想看答案喔 😀
到底是哪個小明呢!?
“部落 A 小明”! 因爲 a function 爲 c function 的外層,因此若往外找到 a function 內有 min 這個變數就會直接使用囉! 相信聰明的你一定猜對了吧!
參數
我們在 Javascript Function 超基礎入門!老司機勿入! 有提到 參數
是用來作爲 function 輸入
。
那他究竟是區域變數
還是全域變數
呢?
執行底下程式碼會得到 min is not defined
的錯誤!
1 | function a(min){ |
區域變數”! 因此他 Scope 作用域也只會作用在在這個 function 內喔!
我們知道參數
爲區域變數
後,我們也一起來猜猜底下第 5 行的 min
變數究竟是誰吧 😆
1 |
|
到底是哪個小明 ?
答案是:”部落 A 小明”! 因爲 a function 沒有 min 這個區域變數,因此若有參數的情況下,會找找看是否有這個
min
的參數,若有找到就會直接使用囉! 相信聰明的你一定猜對了吧!
Block Scope 區塊作用域
咦?那例如 if
或者是 for
等等的語法也有一對 {}
,這樣也會有 Scope 作用域
嗎?
沒錯!他們也是 Scope 作用域
的一種,叫做 區塊作用域 Block Scope
。
不過前提是變數的宣告是要使用 ES6 的 let 與 const 方式喔!若是使用 var 的方式除了 function 以外的 {}
就沒有作用域可言了 😭
我們稍微拿 if
來比較一下吧
1 | if(true){ |
執行後會發現 min1
居然在第 7 行,也就是 if
之外居然還可以被存取到!
剩下的 min2
、min3
因爲無法在 if 的作用域之外被存取,而會產生 min2 is not defined
的錯誤囉!
結論
爲了講個 Scope 居然得畫這麼多個小明加上場景(而且畫風還有點不一樣 😆)
在這篇文章我們講解了 Javascript 的 function 作用域是什麼,以及為什麼需要他。
最常遇到的是 function 變數撞名衝突後,因爲對於 function 作用域的沒有完全地理解而造成預期以外的 Bug。
希望這篇文章用一個瞎掰的小故事可以幫助到大家對於 function 作用域更瞭解一些。
最後感謝你願意看到這裏,希望這篇文章對你有所幫助。
若你想到身邊有需要這篇文章內容的朋友,也請你幫他一個忙把這篇文章分享給他 😍
若文章的內容有錯誤的地方,也歡迎隨時一起討論交流。😘
最後感謝你的閱讀囉,我們下次見!Bye ~ 🚀