
Section3 Unit1 [์๋ฃ๊ตฌ์กฐ/์๊ณ ๋ฆฌ์ฆ] ์ฌ๊ท - ๊ณผ์  JSON.stringify, Tree UI
โญ๏ธ ๊ณผ์  1. JSON.stringify
โ๏ธ ์ด๋ฒ ๊ณผ์ ๋ ์ฌ๊ท๋ฅผ ์ด์ฉํด ๋ฉ์๋ JSON.stringify๋ฅผ ํจ์์ ํํ๋ก ์ง์  ๊ตฌํํ๋ ๊ณผ์ ์๋ค.
์ฌ๊ทํจ์๋ฅผ ๊ตฌํํ๋๊ฒ์ ์ด๋ ค์์ ๋๊ปด์ ๊ทธ๋ฐ์ง ์ด๋ฒ ๊ณผ์ ๋ ์ฝ์ง ์์๋ค.
ํ
์คํธ์ ๊ทธ๋ฅ ํตํํ๊ณ  ์ถ๋ค๋ฉด const stringifyJSON = JSON.stringify; ์ด๋ ๊ฒ ๊ตฌํํ๋ฉด ๋๋ค. (๋๋ฌด๋ ์์ฝ๊ฒ ํด๊ฒฐ~)
ํ์ง๋ง ์ด ๊ณผ์ ๋ ์ฌ๊ท๋ฅผ ๊ณต๋ถํ๊ธฐ ์ํ ๊ฒ์ด๋, ํ๋์ฉ ๊ตฌํํด๋ณด์.
โจ ๊ตฌํ๊ณผ์  & ์ฝ๋
1. ์ฒ์์๋ ๊ฐ์ด ์กํ์ง ์์์ ํ์ฐธ์ ํค๋งค๊ณ , ์์์ ๋ชปํ๊ณ ์์๋ค... ๐ญ
2. ๋ฐฐ์ด๊ณผ ๊ฐ์ฒด๋ฅผ ์ ์ธํ๊ณ ๋, ๋จ์ํ "" ์ด๋ ๊ฒ ๋ฐ์ดํ๊ฐ ์ถ๊ฐ๋๋ ๊ฒ์ ์์์ฐจ๋ฆฌ๊ณ ๋ ์กฐ๊ฑด๋ฌธ์ผ๋ก number, string, boolean, null ์ผ ๊ฒฝ์ฐ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์๋ค.
3. ํจ์์ undefined์ธ ๊ฒฝ์ฐ๋ stringify ๋์ง ์๋๋ค.
4. ๋ฐฐ์ด๊ณผ ๊ฐ์ฒด๋ฅผ ๋ณํ์ํค๋ ๊ฒ์ ๋๋๊ฑฐ๋ฆฌ๋ค ๋ ํผ๋ฐ์ค๋ฅผ ์ฐธ๊ณ ํด์ ์์ฑ์ ์๋ฃํ์๋ค. (๊ทธ๋๋ ์ ๊ทผ์ ๋น์ทํ๊ฒ ํ๊ณ ์์์ด...๐ฅฒ)
function stringifyJSON(obj) {
  // Number ๋๋ Boolean์ผ ๊ฒฝ์ฐ
  if (typeof obj === "number" || typeof obj === "boolean" || obj === null) {
    return `${obj}`
  }
  // String์ผ ๊ฒฝ์ฐ
  if (typeof obj === "string") {
    return `"${obj}"`
  }
  // Array์ผ ๊ฒฝ์ฐ
  if (Array.isArray(obj)) {
    const result = [];
    // Reference ์์๋ forEach๋ก ์์ฑ
    for (let el of obj) {
      result.push(stringifyJSON(el))
    }
    return `[${result}]`
  }
  // Object์ผ ๊ฒฝ์ฐ
  if (typeof obj === "object") {
    let result = "";
    for (let key in obj) {
      // console.log(el, obj[el])
      let objKey = stringifyJSON(key);
      let objValue = stringifyJSON(obj[key])
      // ํจ์์ undefined๋ stringify๋์ง ์๋๋ค.
      if (typeof objValue === "function" || objValue === undefined) {
        continue;
      } else {
        result += `${objKey}:${objValue},`
      }
    }
    return `{${result.slice(0, result.length - 1)}}`
  }
};
โญ๏ธ ๊ณผ์  2. Tree UI
โ๏ธ Tree UI ๊ณผ์ ๋ ํ๋ฉด์ ๊ตฌ์ฑํ ๋ ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ ๊ณผ์ ์ด๋ค.
Tree UI๋ฅผ ๊ตฌํํ๋๋ฐ ์ฌ๊ท๋ฅผ ์ฌ์ฉํ ์๊ฐ์ ํด๋ณธ ์ ์ด ์์ง๋ง(์ฌ๊ทํจ์ ์ฌ์ฉ์ ์ ๋ชปํ๋..), Tree UI๋ฅผ ์ฌ๊ท๋ก ๊ตฌํํ ์ ์๋ค๋ ์ ๊ธฐํ๊ณ ์ฌ๋ฐ๋ ์ฌ์ค์ ์๊ฒ ๋ ๊ณผ์ ์๋ค. ๊ฐ์ธ์ ์ผ๋ก ์ ๊ณผ์ ๋ณด๋ค ์ฌ๋ฐ์๋ค.
์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์ค๋ฉด ๋๊ณ , menu ๋ฐฐ์ด๋ ์๋์ ๊ฐ์ด ๊ตฌ์ฑ๋์ด ์๋ค.

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: 'ํผ์คํ์น์ค ํฌ๋ฆผ ํ๋ผํธ์น๋
ธ' },
        ],
      },
      { ... } // ์์ ๊ฐ์ children์ด ์ฌ๋ฌ ๊ฐ ๋ ์๋ ๊ตฌ์กฐ
     ]
   }
   // ์์ ๊ฐ์ group์ด ์ฌ๋ฌ ๊ฐ ๋ ์๋ ๊ตฌ์กฐ
 ]
