getElementsByClassName 문제

  • Broswer에 존재하는 document.getElementsByClassName 함수를 직접 구현해보는 문제
  • getElementsByClassName 함수는 현재 documnet에서 주어진 className을 가지고 있는 모든 html element를 찾는 함수입니다.
  • 결과는 항상 배열의 형태로 리턴해줍니다.
  • document.body, element.childNodes, element.classList를 사용해보세요
let found = [];
let parentElement = document.querySelector('body');

function check(checkHtml) {
  if(checkHtml.classList && checkHtml.classList.contains(className)) {
    found.push(checkHtml);
  }

  if(checkHtml.hasChildNodes()) {
    for(let i = 0; i < checkHtml.childNodes.length; i++) {
      check(checkHtml.childNodes[i]);
    }
  }
}
check(parentElement);
return found;

checkHtml.classList가 조건에 없으면 if문을 실행하지 않는 이유?

  • element Node에 classList method를 사용하게 되면 DomTokenList라는 것을 얻을 수 있다. DomTokenList이 contains라는 method를 가지고 있어서 아래와 같이 contains method를 사용할 수 있는 것이다.

  • if(checkHtml.classList.contains(className))의 경우

    1. 만약 checkHtml이 textNode일 경우 textNode에 classList 메소드를 실행시키면 undefined를 반환하게 된다.
    2. undefined는 DomTokenList가 아닌 undefined를 반환하기 때문에 contains 메소드를 사용할 수 없다.
    3. 그렇게 때문에 오류가 발생하고, 오류가 발생한 코드 아래로는 실행되지 않음.

    < 해결 방법 >

    if(checkHtml.classList && checkHtml.classList.contains(className)) {
      found.push(checkHtml);
    }

    위의 코드에서 checkHTML이 텍스트 노드일 경우

  1. if의 조건이 true가 아니기 때문에 found.push(checkHTML)은 실행되지 않음
  2. AND 연산자는 A && B에서 A가 false이면 A를 반환한다.
  3. 그렇기 때문에 에러가 나지않고 undefined를 반환하고
  4. 바로 아래의 if문도 실행가능!

stringifyJSON 문제

  • Broswer에 존재하는 JSON.stringfy 함수를 직접구현해보는 문제이다
  • JSON.stringfy 함수는 input 값을 JSON 형식으로 변환합니다.
    • 단, undefind와 function은 JSON으로 생략되거나 null 로 변환됩니다.
  • stringfyJSON은 아래와 같이 작동합니다.
    • Bolean이 input으로 주어졌을 경우
      : stringifyJSON(true); // 'true'
    • String이 input으로 주어졌을 경우
      : stringifyJSON('foo'); // '"foo"'
    • Array가 input으로 주어졌을 경우
      : stringifyJSON([1, 'false', false]); // '[1,"false",false]'
    • Object가 input으로 주어졌을 경우
      : stringifyJSON({ x: 5 }); // '{"x":5}'
    • undefind, function이 주어졌을 경우
      : stringifyJSON(undefined) // undefined
      : stringifyJSON(function(){}) // undefined
      : stringifyJSON({ x: undefined, y: function(){} }) // '{}'
function stringifyJSON(obj) {
  if(typeof obj === 'number' || typeof obj === 'boolean' || obj === null) {
    // 숫자, boolean, 값자체가 null일 경우 문자화
    return String(obj);
  } else if (typeof obj === 'string') {
    // 타입이 문자일 경우 원래 문자에 ""를 더한다.
    /* JSON.stringify()에 문자열 값을 넣을 경우,
    문자열 값 자체가 문자열이 되기 때문이다. */
    return `"${obj}"`;
  } else if (Array.isArray(obj)) {
    // 배열의 길이가 0일 경우 빈배열 반환
    if(obj.length === 0) {
      return '[]';
    } else {
      let result = [];
      for(let elem of obj) {
        // stringifyJSON 함수에 배열의 각 요소 넣고 실행(재귀)
        // stringifyJSON 함수 실행으로 반환된 값을 result에 push
        result.push(stringifyJSON(elem));
      }
      return `[${result}]`;
    }
  } else if (typeof obj === 'object') {
    if(Object.keys(obj).length === 0) {
      return '{}';
    } else {
      let result = [];
      for(let key in obj) {
        if(typeof obj[key] === 'undefined' || typeof obj[key] === 'function') {
          /* obj[key]가 undefined이거나 function이면 제거한 후
          stringifyJSON 함수 실행 (재귀)  */
          delete obj[key]; 
          stringifyJSON(obj);
        } else {
          result.push(`${stringifyJSON(key)}:${stringifyJSON(obj[key])}`);
          /*
            객체의 key와 value를 stringifyJSON 함수에 넣고 실행,
            반환된 값을 a:b의 형태로 조합하여 result에 push
          */
        }
      }
      return `{${result}}`;
    }
  }
};