【JavaScript】要素の取得方法まとめ



JavaScriptの要素を取得するための自分用メモ。
メソッド書く前に毎度のごとく、単語の意味を復習。
### HTMLElement
汎用的なHTMLの要素。
### HTMLCollection
汎用的な要素ノードの集合。HTML要素以外のノードは含まない。配列風のオブジェクト。
リストから選択するためのメソッドとプロパティを提供する。
### NodeList
ノードの集合体。名前の通りノード全般を含む。配列風のオブジェクト。
`forEach`が使えるので、配列のように簡単に処理できる。
## document.getElementById()
返り値：HTMLElement
指定したIDを持つ要素を返す。
要素が存在しない場合はnullを返す。
万が一、指定したIDをもつ要素が複数存在した場合は、最初に取得した要素のみを返す。
```html:HTML
<span id="sample1">sample text</span>
```
```javascript:JavaScript
const result = document.getElementById('sample1');
// result = <span id="sample1">sample text</span>
```
**要素の中のテキストを取得する場合**
```javascript:JavaScript
const result = document.getElementById('sample1').textContent;
// result = sample text
```
## document.getElementsByTagName()
返り値：HTMLCollection
指定したタグ名を持つ要素を返す。
```html:HTML
<ul>
  <li><span>test1</span></li>
  <li>test2</li>
  <li class="test3">test3</li>
</ul>
```
```javascript:JavaScript
const result = document.getElementsByTagName('li');
// result = HTMLCollection(3) [li, li, li.test3]
```
## document.getElementsByClassName()
返り値：HTMLCollection
指定したクラス名を持つ要素を返す。
```html:HTML
<ul>
  <li><span>test1</span></li>
  <li>test2</li>
  <li class="hoge">test3</li>
</ul>
<p class="hoge">hoge</p>
```
```javascript:JavaScript
const result = document.getElementsByClassName('hoge');
// result = HTMLCollection(2) [li.hoge, p.hoge]
```
## document.getElementsByName()
返り値：NodeList
指定したname属性の値を持つ要素を返す。
一般的に`getElementsByName`を使うのは、`form`内の同じ`name属性`をもつ要素を取得する場合になるので他のメソッドと比べたら使う機会は少ない。

:::note warn
※ブラウザによって挙動が変わるので注意。
:::
```html:HTML
<input type="radio" name="q1" value="はい"> はい
<input type="radio" name="q1" value="いいえ"> いいえ
```
```javascript:JavaScript
const result = document.getElementsByName('q1');
// result = NodeList(2) [input, input]
```
## document.querySelector()
返り値：HTMLElement
指定したCSSセレクタとマッチする最初の要素を返す。
```html:HTML
<div id="header">
  <h1 class="title">titie</h1>
  <p class="text">hoge</p>
  <p class="text"><span>huga</span></p>
</div>
```
```javascript:JavaScript
const header = document.querySelector('#header');
const title = document.querySelector('.title');
const text1 = document.querySelector('#header .text');
const text2 = document.querySelector('.text:last-child');
// header = <div id="header">
              <h1 class="title">titie</h1>
              <p class="text">hoge</p>
              <p class="text"><span>huga</span></p>
            </div>
// title = <h1 class="title">titie</h1>
// text1 = <p class="text">hoge</p>
// text2 = <p class="text"><span>huga</span></p>
```
`querySelector()`のほうが直感的でわかりやすいが、
`getElementById()`のほうが処理速度は早い。

## document.querySelectorAll()
返り値：NodeList
指定したCSSセレクタとマッチする要素を返す。
```html:HTML
<div id="header">
  <h1 class="title">titie</h1>
  <p class="text">hoge</p>
  <p class="text"><span>huga</span></p>
</div>
```
```javascript:JavaScript
const header = document.querySelectorAll('#header');
const text1 = document.querySelectorAll('.text');
const text2 = document.querySelectorAll('.text:last-child');
// header = NodeList [div#header]
// text1 = NodeList(2) [p.text, p.text]
// text2 = NodeList [p.text]
```
`querySelectorAll()`のほうが直感的でわかりやすいが、
`getElementsByTagName()`, `getElementsByClassName()`のほうが処理速度は早い。
## HTMLCollectionと動的なNodeList
https://developer.mozilla.org/ja/docs/Web/API/HTMLCollection
>HTML DOM 内の HTMLCollection は生きて (live) います。

