JavaScript / getElementsByTagName()으로 태그별 요소 선택하기

document.getElementsByTagName("p")는 문서 안의 모든 p 요소를 문서 순서대로 모아 HTMLCollection을 반환합니다. 특정 요소에서 호출하면 그 요소의 자손 중 같은 태그만 찾습니다. 결과는 살아 있는 컬렉션이라 요소가 추가·삭제되면 길이도 자동으로 바뀝니다.

문서 전체에서 태그 요소 선택하기

document.getElementsByTagName(tagName)에 "p", "li" 같은 태그 이름을 전달합니다. 결과의 첫 요소는 [0], 두 번째는 [1]입니다. 해당 태그가 없으면 길이가 0인 컬렉션이므로 인덱스로 꺼낸 값은 undefined가 됩니다.

const paragraphs = document.getElementsByTagName('p');
console.log(paragraphs.length); // 문서 안 p 요소 수
if (paragraphs.length > 1) {
  console.log(paragraphs[1].textContent); // 두 번째 p의 텍스트
}

반환값은 배열처럼 인덱스와 length를 사용하지만 배열 자체는 아닙니다. map() 같은 배열 메서드가 필요하면 Array.from(paragraphs)로 복사하세요. MDN의 Document.getElementsByTagName() 문서에서 반환 타입과 검색 범위를 확인할 수 있습니다.

특정 요소 안에서만 찾기

element.getElementsByTagName(tagName)은 기준 요소 자체가 아니라 그 안쪽 자손을 검색합니다. 한 구역의 단락만 다룰 때는 먼저 구역을 찾은 뒤 그 요소에서 호출하세요. 단락 속의 strong처럼 중첩된 자손도 선택할 수 있습니다.

const group = document.querySelector('#group');
if (group) {
  const local = group.getElementsByTagName('p');
  const second = local[1];
  if (second) {
    const strong = second.getElementsByTagName('strong')[0];
    console.log(strong?.textContent);
  }
}

이 예제에서 document로 찾은 단락은 구역 밖 단락까지 포함하지만, group에서 찾은 결과는 구역 안의 두 단락만 포함합니다. 특정 구역으로 범위를 좁히면 같은 태그가 다른 곳에도 있을 때 잘못된 요소를 고를 위험이 줄어듭니다. 범위와 자손 검색 규칙은 MDN의 Element.getElementsByTagName() 문서를 참고하세요.

HTMLCollection은 추가·삭제를 바로 반영합니다

HTMLCollection은 살아 있는(live) 결과입니다. 변수에 한 번 담아도 문서가 바뀌면 length와 인덱스 값이 갱신됩니다. 반대로 Array.from()으로 복사한 배열은 새 요소가 생겨도 길이가 그대로입니다. 반복하면서 요소를 삭제한다면 컬렉션의 인덱스가 바로 당겨지므로 뒤에서부터 처리하거나 배열로 복사해 사용하세요.

const live = group.getElementsByTagName('p');
const snapshot = Array.from(live);

const added = document.createElement('p');
added.textContent = '새 단락';
group.append(added);
console.log(live.length);     // 기존보다 1 증가
console.log(snapshot.length); // 복사할 때의 길이 그대로

MDN의 HTMLCollection 설명에는 살아 있는 컬렉션과 반복 중 변경 시 주의점이 정리되어 있습니다.

전체 예제: 문서 범위와 살아 있는 결과 비교

아래 코드를 UTF-8의 tag-name-example.html로 저장하고 브라우저에서 엽니다. 처음 문서에는 구역 밖 단락 한 개와 구역 안 단락 두 개가 있습니다. ‘단락 추가’를 누르면 HTMLCollection과 처음 복사한 배열의 길이를 비교할 수 있습니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>태그 이름으로 요소 모으기</title>
</head>
<body>
<h1>단락 요소 모으기</h1>
<p>구역 밖 단락</p>
<section id="group">
  <p>첫 번째 단락</p>
  <p><strong>두 번째</strong> 단락</p>
</section>
<button id="add" type="button">단락 추가</button>
<button id="reset" type="button">처음으로</button>
<pre id="output" aria-live="polite"></pre>
<script>
const group = document.querySelector('#group');
const allParagraphs = document.getElementsByTagName('p');
const groupParagraphs = group.getElementsByTagName('p');
const initialArray = Array.from(groupParagraphs);
const output = document.querySelector('#output');

function show() {
  const second = groupParagraphs[1];
  const strong = second.getElementsByTagName('strong')[0];
  output.textContent = `문서 p: ${allParagraphs.length}\n구역 p: ${groupParagraphs.length}\n초기 배열: ${initialArray.length}\n두 번째 단락: ${second.textContent.trim()}\n강조 텍스트: ${strong.textContent}`;
}

document.querySelector('#add').addEventListener('click', () => {
  const paragraph = document.createElement('p');
  paragraph.textContent = `추가 단락 ${groupParagraphs.length + 1}`;
  group.append(paragraph);
  show();
});
document.querySelector('#reset').addEventListener('click', () => {
  while (groupParagraphs.length > initialArray.length) {
    groupParagraphs[groupParagraphs.length - 1].remove();
  }
  show();
});
show();
</script>
</body>
</html>

처음에는 문서 p 3개, 구역 p 2개, 초기 배열 2개가 표시됩니다. 버튼을 한 번 누르면 문서 4개·구역 3개로 바뀌지만 초기 배열은 2개입니다. 두 번째 단락의 강조 텍스트는 계속 두 번째로 보입니다. ‘처음으로’를 누르면 추가된 단락이 제거되어 처음 개수로 돌아갑니다. 원래 글의 정적 결과 캡처 대신 변화 자체를 확인할 수 있습니다.