🦮

Java Scriptで引数に関数を設定する時に、やりがちなミス(高階関数)

2024/03/27に公開

やること

今回は、Java Scriptの引数に、関数を設定する時にやってしまいがちなミスについてまとめたいと思います。

初心者向けに、「Java Scriptで引数に、関数を設定」と書きましたが、**引数に関数が設定されている関数のことは、「高階関数」**と呼ばれておりますので、知らなかった方は覚えていただければと思います。(ここからは高階関数と呼びます。)

この高階関数、やってしまいがちなミスがあるんですよね。よく考えてみれば、「当たり前やん。」と言う内容ですが、特に初心者は、意図せずやってしまうことがあると思いますので、最後まで見ていただければと思います。

※使用例のコードは、Type Scriptで書きます。

まずは高階関数の良い例紹介

やってしまいがちなミスの前に、まずは高階関数の使い方の良い例を紹介します。

引数に設定する関数の引数がない場合

なんだか文字にすると冗長な感じがしてしまいますが、、
高階関数の引数に設定する関数に、引数がない場合です。

// 高階関数
const parentFunction = ( paramFunction: () => string ): string => {
    return paramFunction();
}

// 引数に使う関数
const childFunction = () => {
    return "foo";
}

const result = parentFunction(childFunction);
console.log("result", result);
// foo

引数がある場合

引数がある場合です。

// 高階関数
const parentFunction = ( paramFunction: (foo: string) => string ): string => {
    const params = "ああああ";
    const res = paramFunction(params);
    return res;
}

const childFunction = (foo: string) => {
    return foo;
}

const result = parentFunction(childFunction);
console.log("result", result);
// あああ

引数を無名関数で設定する場合

高階関数に設定する引数の関数を特に定義せず、無名関数で直接書くパターンもあります。

// 高階関数
const parentFunction = ( paramFunction: () => string ): string => {
    return paramFunction();
}

// 引数に設定する関数は定義せず、引数に直接無名関数をセットする。
const result = parentFunction(() => foo);
console.log("result", result);
// foo

良い例はこんな感じになります。
引数に関数を設定するときは、こんな感じで使ってみてくださいね。

やりがちなミス

ここから、やりがちなミスの紹介です。

1つ目「引数にセットする時点で関数をコールする」

当たり前ですが、引数にセットする時点で関数をコールすると、エラーが出ます。
以下のような感じですね。

// 高階関数
const parentFunction = ( paramFunction: () => string ): string => {
    return paramFunction();
}

// 引数に使う関数
const childFunction = () => {
    return "foo";
}

const result = parentFunction(childFunction());
// Argument of type 'string' is not assignable to parameter of type '() => string'.(2345)

これは、高階関数の引数に、関数を呼び出したものをセットしているので、childFunctionが実行された結果の返り値が、高階関数の引数に設定されてしまい、型エラーが出ています。

要は、parentFunctionの引数に、"foo"を設定しているのと同義です。

Java Scriptでコードを書いていると、関数の末尾に、「()」を書く癖がついてしまい、特に何も考えず「()」を書いてしまうようになる初心者もいるかと思います。(私もそうだった。)

引数の関数が呼び出されるのは、高階関数の中なので、引数に設定するタイミングで呼び出す必要はありません。よって、

parentFunction(childFunction);

が正しい形となります。

2つ目「わざわざ無名関数にする」

こちらは、エラーは出ませんが無駄なことをしているのでやらない方が良いと思います。

// 高階関数
const parentFunction = ( paramFunction: () => string ): string => {
    return paramFunction();
}

// 引数に使う関数
const childFunction = () => {
    return "foo";
}

const result = parentFunction(() => childFunction());

高階関数の引数に、childFunctionを呼び出す無名関数にわざわざしている例ですね。

以下だとエラーが出るから、

parentFunction(childFunction())

以下にしたら治ったラッキー!と思ってそのままにしてしまう方もいるかと思いますが、無名関数にわざわざする必要はないです。

parentFunction(() => childFunction())

正しい形

parentFunction(childFunction)

以上です。

最後に

「関数の引数に、関数を設定する」って、なんだか難しく思えて変な使い方してしまうこともありますよね〜
以前この話題になって、少し考え直したことがあったときに気づいたのですが、結構やってしまっている人いるのでは?と思ったのと、早いうちに気づけた方が良いと思い、記事にしました。

少し込み入った実装をすると結構使うので、覚えておきましょう。

Discussion