巻き上げ(ホイスティング)とは?

ホイスティング(Hoisting:巻き上げ)とは、JavaScriptで変数や関数の宣言が、そのスコープの先頭で宣言されたように扱われる仕組みです。
ただし、「コードそのものが移動する」わけではありません。JavaScriptエンジンが実行前に宣言を処理するため、このような挙動になります。
ホイスティングを理解していないと、undefinedになったり、ReferenceErrorが発生したりする原因になります。
varのホイスティング
varで宣言した変数は、宣言だけが巻き上げられます。
console.log(a); // undefined
var a = 10;
console.log(a); // 10
実際には次のように解釈されます。
var a;
console.log(a);
a = 10;
console.log(a);
宣言だけが先に処理され、代入は元の位置で実行されます。
let・constのホイスティング
letやconstもホイスティングされますが、初期化されるまではアクセスできません。
console.log(count);
let count = 10;
実行すると次のエラーになります。
ReferenceError: Cannot access 'count' before initialization
これはTemporal Dead Zone(TDZ:一時的デッドゾーン)と呼ばれる仕組みによるものです。
Temporal Dead Zone(TDZ)とは?
TDZとは、letやconstが宣言されてから初期化されるまでの間を指します。
この期間は変数自体は存在していますが、アクセスするとエラーになります。
{
// TDZ
let value = 100;
console.log(value);
}
TDZのおかげで、初期化前の変数を誤って使用するバグを防ぐことができます。
関数宣言のホイスティング
関数宣言は、関数全体が巻き上げられます。
sayHello();
function sayHello() {
console.log("Hello");
}
このコードは正常に動作します。
関数全体が先に登録されるため、宣言より前でも呼び出すことができます。
関数式のホイスティング
関数式は変数として扱われます。
varで宣言した場合は変数だけがホイスティングされるため、関数はまだ代入されていません。
console.log(sayHi);
sayHi();
var sayHi = function () {
console.log("Hi");
};
このコードでは、sayHiはundefinedなので、関数として呼び出せずTypeErrorになります。
letやconstの場合はTDZのため、さらにReferenceErrorになります。
関数宣言と関数式の違い
| 項目 | 関数宣言 | 関数式 |
|---|---|---|
| ホイスティング | 関数全体 | 変数のみ |
| 宣言前に呼び出し | 可能 | 不可 |
| let・constとの相性 | 問題なし | TDZの影響を受ける |
var・let・constの違い
| 宣言方法 | ホイスティング | 宣言前のアクセス |
|---|---|---|
var |
あり | undefined |
let |
あり | ReferenceError |
const |
あり | ReferenceError |
ホイスティングによるバグを防ぐ方法
varではなくletやconstを使用する。- 変数は使用する前に宣言・初期化する。
- 関数式は定義した後で呼び出す。
- コードを上から順番に読めるように記述する。
まとめ
- ホイスティングとは、宣言がスコープの先頭で処理される仕組みである。
varは宣言だけが巻き上げられ、初期値はundefinedになる。letとconstはTDZにより初期化前はアクセスできない。- 関数宣言は宣言前でも呼び出せる。
- 関数式は宣言後でなければ呼び出せない。
- 現在のJavaScriptでは
letとconstを使用することが推奨される。