関数とは、ある処理を行うために使われる、整理された再利用可能なコードのまとまりです。 JavaScriptで関数を定義する方法はいくつかあります。 ここでは、関数宣言 と 関数式 を見ていきます。 アロー関数のようなその他の方法は、別のコンセプトで扱います。
JavaScriptで関数を定義する標準的な方法は、関数宣言 です。関数定義 や 関数文 と呼ばれることもあります。
関数宣言は、functionキーワード、関数の名前、そして丸括弧(())で囲まれたカンマ区切りの仮引数のリストで構成されます。
その後に、波括弧で囲まれた関数本体(関数が何をするかを定義する文の集まり)が続きます。
function someName(param1, param2, param3) {
// ...
}
JavaScriptでは、関数名のあとに、引数を入れた括弧を書くことで関数を呼び出します。
someName(arg1, arg2, arg3);
JavaScriptでは、関数名を書いただけでは関数は呼び出されません。
function sayHello() {
console.log('Hello, World!');
}
sayHello;
// => [Function: sayHello]
// The text representations varies between environments.
sayHello();
// => 'Hello, World!'
関数本体の中で仮引数を扱うときは、関数に渡された元の値に思わぬ副作用が及ぶ可能性に注意しましょう。 JavaScriptでは、引数は元の値への参照のコピーです。 これが実際に何を意味するかは、引数のデータ型によって変わります。
プリミティブ型の値は イミュータブル です。 「変更」はすべて、常に新しいプリミティブ値を作り出します。 そのため、関数本体の中で引数に何が起きても、元の値が影響を受けることはありません。
const num = 0;
function increase(number) {
number = number + 1;
}
increase(num);
num;
// => 0
オブジェクト、配列、関数 などの値では話が変わります。 参照はコピーされるので、再代入しても元の値には影響しません。 ただし、扱っているのは浅いコピーなので、関数本体で引数を変更すると、渡された元の値も変わってしまいます。
const nums = [0, 1, 2, 3, 4];
function pushFive(arr) {
arr.push(5);
}
pushFive(nums);
nums;
// => [0, 1, 2, 3, 4, 5]
JavaScriptでは、デフォルトで、関数宣言で定義された仮引数はすべて省略可能です。
仮引数の数より少ない引数で関数を呼び出すと、足りない引数は関数本体の中でundefinedになります。詳しくはNullとUndefinedを参照してください。
値が渡されなかったりundefinedが渡されたりした場合には、仮引数を デフォルト値 で初期化するほうが自然なことがよくあります。
これは、関数定義の中で直接デフォルト引数を指定することで行えます。
function someName(param1 = defaultValue1, param2 = defaultValue2) {
// ...
}
関数は、関数定義の仮引数の数よりも多い引数で呼び出すこともできます。 余分な引数も含め、すべての引数はargumentsの「配列」の中にあります。
任意の数の引数を受け取る関数(可変長引数関数)を定義することもできます。詳しくは残余引数とスプレッド演算子の残余引数を参照してください。
return文return文は関数の実行を終了し、関数の呼び出し元に返す値を指定します。関数は複数のreturn文を持つことができます。
function checkNumber(num) {
if (num === 0) {
return 'You passed 0, please provide another number.';
}
return 'Thanks for passing such a nice number.';
}
値をreturnしない関数や、return文を持たない関数の結果はundefinedです。
JavaScriptには暗黙のreturnはありません。
function nakedReturn(a) {
a * 2;
return;
}
nakedReturn(1);
// => undefined
function noReturn(a) {
a * 2;
}
noReturn(1);
// => undefined
JavaScriptでは、返せる値はちょうど1つだけです。 より多くの情報を渡したい場合は、まずそれらを1つにまとめる必要があります。通常はオブジェクトか配列にまとめます。
function divide(a, b) {
return {
quotient: Math.floor(a / b),
remainder: a % b,
};
}
関数宣言は独立した文です。 しかし、関数を別の式の一部として定義すると便利なこともあります。たとえば、代入の中、関数の引数(コールバック)、オブジェクトの値としてなどです。 これは関数式で行えます。 構文は関数宣言と同じですが、関数名を省略して 無名関数 を作れる点だけが異なります。
const someFunction = function (param) {
// ...
};
someOtherFunction(function (param) {
// ...
});
const obj = {
someFunction: function (param) {
// ...
},
};
関数は、JavaScriptに新しい実行コンテキストを導入します。 関数の内側で定義された変数は、その関数の外側からはアクセスできません。 しかし、親スコープ(その関数自身が定義されたスコープ)で定義された変数には、関数の内側からアクセスできます。 MDNのスコープに関するドキュメントに、この動作の例が載っています。
JavaScriptの変数スコープについてもっと知りたい場合は、クロージャを見てみましょう。