JavaScriptの再帰関数の仕組みと使い方を覚えよう
生徒
「先生、再帰関数って何ですか?名前を聞くと難しそうに感じます。」
先生
「再帰関数とは、自分自身を呼び出す関数のことです。つまり、関数の中で同じ関数をもう一度実行するんですよ。」
生徒
「自分で自分を呼び出すなんて、どうしてそんなことをするんですか?」
先生
「それは、複雑な問題を小さな問題に分けて、繰り返し解決するときに便利だからです。例えば階段を一段ずつ上がるように、一歩ずつ問題を解決していくイメージですね。」
生徒
「なるほど。でも、自分を呼び続けたらずっと終わらないのでは?」
先生
「良いところに気づきました!だから再帰関数には『終了条件』が必要なんです。条件を満たしたら自分を呼び出すのをやめて、結果を返します。」
1. 再帰関数とは?基本の仕組み
再帰関数(さいきかんすう)とは、自分自身をもう一度呼び出す関数のことです。JavaScriptでは、同じ形の処理を何度も繰り返したいときに使われますが、普通のループとは少し考え方が違います。再帰関数は「今の問題を、もっと小さな同じ問題に分けて解く」という発想が基本になります。
ただし、再帰関数には必ず終了条件(ベースケース)が必要です。終了条件とは、「ここまで来たらもう自分を呼ばない」というゴールのことです。この条件がないと、関数は終わりなく自分を呼び続けてしまい、プログラムが止まらなくなります。
たとえば「箱を一つずつ開けていく作業」を想像してみてください。箱の中にまた箱があり、さらにその中にも箱がありますが、最後に「空の箱」が出てきたら作業を終えます。この「空の箱」が、再帰関数でいう終了条件にあたります。
次の簡単なサンプルは、「数値が0になったら止まる」という、とてもシンプルな再帰関数の例です。
function checkNumber(n) {
if (n === 0) {
console.log("ここで終了");
return;
}
console.log("今の数値:" + n);
checkNumber(n - 1);
}
checkNumber(3);
このように、再帰関数は「終了条件」と「自分自身の呼び出し」をセットで考えることが大切です。まずはこの基本の仕組みを理解することが、再帰関数を使いこなす第一歩になります。
2. 再帰関数の簡単な例:カウントダウン
まずは再帰関数の動きをつかむために、いちばん分かりやすい「カウントダウン」を見てみましょう。カウントダウンは、数字を一つずつ減らしていき、最後に0になったら終わるだけのシンプルな処理です。JavaScript初心者でも、数字が減っていく流れを目で追いやすいので、再帰関数の練習にぴったりです。
ポイントは、0以下になったら止まるという終了条件と、次は1小さい数で自分を呼ぶという自己呼び出しです。これがセットになっていることで、処理が止まらずに続く心配がなくなります。
function countdown(number) {
if (number <= 0) {
console.log("終了!");
return;
}
console.log(number);
countdown(number - 1);
}
countdown(5);
実行すると、5、4、3、2、1 と表示され、最後に「終了!」が表示されます。つまり、関数は毎回「今の数値を表示する→数値を1減らして次を呼ぶ」という同じ手順を繰り返し、数字が0以下になった瞬間にストップします。
プログラミング未経験の方は、まず「今の数値がいくつか」「次に渡す数値はいくつか」を紙に書き出しながら読むと理解しやすいです。数値が減っていくので、自然にゴールへ近づいていく感覚がつかめます。
3. 再帰関数の重要ポイント:終了条件と自己呼び出し
再帰関数を書くときは、次の2つを必ずセットで意識しましょう。どちらか一方が欠けると、再帰関数は「動かない」「終わらない」「思った結果にならない」といったトラブルにつながりやすくなります。特にJavaScript初心者は、まずこの2点だけを押さえると理解が一気に進みます。
- 終了条件(ベースケース): ここに来たら処理を終える、というゴールを決める条件
- 自己呼び出し: 自分自身の関数を呼び出して、問題を少しずつ小さくしていく処理
終了条件は「止まる合図」です。例えば数を減らしていく再帰なら「0になったら止まる」のように、必ず終わりを用意します。自己呼び出しは「ゴールへ近づく一歩」です。毎回まったく同じ値で呼び出してしまうと、いつまでもゴールに到達できません。
次のサンプルは、再帰関数の形を確認するための超基本例です。nが0になったら終了し、それ以外はnを1つ減らして自分を呼びます。
function stepDown(n) {
if (n === 0) {
console.log("終わり");
return;
}
console.log("いま:" + n);
stepDown(n - 1);
}
stepDown(3);
もし終了条件がなかったり、stepDown(n - 1)のように値を小さくする工夫がなかったりすると、呼び出しが止まらずにメモリを使い切ってしまうことがあります。これが「スタックオーバーフロー」です。再帰関数は便利ですが、まずは「止まる条件」と「近づく変化」を必ず書く、と覚えておくと安心です。
4. 再帰関数の応用例:階乗(かいじょう)を計算しよう
階乗とは、1からその数までの数字をすべて掛け合わせた値のことです。例えば5の階乗は 5 × 4 × 3 × 2 × 1 = 120 です。
これを再帰関数で書くとわかりやすくなります。
function factorial(n) {
if (n === 0) {
return 1; // 0の階乗は1と定義されています
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
ここでは、nが0になったら終了条件です。そうでなければ、自分自身を呼び出して n-1 の階乗を計算します。
5. 再帰関数を使うメリットと注意点
再帰関数は、ループでは書きにくい複雑な問題や木構造(分岐があるデータ構造)を扱うのに便利です。
しかし、終了条件を正しく書かないと無限ループになったり、処理が遅くなったりします。
そのため、再帰関数を書くときは必ず終了条件を確認して、テストしながら動作を確かめましょう。
6. ポイント整理
JavaScriptの再帰関数は「自分自身を呼び出す関数」で、ひとつの大きな問題を小さく分けながら同じ形で解いていく方法です。カウントダウンや階乗のように、ゴールがはっきりしていて「一つ前の状態に戻す」動きが作れる処理と相性が良く、手順を短くまとめやすいのが特徴です。
ただし、再帰関数を安全に使うには終了条件と値を小さくする処理がセットで必要になります。終了条件があるから止まり、値を小さくするからゴールに近づきます。ここを意識するだけで、再帰関数の読み方も書き方もぐっと分かりやすくなります。
次のサンプルは、プログラミング未経験の方でもイメージしやすい「合計を求める」例です。数字を一つずつ減らしながら足していき、最後に0になったら止まるという流れになっています。
function sumTo(n) {
if (n === 0) {
return 0;
}
return n + sumTo(n - 1);
}
console.log(sumTo(4)); // 10(4+3+2+1+0)
初心者の方は、まず「どこで終わるか(終了条件)」と「どうやって小さくするか(n-1のような変化)」を声に出して確認しながら読むのがおすすめです。慣れてきたら、同じ形で解ける問題に当てはめて練習してみましょう。
まとめ
JavaScript再帰関数の考え方をじっくり振り返ろう
JavaScriptの再帰関数は、「関数が自分自身を呼び出す」という少し不思議な仕組みを持っていますが、考え方を整理するととても理にかなった書き方であることが分かります。再帰関数は、複雑に見える処理を小さな問題に分解し、同じルールを何度も適用することで解決していく方法です。これはプログラミング初心者にとって、論理的に考える力を身につける良い練習にもなります。
再帰関数を理解するうえで最も重要なのが、「終了条件」と「自己呼び出し」です。終了条件は処理を止めるためのルールであり、これがなければ関数は永遠に呼び出され続けてしまいます。自己呼び出しは、問題を少しずつ小さくしていくための仕組みです。この二つが正しく組み合わさることで、再帰関数は安全かつ分かりやすく動作します。
再帰関数が活躍する場面
再帰関数は、単純な繰り返し処理だけでなく、階層構造を持つデータを扱うときにも力を発揮します。例えば、フォルダの中にさらにフォルダがあるような構造や、ツリー状に分かれたデータを順番に処理する場合などです。このようなケースでは、for文やwhile文よりも再帰関数のほうが直感的で読みやすいコードになることがあります。
JavaScriptでは、配列やオブジェクト、DOM構造など、階層的なデータを扱う機会が多くあります。そのため、再帰関数の考え方を理解しておくと、後々さまざまな場面で応用が効くようになります。再帰関数は一見難しく感じますが、基本パターンを覚えてしまえば強力な武器になります。
まとめとして確認したい再帰関数のサンプル
function sumTo(n) {
if (n === 0) {
return 0;
}
return n + sumTo(n - 1);
}
console.log(sumTo(5)); // 15
このサンプルでは、「1からnまでの合計」を再帰関数で求めています。nが0になったときに処理を終了することで、無限に呼び出されるのを防いでいます。このように、再帰関数では必ず「どこで終わるのか」を明確にすることが重要です。カウントダウンや階乗計算と同じ考え方で、さまざまな処理に応用できます。
再帰関数とループ処理の違いを意識しよう
再帰関数は便利ですが、すべての繰り返し処理を再帰で書く必要はありません。単純な回数の繰り返しであれば、for文やwhile文のほうが分かりやすく、処理も軽くなる場合があります。再帰関数は、「問題を同じ形で小さくしていけるとき」に使うのがポイントです。
初心者のうちは、再帰関数とループ処理の両方を書いて比べてみるのがおすすめです。そうすることで、それぞれの書き方の特徴や使いどころが自然と身についていきます。JavaScriptの再帰関数は、考え方さえ理解できれば決して難しいものではありません。
生徒
「再帰関数って難しいと思っていましたが、終了条件と自己呼び出しを意識すると整理して考えられるようになりました。」
先生
「それはとても良い理解ですね。再帰関数は考え方が分かれば、問題をきれいに解けるようになります。」
生徒
「カウントダウンや階乗の例を見ると、処理が少しずつ小さくなっていくのが分かりました。」
先生
「その感覚が大切です。再帰関数は、問題を分解して考える力を伸ばしてくれます。」
生徒
「これからは、ループと再帰のどちらが分かりやすいかを考えながら書いてみます。」
先生
「ぜひそうしてください。再帰関数を理解できれば、JavaScriptの理解が一段深まりますよ。」