🌪️

JavaScriptにおける巻き上げ

に公開

JavaScriptの巻き上げ(Hoisting)を正確に把握してなかった為に、挙動に困った事があったので、学習用にまとめました。

巻き上げとは

巻き上げ(Hoisting)とは、変数宣言や関数宣言がスコープの最上部に移動する挙動。

以下コードは関数宣言のhogeFunctionが巻き上げられ、スコープの最上部に移動した結果、1行目でhogeFunction()を呼び出すことができています。

console.log(hogeFunction()); // "こんにちわ"
function hogeFunction() {
  return "こんにちわ";
}

これが基本的な巻き上げです。
ただ、それぞれ注意すべき挙動の違いがあるので見ていきます。

変数の巻き上げ

varで宣言された変数は、そのスコープの最上部に巻き上げられます。
ただ、以下のコードでは最初のconsole.logundefinedを出力しています。

基本的に宣言のみ巻き上げされて、初期化や代入は巻き上げされません。

つまり以下コードでは、var hoge;という宣言のみが巻き上げられ、hoge = 1という代入は巻き上げされません。
なので、最初のconsole.logでは宣言はされているものの未定義のままです。

console.log(hoge); // undefined
var hoge = 1;
console.log(hoge); // 1

varとlet/constの挙動

varは巻き上げられます。
letconstは巻き上げられません。

letconstも内部的には巻き上げられますが、宣言される行まで一時的なデッドゾーンにあります。この間、変数は存在するもののアクセスできないため、参照エラーになります。

console.log(hoge); // ReferenceError: hoge is not defined
let hoge = 1;
console.log(hoge); // 1

関数の巻き上げ

関数の巻き上げは、関数宣言と関数式で挙動が異なります。

関数宣言

関数宣言は、コードの最上部に巻き上げられます。

console.log(hogeFunction()); // "こんにちわ"
function hogeFunction() {
  return "こんにちわ";
}

関数式

関数式は変数に関数を割り当てて定義するため、変数の巻き上げの規則に従います。
varで宣言された場合、変数名は巻き上げられますが、関数の本体は巻き上げられません。
※関数式でもletconstの宣言は巻き上げられない為、変数宣言前にアクセスしようとするとエラーが発生します。

console.log(hogeFunction); // undefined
var hogeFunction = function() {
    return "こんにちわ";
};
console.log(hogeFunction()); // "こんにちわ"

参考
https://developer.mozilla.org/ja/docs/Glossary/Hoisting

Discussion