JavaScript 核心觀念(3)-的語法作用域(Lexical scope)

 嗨大家好嗎?

我是Kris,今天要來跟大家講一個我覺得很重要的東西

算是解題時很常用到的基本觀念哦~

相信大家應該多少都有聽過全域變數、區域變數吧

今天要來講的語法作用域就跟這個有關係

讓我們開始吧!


JS是採用語法作用域,那什麼是語法作用域呢?

就是我們定義的變數能夠發揮功能的區域!

接下來可以跟著動手做做看

圖1

建立一個function 叫做callName

在函式內定義變數Ming並且給予'小明'的值

再用console.log列印出Ming的值。

在主程式呼叫callName(); //這樣callName這個function才會運行

會得到結果:上方圖1右方網頁上反白的資料(會印出小明)


接著假設我們把 console.log那一行移至呼叫callName(); 的下一行

如同下圖2

圖2

會得到結果:圖2右方網頁上寫著錯誤訊息-Ming is not defined(Ming未定義)

這是因為JS有語法作用域的關係

因此var Ming = '小明' 能夠發揮功能的區域只在callName這個function內(大括號{}裡面)

在外層是讀不到的,這就是因為作用域的關係~


語法作用域也跟JS怎麼運行有很大的關係

講到語法作用域呢會牽扯到靜態作用域&動態作用域


靜態作用域也就是語法作用域(JS使用的)

指的是在語法解析什就確定能夠發揮功能的區域(就像上面例子寫callName函式時就確定了)

而動態作用域指的是在函式被調用的時候才會決定作用域


重點筆記👇

靜態作用域

變數的作用域在語法解析時,就已經確定作用域,並且不會改變。

動態作用域

變數的作用域在函式調用時才決定。


JS的作用域是一層一層向內的

最外層有一個全域的作用域,內層是由function所包住(全域作用域所定義的變數=全域變數)

如下圖,callMe和fn2就是兩個獨立的作用域

如果內層作用域有需要一些變數,但是此作用域內沒有這個變數的時候

就會向外查找,找到的話就會拿來使用

找不到時就會出現 變數is not defined的錯誤訊息


接下來用程式碼來解釋一下靜態作用域&動態作用域

先將剛剛的code註解,再來打新的code

首先定義變數value = 1

再建立兩個function分別是fn1()和fn2()

fn1()裡使用console.log列印出value的值

fn2()裡定義變數value = 2; 並且呼叫fn1();

在全域作用域呼叫fn2();

程式碼如下圖,可以跟著做哦



這段code運行的順序是

1.定義變數value = 1;

2.執行fn2();  *小提示:如果程式碼內都沒有呼叫fn2()的話,fn2裡的內容是不會被執行的哦*

3.在fn2的時候重新宣告變數value = 2;

4.執行fn1();

5.console.log() 列印出value的值

此時value的值會列印出1

因為JS是語法作用域(靜態作用域)的關係,在撰寫時作用域就已經決定了,且不會改變

因此最上面的value = 1; 是全域變數,作用域包含了兩個fn,如下圖



雖然在fn2()時,將value重新賦予值為2
但它的作用域只在fn2有效
因此在fn1()要列印出value的值時,會向外查找
也就是全域變數的value = 1;
以上是語法作用域(靜態作用域)會得到的結果。

那如果是動態作用域,答案會是什麼呢?
因為動態作用域是函式調用什才會決定作用域
先呼叫fn2()後才呼叫fn1()
因此執行到fn1()時,會向上層查找變數
而fn1()的上一層為fn2,就會查找fn2裡有沒有value這個變數並拿來使用
所以動態作用域的話,此題答案會是2
*注意JS為靜態作用域,這裡只是跟大家解釋如果是動態作用域時會有什麼差別。


總結來說
JS是語法作用域也就是靜態作用域,作用域會在函式撰寫時就決定,並且不會改變
作用域內找不到變數時,會向外層查找也就是全域變數,找不到的話就會有XXX is not defined.
動態作用域只是要讓大家知道有什麼差別,跟JS沒有關係~

今天就到這邊結束,祝大家有美好的一天✌✌✌


『你可以做任何你想做的事情,一切只不過是你的想法阻礙了你的行動』

评论

此博客中的热门博文

JavaScript 核心觀念(5)-執行環境(Execution context)與執行堆疊(Execution stack)

JavaScript 核心觀念(6)-執行環境與作用域-範圍鍊