오늘은 새로운 그동안 배웠던 재귀함수와 DOM을 활용하여 코드를 작성하는 두 Sprint를 수행하였다. 재귀함수의 활용하는 방법과 작동원리에 대해서 다시한번 이해하게 되었고 이전 Section에 대해서 배웠던 DOM에 대해서 복기하게 되었다.
객체, 배열 등은 javaScript에서 사용 가능한 형태이기 때문에 범용적으로 사용하기 위해서는 문자열로 변환해야 하는데 JSON.stringify()를 사용하면 문자열 형태로 변환이 가능하다.(반대로 JSON.parse()를 사용하면 문자열을 원래 객체 형태로 변경할 수 있다.)
이번 스프린트에서는 재귀함수를 활용하여 JSON.stringify()을 함수로 구현해보았다.
function stringifyJSON(obj) { if (typeof obj === 'undefined' || typeof obj === 'function') return undefined if (typeof obj === 'string') { return '"' + obj + '"' } if (Array.isArray(obj)) { let arr = []; for (el of obj) { arr.push(stringifyJSON(el)) } return '['+ arr +']' } if(typeof obj === 'object' && obj !== null){ if(Object.keys(obj).length === 0){ return '{}' } let str = '' for(el in obj){ if (typeof obj[el] === 'undefined' || typeof obj[el] === 'function' ) return '{}' str += stringifyJSON(el) + ':' + stringifyJSON(obj[el]) +',' } str = str.slice(0, -1) return '{'+ str +'}' } return String(obj) };
obj가 undefined나 function인 경우에는 undefined를 출력하라는 조건이 있어서 if문을 사용하여 예외 케이스로 분리하였고, obj가 문자열, 배열, 객체인 경우도 별도로 분리하였고 그 외의 경우에는 String(obj)을 리턴하도록 코드를 작성하였다. 배열이나 객체 내에 또 다른 배열이나 객체 혹은 3차원 이상의 배열, 객체가 존재하는 경우를 대비하여 재귀함수를 사용하여 문자열로 변환해주는 과정을 거치도록 하였다.
재귀함수와 DOM을 배웠기 때문에 수행할 수 있는 menu라는 배열을 아래의 HTML문서로 변환해주는 createTreeView 함수를 구현하는 스프린트를 진행했다.
const menu = [ { type: 'group', name: '음료', children: [ { type: 'group', name: '콜드 브루', children: [ { type: 'item', name: '나이트로 콜드 브루' }, { type: 'item', name: '돌체 콜드 브루' }, { type: 'item', name: '제주 비자림 콜드 브루' }, { type: 'item', name: '콜드 브루' }, ], }, { type: 'group', name: '프라푸치노', children: [ { type: 'item', name: '애플 쿠키 크림 프라푸치노' }, { type: 'item', name: '더블 에스프레소 칩 프라푸치노' }, { type: 'item', name: '모카 프라푸치노' }, { type: 'item', name: '피스타치오 크림 프라푸치노' }, ], }, { type: 'group', name: '블렌디드', children: [ { type: 'item', name: '망고 바나나 블렌디드' }, { type: 'item', name: '딸기 요거트 블렌디드' }, { type: 'item', name: '자몽 셔벗 블렌디드' }, { type: 'item', name: '피치 & 레몬 블렌디드' }, ], }, { type: 'group', name: '티', children: [ { type: 'item', name: '라임 패션 티' }, { type: 'item', name: '민트 블렌드 티' }, { type: 'item', name: '아이스 유스베리 티' }, { type: 'item', name: '아이스 캐모마일 블렌드 티' }, ], }, { type: 'group', name: '주스', children: [ { type: 'item', name: '한방에 쭉 감당' }, { type: 'item', name: '파이팅 청귤' }, { type: 'item', name: '딸기주스' }, { type: 'item', name: '도와주 흑흑' }, ], }, ], }, { type: 'group', name: '음식', children: [ { type: 'group', name: '빵', children: [ { type: 'item', name: '트러플 미니 스콘' }, { type: 'item', name: '보늬밤 몽블랑 데니쉬' }, { type: 'item', name: '고소한 치즈 베이글' }, { type: 'item', name: '미니 클래식 스콘' }, ], }, { type: 'group', name: '케이크', children: [ { type: 'item', name: '밀당 에그 타르트' }, { type: 'item', name: '마스카포네 티라미수 케이크' }, { type: 'item', name: '블루베리 쿠키 치즈 케이크' }, { type: 'item', name: '부드러운 생크림 카스텔라' }, ], }, { type: 'group', name: '샌드위치', children: [ { type: 'item', name: '애플 까망베르 샌드위치' }, { type: 'item', name: '트리플 머쉬룸 치즈 샌드위치' }, { type: 'item', name: '로스트 치킨 샐러드 밀 박스' }, { type: 'item', name: 'B.E.L.T 샌드위치' }, ], }, { type: 'group', name: '과일', children: [ { type: 'item', name: '하루 한 컵 RED' }, { type: 'item', name: '한라봉 가득 핸디 젤리' }, ], }, { type: 'group', name: '스낵', children: [ { type: 'item', name: '리저브 초콜릿 세트' }, { type: 'item', name: '로스티드 아몬드 앤 초콜릿' }, { type: 'item', name: '마카롱' }, { type: 'item', name: '자일리톨 캔디 크리스탈 민트' }, ], }, { type: 'group', name: '아이스크림', children: [ { type: 'item', name: '자바 칩 유기농 바닐라 아이스크림' }, { type: 'item', name: '넛츠 초콜릿 아포가토' }, { type: 'item', name: '바닐라 아포가토' }, ], }, ], }, { type: 'group', name: '굿즈', children: [ { type: 'group', name: '머그', children: [ { type: 'item', name: '우리 한글 블랙 머그 473ml' }, { type: 'item', name: '서울 투어 머그 355ml' }, { type: 'item', name: '스타벅스 1호점 머그 400ml' }, { type: 'item', name: '서울 제주 데이머그 세트' }, ], }, { type: 'group', name: '텀블러', children: [ { type: 'item', name: 'SS 부산 투어 텀블러 355ml' }, { type: 'item', name: 'SS 블랙 헤리티지 오드리 텀블러 355ml' }, { type: 'item', name: 'SS 에치드 실버 텀블러 473ml' }, ], }, { type: 'group', name: '악세사리', children: [ { type: 'item', name: '리저브 오렌지 카드 홀더' }, { type: 'item', name: '스타벅스 1호점 에코백' }, { type: 'item', name: '스타벅스 1호점 랩탑 파우치' }, ], }, ], }, { type: 'group', name: '카드', children: [ { type: 'item', name: '10000원권' }, { type: 'item', name: '30000원권' }, { type: 'item', name: '50000원권' }, { type: 'item', name: '100000원권' }, ], }, ];
(실제 구현되어야 하는 웹페이지)
Document
- 음료
- 콜드브루
- 나이트로 콜드 브루
- 돌체 콜드 브루
- 제주 비자림 콜드 브루
- 콜드 브루
- 프라푸치노
- 애플 쿠키 크림 프라푸치노
- 더블 에스프레소 칩 프라푸치노
- 모카 프라푸치노
- 피스타치오 크림 프라푸치노
- 블렌디드
- 망고 바나나 블렌디드
- 딸기 요거트 블렌디드
- 자몽 셔벗 블렌디드
- 피치 & 레몬 블렌디드
- 티
- 라임 패션 티
- 민트 블렌드 티
- 아이스 유스베리 티
- 아이스 캐모마일 블렌드 티
- 주스
- 한방에 쭉 감당
- 파이팅 청귤
- 딸기주스
- 도와주 흑흑
- 음식
- 빵
/********************** 생략 **************************/
- 트러플 미니 스콘
- 보늬밤 몽블랑 데니쉬
- 고소한 치즈 베이글
- 미니 클래식 스콘
const root = document.getElementById('root'); function createTreeView(menu, currentNode) { for(el of menu){ if(el.type === 'group'){ const li = document.createElement('li') currentNode.append(li) const input = document.createElement('input') input.type = 'checkbox' const span = document.createElement('span') span.textContent = el.name; const ul = document.createElement('ul') li.append(input, span, ul) createTreeView(el.children, ul) } else { const li = document.createElement('li'); li.textContent = el.name; currentNode.append(li) } } } createTreeView(menu, root);
처음에 코드를 작성하기 전에 샘플 HTML 문서의 구조와 menu의 구조의 공통점을 찾았다. type이 group인 경우에는li,checkbox,span,ul이 생성되는 구조가 객체 내의 객체까지 동일하기 때문에 해당 순서대로 element를 만드는 함수를 반복할 수 있도록 재귀함수를 사용해야겠다는 감이 잡혔다. 그 후 type이 item인 경우에는 else로 분리하여 li를 생성할 수 있도록 작성하였다.
createTreeView 함수에는 menu, currentNode 두가지 파라미터가 입력되는데 HTML을 보면 반복되는 구조들이 ul에 들어가는 구조로 반복되기 때문에 재귀함수를 사용하는 부분에서 currentNode를 ul로 입력하였다.
재귀함수와 관련된 코딩 문제들만 풀었기 때문에 실제 코드를 작성할 때 어떻게 활용할 수 있는지에 대해서 궁금했는데 이번 스프린트들을 통해서 알 수 있었다. DOM도 다시한번 복기할 수 있어서 좋은 기회였다고 생각한다.