iT邦幫忙

0

搞不清楚會很困惱的 語法作用域(Lexical Scope)

  • 分享至 

  • xImage
  •  

範例1:

這個範例下面執行Myname(genius),會秀出Eason名子

var genius='anyone';
function Myname(){
var genius='Eason'
console.log(genius); 
}
Myname(); 

範例2:

這個範例會秀出Eason 下一行 anyone。

var genius='anyone';
function Myname(){
var genius='Eason'
console.log(genius);
}
Myname();
console.log(genius);

我想試著用語法作用域(Lexical Scope)來解釋這件事情。

首先帶入的第一個觀念是:靜態作用域與動態作用域

JavaScript屬於靜態作用域,語法解析的時候就已經決定了作用域,且決定後不會再改變。

而它的作用域是一層一層向內的,如下圖,最外層是全域,裡面有Myname()跟Heyyou()兩個函式,而這兩個函式,各自是一個作用域,若函式內還有函式,裡面包住的那個函式也是一個作用域,

而當函式中需要某變數,而該作用域裏頭沒有這個變數,它就會開始向外查找,如果一直找不到這個變數,就會出現「ReferenceError: OOO is not defined」的錯誤訊息 (OOO是變數名稱)。

範例3: 向外查找

因為Myname()裡面沒有宣告genius所以向外查找,找到了全域變數中的genius,所以後來秀出了anyone

var genius='anyone'; //全域變數
function Myname(){
console.log(genius);
}
Myname();

所以我們回到範例1的部分,最下面那行Myname(); 呼叫了函式,裡面宣告了genius='Eason',並且使用console.log(genius); ,秀出了Eason,展現的是Myname()這個函式的作用域裡的執行狀況。

var genius='anyone';
function Myname(){
var genius='Eason'
console.log(genius); 
}
Myname(); 

接著是範例2,如同範例1,我們知道Myname()函式秀出Eason,套用作用域的觀念,最底下那行console.log(genius);並不會秀出含式的內容,因為作用域是個別運作的,所以沒有因為先執行了函式而改寫了全域變數的var genius='anyone';而最底下的console.log會抓到的就是全域變數。

所以依照執行的順序,秀出的第一行Eason 第二行anyone。

var genius='anyone';
function Myname(){
var genius='Eason';
console.log(genius);
}
Myname();
console.log(genius);

最後一段範例,研究一下動態&靜態作用域的差別。

經過上面的敘述我們可以判斷JavaScript的靜態作用域,在語法解析時便已經決定了作用域,fn02定義的var num=2只會存在於該函式中,fn02中呼叫了fn01,fn01中的console.log(num);函式中變數沒有定義,所以向外查找,找到全域變數的var num=1;,所以秀出了1。

如果是動態作用域呢,程式碼執行的順序會是這樣子:

宣告var num=1;,直行fn02,裏頭從新宣告num=2,然後再fn02中呼叫fn01執行consolo.log,動態作用域再函式調用的時候才決定作用域,所以fn01就向上一層函式宣告的位置取得了num=2的結果。

var num=1;
function fn01(){
           
console.log(num);
}
function fn02(){
var num=2;
fn01();
}
fn02();

參考資料:

六角學院-JavaScript核心篇
連載於Eason的前端筆記


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言