[TIL] JSON, 재귀 활용 과제, 오답노트

ㅜㅜ·2022년 10월 23일
1

Today I learn

목록 보기
37/77
post-thumbnail

JSON

  • JSON = JavaScript Object Notation

  • 데이터 교환을 위해 만들어진 객체 형태의 포맷

  • JSON.stringify : 객체를 JSON으로 변환
    ⇒ stringify하는 과정을 직렬화(serialize)라고 함

  • JSON.parse : JSON을 객체로 변환
    ⇒ JSON.parse 적용 과정은 역직렬화(deserialize)라고 함

  • JSON은 JS객체와 비슷해보이지만 미묘하게 다름

    • 키에 꼭 쌍따옴표 필요 (ex: {”key”:”property”})
    • 문자열 값 꼭 쌍따옴표
    • 키와 값 사이 공백 사용 불가능
    • 키-값 쌍 사이 공백 불가 (ex: {”key”:”property”,”num”:1})




JSON.stringify 과제

이 과제는 위 JSON 파트에서 배운 JSON.stringify라는 매서드가 어떻게 작동하는지 하나하나 구현해보는 것이 목적이다.


function stringifyJSON(obj) {
  //undefined나 function의 경우 undefined
  if (typeof obj === "undefined" || typeof obj === "function") {
    return undefined;
  }

  //문자열인 경우
  //문자열은 그냥 템플릿 리터럴에 넣어주면 원하는 결과가 안 나왔음
  //이스케이프 표현을 사용해 '\"'이런식으로 좌우에 넣어줘야 했음
  if (typeof obj === "string") {
    return '"' + obj + '"';
  }

  //배열이 들어왔을 때 (재귀 함수 이용)
  if (Array.isArray(obj)) {
    const result = [];
    if (obj.length === 0) {
      return "[]";
   //빈 배열일 때는 빈 배열에 쌍따옴표 씌운 형태 반환 
    } else {
      for (let i = 0; i < obj.length; i++) {
        result.push(stringifyJSON(obj[i]));
    //빈 배열이 아닐 때는 반복문을 돌리는데 
    //각 요소를 다시 재귀함수의 전달인자로 넣어준다 
    //일차원 배열이 아니었을 경우, 즉 다차원 배열인 경우에는 배열 속의 배열의 요소들을 또 다시 문자열로 만들어주어야 하므로 이 과정이 필요함 
    //배열 속에 배열 외에도 갤체가 들어있는 경우에는 
    //아래쪽 객체 조건문에 걸려서 객체도 문자열로 하나하나 다 바꿔줄 수 있음
      }
      return "[" + result + "]";
    }
  }

  //객체 형태가 들어왔을 때 
  if (typeof obj === "object" && obj !== null) {
    let result = "";
    // 객체인데 null값이 아닌 경우 (null값 처리를 여기서 해줌)
    //null은 typeof를 할 경우 object로 나오기 때문에 ! 
    for (let key in obj) {
      if (typeof obj[key] === "function" || obj[key] === undefined) {
        //빈 객체인 경우 
        return "{}";
      }
      // 빈 객체가 아닌 경우 
      //key를 재귀함수에 돌려서 문자열로 만들어주고 json이라는 변수에 할당
      //key에 해당하는 값도 재귀함수에 돌려서 문자열로 만들어 준다 
      //처음부터 객체 속으로 이 값들을 넣어주지 않고
      //위쪽에서 선언해둔 빈 문자열 result에 해당 값들을 원하는 모양대로 배치해줌
      let json = stringifyJSON(key);
      obj[key] = stringifyJSON(obj[key]);
      result = result + json + ":" + obj[key];
      result = result + ",";
    }
    result = result.slice(0, -1);
    //맨 마지막 콤마는 잘라내고 나머지 값들만 남겨서 중괄호 속에 넣어준다 
    return "{" + result + "}";
  }

  return String(obj);
  //위의 조건들 외에 남은 케이스들은 모두 문자열로 바꿔주는 String()함수 사용 
}




Tree UI 과제

Tree UI는 화면을 구성할 때 재귀를 사용하는 가장 대표적인 예시이므로 직접 코드를 작성하면서 재귀에 좀 더 친숙해지도록 하는 과제였음.

위의 이미처럼 음료, 음식, 굿즈, 카드라는 큰 노드 아래에 각각 다른 작은 노드들이 존재하고, 각 노드들은 자식 노드를 가지고 있는 경우에만 체크박스를 가지고 있다.

오랜만에 DOM을 사용하려니 살짝 머리가 아팠지만, 페어님과 함께 차근차근 풀다보니 오히려 앞의 JSON.stringify 과제보다도 빠르게 끝낼 수 있었다.

해결 과정

기본 형태 만들기

반복문이나 조건문을 생각하기 이전에 우선 기억을 더듬어서 어떻게 DOM을 사용해 li, checkbox, span 등의 엘리먼트들을 만들지 생각해보았다.

const root = document.getElementById("root");
//html 파일에는 가장 상위의 div에 해당하는 root 변수가 선언&할당되어 있었음.

function createTreeView(menu, currentNode) {
  //함수는 메뉴와 현재 위치한 노드를 전달 인자로 받는다 
  
  	  //list 
	  const li = document.createElement("li");
      currentNode.append(li);
  
      //checkbox
      const input = document.createElement("input");
      input.type = "checkbox";
      li.append(input);
  
      //span
      const span = document.createElement("span");
      li.textContent = item.name;
      li.append(span);
}

createTreeView(menu, root);

반복문 씌워주고, children 키의 존재 여부에 따라 조건문 만들어주기

트리 구조는 menu라는 배열 속에 있는 객체의 개수만큼 반복되어 만들어져야 하므로 배열을 순회하는 반복문을 만들어 준다.

for (let item of menu) {
  if (item.children === undefined) {
    //테스트에서 자식 노드가 없는 경우에는 li 엘리먼트 안에 단순히 이름(name)만 표시하라고 했으므로 li 엘리먼트 외 나머지를 모두 지워줌.
      const li = document.createElement("li");
      currentNode.append(li);
      li.textContent = item.name;
    } else {
     //자식 노드가 있는 경우에는 li,input, span 모두 존재!
      const li = document.createElement("li");
      currentNode.append(li);
      //checkbox
      const input = document.createElement("input");
      input.type = "checkbox";
      li.append(input);
      //span
      const span = document.createElement("span");
      span.textContent = item.name;
      li.append(span);
//childrenUl을 만들어주는 이유는 
//가장 상위의 노드는 root가 이미 작성되어 있어서 맨 처음 매개변수currentNode에 root를 전달 받으면 append 할 수 있지만, 
//재귀함수로 그 아래의 노드들을 만들어줄 때는 root에 append할 것이 아니라 새로운 ul을 만들어준 뒤 append 해주어야 하기 때문. 
      const childrenUl = document.createElement("ul");
      li.append(childrenUl);

      createTreeView(item.children, childrenUl);
    }
  }

createTreeView(menu, root);
  




오답노트

  • 재귀의 base case가 재귀 함수를 구현할 때 재귀의 탈출 조건(재귀 호출이 멈추는 조건)을 구성한다.

  • 객체를 문자열로 변환하기 위해 메서드(message.toString())나 형변환(String(message))을 시도하면, [object Object] 라는 결과를 리턴한다.

  • JSON.stringify : 객체를 JSON으로 변환하고 이때 type은 string

  • JSON.parse : JSON을 객체로 변환하고 이때 type은 object

profile
다시 일어나는 중

0개의 댓글