section3/Unit1/ [자료구조/알고리즘] 재귀(10/20)
블로깅 주제
- JSON.stringify
1. 지금 현재, 당신의 기분이나 느낌을 표현해 주세요.
- 드디어 금요일이다. 역시 재귀 코플릿은 까다로웠다....데일리코딩도 역시 어려웠다. 얼른 알고리즘 푸는 실력이 늘었으면 좋겠다. 복잡하게 생각하지말자. 규칙찾자. 문제를 잘 읽자!
2. 오늘 무엇을 학습한 내용 중 지금 떠올릴 수 있는 단어를 모두 나열해 주세요.
- JSON.stringify, tree UI만들기
3. 2에서 작성한 단어를 가지고, 오늘의 학습 내용을 설명해 보세요.
- JSON.stringify
▶ JSON이란?
JSON은 JavaScript Object Notation의 줄임말로, 데이터 교환을 위해 만들어진 객체 형태의 포맷이다. 네트워크를 통해, 어떤 객체 내용을 다른 프로그램에게 전송한다고 가정해보자. 이 객체 내용을 일종의 메신저 혹은 채팅 프로그램에서 쓰는 하나의 메시지라고 한다면, 다음 객체를 어떻게 전송할 수 있을까?
const message = {
sender: "김코딩",
receiver: "박해커",
message: "해커야 오늘 저녁 같이 먹을래?",
createdAt: "2021-01-12 10:10:10"
}
전송 가능한 조건 (transferable condition)
- 수신자(reciever)와 발신자(sender)가 같은 프로그램을 사용한다.
- 또는, 문자열처럼 범용적으로 읽을 수 있어야 한다.
객체는 타입 변환을 이용해 String으로 변환할 경우 객체 내용을 포함하지 않는다. JavaScript에서 객체를 문자열로 변환하기위해 메서드(message.toString())나 형변환(String(message))을 시도하면, [object Object] 라는 결과를 리턴한다.
이 문제를 해결하는 방법은 객체를 JSON의 형태로 변환하거나 JSON을 객체의 형태로 변환하는 방법이다.
- JSON.stringify : 객체를 JSON으로 변환합니다.
- JSON.parse : JSON을 객체로 변환합니다.
stringify하는 이 과정을 직렬화(serialize)한다고 한다.
let transferableMessage = JSON.stringify(message)
console.log(transferableMessage)
// `{"sender":"김코딩","receiver":"박해커","message":"해커야 오늘 저녁 같이 먹을래?",
// "createdAt":"2021-01-12 10:10:10"}`
console.log(typeof(transferableMessage))
// `string`
JSON으로 변환된 객체의 타입은 문자열이다. 발신자는 객체를 직렬화한 문자열을 누군가에게 객체의 내용을 보낼 수 있다. 그렇다면 수신자는 이 문자열 메시지를 어떻게 다시 객체의 형태로 만들 수 있을까? JSON.stringify와 정반대의 작업을 수행을 하는 메서드 JSON.parse 를 사용할 수 있다.
JSON.parse를 적용하는 이 과정을 역직렬화(deserialize)한다고 합니다.
let packet = `{"sender":"김코딩","receiver":"박해커","message":"해커야 오늘 저녁 같이 먹을래?","createdAt":"2021-01-12 10:10:10"}`
let obj = JSON.parse(packet)
console.log(obj)
/*
* {
* sender: "김코딩",
* receiver: "박해커",
* message: "해커야 오늘 저녁 같이 먹을래?",
* createdAt: "2021-01-12 10:10:10"
* }
*/
console.log(typeof(obj))
// `object`
이처럼, JSON은 서로 다른 프로그램 사이에서 데이터를 교환하기 위한 포맷이다. 그리고 JSON 포맷은 자바스크립트를 포함한 많은 언어에서 범용적으로 사용하는 유명한 포맷이다.
▶ JSON 사용 규칙
자바스크립트 객체 | JSON | |
키 | 키는 따옴표 없이 쓸 수 있음 { key : "property" } |
반드시 쌍따옴표를 붙여야 함 '{"key":"property"}' |
문자열 값 | 작은따옴표도 사용 가능 { "key" : 'property' } |
반드시 큰따옴표로 감싸야 함 '{"key":"property"}' |
키와 값 사이 공백 | 사용 가능 {"key" : 'property'} |
사용 불가능 '{"key":"property"}' |
키-값 쌍 사이 공백 | 사용 가능 { "key":'property', num:1 } |
사용 불가능 '{"key":"property","num":1}' |
- 과제 1 : JSON.stringfy 함수 만들기
stringifyJSON.js
function stringifyJSON(obj) {
// your code goes here
// 불린, 스트링, 널, 넘버, 배열, 객체
if(typeof obj === 'boolean' || obj === null || typeof obj === 'number'){
return `${obj}`;
}
if(typeof obj === 'string'){
return `"${obj}"`;
}
if(Array.isArray(obj)){
let result=[];
for(let i=0;i<obj.length;i++){
result.push(stringifyJSON(obj[i]));
}
return `[${result}]`;
}
if(typeof obj === 'object' && !Array.isArray(obj)){
let strObj = '';
for (let key in obj) {
if (obj[key] === undefined || typeof obj[key] === 'function') {
continue;
}
strObj += `${stringifyJSON(key)}:${stringifyJSON(obj[key])},`;
}
strObj = strObj.slice(0,-1); // 마지막 ',' 빼주기
return `{${strObj}}`;
}
};
// 다음 코드는 결과 제출을 위한 코드입니다. 신경 쓰지 않아도 좋습니다.
if (typeof window === "undefined") {
module.exports = stringifyJSON;
}
이번 과제의 포인트!
※ template literal
예시) let obj = [1,2,3]
obj가 배열인 경우, `${obj}`처럼 템플릿 리터럴을 사용해도 원하는대로 '[1,2,3]' 이런 결과가 나오지 않는다.
템플릿 리터럴이 붙는 순간,
배열([,]) 까지고, 요소 중 문자열이 있으면 그 요소의 따옴표(" 또는 ') 가 한겹 까진 상태로 만들고,
그 상태에서 겉에 ""를 씌워줌으로써 문자열로 만들어준다.
let obj = ["1",2,3];
`${obj}` = "1,2,3" ; //중첩이 몇번이 되어도 다 벗겨지고 스트링화됨.
객체에 템플릿 리터럴이 붙으면,
const description = 'App opened';
const properties = { key1: 'val1', blah: 123 };
const logString = `Description: ${description}. Properties: ${properties}`;
console.log(logString);
그림처럼 [object Object]가 출력된다.
그래서 객체를 스트링형태로 만들어주고 싶으면 JSON.stringify를 사용하는 것이다.
Why is an array inside a template string displayed as a normal string?
Let's assume we have an object: var pet = { "name": "Barky", "species" : "dog", "foods": { "likes": ["bones", "carrots"], "dislikes": ["tuna"] } }; co...
stackoverflow.com
https://stackoverflow.com/questions/46146860/javascript-template-strings-dont-pretty-print-objects
Javascript - Template Strings Don't Pretty Print Objects
Can I use ES6 template strings to pretty print javascript objects? This is from a React Native project, with console.log() outputting to Chrome debugging tools. What I Want const description = 'App
stackoverflow.com
null, undefined의 type
typeof null // "object"
typeof undefined // "undefined"
let value = null;
String(null) // "null"
value.toString() //typeError!
- 과제 2: tree UI
fix_me.js
// TODO: createTreeView 함수를 재귀(자기 자신을 계속 부르게 함)호출하여 테스트케이스를 통과하세요.
// GOAL: 최종 결과가 resut.html와 같은 모습으로 나와야 합니다.
// 데이터 구조)
// menu[0]은 음료 메뉴판. menu[0].children = [ 콜드브루, 프라푸치노, 블렌디드, 티, 주스] ;
// menu[1]은 음식. menu[1].children = [빵, 케이크, 샌드위치, 과일, 스낵, 아이스크림] ;
// menu[2]는 굿즈. menu[2].children = [머그, 텀블러, 악세사리]
// menu[3]은 카드. menu[3].children = [10000원권, 30000원권, 50000원권, 100000원권]
// menu[i].children = [ {type: "item", name: 음식이름 }, {type: "item", name: 음식이름 } ]
// type이 "group" 이면 li에 checkbox,span 및 ul 태그 append 후 재귀 호출(그 ul태그에 또 li태그 append하게!)
// type이 "item" 이면 li 태그로 currentNode(ul태그)에 append
const root = document.getElementById("root");
function createTreeView(menu, currentNode) {
// TODO: createTreeView 함수를 작성하세요.
for (let i = 0; i < menu.length; i++) {
const makeUl = document.createElement("ul");
const makeLi = document.createElement("li");
// 자식요소가 없을때
if (menu[i].type === "item") {
// ↓ li 태그 안에 'name' 값 넣어주기
makeLi.textContent = menu[i].name;
currentNode.append(makeLi);
}
//자식요소가 있을 때
else {
const makeInput = document.createElement("input");
makeInput.setAttribute("type", "checkbox");
const makeSpan = document.createElement("span");
makeSpan.textContent = menu[i].name;
// ↓ li 안에 input, span, ul 한꺼번에 넣어주기
makeLi.append(makeInput, makeSpan, makeUl);
currentNode.append(makeLi);
// 재귀호출(만든 ul에 자식요소 붙히기 위해)
createTreeView(menu[i].children, makeUl);
}
}
}
// 트리 상->하 순으로 만들어주는 구조
// createTreeView(menu, currentNode) = currentNode 태그 안에 append로 ul or li 를 append해주는 함수
// 만약 자식이 있으면 (체크박스,span,ul append된)li의 ul에 자식요소들을 append 하기 위해 재귀함수 호출,
// 없으면 li만 currenNode에 append
// 처음에 createTreeview(menu, root) 선언하기 때문에 첫번째 currentNode는 root 가 됨
// 그 다음에는 createTreeview(menu[i].children, makeUl)로 재귀함수 호출하여, ul에 li append되게 만듦
createTreeView(menu, root);