JavaScript

【JavaScript】関数定義いろいろ

More than 3 years have passed since last update.

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;
};

関数宣言はコード解析時に関数が登録されるため、定義記述前の呼び出しが可能だが、関数式では実行時に関数登録されるためにエラーとなる。

最後に

さらっとまとめましたが、やっぱり詳しく知りたいときはリファレンスが一番です。はい。
関数と関数スコープ