関数宣言
function foo() {}
関数 foo はプログラム全体が実行される前にホイストされるため、関数 foo が定義されているスコープ全体で使用できます。関数定義前に呼び出しても問題ありません。
foo(); // Works because foo was created before this code runs function foo() {}
スコープについては別途記事を書く予定なので、ここでは詳しく説明しません。
関数式
関数宣言の場合、関数の名前は必須ですが、関数式の場合はオプションです。そのため、匿名関数式と名前付き関数式が表示されます。以下のように:
関数宣言: function functionName (){ }
関数宣言: function functionName[optional](){ }
そうすると、関数名がない場合は関数式であることはわかるのですが、関数名がある場合はどう判断すればよいのでしょうか?
Javascript では、関数本体全体が式の一部である場合は関数式、それ以外の場合は関数宣言であると規定されています。以下は式です:
var fuc = foo(){}
さらに極端な表現の例をいくつか挙げてみましょう:
!function foo(){} true && function foo(){}
上記の記述は関数式を区別するためだけのものであり、通常はこのように記述しません。次に、比較例を使用して効果を確認します。
foo1();//foo1 is not defined foo2();//works because foo2 was created before this code runs !function foo1() { alert('foo1 works'); }; function foo2() { alert('foo2 works'); };
匿名関数式
var foo = function() {};
上記の例では、匿名関数を変数 foo に割り当てます。
foo; // 'undefined' foo(); // this raises a TypeError var foo = function() {};
var は宣言であるため、ここで変数 foo がホイストされ、プログラムが実行されると変数 foo が呼び出されます。
ただし、代入ステートメントは実行時にのみ有効となるため、変数 foo の値は未定義です。
名前付き関数式
もう 1 つ話すべきことは、名前付き関数の割り当てです。
var foo = function bar() { bar(); // Works }; bar(); // ReferenceError
ここでは、名前付き関数 bar が変数 foo に割り当てられているため、関数宣言の外からは見えませんが、bar 関数内で呼び出すことができます。これは、JavaScript の名前付き関数の処理方法が原因で、関数の名前は関数内のスコープ内で常に有効になります。