JavaScriptで使えるArray.prototype.find()の活用術10選

JavaScriptのArray.prototype.findメソッドを使って配列内の要素を検索する方法JS
この記事は約23分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

●Array.prototype.find()とは?

JavaScriptを使った開発で、配列操作は欠かせない要素ですよね。

特に、配列から特定の条件を満たす要素を見つけ出すことは、よくある課題だと思います。

そんな時に活躍するのが、Array.prototype.find()メソッドです。

find()メソッドは、ES6で導入された比較的新しいメソッドで、配列内の要素を条件に基づいて検索することができます。

つまり、配列の各要素に対してテスト関数を実行し、その関数が真を返す最初の要素を返してくれるのです。

○find()メソッドの基本的な使い方

では早速、find()メソッドの基本的な使い方を見ていきましょう。

次のような配列があるとします。

const numbers = [1, 4, 9, 16, 25];

ここから、10以上の最初の要素を見つけ出したいとしましょう。

find()メソッドを使えば、次のように書けます。

const found = numbers.find(element => element >= 10);
console.log(found); // 16

find()メソッドには、テスト関数を引数として渡します。

この関数は、配列の各要素に対して実行され、真を返した最初の要素がfind()メソッドの戻り値となります。

上の例では、アロー関数を使ってelement >= 10という条件を表現しています。

実行結果を見ると、10以上の最初の要素である16が見つかったことがわかりますね。

○サンプルコード1:特定の条件を満たす要素を見つける

先ほどの例を応用して、もう少し複雑な条件で要素を探してみましょう。

const fruits = ['apple', 'banana', 'orange', 'melon', 'strawberry'];

const found = fruits.find(fruit => fruit.length > 6);
console.log(found); // "strawberry"

この例では、文字列の長さが6より大きい最初の要素を見つけ出しています。

fruit.length > 6という条件を満たす最初の要素は”strawberry”ですので、それが戻り値になっています。

○find()とfindIndex()の違い

ここで、find()メソッドと似たようなメソッドとして、findIndex()メソッドについても触れておきましょう。

findIndex()メソッドは、find()メソッドと同じように配列内の要素を検索しますが、戻り値が異なります。

find()メソッドが条件を満たした要素そのものを返すのに対し、findIndex()メソッドは、条件を満たした要素の「インデックス」を返します。

つまり、要素の値ではなく、配列内でのその要素の位置を知ることができるのです。

const fruits = ['apple', 'banana', 'orange', 'melon', 'strawberry'];

const index = fruits.findIndex(fruit => fruit.length > 6);
console.log(index); // 4

この例では、findIndex()メソッドを使って、文字列の長さが6より大きい最初の要素のインデックスを取得しています。

“strawberry”のインデックスは4ですので、4が出力されます。

find()メソッドとfindIndex()メソッドは、状況に応じて使い分けると良いでしょう。

要素の値そのものが必要な場合はfind()を、要素の位置を知りたい場合はfindIndex()を使うと覚えておくと便利です。

●find()メソッドを使った実践的な活用例

ここからは、find()メソッドをより実践的に活用する方法を見ていきましょう。

JavaScriptの開発で配列操作に時間を取られることが多いという方も、この例を参考にすることで、コードの可読性や効率を高められるはずです。

○サンプルコード2:オブジェクトの配列から特定のプロパティ値を持つオブジェクトを見つける

実務では、単純な値の配列だけでなく、オブジェクトの配列を扱うことも多いと思います。

そんな時、find()メソッドを使えば、特定のプロパティ値を持つオブジェクトを簡単に見つけ出せます。

const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 3, name: 'Charlie', age: 35 },
  { id: 4, name: 'David', age: 40 }
];

const user = users.find(user => user.id === 3);
console.log(user); // { id: 3, name: 'Charlie', age: 35 }

この例では、usersというオブジェクトの配列から、idプロパティの値が3であるオブジェクトを見つけ出しています。

find()メソッドに渡している関数では、user.id === 3という条件を確認しています。

