javascriptの関数定義は、関数宣言を行う方法と変数に関数式を格納する方法の二種類に大別できます。
//こちらは関数宣言 function hoge(){ console.log('hoge declare'); } //こちらは関数の式を変数に格納 hoge = function(){ console.log('hoge expression'); };
関数宣言を行った場合に起きる動作が巻き上げです。巻き上げは関数宣言を行った場所に関係なくプログラムの最初で関数を定義します。このため
hoge(); function hoge(){ console.log('hoge declare'); }
は実行したい関数の中身が実行され、
hoge(); hoge = function(){ console.log('hoge expression'); };
は実行したい関数の中身が実行されません。
関数を先に書いて主となる実行部分を後に書くことが必須ないし推奨の言語は少なくない(python、シェルなど)ですし、関数式による定義の使用はそうそう問題にならないでしょう。むしろES6で追加されたconstを用いれば再定義を防げるので良いくらいです。問題になるのは関数宣言と関数式による定義を混在と関数の再定義が合わさった場合です。そうそう起きない事態ですがこれが起きた場合、非常にわかりにくいソースコードができます。
function hoge(){ console.log('hoge declare 1'); } hoge(); hoge = function(){ console.log('hoge expression 1'); }; hoge(); function hoge(){ console.log('hoge declare 2'); } hoge(); function hoge(){ console.log('hoge declare 3'); } hoge(); hoge = function(){ console.log('hoge expression 2'); }; hoge();
実行結果が一瞬でわかる人はそういないでしょう。読み解き方は最後の関数宣言を記憶して、関数式の代入の度に再定義する、というものです。実行結果は次の通りです。