โจ ๊ตฌํ๊ณผ์  & ์ฝ๋
๊ตฌํ๊ณผ์ ์ ์ฃผ์์ผ๋ก ์ ๋ฆฌํด๋์๋ค.
์๋ ์ฝ๋๋ ๋ช ๋ นํ(imperitive) ๋ฐฉ์์ผ๋ก ๊ตฌํํ์๊ณ , ๋ ํผ๋ฐ์ค ์ฝ๋๋ฅผ ๋ณด๋ ์ ์ธํ ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ฝ๋๋ ์์๋ค! ์ ์ธํ ์ฝ๋๋ณด๋ค๋ ๋ช ๋ นํ์ผ๋ก ์์ฑ๋ ์ฝ๋๊ฐ ๋๋ ๋ณด๊ธฐ์ ๋ ํธํ๋ค.
function createTreeView(menu, currentNode) {
  
  // menu์ ๊ฐ์ฒด ๊ฒ์ฌ
  menu.map((el) => {
    console.log(el)
    /*
      {type: 'group', name: '์๋ฃ', children: Array(5)}
      {type: 'group', name: '์์', children: Array(6)}
      {type: 'group', name: '๊ตฟ์ฆ', children: Array(3)}
      {type: 'group', name: '์นด๋', children: Array(4)}
    */
    /** result ํํ : ul#root > li > input, span, ul > li > input, span, ul > li ...
     * ul#root ๋ ์ด๋ฏธ ์์ฑ๋์ด ์์
     * li ์์ฑ
     */
    const li = document.createElement("li");
    
    /** ๊ฐ์ฒด ์์ children์ด ์์ ๊ฒฝ์ฐ input, span, ul ์์ฑ
     * input type="checkbox" 
     * span textContent : name (ex.์๋ฃ)
     */
    // ์๋ if ๋ฌธ์ด ๋ฐ๋ณต๋์ด์ผ ํจ. (children์ด ์์ ๋๊น์ง)
    if (el.hasOwnProperty("children")) {
      const input = document.createElement("input");
      const span = document.createElement("span");
      const ul = document.createElement("ul");
      input.setAttribute("type", "checkbox");
      // input.type = "checkbox"
      span.textContent = el.name;
      li.append(input, span, ul);
      
      currentNode.append(li);
      /* ์ต์ด ๋ ๋๋ง
        <ul id="root">
          <li>
            <input type="checkbox" />
            <span>${el.name}</span>
            <ul></ul>
          </li>
        </ul>
      */
      // ์ฌ๊ทํจ์ ํธ์ถ
      // createTreeView(menu, currentNode)
      // menu๋ ์ถ๊ฐํ  ๊ฒ, currentNode๋ ์ถ๊ฐํ  ๊ณณ 
      createTreeView(el.children, ul);
      
    } else {
      // console.log(`${el.name}์๋ ๋์ด์ children ์์`);
      // ๊ฐ์ฒด ์์ children์ด ์๋ ๊ฒฝ์ฐ li๋ง append
      currentNode.append(li);
      li.textContent = el.name;
    }
  })
}
๐ ์ค๋์ ํ๊ณ
์ค๋ ์ ๊ท ์์ ์๊ฐ์๋ ์กฐ๊ธ ๋๋ํ๊ฒ ๊ณต๋ถํ๊ฒ ์๋๊น, ๋ผ๋ ์๊ฐ์ด ๋ค์ด์ ์ ์ง ์์ฌ์์ด ์ข ๋จ์๋ค. ์ฌ๊ทํจ์, ๋๋ฌด ์ด๋ ค์ ์ง๋ง ์ด์  ๊ณผ์ ๋ฅผ ๋ฏธ๋ฆฌ ์กฐ๊ธ ํ์ด๋ดค๋๋(๋ค ํผ๊ฑด ์๋๊ณ , ์ผ๋ถ๋ง ํ์์ง๋ง...) ์ค๋ ์์ ์๊ฐ์ ์ฌ์ ๊ฐ ์๊ฒผ๋ค. ์์ ์๊ฐ์ ์กฐ๊ธ ์ฌ์ ๋ก์ฐ๋ ค๊ณ , ๊ณผ์ ๋ฅผ ๋ฏธ๋ฆฌ ํ์ด๋ณธ๊ฑด ์๋๋ฐ ๐ฅฒ ์ข ๋ ์ดํด๋๋ฅผ ๋์ด๊ธฐ ์ํด ๋ฏธ๋ฆฌ ๊ณต๋ถ๋ฅผ ํ๋ ๊ฑด๋ฐ ์ด์  ๋ฏธ๋ฆฌ ํ ๊ณผ์ ๊ฐ ์ค๋์ ํ์ต ์ง์ค๋์ ๋์ ํ๋์ ์กฐ๊ธ ๋ฐฉํดํ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ๋ ๋ค์๋ค. ๊ณต๋ถ ๊ณํ๊ณผ ๋ฐฉํฅ์ ๋ค์ ์๊ฐํด๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
์ ๊ท ์์ ํ์ ์คํฐ๋๋ญ ์ด๋ฒคํธ(?)์ ๋ง์ง๋ง ์คํฐ๋๋ก “๋๋ง์ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ ๋ง๋ค๊ธฐ”๊ฐ ์งํ๋์๋๋ฐ, ๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ์ฒ์ ๊ตฌ์ถํ๋ฉฐ ์์์ผ ํ ๋ด์ฉ๋ค์ ๋ํ ์์ ์ด ์งํ๋์ด์ ๊ฝค ์ ์ตํ๊ณ , ์ฌ๋ฏธ์์๋ค. npm์ผ๋ก ๋ฐฐํฌ๋ฅผ ํ๋ ๊ฒ๋ ๋๋ฌด ์ ๊ธฐํ๊ณ ์ ์ ํ๋ค. ๋ด๊ฐ ์์ฃผ ์ฌ์ฉํ๋ ์ผ์ข ์ ํ ํ๋ฆฟ์ ๋ฐฐํฌํด์, npm์ผ๋ก ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ค๋?! ๋๋ฌด ์ฌ๋ฐ์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ์์ ์ ๋ฃ๋ค๊ฐ ๊ถ๊ธํ ์ ์ด ๋ ์๊ฒผ๋๋ฐ, ๊ทธ๊ฒ๋ ์ข ๋ ์ฐพ์๋ณด๋ฉฐ ๊ณต๋ถํด์ผ ๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค์๋ค. ๊ถ๊ธํ ๊ฒ ์๊ธด๋ค๋ ๊ฑด ์ฆ๊ฑฐ์ด ์ผ์ด๋ค.
์ต๊ทผ๋ค์ด ๊ฑฐ์ ์ฌ๋๋ ์์ด ๊ณต๋ถ๋ฅผ ํ๋ค๋ณด๋ ํผ๋ก๊ฐ ํ ์์ฌ๊ฐ์ด ๋ชธ์ผ๋ก ๋๊ปด์ง๋ค. ํ๋ณต์ ํด์์ด๋ , ๋ง์ ๋ฆฌํ๋ ์๋ ๋ญ๊ฐ ํ์ํ ๊ฒ ๊ฐ๋ค… ๊ทธ๋ฌ๋ ์ค๋์ ์ด๋์ ์ ์ ์ ์๋ฆฌ์ ๋ค์ด์ผ๊ฒ ๋ค.
๋ด์ผ์ ์ข ๋ ํจ์จ์ ์ด๊ณ , ์ด์ฌํ ๊ณต๋ถํด์ผ์ง.
 
									
								 
									
								 
									
								