https://developer.mozilla.org/ja/docs/Web/API/NodeList
>NodeList には 生きた ものと 静的な ものの 2 種類のものがありますが、どちらも NodeList と考えられています。
>例えば、 Node.childNodes は生きています。

生きた…？
```html:HTML
<div class="content-wrap">
  <p class="content">content1</p>
  <p class="content">content2</p>
  <p class="content">content3</p>
</div>
```
### HTMLCollectionやNode.childNodes
```JavaScript:JavaScript
const contentWrap = document.getElementsByClassName('content-wrap')[0];
const result = document.getElementsByClassName('content');
console.log(result);
// result = HTMLCollection(3) [p.content, p.content, p.content]

// contentWrapに要素を追加
contentWrap.insertAdjacentHTML('beforeend', '<p class="content">content4</p>');

console.log(result);
// result = HTMLCollection(4) [p.content, p.content, p.content, p.content]
```
### 基本的なNodeList
```JavaScript:JavaScript
const contentWrap = document.querySelector('.content-wrap');
let result = document.querySelectorAll('.content');
console.log(result);
// result = NodeList(3) [p.content, p.content, p.content]

// contentWrapに要素を追加
contentWrap.insertAdjacentHTML('beforeend', '<p class="content">content4</p>');

console.log(result);
// result = NodeList(3) [p.content, p.content, p.content]

// 再取得すると変更が反映される
result = document.querySelectorAll('.content');
// result = NodeList(4) [p.content, p.content, p.content, p.content]
```
**動的・・・現在の状態のDOM内の要素を取得する。DOMに変更が入ると即時反映される。**
**静的・・・生成した段階のDOMがコピーされるイメージ。DOMに変更が入っても生成したNodeListには影響しない。**

例えば、動的の場合は取得した要素が3つのとき、取得した要素と同じ要素が4つに増えたら取得した要素も4つに増える。
静的の場合は取得した要素が3つのとき、取得した要素と同じ要素が4つに増えても取得した要素は3つのまま。

こんな感じ？なんとなく理解はできたけど言葉に落とし込めない…
### 注意
* `getElementById()`以外は配列型オブジェクトで返ってくるので、`getElements~()`の`s`を忘れないように。
* NodeListに対しては`forEach`が使える。
HTMLCollectionには使えないので`for`を使用するか`Array.from()`で配列に変換してから`forEach`をするが、ぱっと調べたら`forEach`より`for`のほうが速度が早そうなのでわざわざ変換して使う必要はなさそう。
**追記**：データが莫大でない限り、速度気にする必要ないので使い慣れてるメソッドを使う。
### 使い分けとして
* idが付与されている要素なら`getElementById()`がやりたいこととしても処理速度的にもよさそう。
* 複数存在する要素の場合は`querySelectorAll()`が使いやすいけどプロジェクト内で決まりがあったり、単純にタグを指定したり単一のクラス名を指定する場合は処理速度も早いので`getElements~()`を使うほうがよさそう。
* 要素が増減する場合は`getElements~()`を使う。
### ご教示いただいた参照方法
関数を使うまでもない処理の場合(返り値はそれぞれの関数と同じ)
```html:HTML
<div id="wrap">
  <form id="f">
    <input class="input">
  </form>
</div>
```
getDcumentById()
```javascript:JavaScript
const id = wrap;
// idの中の子要素をid指定で取得はできない
const form = wrap.f;
// 子要素を取得したい場合は以下の書き方
const form = wrap.children.f;
```
getElementsByTagName()
```javascript:JavaScript
const form = document.forms;
// idを指定すれば指定されたidが付与されてるformを取得できる。
// 返り値は HTMLElement
const form = document.forms.f;
```
参考サイト：https://qiita.com/mashuel/items/83c8e0ad6b09590dfcbd
### 最後に
自分はこんな使い分け方してるよ～とかあったら教えてください。