そろそろ、find()・children()・closest()・parent()・parents()・filter() を迷わず使いたい

**「も〜、、、　何回同じこと調べるねん！」**

ということで、自分のためにも覚書です。

「`find()`と`filter()`ってどう違うんだっけ？」
「`closest()`ってセレクタ自身も取得対象に含んでたっけ？」


この曖昧な記憶をスッキリさせたいと思います。

# find()・children()・closest()・parent()・parents()・filter()それぞれの違いと使い方


セレクタ付近の要素を取得するために使うjQueryのメソッドは、大きく分けて

**① 子・孫要素を取得**するメソッド
**② 親・祖先要素を取得**するメソッド
**③ 指定した選択肢の中でフィルタリングをかけて取得**するメソッド

の3つに分類できるかと思います。

## ① 子・孫要素を取得するメソッド

### 1. `find()`

指定した要素よりも中の要素から、**条件にマッチする全ての子孫要素**を取得します。

```html:html
<div class="parent">
    <div class="child active">子要素</div>
    <div class="child">
	    <div class="grandchild">孫要素</div>
    </div>
</div>
```
以下は、parentクラス要素の全ての子孫要素の中から、activeクラスを持つ要素を取得する場合。1つ目の子要素が取れています。
```js:find.js
$('.parent').find('.active').css('background-color', 'yellow');
```
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/94719d54-e6f8-dd89-25c7-c4025eee2623.png">

次は、parentクラス要素の全ての子孫要素の中からchildクラスを持つ要素を探す場合。
`find()`は条件にマッチする全ての子孫要素を取得するので、`<div class="child active">子要素</div>`と、`<div class="child"><div class="grandchild">孫要素</div></div>`の2つが取れています。

```js:find.js
$('.parent').find('.child').css('background-color', 'yellow');
```
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/512453f4-7b91-31ec-d9ed-da568412593f.png">

そして、parentクラスの中でgrandchildクラスを持つ要素を探す場合。子要素より下の階層にある孫要素も取得できています。
```js:find.js
$('.parent').find('.grandchild').css('background-color', 'yellow');
```
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/6594e6e7-c3b6-0ce3-50f7-17260cf95d7f.png">

### 2. `children()`

`children()`は、指定した要素の**直下の子要素だけ**を取得するメソッドです。
直下の子要素**だけ**を対象にするので、孫要素やそれ以上の深さの要素を取得できない点で`find()`とは異なります。

```js:children.js
$('.parent').children('.child').css('background-color', 'yellow');
```

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/69a73f17-c587-6f4f-2490-bfd08960e106.png">

上のように、子要素は問題なく取得できるのですが、

```js:children.js
$('.parent').children('.grandchild').css('background-color', 'yellow');
```

としても、直下の子要素にgrandchildクラスは存在しないので、要素を見つけることができません。

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/894661d9-963b-96dc-a592-82a8c3133741.png">



## ② 親・祖先要素を取得するメソッド

### 1. `parent()`

`parent()`は、**指定した要素の直近の親要素だけ**を取得するメソッドです。

```html:html
<div class="grandparent active">祖先要素
   <div class="parent active">親要素
      <div class="child">子要素</div>
   </div>
</div>
```

```js:parent.js
$('.child').parent('div').css('border', '5px solid red');
```

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/7a772849-6891-4f2f-b38b-31f9c4ea8bb6.png">

今度は、取得できた要素に赤枠をつけています。childクラスの直近の親要素のdivタグは`<div class="parent active">`なので、そのエリアに赤枠がつきました。

直近の階層しか取得できないという意味では`children()`と対になるメソッドです。ただ、1つの親要素に対して複数の子要素が存在しうるのに対し、1つの子要素に親は1つなので、原則、指定した要素の数だけの要素が`parent()`の取得できる選択肢になるという点でやや異なります。
### 2.  `parents()`

`parents()`は、**指定した要素の全ての祖先要素**が取得範囲になります。今度は親より遠い祖先も取得範囲になり、「全て」取得できるので、複数形になるんですね。

```js:parents.js
$('.child').parents('div').css('border', '5px solid red');
```

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/a3f9c458-0d85-1471-4714-8ea8b3102c31.png">

childクラス要素の親以上に当たるdivタグは`<div class="parent active">`と`<div class="grandparent active">`の2つなので、二重に赤枠がついています。

### 3. `closest()`

`closest()`は、**指定した要素から見て、最も近い祖先要素を探索し、条件に一致する最初の要素を選択**します。

```js:closest.js
$('.child').closest('div').css('border', '5px solid red');
```
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/b8eac674-642a-61c9-1285-05082b91778d.png">