実行結果を見ると、idが3のオブジェクト{ id: 3, name: 'Charlie', age: 35 }が見つかったことがわかります。

このように、オブジェクトの配列からも、find()メソッドを使って目的のオブジェクトを取得できるのです。

○サンプルコード3:複雑な条件を満たす要素を見つける

次に、もう少し複雑な条件で要素を探してみましょう。

find()メソッドに渡す関数では、論理演算子を使って複数の条件を組み合わせることもできます。

const products = [
  { name: 'Apple', price: 100, category: 'Fruit' },
  { name: 'Banana', price: 80, category: 'Fruit' },
  { name: 'Carrot', price: 120, category: 'Vegetable' },
  { name: 'Donut', price: 150, category: 'Dessert' }
];

const found = products.find(product => product.price > 100 && product.category !== 'Fruit');
console.log(found); // { name: 'Carrot', price: 120, category: 'Vegetable' }

ここでは、productsという商品のオブジェクトの配列から、価格が100より大きく、かつカテゴリーがFruitではない要素を見つけ出しています。

find()メソッドに渡している関数内で、product.price > 100 && product.category !== 'Fruit'という条件を確認しています。

実行結果は{ name: 'Carrot', price: 120, category: 'Vegetable' }となり、条件を満たす最初の要素が見つかっています。

このように、論理演算子を使えば、より細かな条件で要素を検索することができます。

○サンプルコード4:find()メソッドとArrow Functionを組み合わせる

ここまでの例では、find()メソッドに渡す関数をその都度定義していましたが、Arrow Functionを使えばもっと簡潔に書けます。

Arrow Functionは、ES6で導入された新しい関数の定義方法で、=>を使って関数を表現します。

const numbers = [1, 4, 9, 16, 25];

const found = numbers.find(num => num > 10);
console.log(found); // 16

この例では、numbers配列から、10より大きい最初の要素を見つけ出しています。

find()メソッドに渡す関数を、num => num > 10というArrow Functionで定義しています。

通常の関数定義と比べると、Arrow Functionを使うことで、コードがよりシンプルで読みやすくなることがわかります。

特に、短い関数を定義する場合には、Arrow Functionを活用すると良いでしょう。

○サンプルコード5:find()メソッドとdestructuring assignmentを組み合わせる

最後に、find()メソッドとdestructuring assignmentを組み合わせる方法を見ておきましょう。

destructuring assignmentは、ES6で導入された構文で、配列やオブジェクトから特定の値を取り出して変数に代入することができます。

const users = [
  { id: 1, name: 'Alice', age: 25 },
  { id: 2, name: 'Bob', age: 30 },
  { id: 3, name: 'Charlie', age: 35 },
  { id: 4, name: 'David', age: 40 }
];

const { name, age } = users.find(user => user.id === 3);
console.log(name); // "Charlie"
console.log(age); // 35

この例では、users配列からidが3のオブジェクトを見つけ出し、そのオブジェクトのnameageプロパティの値を、destructuring assignmentを使って変数に代入しています。

実行結果を見ると、name変数には”Charlie”が、age変数には35が代入されていることがわかります。

このように、find()メソッドとdestructuring assignmentを組み合わせることで、見つけ出したオブジェクトから必要なプロパティだけを簡単に取り出せます。

●find()メソッドを使う際のよくあるエラーと対処法

ここまでは、find()メソッドの基本的な使い方や実践的な活用例を見てきました。

しかし、find()メソッドを使っていると、時にエラーに遭遇することがあります。

そんな時、どのように対処すればいいのでしょうか?

JavaScriptの開発で配列操作周りに時間を取られることが多いという方も、これらのエラーとその対処法を知ることで、スムーズに開発を進められるようになるはずです。

では早速、よくあるエラーとその対処法を見ていきましょう。

○TypeError: undefined is not a function

find()メソッドを使おうとした時に、次のようなエラーが発生することがあります。

const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(x => x > 3);
// TypeError: numbers.find is not a function

