JavaScript 的 hoisting 是什麼

2024-10-01

今天複習一下怎麼解釋 JavaScript 的 "hoisting" ,順便記錄一下,免得自己未來被問到又忘記怎麼解釋。

Hoisting

JavaScript 在執行我們的程式碼之前,會先把變數掃過一遍,並且將變數和對應的 value 存進 memory ,根據不同的變數宣告方式,會有不同的 value 存進去。可以想像成我們宣告變數的那一行程式碼,會被移到最上面,不過只有 declaration, initialization 不會。

console.log(foo);
var foo = 1;
var foo;
console.log(foo);
foo = 1;

JavaScript 的 compiler 並不會真的這樣做,這邊只是為了方便理解

前面有提到不同的宣告方式,會存不同的 value 進 memory ,可能是 undefined,也可能是 ReferenceError,接下來放幾個範例讓讀者猜猜 console.log 會有什麼結果。

console.log(foo);
var foo = 1;
console.log(foo);
console.log(foo);
let foo = 1;
console.log(foo);
console.log(foo);
const foo = 1;
console.log(foo);
console.log(foo);
foo();
var foo = function () {
  console.log('foo');
};
console.log(foo);
foo();
function foo() {
  console.log('foo');
}
console.log(foo);
class Foo {
  constructor() {}
}
foo();
import foo from './foo';

如果不確定答案的話,可以試著直接執行這些程式碼看看。

這些範例程式碼不能直接跑在 REPL 的環境(例如瀏覽器 console)

Cheat sheet

宣告方式在宣告前就 access 的結果
var fooundefined
let fooReferenceError
const fooReferenceError
class FooReferenceError
var foo = function() {}undefined
function foo() {}可以直接 access
import foo可以直接 access

結語

其實在現在的 codebase 裡面,已經很難找到用 var 來定義變數了,因為在 init 之前就去 access var 定義的變數並不會像 const, let 一樣報錯,而是會得到 undefined ,這樣還滿難 debug 的。

雖然我覺得寫 JS 的人不太可能不知道這個,但因為面試偶而還是會考這個,所以拿出來複習一下。畢竟也不是什麼很難的觀念,有個大概的印象就好。