魔法JS☆あれい 第8話「filterって、ほんとfindとfindIndex」


登場人物

丹生(にゅう)あれい
魔法少女「魔法(マジカル)JS(女子小学生)☆あれい」として活動中。

イテレー太
正体不明の魔法生物。

第1部「ミューテーター・メソッド編」
* 第1話「popでpushした、ような……」
* 第2話「shiftはとってもunshiftって」
* 第3話「もうsortもreverseも怖くない」
* 第4話「fillも、spliceも、copyWithinもあるんだよ」

第2部「アクセサ・メソッド編」
* 第5話「joinなんて、concatなわけない」
* 第6話「indexOfなの絶対lastIndexOf」
* 第7話「includesのsliceと向き合えますか?」

filter()

イテレー太「この話から読んだ人のために改めて説明するけど、あれいは魔法少女で、僕はイテレータ型魔法生物で、僕が魔法世界からデータを召喚して、あれいが配列魔法を使ってそのデータを敵の弱点に合わせた値に変換してreturnする事でダメージを与えることができて、そして今戦闘の真っ最中だよ!」
あれい「おつかれさん」
イ「そして、今回から『イテレーション・メソッド編』突入ということで、僕が召喚するデータもQiita APIから取得できるデータとし、さらに今まで登場したメソッドも組み合わせて、より実践的な配列魔法を使ってもらうよ!」
あ「真面目なセリフも言えるんだな駄犬のくせに」
イ「さて今回は、Qiitaに'8amjp'というユーザーが投稿した記事一覧データを召喚するよ! それっ!」

GET /api/v2/users/8amjp/items

イ「そして返ってきたデータがこれだよ!」

items = [
  {
    "rendered_body": "<p>登場人物</p>\n\n<p>丹生(にゅう)あれい…",
    "body": "登場人物\n\n丹生(にゅう)あれい…",
    "created_at": "2020-03-14T21:00:28+09:00",
    "id": "e44e707ccc8c95b4a40d",
    "likes_count": 1,
    "tags":[
      {
        "name": "JavaScript",
        "versions":[]
      },
      ...
    ],
    "title": "魔法JS☆あれい 第1話「popでpushした、ような……」",
    "url": "https://qiita.com/8amjp/items/e44e707ccc8c95b4a40d",
    "user":{
      "id": "8amjp",
      ...
    },
  },
  ...
]

イ「スペースの都合上かなり省略しているけど、こんな感じのオブジェクトが作成日の新しい順に並んだJSONデータが返ってくるよ! 詳しい仕様はドキュメントを参照してね!」
あ「誰に言ってんだよ」
イ「そして、今回の敵の弱点は、『LGTM(likes_count)が10以上の記事の一覧』だよ! さあ、LGTMが10以上の記事だけを抽出したデータをreturnして敵を倒してよ!」
あ「本当に急に実践的になったな。前回までの悪ふざけは何だったんだよ」
イ「さあ、あれいなら出来るよ! 頑張って!」
あ「面倒くせえなあ……」

return items.filter(item => item.likes_count >= 10);

あ「これでいいのか」
イ「あれい、念の為に解説をお願いするよ!」
あ「ああん? 面倒くせえなあ……だから、すべての記事アイテムをfilter()メソッドで検索して、likes_countの値が10以上のものだけを抽出してるんだよ」
イ「さすがはあれい! 悩んで試行錯誤するとか、間違ってピンチに陥るとか、そういうストーリー展開的なやつをガン無視だね!」
あ「うるせえよ」

解説

filter() メソッドは、引数として与えられたテスト関数を各配列要素に対して実行し、それに合格したすべての配列要素からなる新しい配列を生成します。

MDNより)

配列のすべての要素に対してテスト関数を実行し、条件に合致した要素のみを抽出するメソッドです。
テスト関数では、「現在の要素、現在の要素のインデックス、元の配列」という3つの引数を使用できます。引数を3つとも使用したい場合は、例えばitems.filter((item, i, _items) => ...)などというように記述します。

find()

イ「さて、次の敵の弱点は、『本文(body)中に'JavaScript'という文字列を含む記事のうち、一番新しい記事のデータ』だよ!」
あ「本気で面倒くせえやつだなあ……」
イ「頑張れ! あれい!」

return items.find(item  => /JavaScript/.test(item.body));

イ「あれい、これも念の為に解説をお願い!」
あ「ああん? 面倒くせえなあ……だから、find() メソッドで記事アイテムを順に検索してだな、本文に'JavaScript'って文字列があるかどうかをtest()メソッドで判定し、最初にtrueになったアイテムを返してるんだよ」
イ「さすがはあれい! ちっとも盛り上がらないね!」
あ「だからうるせえよ」

解説

find() メソッドは、提供されたテスト関数を満たす配列内の 最初の要素 を返します。

MDNより)

find() メソッドはfilter() メソッドとよく似ており、テスト関数に渡される引数も同じです。
大きな違いは、filter() メソッドが条件に合致したすべての要素を配列で返すのに対し、find() メソッドは条件に合致した最初の要素のみを返します。なのでfind() メソッドの戻り値は、条件に合致する要素があった場合はその単一の要素、なかった場合はundefinedとなります。

findIndex()

解説

findIndex() メソッドは、配列内の要素が指定されたテスト関数を満たす場合、配列内の インデックス を返します。そうでない場合は -1 を返します。

MDNより)

find() メソッドに似たメソッドとしてfindIndex() メソッドもあります。
条件に合致した最初の要素のインデックスを返す、というところがfind() メソッドとの違いです。

次回予告

バカと思うかもしれないけど、私はね、本当に配列のすべての要素がテスト関数にtrueを返すのか、それを確かめるまで、諦めたくない。

第9話 someなの、everyが許さない