iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0
自我挑戰組

Jr 前端工程師面試題目檢討賽系列 第 2

【2023 挑戰賽 Day2】 #JS 變數提升

  • 分享至 

  • xImage
  •  

好的各位,我們今天要接續昨天的題目,來討論一個我在面試中遇到的 JavaScript 考題。

先讓我們重新複習一下題目:

請問下列程式碼執行結果為何?

try {
 throw new Error();
}catch(x){
    var x = 'X'
    var y = 'Y'
    const z = 'Z'
    console.log(`${x} is in the catch`)
    console.log(`${y} is in the catch`)
    console.log(`${z} is in the catch`)
}
    console.log(`${x} is outside the catch`)
    console.log(`${y} is outside the catch`)
    console.log(`${z} is outside the catch`)

在第一天,我們了解由於 try...catch 機制的關係,六行程式碼依序執行的順序會是:
console.log(${x} is in the catch)
console.log(${y} is in the catch)
console.log(${z} is in the catch)
console.log(${x} is outside the catch)
console.log(${y} is outside the catch)
console.log(${z} is outside the catch)

那麼在第二天,我們即將討論 JavaScript 變數提升的特性在這個題目中造成的影響。

開始!
/images/emoticon/emoticon08.gif

二、變數提升的作用

在討論題目本身之前,讓我們先複習一下 var, let, const 三種變數的特性(這本身也是一個很常見的考題唷!)

  1. 作用域:var 為函數作用域、 let 跟 const 為區塊作用域。

  2. ① var 變數可重新聲明、重新賦值;
    ② let 變數不可重新聲明、可重新賦值;
    ③ const 不能重新聲明也不可以重新賦值。const 最嚴格,只有聲明為物件時才能改變物件內部的值。

  3. 三種變數都會被提升,但是提升之後的狀態不太一樣。var 在提升後,會被初始化為 undefined,而 let 跟 const 則會進入 「暫時性死區」(Temporary Dead Zone,簡稱 TDZ)

/images/emoticon/emoticon77.gif (暫時性死區?殭屍復活?)

如果常常跟我一樣去複習面試題的話,第 1、第 2 點應該都算熟悉,但針對第 3 點的「暫時性死區」可能也有點陌生。那是一個 介於「提升」與「賦值」之間的奇異時空!所以當 var 被提升後,我們還是可以存取到(顯示值為 undefined),但在 let 跟 const 進入「暫時性死區」後,我們試圖存取就會拋出錯誤,在控制台看到 ReferenceError: Cannot access ... before initialization,此時程式碼暫停,不再往下執行。

回到題目本身,綜合以上三點的概念,我們透過註解來說明:

var x; // var 變數為函數作用域,被提升到外部,此時若存取 x 變數將獲得 undefined
var y; // var 變數為函數作用域,被提升到外部,此時若存取 y 變數將獲得 undefined

try {
 throw new Error();
}catch(x){
    const z; // const 變數為區塊作用域,於是提升到 catch 區塊的頂部,並進入 TDZ
    x = 'X' // var x 被重新賦值為 'X'
    y = 'Y' // var y 被重新賦值為 'Y'
    z = 'Z' // 此處 z 變數才賦值為 'Z'
    console.log(`${x} is in the catch`) // 存取到變數 x 的 'X'值
    console.log(`${y} is in the catch`) // 存取到變數 y 的 'Y'值
    console.log(`${z} is in the catch`) // 存取到變數 z 的 'Z'值
}
    console.log(`${x} is outside the catch`) // 這裡會是什麼呢?明天繼續討論!
    console.log(`${y} is outside the catch`) // 變數 y 是函數作用域,'Y'值仍可以被存取
    console.log(`${z} is outside the catch`) // 變數 z 是區塊作用域,離開區塊後就無法存取,顯示 ReferenceError 拋出錯誤 

綜合結論,以上的執行會在控制台看到的結果依序是:

X is in the catch
Y is in the catch
Z is in the catch
// 這裡會是什麼呢?明天繼續討論!
Y is outside the catch
Uncaught ReferenceError: z is not defined

好的,以上就是今天討論的變數提升概念,現在我們已經知道這 6 行代碼其中 5 行會印出的答案了~(灑花)
明天我們將討論 catch 的陷阱,也就是 console.log(${x} is outside the catch) 這一行的答案。

我們明天見!

/images/emoticon/emoticon07.gif

參考資料:

Huli:我知道你懂 hoisting,可是你了解到多深?
Eva:2021鐵人賽[Day 18] JS - 變數提升Hoisting


上一篇
【2023 挑戰賽 Day1】 #JS try...catch 例外處理機制
下一篇
【2023 挑戰賽 Day3】 #JS catch()的陷阱
系列文
Jr 前端工程師面試題目檢討賽14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言