Frontend/๐Ÿ”จ JS

getElementsByClassName ํ•จ์ˆ˜ ๊ตฌํ˜„ํ•˜๊ธฐ (+์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์œ ์‚ฌ๋ฐฐ์—ด๊ณผ ๋ฐฐ์—ด, ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•)

haeunkim.on 2025. 9. 3. 18:56

ํ”„๋ก ํŠธ์—”๋“œ ๋ผ์ด๋ธŒ ์ฝ”๋”ฉ์ด๋‚˜ ํ™”์ดํŠธ๋ณด๋“œ ํ…Œ์ŠคํŠธ์—์„œ ์ž์ฃผ ๋‚˜์˜ค๋Š” ๊ณผ์ œ ์ค‘ ํ•˜๋‚˜๊ฐ€ DOM API๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๊ทธ์ค‘ ๋Œ€ํ‘œ์ ์ธ ๊ฒƒ์ด document.getElementsByClassName์„ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋ผ๋Š” ๊ณผ์ œ์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ด ๋ฌธ์ œ๋ฅผ ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜๋ฉด ์ข‹์„์ง€ ๋ฒ ์ด์Šค์ผ€์ด์Šค → ์—ฃ์ง€์ผ€์ด์Šค → ํšจ์œจ์„ฑ → ๊ฐ€๋…์„ฑ ์ˆœ์„œ๋กœ ํ’€์–ด๋ด…๋‹ˆ๋‹ค.

 

 

๋ฌธ์ œ ์ดํ•ด

๋ชฉํ‘œ๋Š” ์ฃผ์–ด์ง„ className์„ ๊ฐ€์ง„ ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ฐพ์•„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” DOM ํŠธ๋ฆฌ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ์กฐ๊ฑด์— ๋งž๋Š” ์š”์†Œ๋ฅผ ๋ชจ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

function getElementsByClassName(className) {
  const bodyChildrenEls = document.body.children;
  const result = [];
  const stack = [...bodyChildrenEls];

  while (stack.length) {
    const currentElement = stack.pop();
    const currentElementChildren = currentElement.children;

    for (let i = 0; i < currentElementChildren.length; i++) {
      const currentChildrenEl = currentElementChildren[i];
      stack.push(currentChildrenEl);
    }

    if (currentElement.classList.contains(className)) {
      result.push(currentElement);
    }
  }

  return result;
}

 

 

1. ๋ฒ ์ด์Šค์ผ€์ด์Šค

 

  • ์ตœ์ƒ์œ„ ์š”์†Œ์—๋งŒ ํด๋ž˜์Šค๊ฐ€ ๋ถ™์€ ๊ฒฝ์šฐ
  • DOM์ด ๋น„์–ด์žˆ์„ ๋•Œ (<body></body>)
  • ์ฐพ๋Š” ํด๋ž˜์Šค๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
function getElementsByClassName(className) {
  const bodyChildrenEls = document.body.children;
  const result = [];

  for (let i = 0; i < bodyChildrenEls.length; i++) {
    const currentEl = bodyChildrenEls[i];
    const currentElClassName = currentEl.className;

    if (currentElClassName === className) {
      result.push(currentEl);
    }
  }

  return result;
}

 

 

2. ์•ณ์ง€ ์ผ€์ด์Šค

  • ํด๋ž˜์Šค๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ๋ถ™์€ ๊ฒฝ์šฐ
  • ์ค‘์ฒฉ๋œ ์š”์†Œ์ผ ๊ฒฝ์šฐ
  • ์ค‘์ฒฉ ๋Œ‘์Šค๊ฐ€ ๊นŠ์–ด์งˆ ๊ฒฝ์šฐ ... ๋“ฑ ๊ทธ ์™ธ์— ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถ”๊ฐ€๋˜๋Š” ์กฐ๊ฑด๋“ค .. ? 

2-1. ์ค‘์ฒฉ๋œ ์ž์‹๊นŒ์ง€ ์ˆœํšŒ (DFS / Stack)

