関数式と関数宣言は、関数を定義する2つの形式です。関数式はJSではとても基本的なものです。関数式はコードの隠蔽や変数の分離などに使えます。関数宣言は変数リフティングの特徴があります。
V8の関数宣言の扱い方
V8はJSを実行する前にコンパイルします。
コンパイル段階では、関数宣言が解析されると、V8はそれをメモリ上の関数オブジェクトに変換してスコープに入れます。変数宣言が解析されると、それもスコープに入りますが、初期値はundefinedに設定され、その変数がまだ使われていないことを示します。実行段階では、V8は使用する必要のある変数や関数をスコープから探します。このようにコンパイル段階ですべての変数をスコープに入れることを、変数リフティングと呼びます。
質問:通常の変数は未定義なのに、変数リフティングの関数宣言はなぜ完全な関数オブジェクトなのですか?
V8は変数の定義や関数の宣言など、基本的な文だけを分析します。関数はオブジェクトなので、V8は関数全体をスコープに取り込みます。また、通常の変数の代入は式なので、コンパイル段階では実行されず、初期値のundefindだけが保持されます。
V8が関数式を扱う方法
a=function(){}のように、式中で関数を使用して関数を定義することは、関数を関数式として参照します。V8はコンパイル段階で関数式を扱いません。
var getName = function(name){
return name;
}
関数式と関数宣言の違い
- 関数式とは、式文の中で関数を使うことで、a=function(){}のようになります。
- 関数名が省略された関数式は無名関数を作成します。
- 関数式は即時呼び出し関数式(IIFE)として扱うことができます。
IIFE-即時呼び出し関数式
(function(){
....
})()
IIFEの利点は環境を汚染しないことで、関数や関数内部の変数が外部からアクセスされることはなく、オブジェクトのカプセル化に適しています。また、関数即値式は即座に実行され、変数に代入された場合、その変数にはIIFEそのものではなく、IIFEの実行結果が格納されます。
まとめ
関数宣言の本質は文であり、関数式の本質は式です。
V8のコンパイルフェーズでは、実行フェーズでステートメントのリフティングと式の代入のみを行います。
V8はコンパイル段階で、関数宣言と変数宣言に対して変数のスコープへの昇格を行います。変数がスコープに引き上げられると、デフォルト値のundefinedが設定されます。関数宣言がスコープに引き上げられると、V8はメモリ上に関数オブジェクトを作成し、関数オブジェクト全体を持ち上げます。
関数式は変数によって昇格されることはありませんが、IIFEを使用して変数や関数などをカプセル化し、変数の分離やコードの隠蔽の役割を果たすことができます。