2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【JS】高階関数をざっくりと理解してみる

Last updated at Posted at 2022-12-18

高階関数について簡単に言語化してみました。

高階関数とは

高階関数とは、一言で説明すると「関数を受け取ったり関数を返す関数」のことです。
噛み砕くと、

・引数として関数を受け取る

・戻り値に関数を指定する

関数になります。

ちょっとイメージしづらい、、、。
簡単ですが高階関数のコードを書いてみます。

higher-order-function.js
//高階関数を定義します。
//桃鉄ののぞみカードをイメージ笑
function nozomiCard(f) {
    let total = 0;
    for(let i = 0; i < 5; i++) {
        total += f();
    }
    return total;
}

//高階関数の引数となる関数を定義します。
//1~6の数字を返却
function dice() {
    const resultNum = Math.floor(Math.random() * 6) + 1;
    return resultNum;
}

nozomiCard(dice);

まず、高階関数のnozomiCardを定義しています。
この関数の引数fは関数を受け取ります。(今回はdiceを渡しています。)
受け取った関数f実行し、実行結果を変数totalの中に格納しています。
これをループで5回行い合計の値を戻り値として返却しています。

この時の私的注意ポイントは関数の実行ではなく、関数を渡すことです。

関数を渡す。
nozomiCard(dice);

関数を実行してしまう。
nozomiCard(dice());

関数の実行をしてしまうと、関数diceの実行結果(数字の1〜6)が引数として渡されてしまい、
想定している結果が得られません。

最初は関数を渡すということが違和感がある方は、
関数もオブジェクトの一種で、値の一種だ!!
という感覚を持ってください。
すんなり高階関数が理解できるようになると思います。
(一度関数をconsole.dirで確認すると理解が深まるかもしれません。)

よく使用する(よく見る)高階関数

よく使用する(よく見る)高階関数にforEach, map filter, every, some, sort, reduceがあります。

forEach

コールバック関数を受け取り、配列の要素毎に関数を呼び出します。

forEach(function(element, index, array) { /* … */ }, thisArg)

element
現在処理されている配列の要素です。
index
配列内の element の添字です。
array
forEach() が呼び出されている配列です。
thisArg 省略可
コールバック関数内で this として使用する値です。

forEach.js
const nums = [2,4,6,8];
nums.forEach(function(element) {
    console.log(element * element);
    // 4, 8, 12, 16
}); 

個人的にはforEachよりもfor ofの方がよく使うような気がしてます。

map

コールバック関数を配列要素毎に呼び出し、その結果からなる新しい配列を生成します。

map(function(element, index, array) { /* … */ }, thisArg)

element
配列内で現在処理中の要素です。
index
現在処理中の要素の配列内における添字です。
array
map が呼び出された配列です。
thisArg省略可
コールバック関数を実行するときに this として使う値です。

map.js
const nums = [2,3,5,18];
const doubleNums = nums.map(function(element) {
    return element * 2;
});
nums; //[2,3,5,18]
doubleNums; //[4,6,10,36]

forEachとの違いは、mapは新しい配列を生成します。

filter

提供されたテスト関数を満たす要素から新しい配列を生成します。

filter(function(element, index, array) { /* … */ }, thisArg)

element
配列内で処理中の現在の要素です。
index
配列内で処理中の現在の要素の位置です。
array
filter() が呼び出された配列です。
thisArg 省略可
コールバック関数を実行するときに this として使用する値です。

filter.js
conts nums = [1,2,3,4,5,6,7,8,9,10];
const evenNumber = nums.filter(function(element) {
    return element % 2 === 0;
});
evenNumber; // [2,4,6,8,10]

提供されたコールバック関数はtrueかfalseを返します。
trueであればelementはfilterされた新しい関数(evenNumber)に追加されます。
filterなのでtrue を返した要素は残され、false を返した要素は取り除かれます。の方が正しいかも、、、。

every