このエラーは、find()メソッドが呼び出せない場合に発生します。

原因としては、次のようなことが考えられます。

  • find()メソッドをサポートしていないブラウザを使っている
  • 配列のようなオブジェクトに対してfind()メソッドを呼び出そうとしている

1つ目の原因については、find()メソッドがES6で導入された比較的新しいメソッドであることが関係しています。

古いブラウザでは、find()メソッドがサポートされていない可能性があります。

この場合の対処法としては、トランスパイラ(Babel等)を使ってES6のコードをES5に変換するか、ポリフィル(互換性を維持するためのコード)を使ってfind()メソッドを実装するかのどちらかです。

2つ目の原因については、配列のように見えるけれども実際は配列ではないオブジェクトに対してfind()メソッドを呼び出そうとすると発生します。

const arrayLike = {
  0: 'apple',
  1: 'banana',
  2: 'orange',
  length: 3
};

const found = arrayLike.find(fruit => fruit === 'banana');
// TypeError: arrayLike.find is not a function

この場合の対処法としては、Array.prototype.slice()メソッドを使って配列のようなオブジェクトから新しい配列を作るという方法があります。

const arrayLike = {
  0: 'apple',
  1: 'banana',
  2: 'orange',
  length: 3
};

const arr = Array.prototype.slice.call(arrayLike);
const found = arr.find(fruit => fruit === 'banana');
console.log(found); // "banana"

Array.prototype.slice()メソッドを使うことで、配列のようなオブジェクトから新しい配列を作ることができます。

そうすれば、その新しい配列に対してfind()メソッドを呼び出すことができるようになります。

○見つからない場合のundefined

find()メソッドは、条件を満たす要素が見つからない場合、undefinedを返します。

これは、find()メソッドの仕様です。

const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(x => x > 10);
console.log(found); // undefined

この例では、numbers配列に10より大きい要素がないため、find()メソッドはundefinedを返しています。

undefinedが返ってくる可能性があることを理解しておくことが大切です。

undefinedが返ってきた場合の処理を適切に行わないと、思わぬバグにつながる可能性があります。

undefinedが返ってきた場合の対処法としては、次のようなことが考えられます。

  • 条件に合う要素が必ず存在することが保証されている場合は、特に何もしなくて良い
  • 条件に合う要素が存在しない可能性がある場合は、undefinedチェックを行う
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(x => x > 10);

if (found !== undefined) {
  console.log(`Found: ${found}`);
} else {
  console.log('Not found');
}
// "Not found"

このように、undefinedチェックを行うことで、条件に合う要素が見つからなかった場合の処理を適切に行うことができます。

○this参照に関するエラー

find()メソッドに渡すコールバック関数内でthisを使う場合、思わぬエラーが発生することがあります。

const obj = {
  numbers: [1, 2, 3, 4, 5],
  findNumber: function(n) {
    return this.numbers.find(function(x) {
      return x === n;
    });
  }
};

console.log(obj.findNumber(3)); // undefined

この例では、obj.findNumber(3)を呼び出した時、期待される結果は3ですが、実際にはundefinedが返ってきています。

これは、find()メソッドに渡したコールバック関数内のthisが、objではなくグローバルオブジェクトを参照しているためです。

このようなエラーを防ぐためには、次のような対処法があります。

  • コールバック関数をArrow Functionで定義する
  • Function.prototype.bind()メソッドを使ってthisを束縛する
  • find()メソッドの第2引数にthisを指定する

1つ目の対処法は、Arrow Functionを使うというものです。

Arrow Functionは、thisを囲むスコープの this を継承するため、このようなエラーを防ぐことができます。

const obj = {
  numbers: [1, 2, 3, 4, 5],
  findNumber: function(n) {
    return this.numbers.find(x => x === n);
  }
};

console.log(obj.findNumber(3)); // 3

2つ目の対処法は、Function.prototype.bind()メソッドを使ってthisを束縛するというものです。

