Jsmanga.github.io

GitHub - Ref - Neetsha -

はじめての関数の関数

前々回、関数はデータだから名前を付けて、好きな動かせることを見ました。 他のデータ同様に、関数に関数を入力してみましょう(次回は関数を出力してみます)。

値呼び出し

値呼出し:関数への入力を値になるまで評価する呼び出し方です。

const loop = _ => loop(); // 無限ループする関数
loop; // エラーにはならない
loop(); // エラーになる:評価すると無限ループしてエラー

const one = _ => 1; // 引数を使わない関数
one(loop()); // エラーになる:値を入力しようとしてloop()を評価した

関数名(引数 ...) とすると、関数の右辺が評価されるのでした。


名前呼び出し

では、関数を渡す方法について説明します。 今度は関数oneは「関数の出力値」でなく「関数の名前」が入力されます。 これを名前呼び出しといいます。

one(loop); // これがエラーにならないから
one(_=>loop()); // これもエラーにならない:上と同じ

(註)他にもyield などジェネレータやイテレータで使うまで評価を遅らせることもできます


入力が関数の関数の例 : 実行時間の計測

こんな関数 time が作れたら便利ですよね。

// 使い方 1回だけ計る
time(_=> square(2000));
// 1000回分の平均時間
time(_=> square(2000), 1000);

中身はこんな感じになってます。

const time = (input, n = 1, average = 0.0) =>
{
    for (let i = 0; i < n; ++i) // n回ループ
    {
        const start = window.performance.now(); // 現在時刻の取得
        input(); // ここで入力の関数を動かす
        const elapsed = window.performance.now() - start; // 掛かった時間
        average += elapsed / n;
    }

    return average; // 戻り値
};

今までの関数より大きくて、新しい仲間がでてきました。

  • 2行目 (input, n = 1, average = 0.0)= がであります。 これはデフォルト引数といって、入力が指定されなかったときの値になります。

  • 3行目 ... 最後の行の { ... return } は、複数の命令と、返す(return)値を書く方法です。

  • 4行目 for (let i = 0; i < n; ++i) は再帰を使わずに n 回ループする方法です。 いままで通り再帰を使うとこんな感じでかけます。

// 再帰ver : for ループと比べてみよう
const time_rec = (process, n = 1, average = 0.0, i = 1) =>
{
    const start = window.performance.now();
    process();
    const elapsed = window.performance.now() - start;
    average += elapsed / n;

    return i < n
        ? time_rec(process, n, average, i + 1)
        : average;
};

それでは、次はいよいよ関数を入力にとって出力する関数の登場です。 そんなことして何が嬉しいのでしょうか??

次へ