概要

今回の記事では、JavaScriptが備えているhoistingという性質について取り上げることにしました。この性質について正しく理解できていないとデバッグが困難なエラーなどが生じ得る一方で、直感的に理解するのが難しい概念であるため、まとめることにしました。

【hoisting】 巻き上げ、吊り上げ

Function declarationにおけるhoisting

多くの人が初めてhoistingの概念を意識するのは、関数の2つの定義方法の使い分けを考えるときであると思います。JavaScriptにおける関数の2つの定義方法 “Function declaration”, “Function expression"は通常下記のようなコーディングとなります。

// Function decralation

    function fncDecralation() {
        // code
    };
// Function expression

    const fncExpression = function() {
        // code
    };

ここでhoistingについて理解するために例を挙げてその仕組みを考えます。

    function aaa() {
        console.log("aaa");
    };
    const bbb = function() {
        console.log("bbb");
    };

    aaa(); // aaa
    bbb(); // bbb

次に、同じ関数について実行場所を前にしたものを考えます。

    aaa(); // aaa
    bbb(); // index.html:32 Uncaught TypeError: bbb is not a function
    ccc(); // Uncaught ReferenceError: ccc is not defined

    function aaa() {
        console.log("aaa");
    };

    const bbb = function() {
        console.log("bbb");
    };

この例から、function declarationによって定義された関数はコード上のいずれの位置からでも呼び出せていることがわかりますが、簡単にはhoistingはこのような仕組みのことを指します。

宣言と初期化について

プログラミングにおいて"変数"の取り扱いは基本中の基本です。ここでは、コード中での変数の取り扱いに関わる、宣言(declaration)と初期化(initialization)について説明します。

宣言

宣言とは、コード中で使用する変数名を定め、値を格納するためのメモリを確保することを言います。JavaScriptでは、変数を定義する際にvarを用いて次のように書きます。(ES6以降ではconst, letによる定義方法が追加されました。)

    const ddd;

このコードによって、dddという名前を持った変数が定義されます。この時点では、dddという変数がどのような変数であるかについては定義されていません。
(JavaScriptにおいては定義時にクラスを指定せずに定義することができます。)

初期化

初期化とは、定義した変数に対して初期値を与えることを言います。具体的には先の例で次のようにコードを書くことで初期値を与えることができます。

    const ddd = "ddd";

このコードによって、dddという変数はstring型の"ddd"という文字列を持つ変数であることが定義されます。

宣言のhoistingについて

Function declarationと同様に、変数の定義時にもhoistingが起こります。次のコードの結果を見てみましょう。

    console.log(eee); // undefined
    const eee = "eee";
    console.log(eee); // eee

    console.log(fff); // Uncaught ReferenceError: ccc is not defined

前説で初期化しない宣言の方法を例として挙げましたが、初期化せず変数を宣言した場合の初期値にはundefinedが定義されます。そのため、上のコードにおける1つ目のconsole.log()の出力はundefinedとなり、“eee"が代入された以降のコードである2つ目のconsole.log()の出力は"eee"となります。

まとめ

本記事では、hoistingがコード上で宣言した変数や関数を他のコードの実行前にメモリに配置する仕組みであることを紹介してきました。この性質を正しく理解し、ある関数・変数がどのように定義されているのか把握しながらコードを書くことによって、より高いレベルでのコーディングが可能になるでしょう。