const obj = {
  numbers: [1, 2, 3, 4, 5],
  findNumber: function(n) {
    return this.numbers.find(function(x) {
      return x === n;
    }.bind(this));
  }
};

console.log(obj.findNumber(3)); // 3

3つ目の対処法は、find()メソッドの第2引数にthisを指定するというものです。

const obj = {
  numbers: [1, 2, 3, 4, 5],
  findNumber: function(n) {
    return this.numbers.find(function(x) {
      return x === n;
    }, this);
  }
};

console.log(obj.findNumber(3)); // 3

このように、this参照に関するエラーに対しては、何点もの対処法があります。

状況に応じて適切な方法を選択することが大切ですね。

●Array.prototype.find()の応用的な使い方

ここまでは、find()メソッドの基本的な使い方や実践的な活用例、そしてよくあるエラーとその対処法について見てきました。

しかし、find()メソッドの本当の力は、もっと応用的な場面で発揮されます。

JavaScriptの開発で配列操作のスキルを向上させたいという方も、これらの応用的な使い方を知ることで、find()メソッドを使いこなせるようになるはずです。

では、具体的なサンプルコードを交えながら、find()メソッドの応用的な使い方を見ていきましょう。

○サンプルコード6:再帰的なデータ構造から要素を見つける

まずは、再帰的なデータ構造から要素を見つける方法から見ていきましょう。

再帰的なデータ構造とは、自分自身を含むようなデータ構造のことを指します。

例えば、次のようなオブジェクトの配列があるとします。

const comments = [
  {
    id: 1,
    text: 'First comment',
    children: [
      {
        id: 2,
        text: 'First reply',
        children: []
      },
      {
        id: 3,
        text: 'Second reply',
        children: [
          {
            id: 4,
            text: 'First reply to the second reply',
            children: []
          }
        ]
      }
    ]
  },
  {
    id: 5,
    text: 'Second comment',
    children: []
  }
];

この例では、comments配列の各要素がchildrenプロパティを持ち、そのchildrenプロパティがまた配列になっています。

このような再帰的なデータ構造から特定の要素を見つけ出すには、再帰的にfind()メソッドを呼び出す必要があります。

function findComment(id, comments) {
  return comments.find(comment => {
    if (comment.id === id) {
      return true;
    }
    if (comment.children.length > 0) {
      return findComment(id, comment.children);
    }
    return false;
  });
}

console.log(findComment(4, comments));
// { id: 4, text: 'First reply to the second reply', children: [] }

この例では、findComment関数を定義しています。

この関数は、idcomments配列を引数に取り、再帰的にfind()メソッドを呼び出して、idが一致するコメントを見つけ出します。

実行結果を見ると、idが4のコメントが見つかっていることがわかります。

このように、再帰的にfind()メソッドを呼び出すことで、複雑な階層構造を持つデータからも目的の要素を見つけ出すことができます。

○サンプルコード7:カスタムオブジェクトの配列から要素を見つける

次に、カスタムオブジェクトの配列から要素を見つける方法を見ていきましょう。

JavaScriptでは、独自のオブジェクトを定義することができます。

そのようなカスタムオブジェクトの配列に対しても、find()メソッドを使うことができます。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  isAdult() {
    return this.age >= 18;
  }
}

const people = [
  new Person('Alice', 25),
  new Person('Bob', 17),
  new Person('Charlie', 30)
];

const adult = people.find(person => person.isAdult());
console.log(adult); // Person { name: 'Alice', age: 25 }

この例では、Personクラスを定義しています。

Personクラスは、nameageのプロパティを持ち、isAdultメソッドを持っています。

isAdultメソッドは、その人物が成人(18歳以上)であるかどうかを判定します。

そして、people配列には、Personオブジェクトのインスタンスが格納されています。

ここで、find()メソッドを使って、people配列から最初の成人を見つけ出しています。

実行結果を見ると、Person { name: 'Alice', age: 25 }が見つかっていることがわかります。

