【JavaScript】findメソッドの危険性についての考察

公開:2020/11/30
更新:2020/12/02
3 min読了の目安(約3100字TECH技術記事 8

はじめに

最近JavaScriptのfindメソッドを使った時に、急に怖くなったので記事にしてみたいと思いました。

findメソッドとは❓

ES6(ES2015)で追加されたメソッドでMDNでは以下のように説明されています。

提供されたテスト関数を満たす配列内の 最初の要素 の 値 を返します。

簡単に言うと、配列の中から上から順番に検索して、最初に条件に合致するものを返すということになります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find

MDNにはこのような例文が記載されています。

const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found);
// expected output: 12

この例だとarray1を順番に検索して行って、10より大きい値があったらそれを返すので、12が出力されます。
まあこの辺はJavaScript書く方なら皆さん知っている内容かと思います。

何が怖くなったのか❓

実際に使用するときの例としては、以下のような配列からidが合致するものを検索してnameを取り出したい場合があると思います。

次のコードはid001のデータをdatasetから取得してnameを取り出しています。

const dataset = [
  { id: "001", name: "aaa" },
  { id: "002", name: "bbb" },
  { id: "003", name: "ccc" },
  //・・・
];
const id = "001"
const resFind = dataset.find((data) => data.id === id);
console.log(resFind.name);
// expected output: aaa

うん。普通にid001のデータからnameが取り出せてますね。
しかし、以下のようにdatasetに実はもう一つid=001があった場合には、

const dataset = [
  { id: "001", name: "aaa" },
  { id: "002", name: "bbb" },
  { id: "003", name: "ccc" },
  //・・・
  { id: "001", name: "zzz" }, // さらにこういうデータがあった場合
];

次のように何事もなくaaaが取得できます。

const id = "001"
const resFind = dataset.find((data) => data.id === id);
console.log(resFind.name);
// expected output: aaa

この何事もなく取得できてしまうのって怖くないですか??
私はこの部分にfindメソッドを使う怖さを感じました。

よくあるユースケースとして、データベースからユーザー情報を持ってきて、IDで名前や年齢などの情報を取得することが多いと思います。基本的にはIDは一意の値にしていると思いますが、実は一意になってなかった場合に、この辺りの情報を間違えて取得することがあるし、それに気づくことができない可能性があります。

なので、個人的にはfindは使うのが怖いので使わないようにしようかと思っています。

なのでfilter使う

じゃあどうしようかという問題が出てくるけど、filterで代用が可能です。

MDNでは以下のように説明されています。

与えられた関数によって実装されたテストに合格したすべての配列からなる新しい配列を生成します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

findメソッドと違うのは条件に合致しているものを全て取得して配列にしてくれます。
以下の例だとid001のものが二つあるので、二つを取得して配列に格納してくれます。

const dataset = [
  { id: "001", name: "aaa" },
  { id: "002", name: "bbb" },
  { id: "003", name: "ccc" },
  //・・・
  { id: "001", name: "zzz" },
];

const id = "001"
const resFilter = dataset.filter((data) => data.id === id);
console.log(resFind);
// expected output: [{id: "001", name: "aaa},{id: "001", name: "zzz}]

ここでfindメソッドとは違って条件に合致したものを全て配列に格納してくれるので、length1であれば一意のデータが取得できているということになります。
ですので、lengthが1ではなかったらログに出したり、アラート出したりすれば気づけると思います。

if (resFilter.length === 1) {
  console.log(resFilter[0].name);
}
else{
  console.log("multiple same id.");
}

こうすれば安心ですよね!!

コメントから追記(rithmetyさんありがとうございます!!)

productionモードでは無駄な処理をさせないことも重要なので、以下のようにdevelopモードだけfilterを使ったチェックを行うのが良さげです。その場合はそのままfindで取得しても問題なさそうです。

if ("development" === process.env.NODE_ENV) {
  if (1 !== dataset.filter((data) => data.id === id).length) {
    console.log("multiple same id.")
    process.exit(1)
  }
}

まとめ

今回はfindメソッド危険性についての考察と題して、実際にコード書くときに使って見たら怖いなと思ったので記事にしてみました。初学者レベルなので他にもっといいやりかたなどがあれば教えて欲しいと思ったというのも記事にした理由になります。

間違っていたり、もっとこうしたほうがいいよとかありましたら、是非コメントいただければと思います!

最後までお読みいただきありがとうございました。