iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 4
0
Modern Web

教練我想學 JavaScript 系列 第 4

Day 4 執行環境的創造階段與 Hoisting

我們已經知道全域執行環境會替我們產生全域物件(Global Object)與特殊變數 this,在執行環境裡也會產生外部環境,

可以將執行環境可以分成兩個階段,我們先來看第1階段,第1階段是創造階段,
透過範例來看:

var a = 'Hello World!';

function b() {
  console.log('Called b!');
}

b();
console.log(a);

透過 Chrome 的 Console 來看結果如下:

我們再把程式碼改寫如下:

b();
console.log(a); 

function b() {
  console.log('Called b!');
}

會看到 Console 中的結果如下:

因為我們沒有宣告變數,

在執行環境在創造階段時,變數 a 沒有被設定進記憶體空間中,
所以會出現錯誤,

但如果們們改變一下程式碼的順序,將程式碼調整如下:


b();
console.log(a); 

var a = 'Hello World!';

function b() {
  console.log('Called b!');
}

現在在 Console 中變數 a 輸出的值為 undefined:

在其他程式語言中,這樣可能會報錯,但 JavaScript 不會,
因為電腦無法直接看懂 JavaScript ,
需要透過語法解析器將 JavaScript 轉換成電腦看的懂的東西,
電腦實際在執行轉換後的指令時執行環境被創造,
在執行環境的創造階段時變數與函數會被設定進記憶體空間,
這個現象稱作 hoisting,

接著是執行階段,
可以將剛才的程式碼看成這樣:

var a;
console.log(a); // undefined

a = 'Hello World!';

執行環境在創造階段時,不知道變數的值為何,
會將變數的預設值設為 undefined,
只有在執行環境進入執行階段時(變數被等號這種賦值符號賦值時)才會知道變數的值:

var a;

a = 'Hello World!';
console.log(a); // 'Hello World!'

接著來了解 JavaScript 和 undefined 之間的關係,
我們再回顧創造執行環境的第1階段,
在執行環境被創造的創造階段,會在全域執行環境幫我們產生全域物件、特殊變數 this 與外部環境(如果有外部環境 this 會與外部環境連結),還會在創造階段替我們將變數與函數設置到記憶體空間(hoisting),

圖片來源:JavaScript 全攻略:克服 JS 的奇怪部分課程第 2 節講座 11 影片截圖

變數在創造階段時會被設定一個初始值 undefined

我們來看個例子:

var a;
console.log(a);

我們到 Chrome 的 Console 中看:

會看到 undefined

但如果我們不用 var 宣告變數,
直接把 a console.log 出來:

console.log(a);

會看到結果如下:

你可能會好奇, undefinedis not defined 的差異,

讓我們再來看個例子:

var a;
console.log(a);


if (a === undefined) {
    console.log('a is undefined!');   
}
else {
    console.log('a is defined!');   
}

在執行環境的創造階段就在記憶體空間中設定變數 a 的值為 undefined
可以看到在 if 判斷中 我們用3個等號(之後會解釋)來比較 aundefined
如果 a 等於 undefinedundefined 不是字串,沒有加單(雙)引號,是 JavaScript 中特殊的值),我們在 Chrome 的 Console 中看到結果如下:

如果我們再將 var a 拿掉:

console.log(a);


if (a === undefined) {
    console.log('a is undefined!');   
}
else {
    console.log('a is defined!');   
}

在 Chrome 的 Console 結果如下:

這是因為在執行環境的創造階段,變數 a 尚未被設定到記憶體中,
所以在進入執行階段時,JavaScript 的執行環境會說「嘿,我在記憶體中找不到 a 這個值」,所以會顯示參照不到這個值的錯誤,

undefined 不代表沒有被設值,會佔據記憶體空間,是 JavaScript 中特殊的關鍵字,一個特殊的值,表示這是 JavaScript 設定的初始值,

永遠不要手動將變數設值為 undefined
我們再來看這個例子:

var a = 'Hello World!';
console.log(a);

a = undefined;

if (a === undefined) {
    console.log('a is undefined!');   
}
else {
    console.log('a is defined!');   
}

在 Chrome 的 Console 中會看到結果如下:

可以看到在 JavaScript 中這樣是完全有效的,
但不建議這樣做,
因為這樣就分辨不出 undefined 是 JavaScript 幫我們設定的初始值或是我們自己設定的了,
這在除錯時會替自己找麻煩,最好讓 undefined 表示我從未設定過這個值。


上一篇
Day 3 物件與全域物件
下一篇
Day 5 執行環境的執行階段
系列文
教練我想學 JavaScript 30

尚未有邦友留言

立即登入留言