このように、カスタムオブジェクトの配列に対しても、find()メソッドを使って目的の要素を見つけ出すことができます。

○サンプルコード8:非同期処理と組み合わせる

find()メソッドは、非同期処理と組み合わせることもできます。

非同期処理とは、処理の完了を待たずに次の処理を進めるような処理のことを指します。

JavaScriptでは、非同期処理を扱うために、PromiseやAsync/Awaitが使われます。

async function findAsync(array, asyncCallback) {
  for (const item of array) {
    if (await asyncCallback(item)) {
      return item;
    }
  }
  return undefined;
}

(async () => {
  const numbers = [1, 2, 3, 4, 5];
  const found = await findAsync(numbers, async (num) => {
    await new Promise(resolve => setTimeout(resolve, 1000));
    return num > 3;
  });
  console.log(found); // 4
})();

この例では、findAsync関数を定義しています。

この関数は、arrayasyncCallbackを引数に取ります。

asyncCallbackは、非同期の条件関数です。

findAsync関数内では、for...ofループを使って配列の要素を1つずつ処理しています。

そして、await asyncCallback(item)で非同期の条件関数を呼び出し、その結果がtrueであれば、その要素を返します。

実行結果を見ると、1秒の遅延の後、4が見つかっていることがわかります。

このように、find()メソッドを非同期処理と組み合わせることで、非同期的な条件で要素を見つけ出すことができます。

○サンプルコード9:ジェネレータ関数から要素を見つける

find()メソッドは、ジェネレータ関数から要素を見つけ出すこともできます。

ジェネレータ関数とは、function*構文で定義される特殊な関数で、yieldキーワードを使って値を返すことができます。

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}

const numbers = [...numberGenerator()];
const found = numbers.find(num => num > 3);
console.log(found); // 4

この例では、numberGeneratorジェネレータ関数を定義しています。

このジェネレータ関数は、1から5までの数字を順番にyieldしています。

そして、スプレッド演算子(...)を使って、numberGenerator関数から返された値を配列に変換しています。

その配列に対して、find()メソッドを使って、3より大きい最初の数字を見つけ出しています。

実行結果を見ると、4が見つかっていることがわかります。

このように、ジェネレータ関数から返された値の配列に対しても、find()メソッドを使って目的の要素を見つけ出すことができます。

○サンプルコード10:無限リストから要素を見つける

最後に、無限リストから要素を見つける方法を見ておきましょう。

無限リストとは、理論上は無限に要素を持つリストのことを指します。

JavaScriptでは、ジェネレータ関数を使うことで、無限リストを表現することができます。

function* fibonacciGenerator() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fibonacci = fibonacciGenerator();
const found = [...Array(10)].find(() => {
  const value = fibonacci.next().value;
  return value > 100;
});
console.log(found); // 144

この例では、fibonacciGeneratorジェネレータ関数を定義しています。

このジェネレータ関数は、フィボナッチ数列を無限に生成します。

そして、[...Array(10)]で長さ10の配列を作り、その配列に対してfind()メソッドを使っています。

find()メソッドに渡している関数内では、fibonacci.next().valueで次のフィボナッチ数を取得し、それが100より大きいかどうかを判定しています。

実行結果を見ると、144が見つかっていることがわかります。

このように、無限リストから目的の要素を見つけ出すこともできます。

ただし、無限リストを扱う場合は、適切な終了条件を設定しないと、処理が終わらなくなってしまうので注意が必要です。

まとめ

この記事では、JavaScriptのArray.prototype.find()メソッドについて、基本的な使い方から応用的な使い方まで、実践的なサンプルコードを交えながら詳しく解説してきました。

find()メソッドは、配列内から特定の条件を満たす要素を効率的に見つけ出すために非常に便利なメソッドであり、様々な場面で活用することができます。

この記事を通じて、読者の皆さんがfind()メソッドについて理解を深め、実務での活用方法を学んでいただければ幸いです。

ぜひ、実際のコーディングの中で活用してみてください。