ここで、`parent()`や`parents()`と違うのは、取得の選択肢に**自身も含む**ということ。
親方向に2階層以上遡れるという意味ではparentsと似ていて、条件を満たす1つを取得するという意味ではparentと同じですが、自身が条件に一致する場合、自身を選ぶことができます。自身が条件に合わない場合は、順に祖先を辿り、一番最初にマッチするものを取得します。


なので、例えば以下のようにすると、親以上の中で一番近いactiveクラスの要素を取得するので、

```js:closest.js
$('.child').closest('.active').css('border', '5px solid red');
```

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/9a20d22e-d912-8126-c608-45a24dc82f3f.png">


と、直近の親要素を取得します。
これが、`parents()`に置き換えると、親以上のactiveクラスを持つ要素全てが取得できるので、親要素と祖先要素の周りに二重に枠がつくというわけです。


## ③ "ちょっと異質" 指定した選択肢の中でフィルタリングをかける `filter()` メソッド



**`filter()`** は、**自分で指定した選択肢の中から、指定した条件にマッチする要素だけ**を取得するメソッドです。

私の認識としては、その名の通り、「フィルター」。
絞り込みで要素を探していくイメージです。指定した要素の内、条件に当てはまるものを探します。親子関係や個数は関係ありません。とにかくフィルターに引っかかりさえすれば良いのです。

```html:html
<div class="container">
	<ul>
	    <li class="item">Item 1</li>
	    <li class="item">Item 2</li>
	    <li class="item active">Item 3</li>
	    <li class="item">Item 4</li>
	</ul>
</div>
```

```js:filter.js
$('li').filter('.active').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/6cd848e5-a201-1268-7052-b83ef9af284d.png">

この場合、liタグ全て（4つ）を選択肢として指定して、その中でactiveクラスであるという条件を満たすものが取得できます。

つまり、以下のようにitemクラスであることを取得の条件にすれば、全てのliタグが条件を満たすので、4つとも取得されます。

```js:filter.js
$('li').filter('.item').css('background-color', 'yellow');
```

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/0a0d7b73-ff8e-f37c-865a-1112e1531529.png">


逆に`filter()`のセレクタにulを指定してしまうと、itemクラスを満たすulタグはないので、もちろん何も取得できません。
```js:filter.js
$('ul').filter('.item').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/a85fb761-b19f-d53f-7813-8d83c0b5c8d4.png">


## 子孫取得系とfilter()、ちょっとややこしい。 違いを整理

個人的にやや混乱したことを整理して以下にまとめます。主に、`filter()`と`find()`、`children()`って具体的にどう違う？というお話です。


先ほどの例で、liタグの内からitemクラスを検索すると、itemクラスである要素が全て取れました。

```js:filter.js
$('li').filter('.item').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/0a0d7b73-ff8e-f37c-865a-1112e1531529.png">

しかし、この指定方法は`find()`だと機能しません。`find()`は自分より中の階層にいる子孫要素しか対象にならないので、`find()`のセレクタにliタグを指定した時点で、liタグ要素を取得することはできないのです。

```js:find.js
$('li').find('.item').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/a85fb761-b19f-d53f-7813-8d83c0b5c8d4.png">

`find()`で同様にitemクラスを探したいなら、ひとつ上（親）のulタグを指定するとOKです。
```js:find.js
$('ul').find('.item').css('background-color', 'yellow');
```
ちなみに以下にしても結果は同じです。`find()`は孫以下も取得対象でしたね。
```js:find.js
$('.container').find('.item').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/0a0d7b73-ff8e-f37c-865a-1112e1531529.png">

ただし、`children()`は違います。直下の子要素しか取得できません。containerクラスの直下の子要素はulタグになるので、liタグを取得できないのです。
```js:children.js
$('.container').children('.item').css('background-color', 'yellow');
```

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/a85fb761-b19f-d53f-7813-8d83c0b5c8d4.png">

`children()`でliタグのitemクラス要素を取得したいなら、直近の親要素であるulタグをセレクタに指定する必要があります。

```js:children.js
$('ul').children('.item').css('background-color', 'yellow');
```
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798901/0a0d7b73-ff8e-f37c-865a-1112e1531529.png">

無事取得できました。以上、混乱しそうなパターンを記してみました。

## まとめ
|メソッド|検索対象|結果|
|:-:|:-:|:-:|
|find()|全ての子孫要素|子孫要素の中から条件にマッチする要素全て|
|children()|直下の子要素のみ|条件にマッチする直下の子要素全て|
|parent()|直近の親要素のみ|条件にマッチする直近の親要素|
|parents()|全ての祖先要素（自身は含まない）|祖先要素の中から条件にマッチする要素全て|
|closest()|全ての祖先要素（自身含む）|指定した要素から見て、条件にマッチする最初の（=自身から一番近い）要素|
|filter()|指定した要素|条件にマッチする要素全て|



p.s.
これでしばらくは「 find()　filter()　違い 」と、Google先生に何度も同じことを聞かなくて済みそうです。