- JSON 구조가 재귀 함수를 사용할 수 있는 트리 구조임을 이해할 수 있다.
JSON.stringify
와JSON.parse
가 serialize, deserialize라는 것을 이해할 수 있다.JSON.stringify
와JSON.parse
를 사용하여 자바스크립트 값과 JSON을 넘나들 수 있다.- JSON에 재귀 호출을 사용할 때, 어디에 사용해야 할지 이해할 수 있다.
JSON.stringify : 객체를 JSON으로 변환합니다.
JSON.parse : JSON을 객체로 변환합니다.
let transferableMessage = JSON.stringify(message)
console.log(transferableMessage)
// `{"sender":"김코딩","receiver":"박해커","message":"해커야 오늘 저녁 같이 먹을래?","createdAt":"2021-01-12 10:10:10"}`
console.log(typeof(transferableMessage))
// `string`
-> 직렬화(serialize)한다.
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`
-> 역직렬화(deserialize) 한다.
자바스크립트 객체 | JSON | |
---|---|---|
키 | 키는 따옴표 없이 쓸 수 있음 { key : "property" } | 반드시 쌍따옴표를 붙여야 함 '{"key":"property"}' |
문자열 값 | 작은따옴표도 사용 가능 { "key" : 'property' } | 반드시 큰따옴표로 감싸야 함 '{"key":"property"}' |
키와 값 사이 공백 | 사용 가능 {"key" : 'property'} | 사용 불가능 '{"key":"property"}' |
키-값 쌍 사이 공백 | 사용 가능 { "key":'property', num:1 } | 사용 불가능 '{"key":"property","num":1}' |
- 표현식과 문자열 삽입, 여러 줄 문자열 등 다양하고 편리한 기능을 제공하는 문법
- 백틱(`)을 이용해서 감싸주며, 표현식은 ${변수}로 나타내고, 줄 띄어쓰기가 가능하다.
let obj = [1,2,3]
${obj} 안에 객체(배열 또는 진짜 객체)를 입력받는 경우, 객체의 문자열로 변환하여 대입한다.
obj가 배열인 경우에는, ${obj}
처럼 template literal을 사용해도
겉에 '[1,2,3]' 이러한 결과 가 나오지 않는다.
template literal이 붙는 순간,
배열([,])이 걷히고 그 요소에 문자열이 있으면 그 요소에 ''한 번 붙은 값이 나오게 된다.
let obj = ["1",2,3];
`${obj}` = "1,2,3" ; //중첩이 몇번이 되어도 다 벗겨지고 스트링화
나중에 [${}] 이러한 작업을 하기 위해, 즉
template literal이 한 번 더 붙어야 하기 때문에 문자열을 한 번 더 중첩시켜준다.
그리고 []브라켓으로 감싸 배열로 만들어준다 (빈 배열인 경우를 위해)
마지막으로 배열이 걷히고, 문자열이 1겹 걷히고 []브라켓을 추가로 넣어준다.
그러면 obj에 ''리터럴이 붙은형태인 '[1,2,3]'이 출력된다.
➡️ 템플릿 리터럴은 자료형을 문자열로 바꾸는 거라 배열에 템플릿 리터럴을 하는 건 배열에 toString을 하는 거랑 마찬가지!
function stringifyJSON(obj) {
// obj 처리 타입 종류 : boolean, string, array, object, null, number
if (typeof obj === 'boolean' || typeof obj === 'number') { // Boolean or number가 input으로 주어졌을 경우
return `${obj}` // stringifyJSON(true); -> 'true'
}
if (typeof obj === 'string') { // String이 input으로 주어졌을 경우
return `"${obj}"` // stringifyJSON('foo'); -> '"foo"'
}
if (obj === null) {
return 'null'
}
if (Array.isArray(obj)) { // Array가 input으로 주어졌을 경우
let result = [];
for (let i = 0; i<obj.length; i++) {
result.push(stringifyJSON(obj[i]))
} return `[${result}]` // stringifyJSON([1, 'false', false]); -> '[1,"false",false]'
}
// 객체에는 배열, 객체가 모두 포함되지만 배열인 경우보다 아래에 작성하였으므로 배열은 제외.
if (typeof obj === 'object') { // obj 가 객체인 경우
let result = '';
for (let key in obj) {
if (obj[key] === undefined || typeof obj[key] === 'function') { // - undefined, function이 주어졌을 경우
delete obj[key]
stringifyJSON(obj)
} else {
result += `${stringifyJSON(key)}:${stringifyJSON(obj[key])},`
}
}
result = result.slice(0, result.length-1) // 마지막 ',' 빼주기
return `{${result}}`
}
};
stringifyJSON는 JSON.stringify 함수를 실행했을 때와 같은 결과를 리턴해야 합니다.
✓ 객체는 문자열 "9"로 변환되어야 합니다
✓ 객체는 문자열 "null"로 변환되어야 합니다
✓ 객체는 문자열 "true"로 변환되어야 합니다
✓ 객체는 문자열 "false"로 변환되어야 합니다
✓ 객체는 문자열 ""Hello world""로 변환되어야 합니다
✓ 객체는 문자열 "[]"로 변환되어야 합니다
✓ 객체는 문자열 "[8]"로 변환되어야 합니다
✓ 객체는 문자열 "["hi"]"로 변환되어야 합니다
✓ 객체는 문자열 "[8,"hi"]"로 변환되어야 합니다
✓ 객체는 문자열 "[1,0,-1,-0.3,0.3,1343.32,3345,0.00011999]"로 변환되어야 합니다
✓ 객체는 문자열 "[8,[[],3,4]]"로 변환되어야 합니다
✓ 객체는 문자열 "[[[["foo"]]]]"로 변환되어야 합니다
✓ 객체는 문자열 "{}"로 변환되어야 합니다
✓ 객체는 문자열 "{"a":"apple"}"로 변환되어야 합니다
✓ 객체는 문자열 "{"foo":true,"bar":false,"baz":null}"로 변환되어야 합니다
✓ 객체는 문자열 "{"boolean, true":true,"boolean, false":false,"null":null}"로 변환되어야 합니다
✓ 객체는 문자열 "{"a":{"b":"c"}}"로 변환되어야 합니다
✓ 객체는 문자열 "{"a":["b","c"]}"로 변환되어야 합니다
✓ 객체는 문자열 "[{"a":"b"},{"c":"d"}]"로 변환되어야 합니다
✓ 객체는 문자열 "{"a":[],"c":{},"b":true}"로 변환되어야 합니다
✓ 함수와 undefined는 stringify되지 않습니다.
// TODO: createTreeView 함수를 재귀(자기 자신을 계속 부르게 함)호출하여 테스트케이스를 통과하세요.
// GOAL: 최종 결과가 resut.html와 같은 모습으로 나와야 합니다.
// 데이터 구조
// menu[0]은 음료 메뉴판 .children = [ 콜드브루, 프라푸치노, 블렌디드, 티, 주스]
// menu[1]은 음식 .children = [ 빵, 케이크, 샌드위치, 과일, 스낵, 아이스크림 ]
// menu[2]은 굿즈 .children = [ 머그, 텀블러, 악세사리 ]
// menu[3]은 카드 .children = [ 10000원권, 30000원권, 50000원권, 100000원권 ]
// menu[i].children = [ {type: 'item', name: 이름}, {type: 'item', name: 이름} ]
const root = document.getElementById('root');
function createTreeView(menu, currentNode) {
for (let i = 0; i < menu.length; i++) {
const li = document.createElement('li')
if (menu[i].children) { // children 요소가 존재할 경우
const input = document.createElement('input')
input.type = 'checkBox'
const span = document.createElement('span')
span.textContent = menu[i].name // ''씌우면 안됨
// const makeInput = document.createElement("input");
// makeInput.setAttribute("type", "checkbox");
const ul = document.createElement('ul')
// ↓ li 안에 input, span, ul 한꺼번에 넣어주기
li.append(input, span, ul)
currentNode.append(li)
// 만든 ul에 자식요소를 붙이기 위해 재귀함수 호출
createTreeView(menu[i].children, ul)
}
else { // children 요소가 없을 때
// ↓ li 태그 안에 'name' 값 넣어주기
li.textContent = menu[i].name
currentNode.append(li)
}
}
}
createTreeView(menu, root);
// 트리 상 -> 하 만드는 구조
// createTreeView(menu, currentNode) = currentNode 태그 안에 append로 ul 이나 li를 추가해주는 함수
// - 자식이 있으면 li에 ul 추가 재귀함수 호출, 없으면 li만 currentNode에 추가해준다
// 처음에 createTreeView(menu, root) 선언하기 때문에 첫 번째 currentNode는 ul #root가 됨
// 그 다음에는 createTreeView(menu[i].children, ul)로 재귀함수를 호출하여, ul에 li가 추가되게 만든다.
추후 만들 li를 묶는 ul
맨 위에 선언된 루트 노드.
===> const root = document.getElementById('root')
처음에 menu가 들어가면 menu에 자식 노드들이 있는데, 얘들을 붙여부려면 본인 li에 ul을 append해주고 거기에 붙여주어야 하니까
재귀함수를 호출 한다
createTreeView(menu[i].children, 요기)
맨 처음 재귀함수가 호출될 때, '요기'에 들어가는 노드는 root 노드