6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2021年10月26日 JavaScript (JS Primer) 再帰関数

First-class Function (第一級関数)とは?

プログラミング言語が第一級関数 (First-class functions) を持つと言われる場合、その言語の関数がその他の変数と同様に扱われることを表します。例えば、こうした言語では、関数を他の関数への引数として渡したり、他の関数から返却したり、変数の値として代入したりすることができます。

つまり、関数が(オブジェクト)として扱えることが、ファーストクラスファンクション第一級関数)です。関数を値として扱うときは、関数名の後ろに()を書きません。

以下で関数を値として、扱えるとはどういうことかまとめてみました。

//functionに()をつけないことで、関数自体を値として扱うことが出来るようになります。
function fn() {
    console.log("fnが呼び出されました");
}
// 関数`fn`を`myFunc`変数に代入している
// 関数に()をつけないとオブジェクトとして扱う事ができます。
// 処理を呼び出す事なく関数のオブジェクトそのものを代入できます。
const myFunc = fn;
// 関数に()をつけると関数の処理を呼び出す
myFunc();

// 変数に関数名を代入することが出来ます。
// ここではmyFuncという変数に最初に定義したfn関数に()を付けずにオブジェクトとして代入しています。
// 関数の処理が入った変数も呼び出すときは()をつけないと処理は呼び出せません。
// ()をつけなかったら関数の式がオブジェクトとして呼び出されます。

上記のことをまとめて行うのが関数式です。関数式では、関数の定義と変数への代入を同時に行います。関数全体をオブジェクトとして直接変数に代入しているのです。

  • 関数式では変数に関数オブジェクトを代入するため匿名関数を定義できます。変数に代入することで関数名を使う必要がなくなるため、匿名関数を使用できるのです。

  • 変数名を使って、関数を参照することが出来ます。

// 関数式
const 関数名 = function() {
    // 関数を呼び出したときの処理
    // ...
    return 関数の返り値;
};

📌関数定義時につけられる()は引数を格納するための()であり、関数の処理を実行するための()ではないところに注意してください。

関数を実行するとき

  • 関数名に()をつけることで、関数としてまとめた処理を呼び出せます

  • 関数名に()をつけないことで、関数をオブジェクトとして参照出来ます(変数に代入したり、引数として扱える)

関数の再帰的呼び出し

再帰関数は、関数の中から自分自身を呼び出す関数のことです。関数名()で関数を呼び出せます。

// factorialは関数の外から呼び出せる名前
// innerFactは関数の外から呼び出せない名前
const factorial = function innerFact(n) {
    if (n === 0) { // => nが0になる時
        return 1; // =>return文で関数の処理を終了させる
    }
    // innerFactを再帰的(関数の中から関数を呼び出す)に呼び出している
    return n * innerFact(n - 1);
    // innerFact(3)を呼び出し引数として3を渡す。
    // innerFact(2)を呼び出し引数として2を渡す。
    // innerFact(1)を呼び出し引数として1を渡す。=>return文で1を渡しreturn文が実行されることにより処理が終了する
};
console.log(factorial(4)); // => 24
  1. return n * innerFact(n - 1);の部分で処理を終了させたいが、innerFact(n - 1)で関数の呼び出しをしているので処理を終了させる前に再帰的な関数の呼び出しが行われています。

  2. 関数の中で、関数を呼び出すことを再帰的な関数の呼び出しと言います。

  3. if文の処理がtrueになる時、1をinnerFactに戻り値として返しつつ関数の処理を終了させます。

  4. innerFact(n - 1)にreturn 1;で1が返るとreturn 4 * innerfact(3) * innerfact(2) * innerfact(1)innerfact(1)に1が1が返ります。

  5. 今までのn * innerFact(n - 1)処理の計算を行うと以下のようになります。(実際はこの処理の流れではないがわかりやすさを求めて以下の記述を載せます。)

innerFact(4) = 4 * innerFact(3)
             = 4 * (3 * innerFact(2))
             = 4 * (3 * 2 * innerFact(1))
             = 4 * 3 * 2 * 1 

最後にreturn 1;の部分の処理が実行されて関数の処理が終了します。

画像引用

遊戯王再帰関数の関係とは?

実は、遊戯王のワンシーンに再帰関数が使われています。遊戯対インセクター羽蛾のコードを、以下に示します。こちらが例のワンシーンです。 【作業用】永遠に攻撃され続けられるインセクター羽蛾【遊戯王】

youtu.be

const card = function monster(n) {
    // nはインセクター羽蛾のライフを表している。
    if (n === 0) {
        // ライフが0になったら杏子が登場する。
        console.log("ハガのライフは0よ!!!");
        console.log("HANASE!!!");
        console.log("次回 城之内死す")
        return 1;
    }
    
    // 羽蛾のライフが0になるまでmonster関数を呼び出す。
    return n * monster(n - 1);
};

console.log(card(5)); 
//=> ハガのライフは0よ!!!
//=> HANASE!!!
//=> 次回 城之内死す
//=> 120

参照 😉

First-class Function (第一級関数)
JavaScript Primer
【作業用】永遠に攻撃され続けられるインセクター羽蛾【遊戯王】