iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 5
1
Modern Web

JavaScript基礎二三事系列 第 5

Day05 變數與函式環境、外部參照

執行JavaScript時,接收到翻譯的電腦會先創造一個全域執行環境。當程式呼叫函式,就會在全域環境中創造該函式的(區域)執行環境。而每個執行環境不論全域或區域,都有屬於自己的變數作用域存在。

來看看以下程式碼:

function b() {
	var myVar;
	console.log(myVar);
}

function a() {
	var myVar = 2;
	console.log(myVar);
	b();
}

var myVar = 1;
console.log(myVar); 
a(); 

這樣會顯示什麼呢?

在創造與執行階段,發生了什麼事?我們按照順序來看:

  1. 首先電腦先創造全域執行環境
  2. 函式a、b被設定進記憶體(但還沒被呼叫執行其內容)變數myVar也被創造設定進記憶體,並且它是全域變數,它的全域是瀏覽器(window)。
  3. 接著在執行階段,賦值1給myVar。
  4. 接著console.log(myVar); 印出1。
  5. 接著執行(呼叫)a函式。
  6. 此時函式a執行環境被創造出來。
  7. 在函式a的執行環境中,創造了一個函式a裡的區域變數myVar。
  8. 函式a的變數myVar被賦值2。
  9. console.log印出函式a的變數myVar 顯示是2。
  10. 接著執行(呼叫)b函式。
  11. 此時函式b執行環境被創造出來。
  12. 在函式b的執行環境中,創造了一個函式b裡的區域變數myVar。
  13. console.log印出函式b的變數myVar,顯示是undefined(因為我們沒賦值給它)。

所以雖然myVar被宣告了3次,但因為它都在不同的執行環境中,所以這3個其實是不同的變數
如果我們在剛剛的程式a(); 下面再加一行console.log(myVar);
執行後回發現重新印出myVar仍然顯示1,因為這個myVar就是原本全域的變數myVar,代表其實他沒有被覆蓋掉。

如果函式裡的變數宣告沒有使用var呢?
看看以下程式碼

function a() {
	var myVar = 2;
	b();
}

function b() {
	console.log(myVar);
}

var myVar = 1;
a(); 

執行 結果是

console.log(myVar);這段程式碼是在function b中
b這個函式中根本沒有宣告變數
那為何會印出1而非undefined?

當函式中使用到沒有定義的變數時,JS會接著到外部環境尋找(外部參照),注意這裡的外部環境不是指呼叫這個函式的執行環境,而是指定義宣告這個函式的外部環境。
函式b是在全域環境定義,在函式a中呼叫執行,既然是向定義環境找,所以函數b的外部環境就是全域環境,而不是函式a,故它就找到全域環境的變數myVar,最後印出1。

再看看以下程式碼

function a() {

	function b() {
		console.log(myVar);
	}

	var myVar = 2;
	b();
}

var myVar = 1;
a();
b();

這樣會顯示什麼呢?

為何b會報錯?
因為全域執行環境找不到function b,function b是被定義在function a的環境之中,而全域執行環境只有看到function a的定義存在。

那為何一開始又會先顯示2呢?
當外部環境呼叫執行function a,a裏頭宣告了變數myVar賦值2,再呼叫執行function b,此時執行function b裡的console.log(myVar),因為b裡面沒有宣告myVar這個變數存在,於是便往外部環境查找,也就是外部定義的環境,b是定義在function a中,所以找到的自然是function a的myVar,顯示印出2囉。

上述筆記了這麼多,那有沒有強調區域性的宣告方式?
讓變數在使用不會這麼複雜,沒宣告就會報錯,而不是外部查找。

還是有的!那就是使用ES6新增的let宣告!
let具有區塊範圍(block scoping)特性,用let宣告的相同變數名稱,在全域、區域、不同執行環境彼此互不影響。
 
 
 
小結
今天我們知道全域執行環境就有全域變數、區域執行環境就有區域變數,並且知道當區域內找不到變數時會向外查找,向外查找的外部環境是指外部定義的環境,不能直接認定就是全域環境與呼叫的環境。
 
今天的筆記內容可以參照Udemy課程:JavaScript 全攻略:克服JS 的奇怪部分2-14~2-16


上一篇
Day04 undefined與not defined
下一篇
Day06 JS是同步還是非同步?
系列文
JavaScript基礎二三事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言