配列内の全ての要素が指定されたテスト関数を満たすかどうかをtrue,falseで返す。

every(function(element, index, array) { /* … */ }, thisArg)

element
現在処理されている要素です。
index
現在処理されている要素の添字です。
array
every が実行されている配列です。
thisArg 省略可
コールバック関数を実行するときに this として使用すされる値です。

every.js
const nums = [2,4,5,7];
nums.every(function(element) {
    return element % 2 === 0;
}); // false

const nums2 = [2,4,6,8];
nums2.every(function(element) {
    return element % 2 === 0;
}); // true

some

1つでもテスト関数を満たす要素があればtrueを返す。

some(function(element, index, array) { /* … */ }, thisArg)

element
配列内で現在処理中の要素です。
index
現在処理中の要素の配列内における添字です。
array
some が呼び出された配列です。
thisArg省略可
コールバック関数を実行するときに this として使う値です。

some.js
const nums = [1,2,3,4,5];
nums.some(function(element) {
     return element % 2 === 0;
}); // true

const nums2 = [1,3,5,7];
nums2.some(function(element) {
     return element % 2 === 0;
}); // false

sort

ソート順を定義する関数を指定し、辞書順にソートを行います。
ソート順を定義する関数が省略された場合、各文字の Unicode コードポイント順に従ってソートされます。

sort(function compareFn(a, b) { /* … */ })

a
比較する第一要素。

b
比較する第二要素。

compareFn(a, b) の返値 ソート順
> 0 ab の後に並べる
< 0 ab の前に並べる
=== 0 ab の元の順序を維持する
sort.js
let nums = [5,8,7,6];
let ascOrder = nums.sort(function(a, b){
  return a - b; //昇順
});

ascOrder; //[5, 6, 7, 8]

let discOrder = nums.sort(function(a, b){
  return  b - a; //降順
});

discOrder; //[8, 7, 6, 5]

コピーは作成されず、ソートを実行した配列自体がソートされるため、注意が必要です。

reduce

配列の各要素に対して(引数で与えられた)reducer関数を実行して「単一の出力値」を生成します。

reduce(function(previousValue, currentValue, currentIndex, array) { /* … */ }, initialValue)

previousValue
前回の callbackFn の呼び出し結果の値です。初回の呼び出しでは initialValue が指定されていた場合はその値、そうでない場合は array[0] の値です。
currentValue
現在の要素の値です。初回の呼び出しでは initialValue が指定された場合は array[0] の値であり、そうでない場合は array[1] の値です。
currentIndex
currentValue の位置です。初回の呼び出しでは、 initialValue が指定された場合は 0、そうでない場合は 1 です。
array
走査する配列です。
initialValue 省略可
コールバックが初めて呼び出されたときの previousValue の初期値です。

reduce.js
//配列内の合計値を求める
const nums = [3,5,6,7,8];
const result = nums.reduce(function(previousValue, currentValue){
    return previousValue + currentValue;
});
result; //29

//配列内の最大値を求める
const maxNum = nums.reduce(function(max, currentValue){
    if(max < currentValue) {
        return currentValue;
    }
});
maxNum; //8

上記の配列内の合計値を求める場合は、以下のようにreduceが実行されています。

Callback previousValue currentValue return value
1回目 3 5 8
2回目 8 6 14
3回目 14 7 21
4回目 21 8 29

上記の配列内の最大値を求める場合は、以下のようにreduceが実行されています。

Callback max currentValue return value
1回目 3 5 5
2回目 5 6 6
3回目 6 7 7
4回目 7 8 8

reduceはこれら以外にも様々な場面で使用することができます。
使い勝手はいいですが、私はまだまだ使いこなせていません泣

まとめ

・高階関数とは、「関数を受け取ったり関数を返す関数」のこと。
・関数もオブジェクトの一種で、値の一種だ!

参考

MND Web Docs
https://developer.mozilla.org/ja/

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?