๋ชจ๋“  ํ•˜์œ„ ๋…ธ๋“œ๊นŒ์ง€ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก stack์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.

function getElementsByClassName(className) {
  const bodyChildrenEls = document.body.children;
  const result = [];
  const stack = [...bodyChildrenEls];

  while (stack.length) {
    const currentElement = stack.pop();
    const children = currentElement.children;

    // ์ž์‹ ์š”์†Œ ์Šคํƒ์— ์ถ”๊ฐ€
    for (let i = 0; i < children.length; i++) {
      stack.push(children[i]);
    }

    if (currentElement.className === className) {
      result.push(currentElement);
    }
  }

  return result;
}
 

โœ… ๋™์ž‘: ์ค‘์ฒฉ ๊ตฌ์กฐ๊นŒ์ง€ ํƒ์ƒ‰ ๊ฐ€๋Šฅ
โŒ ๋ฌธ์ œ: className์ด "a b"์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๊ฒฝ์šฐ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜์ง€ ์•Š์Œ

 

2-2 ๋‹ค์ค‘ํด๋ž˜์Šค ๋Œ€์‘ ("a b")

function getElementsByClassName(className) {
  const bodyChildrenEls = document.body.children;
  const result = [];
  const stack = [...bodyChildrenEls];

  while (stack.length) {
    const currentElement = stack.pop();
    const children = currentElement.children;

    for (let i = 0; i < children.length; i++) {
      stack.push(children[i]);
    }

    // classList.contains๋กœ ํŠน์ • ํด๋ž˜์Šค๋งŒ ๊ฒ€์‚ฌ
    if (currentElement.classList.contains(className)) {
      result.push(currentElement);
    }
  }

  return result;
}

 

โœ… ๋™์ž‘: <div class="a b"> ์—์„œ getElementsByClassName("a") ํ˜ธ์ถœ ์‹œ ์ •์ƒ์ ์œผ๋กœ ๋งค์นญ๋จ

 

3. ํšจ์œจ์„ฑ (์‹œ๊ฐ„๋ณต์žก๋„ & ๊ณต๊ฐ„๋ณต์žก๋„)

  • ์‹œ๊ฐ„๋ณต์žก๋„: ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธํ•˜๋ฏ€๋กœ O(N) (N์€ DOM ๋…ธ๋“œ ์ˆ˜)
  • ๊ณต๊ฐ„๋ณต์žก๋„: ์Šคํƒ๊ณผ ๊ฒฐ๊ณผ ๋ฐฐ์—ด์— ์ตœ๋Œ€ O(N)๊นŒ์ง€ ์ €์žฅ ๊ฐ€๋Šฅ


4. ๊ฐ€๋…์„ฑ 

๋ฉด์ ‘ ํ›„๋ฐ˜์—๋Š” ์ฝ”๋“œ์˜ ๊น”๋”ํ•จ๋„ ํ‰๊ฐ€ ์š”์†Œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ 

  • stack → pendingNodes
  • result → matchedElements
  • currentElementChildren → children

 

 

 

+ ์œ ์‚ฌ๋ฐฐ์—ด ์ •๋ฆฌ 
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์“ฐ๋‹ค ๋ณด๋ฉด ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋ณด์ด๋Š”๋ฐ ๋ฐฐ์—ด์€ ์•„๋‹Œ ๊ฐ’๋“ค์„ ์ข…์ข… ๋งŒ๋‚ฉ๋‹ˆ๋‹ค. ํ”ํžˆ ์œ ์‚ฌ๋ฐฐ์—ด(array-like) ์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ๋“ค์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์œ ์‚ฌ๋ฐฐ์—ด๊ณผ ๋ฐฐ์—ด์˜ ์ฐจ์ด๋ฅผ ์ •๋ฆฌํ•˜๊ณ , ์œ ์‚ฌ๋ฐฐ์—ด์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


์œ ์‚ฌ๋ฐฐ์—ด์ด๋ž€?

