メインコンテンツまでスキップ

関数宣言と巻き上げ (hoisting)

JavaScriptの関数宣言と関数式の違いが現れるひとつの例は巻き上げ(hoisting)です。関数宣言には巻き上げがあり、関数式には巻き上げがありません。

まずは関数宣言の例を見てみましょう。次のコードは、3行目にhello関数の関数宣言があります。そして、その宣言の前でhello関数を実行しています。

javascript
hello();
function hello() {
console.log("Hello World");
}
javascript
hello();
function hello() {
console.log("Hello World");
}

このコードは、hello関数の定義行より前でその関数を呼び出しているのに、エラーにはならず問題なく"Hello World"が出力されます。これは関数宣言には巻き上げがあるためです。

次に関数式の例を見てみましょう。下のコードはhello関数を関数式を使って定義するようにしたものです。

javascript
hello();
const hello = function () {
console.log("Hello World");
};
javascript
hello();
const hello = function () {
console.log("Hello World");
};

このコードをJavaScriptとして実行してみると、1行目で「ReferenceError: Cannot access 'hello' before initialization」というエラーが起こります。関数式で関数を定義した場合は巻き上げがないため、このようなエラーが発生します。

以上のように、関数宣言と関数式には巻き上げの有無の違いがあります。関数式の場合は、関数定義と実行の順番を意識する必要が出てくるわけです。

TypeScriptでは、定義前の関数を呼び出そうとするとコンパイラーが指摘してくれます。

typescript
hello();
// コンパイルエラー: Block-scoped variable 'hello' used before its declaration.(2448)
const hello = function () {};
typescript
hello();
// コンパイルエラー: Block-scoped variable 'hello' used before its declaration.(2448)
const hello = function () {};