🔝

JavaScript は全ての宣言を巻き上げる

2021/07/20に公開

巻き上げ

JavaScript において、巻き上げ (英語: hoisting)[1]変数の宣言がスコープの先頭で行われたかのように扱われる動作 を指します。

              // | let b      |
{             // |            |
              // | let a      |
  let a = 10  // |     a = 10 |
}             // |            |
let b = 20    // |     b = 20 |

巻き上げ function

function で宣言した関数は巻き上げによって 前方から実行できます

                  // | function f () {  |          |
                  // |   return "hello" |          |
                  // | }                |          |
console.log(f())  // | console.log(f()) | => hello |
                  // |                  |          |
function f () {   // |                  |          |
  return "hello"  // |                  |          |
}                 // |                  |          |

巻き上げ var

var で宣言した変数は巻き上げによって 前方から参照できます

ただ、巻き上げの対象となるのは宣言のみで、初期化や代入は反映されません
var で宣言と初期化を行った変数を前方から参照した場合、初期化時の値ではなく undefined が取得されます。

                 // | var x           |              |
console.log(x)   // | console.log(x)  | => undefined |
                 // |                 |              |
var x = "hello"  // |     x = "hello" |              |

巻き上げ let, const, class

let, const, class で宣言した変数は巻き上げによって 前方から参照できません
let, const, class で宣言した変数を前方から参照した場合、エラー[3]が発生します。

                 // | let x           |                                                            |
console.log(x)   // | console.log(x)  | => ReferenceError: Cannot access 'x' before initialization |
                 // |                 |                                                            |
let x = "hello"  // |     x = "hello" |                                                            |

let, const, class で宣言した変数は巻き上げによって前方から参照できませんが、宣言の巻き上げ自体は行われています。
よって、変数の初期化後に実行される関数内であれば 表記上での前方から初期化後の値を参照できます

                   // | let x           |          |
const f = () => {  // |                 |          |
  console.log(x)   // |                 |          |
}                  // |                 |          |
                   // |                 |          |
let x = 'hello'    // |     x = 'hello' |          |
                   // |                 |          |
f()                // | console.log(x)  | => hello |

使い道としては 相互再帰な関数の定義補助関数の記述位置を下にしたい 場合が考えられそうです。

相互再帰な関数の定義
const main = () => {
  // ...
  sub()
}
const sub = () => {
  // ...
  main()
}
補助関数の記述位置を下にしたい
export const main = () => {
  sub()
}
const sub = () => {
  // ...
}

(まとめ) JavaScript は全ての宣言を巻き上げる

巻き上げ 変数の宣言がスコープの先頭で行われたかのように扱われる動作
宣言方法 宣言の巻き上げ 定義の巻き上げ
function
var
let, const, class ×

end

脚注
  1. https://developer.mozilla.org/ja/docs/Glossary/Hoisting ↩︎

  2. https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let#一時的なデッドゾーン_tdz ↩︎

  3. https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors/Cant_access_lexical_declaration_before_init ↩︎

GitHubで編集を提案

Discussion