JavaScriptで関数を定義する方法は、一般的に3つに分かれる。
ここではそれらの定義方法と挙動の違いに触れる。
##関数コンストラクタ
var addConstructor = new Function('x', 'y', 'return x + y');
console.log(addConstructor(1,2)); // 出力:3
関数コンストラクタによる定義方法では、末尾の引数が関数本体を表し、それ以外の引数が関数本体に渡すべき引数を表している。
特長として、「関数の本体部分を文字列として指定できる」点が挙げられるが、記述が他の定義方法に比べてシンプルでないことや、パフォーマンスの観点などから避けるべきとされている。
##関数式(関数リテラル)
var addExpression = function(x, y) {
return x + y;
};
console.log(addExpression(1,2)); // 出力:3
式による関数定義は一番よく見る形である。
関数定義と同時に変数へ代入するような形式をとり、またその関数は名前がついていない場合が多い(無名関数や匿名関数といわれる)。
関数名をつけた場合には再帰を実現することができ、またその関数名は関数本体の外側で使用された場合にエラーとなる。
var foo = function hoge(x) {
console.log(x);
x--;
if(x<0) {return;}
// 再帰(関数名hogeを使用できる)
hoge(x);
};
foo(5); // 出力:5 4 3 2 1 0
hoge(5); // エラー:hoge is not defined
// 関数名hogeを関数外で使用することはできない
また、関数が代入された変数には再代入することが可能である。
var calc = function(x, y) {return x + y};
console.log(calc(5, 3)); // 出力:8
// 別関数を再代入
calc = function(x, y) {return x - y};
console.log(calc(5, 3)); // 出力:2
##関数宣言
function addStatement(x, y) {
return x + y;
};
console.log(addStatement(1, 2)); // 出力:3
関数宣言の定義方法は関数式とほぼ同じ形式で、式として扱われているか否かくらいの違いしかない。
ただ、関数宣言にしかない大きな特徴の一つに「ホイスト(巻き上げ)」がある。
console.log(bar(2, 3)); // 出力:6
// 定義は使用する箇所よりもあとに記述されている
function bar(x, y) {
return x*y;
};
// 関数式による定義では巻き上げしない
console.log(foo(4, 5)); // エラー:undefined is not a function
var foo = function(x, y) {
return x*y;
};
関数宣言はコード解析時に関数が登録されるため、定義記述前の呼び出しが可能だが、関数式では実行時に関数登録されるためにエラーとなる。
##最後に
さらっとまとめましたが、やっぱり詳しく知りたいときはリファレンスが一番です。はい。
関数と関数スコープ