iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 3
0
Software Development

跟我一起上課吧:了解 JavaScript 的奇怪部分系列 第 3

Day3-創造(creation)和提升(hoisting)、undefined

javascript 在創建執行環境時做的其中兩件事是做創造和提升

先來看看示範:

// app.js
var a = 'Hello world!'

function b () {
  console.log('call b!')
}
b()
console.log(a)

在 console 會出現

// console
call b!
Hello world!

那將執行的程式碼移到宣告前面會怎麼樣?

// app.js
b()
console.log(a)

var a = 'Hello world!'

function b () {
  console.log('call b!')
}
// console
call b!
undefined

可以看到沒有出現錯誤,函數一樣被執行,而變數變成 undefind,這是 javascript 特有的現象,稱為 hoisting

首先,執行環境被分為兩階段

第一階段是創造跟提升

執行環境「創造」了全域物件、this 和外部環境,還有「提升」,主要就是「設定變數和函數到記憶體裡」

設定變數時,都會給它 undefind 當作初始值,就像是 placeholder 一樣,換成中文就是「未被宣告的」

所以以前面的例子來說,變數 a 跟函數 b 都會存進記憶體

// 記憶體

a = undefind
function b () {
  console.log('call b!')
}

這是第一階段,那第二階段呢?就是開始執行程式碼,一行一行的按照順序執行,用上面的例子稍微修改一下:

// app.js
b()
console.log(a)

var a = 'Hello world!'

console.log(a)

function b () {
  console.log('call b!')
}

從第一行 b() 開始,這邊編譯器就會發現需要 b 這個函數,於是到記憶體找一找,發現真的有存這個函數,於是執行函數

第二行發現需要 a 這個變數,於是到記憶體找一找,發現有 a 這個變數,值為 undefind,於是 console.log 出來為 undefind

第三行發現了等號,把記憶體中 a 的值改為 Hello world!

第四行又需要 a 變數,再找一下記憶體,發現有 a 且此時的值為 Hello world!,於是印出 Hello world!

故事大概是醬子。

來聊聊特殊的值 undefined

首先比較一下,有使用 var 宣告 a 跟沒有的情況

有使用 var 宣告:

// app.js
var a
console.log(a) 
// console
undefind

沒有宣告:

// app.js
console.log(a)
// console
> Uncaught ReferenceError: a is not defined

可以看到一個是 undefind 一個是 not defined
對變數來說,undefindnot defined 是不同的

Uncaught ReferenceError: a is not defined

仔細看這個錯誤,他的意思是「無法參照的錯誤」,因為在創造階段時,沒有設定 a 到記憶體中,所以執行的時候他找不到。

undefind 是一個特殊關鍵字,是變數在創造階段被設定的值

不要將變數設為 undefind,這會增加 debug 的困難,最好讓 undefind 就表示為你從沒宣告過的值。

總結

  • 執行環境時共有兩個階段,第一階段是創造跟提升,第二階段是執行程式碼
  • 執行環境的「創造」階段會創造全域物件、this 和外部環境
  • 提升就是設定變數和函數到記憶體裡
  • undefind 是 javascript 給變數的初始值,不要自己設定

上一篇
Day2-名詞定義:語法解析器、詞彙環境、執行環境、名稱與值的配對、全域環境
下一篇
Day4-單執行緒、同步執行、執行堆
系列文
跟我一起上課吧:了解 JavaScript 的奇怪部分7

尚未有邦友留言

立即登入留言