์œ ์‚ฌ๋ฐฐ์—ด์€ length ์†์„ฑ๊ณผ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ๊ฒ‰๋ชจ์Šต์€ ๋ฐฐ์—ด ๊ฐ™์ง€๋งŒ ์‹ค์ œ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ(map, forEach, filter ๋“ฑ)๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ:

  • ํ•จ์ˆ˜ ์•ˆ์˜ arguments
  • document.querySelectorAll ๊ฐ™์€ DOM API ๊ฒฐ๊ณผ๊ฐ’
  • HTMLCollection
 
function example() {
  console.log(arguments); // [Arguments] { '0': 1, '1': 2, '2': 3 }
}

example(1, 2, 3);
const divs = document.querySelectorAll('div');
console.log(divs); // NodeList(3) [div, div, div]

 


๋ฐฐ์—ด๊ณผ์˜ ์ฐจ์ด

๋ฐฐ์—ด์€ Array.prototype์„ ์ƒ์†๋ฐ›์•„ ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ์œ ์‚ฌ๋ฐฐ์—ด์€ ๋‹จ์ˆœ ๊ฐ์ฒด๋ผ ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

 
const arr = [1, 2, 3];
arr.forEach(x => console.log(x)); // ์ •์ƒ ๋™์ž‘

const divs = document.querySelectorAll('div');
divs.forEach(x => console.log(x)); 
// TypeError: divs.forEach is not a function

์œ ์‚ฌ๋ฐฐ์—ด → ๋ฐฐ์—ด ๋ณ€ํ™˜ ๋ฐฉ๋ฒ•

1. Array.from()

ES6์—์„œ ๋„์ž…๋œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

 
const divs = document.querySelectorAll('div');
const divArray = Array.from(divs);

divArray.forEach(div => console.log(div));

2. ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž [... ]

๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋ฐฐ์—ด๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const argsToArray = (...args) => {
  const arr = [...arguments];
  console.log(arr);
};

argsToArray(1, 2, 3); // [1, 2, 3]
 

3. Array.prototype.slice.call()

ES6 ์ด์ „์— ๋งŽ์ด ์“ฐ์ด๋˜ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 
function oldSchool() {
  const arr = Array.prototype.slice.call(arguments);
  console.log(arr);
}

oldSchool('a', 'b', 'c'); // ['a', 'b', 'c']

๊ทธ ์™ธ ์‹ค์ œ ํ™œ์šฉ ์˜ˆ์‹œ

DOM ์กฐ์ž‘

querySelectorAll๋กœ ์„ ํƒํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด map์„ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 
const buttons = document.querySelectorAll('button');

// ์œ ์‚ฌ๋ฐฐ์—ด ๊ทธ๋Œ€๋กœ๋Š” map ๋ถˆ๊ฐ€
// buttons.map(...) -> ์—๋Ÿฌ ๋ฐœ์ƒ

// ๋ณ€ํ™˜ ํ›„ ์‚ฌ์šฉ
const texts = [...buttons].map(btn => btn.innerText);
console.log(texts);

ํ•จ์ˆ˜ ์ธ์ž ์ฒ˜๋ฆฌ

arguments ๊ฐ์ฒด๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ”๊พธ๋ฉด ํŽธ๋ฆฌํ•˜๊ฒŒ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function sum() {
  const nums = Array.from(arguments);
  return nums.reduce((acc, cur) => acc + cur, 0);
}

console.log(sum(1, 2, 3, 4)); // 10

ํƒ€์ž… ํŒ๋ณ„ํ•˜๊ธฐ

์œ ์‚ฌ๋ฐฐ์—ด์ธ์ง€ ๋ฐฐ์—ด์ธ์ง€ ํ—ท๊ฐˆ๋ฆด ๋•Œ๋Š” Array.isArray()๋ฅผ ์“ฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Array.isArray([1, 2, 3]);        // true
Array.isArray(document.querySelectorAll('div')); // false
๋ฐ˜์‘ํ˜•