JavaScript - 関数の巻き上げ


はじめに

次にようなコードを書いていてエラーが起きたので、今回は関数の巻き上げについてメモ。

func(); //=> Hello function

funcExpression(); //=> Uncaught ReferenceError: Cannot access 'funcExpression' before initialization

function func () {
    console.log('Hello function');
}

const funcExpression = function () {
    console.log('Hello function expression');
}



巻き上げとは?

巻き上げとは、Hoistingとも言われECMAScript2015 (ES6)から導入された仕様です。MDNの説明では、

例えば、巻き上げでは変数と関数定義は物理的にコードの一番上に移動すると厳密に定義されています、これは実際に起こっていません。その代わりに、変数と関数宣言は compile フェーズでメモリーに配置されますが、コーディングでタイプされた場所は変わりません。

JavaScript では定義のみが巻き上げられ、初期化はそうでありません。変数が使用された後に定義や初期化された場合、値は undefined になります。

とのことです。変数定義関数定義は、定義した行より前で呼び出し可能で、初期化は不可ということですね。

なので、上のコードは、

  • 関数宣言で定義されたfunc()は、定義された行より前で呼び出し可能
  • 関数式で定義されたfuncExpression()は不可

となります。

実際のコードで確認します。

巻き上げが起こる場合

巻き上げが起こるのは、関数宣言で定義された関数です。

関数宣言とはこんなやつ。

function func () {
    console.log('Hello function');
}


関数宣言での関数は、レンダリング(解析)が終わった瞬間に生成されるので、宣言される前から実行することができます。

func(); //=> Hello function  

function func () {
    console.log('Hello function');
}


巻き上げが起きない場合

巻き上げが起こらないのは、関数式で定義された関数です。関数式とは、式の中で定義される関数のこと。

関数式とはこんなやつ。

const funcExpression = function () {
    console.log('Hello function expression');
}

関数式での関数定義は、代入処理が行われたときに初めて定義されるので、巻き上げ処理は行われません。

funcExpression(); //=> Uncaught ReferenceError: Cannot access 'funcExpression' before initialization

const funcExpression = function () {
    console.log('Hello function expression');
}

今回は以上にです。ご覧いただきありがとうございます。