🔝
JavaScript は全ての変数を巻き上げる
概要
JavaScript は var
, function
以外の変数も巻き上げる。
const f = () => {
console.log(a)
console.log(b)
console.log(c)
}
let a = 'A'
const b = 'B'
class c {}
f()
結果
A
B
class c {}
説明
巻き上げ (英語: Hoisting) は、JavaScript における「変数をスコープの先頭で宣言されたかのように扱う」挙動のことです。
// ← global
{
// ← local
let local
}
let global
実用的 (?) な例として function
で宣言した関数を前方から呼び出すものが有名です。
f() // Hello
function f () {
console.log('Hello')
}
巻き上げの対象は宣言のみで、初期化や代入は反映されません。
例えば var
で宣言と初期化を行った変数を前方から参照すると undefined
が返ります。
console.log(x) // undefined
var x = 'init!'
初期化前の変数は使いどころが無く、意図せず参照しかねないので let
, const
, class
では、参照するとエラーが発生するようになっています[1]。
console.log(x) // Error
let x = 'init!'
結果
Uncaught ReferenceError: Cannot access 'x' before initialization
-> 初期化前の 'x' にアクセスできない
未宣言時のエラーメッセージ[2]と見比べると分かりやすいですが、宣言の巻き上げ自体は var
, function
同様に行われています。
未宣言時
Uncaught ReferenceError: x is not defined
-> x が定義されていない
よって、表記上での前方にて変数を参照することも参照が行われる時点において初期化されていれば可能です。
const f = () => {
// 表記上では前方からの参照
console.log(x)
}
let x = 'init!'
// 実際に参照するタイミングは初期化後
f() // init!
使い道としては「補助関数の記述位置に拘りがあって並び替えたい」場合や「相互再帰な関数の定義」などが考えられそうです。
モジュール
export const main_func = () => {
sub_func()
}
const sub_func = () => {
// ...
}
相互再帰
const main_func = () => {
// ...
sub_func()
}
const sub_func = () => {
// ...
main_func()
}
以上、変数の巻き上げの解説と実用できそうな例の紹介でした。
Discussion