變數宣告與作用域
首先,我們要知道 JavaScript 的變數有它作用域的範圍,未使用 var 所宣告的變數都會自動變成全域變數,而切分變數有效範圍的最小單位是 “function” (ES6 之後有 let 與 const 分別定義「變數」與「常數」。 與 var 不同的是,它們的 scope 是透過大括號 { } 來切分的。)這邊我們舉一個例子,當我們將 console.log(ASin)
放在函式內執行函式時,其結果可以成功印出 ‘名字’,但若我們將其放在函式外時,其結果會顯示 ASin 這個變數並沒有被定義,這就是因為作用域的關係。
1 | function callName() { |
1 | function callName() { |
靜態作用域與動態作用域的差別
JavaScript 是採用靜態作用域(語法作用域),靜態作用域是原始碼在透過直譯器解析語法時,就確定了它的作用域,例如我們上面範例中 console.log(ASin)
在寫 function 時就已經定義好他的作用域。而動態作用域則是在函式調用的時候才決定它的作用域。
JavaScript 作用域的查找
在我們所寫的原始碼中最外層會有一個全域的作用域,然後是各個 function 所形成的作用域,各 function 間的作用域是獨立的。但是,當某個 function 內需要取用一個變數,而這個 function 內沒有這個變數時,就會向外查找,若有則取用,若沒有則會回報錯誤。
靜態作用域與動態作用域執行的結果
所以當我們在寫好這些語法時,它的作用域就已經確定了,不會因為我們在執行時做改變。以下範例我們可以看到,ASin
的作用域在最外層,HYH
作用域只在 CallName2()
這個函式內,當我們執行 CallName2()
時,CallName1()
也會被調用並執行 console.log(name)
,其結果會是 ASin
而不是 HYH
,這邊我們要記得我們在寫好語法時,它的作用域就已經確定了,所以 callName1()
內沒有 name
這個變數因而往外層查找,得到 ASin 這個結果。
那麼如果是動態作用域其情況就會不同,在調用CallName2()
時,它會在函式宣告時才決定他的作用域,所以 callName1()
宣告時在 CallName2()
內,CallName1()
沒有 name
這個變數,所以往外層 CallName2()
查找,最後找到 HYH
。
1 | var name = 'ASin'; |