関数式って何者?
関数式は、
「関数そのものを“値”として扱い、変数に代入したり、他の関数に渡したりする書き方」 です。
これだけだと少し抽象的なので、
まずは「関数宣言」との違いから見ていきます。
関数宣言との違いから理解する
関数宣言(おさらい)
関数宣言はこういう書き方でした。
function greet(name) {
console.log("こんにちは、" + name + "さん");
}
greet("太郎");
JavaScriptここでは、greet という名前の関数を「宣言」しています。
この書き方の特徴は、
スクリプトのどこからでも(同じスコープ内なら)呼び出せる ことです。
greet("前から呼んでもOK");
function greet(name) {
console.log("こんにちは、" + name + "さん");
}
JavaScriptこう書いても動きます。
これは「関数宣言がホイスティングされる(上に持ち上げられる)」からです。
関数式の基本形
関数式はこう書きます。
const greet = function (name) {
console.log("こんにちは、" + name + "さん");
};
greet("太郎");
JavaScriptfunction (name) { ... } という“無名の関数”を、greet という変数に代入しています。
ここが重要です。
関数式は「関数を作る」と同時に、「それを変数に代入している」 という点がポイントです。
そして、関数式はホイスティングされません。
greet("これはエラーになる");
const greet = function (name) {
console.log("こんにちは、" + name + "さん");
};
JavaScriptこのコードはエラーになります。greet が定義される前に呼び出しているからです。
関数式は「その行に到達したとき」に初めて代入される、
という感覚を持っておいてください。
関数式の「おいしいところ」
関数を“値”として扱いやすい
関数式の一番の強みは、
関数を「値」として自然に扱えること です。
例えば、こんなことができます。
変数に代入して使う
const add = function (a, b) {
return a + b;
};
console.log(add(2, 3)); // 5
JavaScript配列に入れる
const funcs = [
function () { console.log("一つ目"); },
function () { console.log("二つ目"); },
];
funcs[0](); // 一つ目
funcs[1](); // 二つ目
JavaScript他の関数に渡す
function runTwice(fn) {
fn();
fn();
}
const hello = function () {
console.log("こんにちは");
};
runTwice(hello);
// こんにちは
// こんにちは
JavaScriptここが重要です。
関数式を使うと、「関数を変数に入れる」「関数を引数として渡す」「関数を戻り値として返す」が自然にできる。
これが“関数を第一級の値として扱う”という JavaScript の強みです。
無名関数と名前付き関数式
無名関数の関数式
さっきの例は「無名関数(名前なし)」でした。
const greet = function (name) {
console.log("こんにちは、" + name + "さん");
};
JavaScriptこの場合、関数自体には名前がありません。greet という変数名でアクセスします。
名前付き関数式
実は、関数式にも名前をつけることができます。
const greet = function greetInner(name) {
console.log("こんにちは、" + name + "さん");
};
JavaScriptこのとき、
外からは greet() として呼び出す
関数の中からは greetInner() という名前で自分自身を呼べる
というメリットがあります。
例えば、再帰関数を書くときに使えます。
const factorial = function fact(n) {
if (n === 0) return 1;
return n * fact(n - 1);
};
console.log(factorial(5)); // 120
JavaScriptただし、初心者のうちは
「関数式=無名関数を変数に代入するもの」
と覚えておけば十分です。
関数式とアロー関数の関係
実はアロー関数も「関数式」の一種
アロー関数も、形を変えただけで本質は関数式です。
const greet = (name) => {
console.log("こんにちは、" + name + "さん");
};
JavaScriptこれは、
const greet = function (name) {
console.log("こんにちは、" + name + "さん");
};
JavaScriptとほぼ同じ意味です(this の扱いなど細かい違いはありますが、今は置いておいてOK)。
つまり、
「function を使った関数式」
「=> を使った関数式(アロー関数)」
という2種類がある、と捉えるとスッキリします。
実務で関数式がよく使われる場面
コールバックとして渡すとき
イベントリスナーなどで、よくこう書きます。
button.addEventListener("click", function () {
console.log("クリックされました");
});
JavaScriptここで function () { ... } は、
まさに「関数式」です。
アロー関数で書くとこう。
button.addEventListener("click", () => {
console.log("クリックされました");
});
JavaScript「イベントが起きたときに実行する処理」を、
その場で関数式として定義して渡しているわけです。
配列操作(map, filter, forEach など)
配列メソッドでも、関数式は大活躍します。
const numbers = [1, 2, 3];
const doubled = numbers.map(function (n) {
return n * 2;
});
console.log(doubled); // [2, 4, 6]
JavaScriptアロー関数ならこう。
const doubled = numbers.map((n) => n * 2);
JavaScriptここが重要です。
「何かを“後で実行する処理”として渡したいとき、
その場で関数式を書く」というパターンが、実務ではめちゃくちゃ多い。
初心者として押さえておきたい「関数式の感覚」
「関数も値」という感覚を持つ
関数式を理解するうえで一番大事なのは、
「関数も数値や文字列と同じ“値”として扱える」
という感覚です。
数値を変数に入れる:
const x = 10;
JavaScript関数を変数に入れる:
const fn = function () {
console.log("関数です");
};
JavaScriptどちらも「何かを変数に代入している」だけです。
違うのは、その「何か」が数値か関数か、というだけ。
この感覚が腑に落ちると、
「関数を引数に渡す」「関数を返す」といった書き方が
一気に自然に感じられるようになります。
まとめ:関数式で本当に押さえてほしいこと
関数式は、
const 名前 = function (引数) {
// 処理
};
JavaScriptという形で書く「関数を値として扱うための書き方」。
関数宣言との主な違いは、
ホイスティングされない(定義より前では使えない)
変数に代入する前提なので、「関数を値として扱う」場面に強い
実務では、
イベントリスナー
配列メソッド(map, filter, forEach など)
コールバックや非同期処理のハンドラ
などで、ほぼ必ず関数式(またはアロー関数)が登場します。
もし今、
function greet() { ... }
JavaScriptには慣れてきたなら、
次の一歩として、
const greet = function () { ... };
const greet = () => { ... };
JavaScriptという「関数式の形」にも慣れていくと、
書けるコードの幅が一気に広がります。
