정보를 담고있는 json은 객체 형태로 나타내진다.
const message = {
sender:"mike",
receiver:"lisa",
message:"hello",
createdAt:"2021-01-12 10:10:10"
}
메시지 객체가 전송할 수 있게 하려면, 메시지를 보내는 발신자와 메시지를 받는 수신자가 같은 프로그램을 사용하거나, 문자열처럼 범용적으로 읽을 수 있는 형태여야 한다.
따라서 다음과 같은 메소드를 사용한다.
JSON.stringify
: 객체를 JSON으로 변환
JSON.parse
: JSON을 객체로 변환
첫 번째 과제는 JSON.stringify를 구현하는 것이다.
const stringifiableObjects = [
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 },
// basic nesting
{ a: { b: "c" } },
{ a: ["b", "c"] },
[{ a: "b" }, { c: "d" }],
{ a: [], c: {}, b: true },
];
위 배열을 전부 string형으로 바꿔주는 함수를 작성 해주면 된다.
stringifiableObjects.forEach(function (test) {
const stringified = JSON.stringify(test)
it(`객체는 문자열 "${stringified}"로 변환되어야 합니다`, function (done) {
const expected = stringified;
const result = stringifyJSON(test);
expect(result).to.equal(expected);
done();
});
});
밑에 for문을 보면 위 배열의 인덱스를 하나하나씩 순회하는 것을 볼 수 있다.
따라서, 조건에 맞게 함수를 작성하면 될 것 같다.
조건
1. Boolean은 string형으로 바꿔줘야한다.
2. String형은 다음과 같이 바꿔줘야 한다. > '"string"'
3. undefined와 function은 변환해주지 않는다.
4. 객체와 배열은 다음과 같이 변환해준다 > '[1,"false",false]' , '{"x":5}'
function stringifyJSON(obj) {
if (typeof obj === "boolean" || typeof obj === "number" || obj === null) {
return `${obj}`;
} // toString도 있지만 null은 바뀌지 않아서 ``를 사용
if (typeof obj === "string") {
return `"${obj}"`;
}
if (Array.isArray(obj)) {
let newarr = [];
for (let i = 0; i < obj.length; i++) {
newarr.push(stringifyJSON(obj[i]));
}
return `[${newarr}]`;
} // 새로운 배열에 값을 넣고 마지막에 string형으로 바꿔준다.
if (typeof obj === "object") {
let str = "";
for (let key in obj) {
if (
typeof key === "function" ||
typeof obj[key] === "function" ||
key === "undefined" ||
obj[key] === undefined
) {
continue;
}
let newkey = stringifyJSON(key);
let newvalue = stringifyJSON(obj[key]);
str = str + `${newkey}:${newvalue},`;
}
return `{${str.slice(0, str.length - 1)}}`;
}
}
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: "피스타치오 크림 프라푸치노" },
],
},
......
위와 같은 배열을
이렇게 트리 형태로 바꿔줘야한다.
가장 상위 트리를 보면, 루트 밑에 크게 4종류의 트리가 있다.
이것은, 배열을 for문을 돌려서 작성해주면 편할 것 같다.
이후 자식노드의 구조를 보면 부모노드의 구조와 비슷하다. >> 재귀로 구현
다만, 자식노드가 없는 노드는 button이 없는 것을 보아 자식노드가 없는 노드는 버튼추가를 안 해도 될 것 같다.
const root = document.getElementById("root");
function createTreeView(menu, currentNode) {
for (let i = 0; i < menu.length; i++) {
let menuitem = document.createElement("li");
if (menu[i].children !== undefined) {
// 각 메뉴에 자식 노드가 있으면 -> radiobutton하고 내용 넣어야함
const inputbutton = document.createElement("input");
inputbutton.type = "checkbox";
const spantext = document.createElement("span");
spantext.textContent = menu[i].name;
// 새로운 list 만들 ul
// 자식노드의 자식노드 list
const newul = document.createElement("ul");
menuitem.append(inputbutton, spantext, newul); // li에 넣어줌
currentNode.append(menuitem);
createTreeView(menu[i].children, newul); // 자식 노드가 있으니까 재귀 한번 더돔
} else {
// 메뉴에 자식 노드가 없으면 -> li 엘리먼트 안에 단순히 이름만 표시
menuitem.textContent = menu[i].name;
currentNode.append(menuitem);
// 자식 노드가 없으므로 재귀 돌릴 필요 없음.
}
}
}
createTreeView(menu, root);