<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>프로그래밍 공부하기</title>
    <link>https://study-ihl.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 25 Jul 2026 19:13:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ihl</managingEditor>
    <item>
      <title>Clean Code</title>
      <link>https://study-ihl.tistory.com/232</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LeAox/btsd0Tz0ZeB/ShkzMZzBgVNZkMHtoRUat1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LeAox/btsd0Tz0ZeB/ShkzMZzBgVNZkMHtoRUat1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LeAox/btsd0Tz0ZeB/ShkzMZzBgVNZkMHtoRUat1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLeAox%2Fbtsd0Tz0ZeB%2FShkzMZzBgVNZkMHtoRUat1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;280&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스터디: &lt;a href=&quot;https://github.com/lghihl/CleanCode-Archetecture&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/lghihl/CleanCode-Archetecture&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 작년에 클린코드 스터디를 진행했었다. 블로그에도 몇 가지 인상 깊었던 부분을 기록해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 코드란 요구사항을 상세히 표현하는 수단이며, 프로그래밍은 기계가 실행할 정도로 상세하게 요구사항을 명시하는 작업이다. 코드의 추상화 수준이 높아지면서 프로그래머가 작성하는 코드 수가 줄어들 수는 있겠지만 코드 자체가 사라지지는 않을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 좋은 코드란 어떤 것일까? 사람마다 생각하는 기준이 다를 수 있지만 책에서 몇 가지 기준을 유명인의 말을 인용하여 제시하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좋은 코드 조건&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;읽기 쉽다.&lt;/li&gt;
&lt;li&gt;다른 사람이 고치기 쉽다.&lt;/li&gt;
&lt;li&gt;추측이 아닌 사실에 기반한다.&lt;/li&gt;
&lt;li&gt;시스템 내 모든 설계 아이디어를 표현한다.&lt;/li&gt;
&lt;li&gt;의미있는 이름을 쓴다.&lt;/li&gt;
&lt;li&gt;세세한 사항까지 꼼꼼히 신경썼고, 효율적이다.&lt;/li&gt;
&lt;li&gt;테스트 케이스가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 우리의 코드는 왜 나쁜 코드가 될까? 이 부분은 클린코드 뿐만 아니라, 클린 아키텍처 첫 장에서도 나오는 부분인데 &quot;&lt;b&gt;개발자가 전문가 답지 못했기 때문&lt;/b&gt;&quot;이다. 좋은 코드, 좋은 구조를 사수하는 것은 프로그래머의 책임이다. 업무 관리자는 보통 좋은 코드/구조의 중요성을 평가할만한 능력을 갖추지 못했기 때문에 개발자를 고용하는 것이기 때문이다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;일반적으로 당장 시장에 출시하는 것이 먼저라는 말로 구조를 신경쓰지 않고 뼈빠지게 일하게 된다. 그러나 이는 개발자가 자신의 생산성을 유지할 수 있다고 착각하는 것이며, 시장의 압박은 결코 수그러지지 않아 결국 생산성이 0에 수렴하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 시스템이란 구현할 프로그램이 아닌, 풀어가야할 이야기에 가깝다. 이야기를 쉽게 풀기 위해선 각 구성요소가 정확한 언어로 깔끔하게 맞아 떨어져야 한다. 즉, 일관성이 있어야 한다. 이를 이해한다면 프로그래밍을 하며 어떤 이름을 써야할지, 함수를 어떻게 써야할지 판단할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이름 짓는 기준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의도가 분명함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;널리 쓰이는 의미가 있는 단어를 다른 의미로 사용하지 않는다.&lt;/li&gt;
&lt;li&gt;흡사한 일므을 사용하지 않는다.&lt;/li&gt;
&lt;li&gt;일관된 표기법을 사용한다.&lt;/li&gt;
&lt;li&gt;의미있게 구분할 것 ex. var1, var2 X&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;검색하기 쉬움&lt;/li&gt;
&lt;li&gt;발음하기 쉬움&lt;/li&gt;
&lt;li&gt;한 개념에 한 단어 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fetch, get, reqeust, retrieve... 를 혼용하지 않는다.&lt;/li&gt;
&lt;li&gt;같은 코드 기반에 controller, manager, driver 등을 섞어 쓰지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;한 단어에 2가지 목적을 사용하지 않음&lt;/li&gt;
&lt;li&gt;해법 영역에서 가져온 이름 사용&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전산용어, 알고리즘, 패턴, 수학 용어 등을 사용&lt;/li&gt;
&lt;li&gt;기술 개념에는 기술 이름을 적용&lt;/li&gt;
&lt;li&gt;적절한 용어가 없다면, 도메인 영역에서 단어를 가져올 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;의미있는 맥락을 추가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불필요한 맥락은 제거한다. ex. m_ 같은 불필요한 인코딩은 제거한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수 작성 기준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 크기는 짧을 수록 좋고, 중첩 구조는 지양한다.&lt;/li&gt;
&lt;li&gt;하나의 함수는 추상화 수준이 하나인 단계만 수행해야한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;함수의 인수도 적을 수록 좋다.&lt;/li&gt;
&lt;li&gt;플래그 인수, Switch 등은 필연적으로 N가지 일을 한다. 다형성을 이용하여 해결하자&lt;/li&gt;
&lt;li&gt;부수효과를 일으키지 않는다.&lt;/li&gt;
&lt;li&gt;중복을 지양한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 책을 읽고, 다른 자료를 찾아 공부하면서 내가 아직 애자일과 TDD, 추상화에 대해 100%는 이해하지 못하고 있는 것 같다는 생각이 들었다. 책을 읽고나니, 많은 개발 조직들의 애자일 개발은 근본적으로 폭포수와 다를 바가 없다는 생각이 든다. 그렇다고 뭔가 애자일에 대해 깨달음을 얻은 것은 아니고 내가 생각했던 애자일이 그게 아니구나 라는 생각이 들었고 진짜 애자일을 경험해보고싶다는 생각이 들었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이 책에서 배우는 가장 중요한 부분은 &lt;b&gt;좋은 코드의&amp;nbsp;조건을 구체적으로 알아가는 것&lt;/b&gt; 이라 생각한다. 누구나 좋은 코드를 만들고 싶고, 좋은 이름을 짓기위해 고민한다. 그러나 어떤 코드가 좋은지 어렴풋이 아는 것이 아니라, 구체적으로 자신만의 기준을 만들어나가는 것이 본인의 업무를 수행하고 커뮤니케이션하는데 굉장히 중요하다. 이런 의미에서 클린 코드라는 책은 나만의 좋은 코드 기준을 더 구체화할 수 있어서 좋은 책인 것 같다.&lt;/p&gt;</description>
      <category>감상문</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/232</guid>
      <comments>https://study-ihl.tistory.com/232#entry232comment</comments>
      <pubDate>Fri, 5 May 2023 16:17:19 +0900</pubDate>
    </item>
    <item>
      <title>nvm: install failed! python: not found (mac m1)</title>
      <link>https://study-ihl.tistory.com/231</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2925&quot; data-origin-height=&quot;713&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUThVm/btrJ2ncgABs/uL3KwKzmU7YL0WOqn78ieK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUThVm/btrJ2ncgABs/uL3KwKzmU7YL0WOqn78ieK/img.png&quot; data-alt=&quot;nvm install fail&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUThVm/btrJ2ncgABs/uL3KwKzmU7YL0WOqn78ieK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUThVm%2FbtrJ2ncgABs%2FuL3KwKzmU7YL0WOqn78ieK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2925&quot; height=&quot;713&quot; data-origin-width=&quot;2925&quot; data-origin-height=&quot;713&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;nvm install fail&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; node 12버전이 필요해서 nvm install을 했더니 python: not found 라며 오류가 발생한다. 나의 경우 다음과 같은 해결책이 유효했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgcC2n/btrJ1IIiWjO/Yp8TjgJEdqlU9AzBHKOFsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgcC2n/btrJ1IIiWjO/Yp8TjgJEdqlU9AzBHKOFsK/img.png&quot; data-alt=&quot;nvm list&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgcC2n/btrJ1IIiWjO/Yp8TjgJEdqlU9AzBHKOFsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgcC2n%2FbtrJ1IIiWjO%2FYp8TjgJEdqlU9AzBHKOFsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;234&quot; height=&quot;212&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;nvm list&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 nvm의 default alias를 바꾸는 것이다! 나의 노드 설치 역사가 node 14를 먼저 설치 -&amp;gt; homebrew로 nvm을 설치 -&amp;gt; node 12버전 설치 -&amp;gt; node 12 제거 -&amp;gt; node 12 설치(오류!) 라서 뭔가 내부에서 꼬인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660814095823&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nvm alias default 14.19.2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nvm alias 명령어로 기존에 갖고있던 node 버전을 nvm의 default로 바꾼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9sHSd/btrJ0UWxiDB/p99fItPJeH7mpIDqInmFD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9sHSd/btrJ0UWxiDB/p99fItPJeH7mpIDqInmFD0/img.png&quot; data-alt=&quot;바뀐 default&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9sHSd/btrJ0UWxiDB/p99fItPJeH7mpIDqInmFD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9sHSd%2FbtrJ0UWxiDB%2Fp99fItPJeH7mpIDqInmFD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;245&quot; height=&quot;211&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;바뀐 default&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바뀐 default alias를 확인 후, nvm install 12를 했더니 성공했다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;85&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSMBli/btrJ2ni4l2K/Z8vMfcgZrriZkF6a1DcbDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSMBli/btrJ2ni4l2K/Z8vMfcgZrriZkF6a1DcbDK/img.png&quot; data-alt=&quot;성공!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSMBli/btrJ2ni4l2K/Z8vMfcgZrriZkF6a1DcbDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSMBli%2FbtrJ2ni4l2K%2FZ8vMfcgZrriZkF6a1DcbDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;767&quot; height=&quot;85&quot; data-origin-width=&quot;767&quot; data-origin-height=&quot;85&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;성공!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 메시지가 python: not found로 나와서 python 새로 설치해보고, 환경변수도 만져보고, 심볼릭 링크도 걸어보고 했는데 결국 이렇게 해결되다니..ㅠㅠ 참 어렵다..&lt;/p&gt;
&lt;div id=&quot;__endic_crx__&quot;&gt;
&lt;div class=&quot;css-diqpy0&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>ErrorLog</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/231</guid>
      <comments>https://study-ihl.tistory.com/231#entry231comment</comments>
      <pubDate>Thu, 18 Aug 2022 18:32:28 +0900</pubDate>
    </item>
    <item>
      <title>nodejs Debug Error : Unexpected token '.'</title>
      <link>https://study-ihl.tistory.com/230</link>
      <description>&lt;pre id=&quot;code_1659690304785&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/usr/local/bin/node ./app.js
SyntaxError: Unexpected token '.'
process exited with code 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 오랜만에 nodeJS를 디버깅을 하려는데 위와 같은 형식의 에러가 발생한다. 분명히 전에도 디버깅했던 프로젝트인데 무슨일인걸까..ㅜㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의심가는 것은 내가 최근에 node를 12로 낮췄다는 것인데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1659690462949&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Importing in Node.js: error &amp;quot;Must use import to load ES Module&amp;quot;&quot; data-og-description=&quot;I'm trying to import myArr from hello.js into index.js. However I get an error of Error [ERR_REQUIRE_ESM]: Must use import to load ES Module File hello.js export let myArr = ['hello', 'hi', 'hey'];&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&quot; data-og-url=&quot;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfZLqP/hyPkIPeZy1/T4Qp2BNcRuOjuN4Tc9HSW0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/questions/61670459/importing-in-node-js-error-must-use-import-to-load-es-module&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfZLqP/hyPkIPeZy1/T4Qp2BNcRuOjuN4Tc9HSW0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Importing in Node.js: error &quot;Must use import to load ES Module&quot;&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;I'm trying to import myArr from hello.js into index.js. However I get an error of Error [ERR_REQUIRE_ESM]: Must use import to load ES Module File hello.js export let myArr = ['hello', 'hi', 'hey'];&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택오버플로우에 찾아보니 ES6 모듈을 디버깅하기 위해선 2가지 조건이 필요한 것 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;node 14 버전 이상&lt;/li&gt;
&lt;li&gt;package.json 에서 &quot;type&quot;: &quot;module&quot; 넣어주기&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>ErrorLog</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/230</guid>
      <comments>https://study-ihl.tistory.com/230#entry230comment</comments>
      <pubDate>Fri, 5 Aug 2022 18:09:51 +0900</pubDate>
    </item>
    <item>
      <title>Bounce Rate vs Exit Rate</title>
      <link>https://study-ihl.tistory.com/229</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/riGKX/btrH31iFAub/wJbm1fhFu11TF7wPcxy3C1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/riGKX/btrH31iFAub/wJbm1fhFu11TF7wPcxy3C1/img.jpg&quot; data-alt=&quot;Exit&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/riGKX/btrH31iFAub/wJbm1fhFu11TF7wPcxy3C1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FriGKX%2FbtrH31iFAub%2FwJbm1fhFu11TF7wPcxy3C1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;480&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Exit&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 리액트의 reportWebVitals에서 측정한 사용자 경험 수치들을 Google Analytics로 보낼 때 nonInteraction이라는 옵션을 볼 수 있다. 이 옵션이 어떤 의미인지, Bounce Rate와 Exit Rate는 무슨 차이인지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658668974561&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import {getCLS, getFID, getLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, id}) {
  ga('send', 'event', {
    eventCategory: 'Web Vitals',
    eventAction: name,
    eventLabel: id,
    eventValue: Math.round(name === 'CLS' ? delta * 1000 : delta),
    // Use a non-interaction event to avoid affecting bounce rate.
    nonInteraction: true,
    transport: 'beacon',

    // OPTIONAL: any additional params or debug info here.
    // See: https://web.dev/debug-web-vitals-in-the-field/
    // dimension1: '...',
    // ...
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; GoogleAnalytics에 데이터를 보내는 위 코드에서 보이듯이 nonInteraction은 bounce rate의 영향을 피하기 위해 사용하는 옵션이다. 그렇다면 Bounce Rate 란 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/el3Rc9/btrH2nsh7S1/4Dv84B7SR4Xjibtd6dJv60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/el3Rc9/btrH2nsh7S1/4Dv84B7SR4Xjibtd6dJv60/img.png&quot; data-alt=&quot;이탈률 계산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/el3Rc9/btrH2nsh7S1/4Dv84B7SR4Xjibtd6dJv60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fel3Rc9%2FbtrH2nsh7S1%2F4Dv84B7SR4Xjibtd6dJv60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;103&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이탈률 계산&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Bounce Rate(이탈률)는 사용자가 사이트에 방문하여 아무 인터렉션 없이 페이지를 이탈한 비율이다. 다시 말하면 사이트의 첫 페이지에서의 클릭, 스크롤 등의 상호작용이나 사이트 내의 다른 페이지로의 없이 나가버린 것이다. 이탈률을 계산할 때는 해당 페이지로 시작하는 방문(세션)을 바탕으로만 계산된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tinLy/btrH1bs3A90/5enRoTeLPg91gYkWwQnSz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tinLy/btrH1bs3A90/5enRoTeLPg91gYkWwQnSz0/img.png&quot; data-alt=&quot;종료율&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tinLy/btrH1bs3A90/5enRoTeLPg91gYkWwQnSz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtinLy%2FbtrH1bs3A90%2F5enRoTeLPg91gYkWwQnSz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;107&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;128&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;종료율&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Bounce Rate와 비슷한 수치로 Exit Rate라는 것이 있다. Exit Rate는 사이트에서 어떤 상호작용을 한 후에 특정 페이지에서 나간 사용자의 비율을 의미한다. 즉, Bounce Rate는 사용자가 사이트를 방문하자마자 바로 나간 것이고, Exit Rate는 사이트를 둘러보다가 어떤 페이지에서 나갔느냐에 대한 수치라 말할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;What is Bounce Rate? &lt;a href=&quot;https://backlinko.com/hub/seo/bounce-rate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://backlinko.com/hub/seo/bounce-rate&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google Analytrics 고객센터 : &lt;a href=&quot;https://support.google.com/analytics/answer/2525491?hl=ko&quot;&gt;https://support.google.com/analytics/answer/2525491?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bounce rate vs exit rate : &lt;a href=&quot;https://cxl.com/guides/bounce-rate/bounce-rate-vs-exit-rate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://cxl.com/guides/bounce-rate/bounce-rate-vs-exit-rate/&lt;/a&gt;&lt;/p&gt;</description>
      <category>기타</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/229</guid>
      <comments>https://study-ihl.tistory.com/229#entry229comment</comments>
      <pubDate>Sun, 24 Jul 2022 22:55:16 +0900</pubDate>
    </item>
    <item>
      <title>포스트 메타버스</title>
      <link>https://study-ihl.tistory.com/228</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5InAo/btryQqkTP1G/ieJzCqjKjCoWdX5WIDAKbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5InAo/btryQqkTP1G/ieJzCqjKjCoWdX5WIDAKbk/img.png&quot; data-alt=&quot;포스트 메타버스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5InAo/btryQqkTP1G/ieJzCqjKjCoWdX5WIDAKbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5InAo%2FbtryQqkTP1G%2FieJzCqjKjCoWdX5WIDAKbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;304&quot; height=&quot;452&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;포스트 메타버스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 요즘 메타버스, 블록체인, NFT 등 알듯 말듯한 단어들이 들리고 있다. 심지어 이런 단어들이 세상을 지배할 것이라 한다. 앞으로는 대체 어떤 세상이 오는 걸까? 특히 메타버스라는 것은 대체 무엇일까?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메타버스에 대한 정의를 찾아보면 굉장히 다양하다. 현실 세계의 확장, 게임의 새로운 형태, 3D, VR 등등 사람마다 정의가 다르다. 책에 의하면 이러한 정의가 사실  거의 맞는 말이라 한다. 왜냐하면 메타버스는 굉장히 여러 개념이 포함되어있기 때문에, 마치 여러 맹인이 코끼리를 더듬어 설명하듯, 메타버스의 한 부분만 보고 이야기하는 것과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0W0ZJ/btryP8rPDjB/kkhknxq9oQJeSkjKOAgjI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0W0ZJ/btryP8rPDjB/kkhknxq9oQJeSkjKOAgjI0/img.png&quot; data-alt=&quot;메타버스 로드맵&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0W0ZJ/btryP8rPDjB/kkhknxq9oQJeSkjKOAgjI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0W0ZJ%2FbtryP8rPDjB%2Fkkhknxq9oQJeSkjKOAgjI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;432&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메타버스 로드맵&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메타버스는 크게 사람-환경 축과, 증강(데이터-&amp;gt;현실)-시뮬레이션(현실-&amp;gt;인터넷세상) 축으로 이루어져 있다. 이 중 증강 현실은 환경에 데이터를 겹쳐 보이게 증강하는 것(ex. 포켓몬 고)이고, 가상 세계는 사람의 활동을 시뮬레이션한 것(ex. 제페토)이다. 라이프 로깅은 사람의 활동 데이터를 쌓아 올린 것(ex. 인스타), 미러 월드는 환경 데이터를 시뮬레이션한 것(ex. 구글 맵)이다. 이 모든 것은 메타버스의 일부이다. 즉, 메타버스는 이렇게 현실과 가상이 혼재된 여러 세계들이 아주 긴밀하게 연결된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그렇다면 메타버스는 언제쯤 올까? 과거 90년대에도 앞으로 인터넷이 세계를 지배할 것이라는 예측이 있었다. 당시 90년대에는 www, IE 등이 이미 존재하는데 인터넷이 세계를 지배한다는 것이 무슨 의미인지 이해하기 어려웠다. 그러나 지금의 우리는 90년대의 인터넷의 위상과 현재의 위상이 확연히 다르다는 것을 알고 있다. 즉, 인터넷이 등장했다고 바로 세계를 지배하는 것이 아니라, 단계적으로 영향력을 넓혀 가고, 특히 스마트폰이라는 킬러 디바이스의 효과가 컸다. 메타버스도 인터넷과 비슷한 단계를 거칠 것으로 예상된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 사실 이미 1차 메타버스는 지나갔다. 90년대 PC와 VR, 디지털 트윈 등의 기술을 기반으로한 가상과 현실의 혼합이 시작되었고, 큰 영향력을 끼치지는 못한 채 마무리되었다. 그리고 현재 스마트폰을 기반으로 하는 2차 메타버스 세상이다. 그러나, 스마트폰에는 한계가 있다. 세상을 스마트폰이라는 작은 화면을 거쳐 본다는 것이 굉장히 불편하다는 점이다. 책에서는 인터넷의 킬러 디바이스 스마트폰처럼, 메타버스의 킬러 디바이스가 필요할 것이라 하며 그것이 안경형 디바이스가 될 것이라 한다. 이 안경형 디바이스가 활성화될 때, 일반인들도 알 수 있는 메타버스 세상이 와있을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메타버스는 어떤 세상일까? 산업혁명을 살펴보면 사람의 시공간에 대한 개념이 점점 확장되고 있다는 사실을 발견할 수 있다. 1차 산업혁명에서는 밤과 낮이라는 자연이 정해준 시간개념을 극복하여 인간이 활동할 수 있게 되었다. 2차 에서는 에펠탑처럼 높은 건물을 지으면서 공간에 대한 개념이 X-Y좌표에서 Z 축이 추가되었다. 3차 산업혁명에서는 인터넷이라는 새로운 공간이 생겼고, 4차 혁명에서는 공간과 장소 개념이 분리되었다. 과거 사람들은 공간과 장소를 동일하다고 생각했다. 그러나 요즘에는 집이라는 현실의 공간에서 인터넷 상에 있는 게더 타운, 줌 등의 장소에서 회의를 하곤 한다. 이런 식으로 공간과 장소의 개념이 분리되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 산업혁명은 매슬로의 욕구 피라미드에 대응되기도 한다. 사람들은 산업화 시대에서 생리적 욕구와 안전 욕구를 충족시켰다. 인터넷 시대에서는 친밀감, 자존감에 대한 욕구를 충족시켰다. 따라서 전세계가 인터넷으로 연결되어 자신의 일상을 공유하는 페이스북과 같은 서비스가 성공한 것이다. 따라서 이후 세계에서는 궁극적으로 사람들이 쉽게 나를 표현하고, 창작할 수 있는 기술이 발전할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 메타버스의 앞으로의 극복 과제는 무엇일까? 굉장히 여러 가지가 있겠지만, 개인적으로 3가지가 생각난다. 첫 번째는 접근성이다. 현재 메타버스는 10대 위주이다. 앞으로는 모든 세대를 아우를 수 있는 콘텐츠가 필요하다. 또한 노인, 장애인들도 쉽게 접근할 수 있어야 한다. 다음으로는 몰입감 있는 인터렉션이다. 메타버스 세상에서는 특히 아바타를 많이 사용할 것으로 예상되는데 이 아바타를 사용자가 내 몸처럼 다루기 위한 감지, 피드백, 디스플레이 기술들이 발전 중이다. 또한, 가상과 현실의 환경이 다르기 때문에 사용자 행동의 의미를 분석하여 적용할 필요가 있다. 예를 들어 사용자가 의자에 앉는 행동을 했을 때, 메타버스 내에 의자가 없다면 아바타는 어색한 행동을 취하게 될 것이다. 마지막으로 현실과의 공존이다. 메타버스가 파라다이스인 것 마냥 이야기하고 있지만, 사실 현실의 자연, 자유를 완전히 대체할 수 없다. 따라서 현실을 대체하는 것이 아닌 공존하는 형태로 나아가야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>감상문</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/228</guid>
      <comments>https://study-ihl.tistory.com/228#entry228comment</comments>
      <pubDate>Sat, 9 Apr 2022 18:49:15 +0900</pubDate>
    </item>
    <item>
      <title>DOM에서 사라진 요소는 dragEnd 이벤트가 발생할 수 없다.</title>
      <link>https://study-ihl.tistory.com/227</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKgX4E/btrvK4xMAvq/7t3FThIUZulwJST5NCuCOk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKgX4E/btrvK4xMAvq/7t3FThIUZulwJST5NCuCOk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKgX4E/btrvK4xMAvq/7t3FThIUZulwJST5NCuCOk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bKgX4E/btrvK4xMAvq/7t3FThIUZulwJST5NCuCOk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;302&quot; height=&quot;254&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 오늘은 dragEnd 이벤트가 발생하지 않는 오류를 기록해보려한다. DND(Drag &amp;amp; Drop)란, 위와 같이 마우스 포인터를 누른 채로 움직였다가 손을 떼는 동작을 의미한다. 일반적으로 화면상의 요소를 쉽게 움직이기 위해 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; DND 이벤트는 dragstart, dragend, dragover, dragenter, dragleave, dragexit, drop 7가지가 있다. 그 중 나는 dragstart, dragend 이벤트를 사용하는 예제를 만들어 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;zYpOWQB&quot; data-user=&quot;imhyelim1209&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/imhyelim1209/pen/zYpOWQB&quot;&gt; draggable&lt;/a&gt; by ImHyeLim1209 (&lt;a href=&quot;https://codepen.io/imhyelim1209&quot;&gt;@imhyelim1209&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; dragstart 이벤트가 발생하면 '&lt;span style=&quot;color: #ee2323;&quot;&gt;dragging&lt;/span&gt;', dragend 이벤트가 발생하면 '&lt;span style=&quot;color: #006dd7;&quot;&gt;nothing&lt;/span&gt;' 이라는 텍스트를 보여주도록 만든 간단한 예제이다. 이 때 만약, dragstart가 발생할 때 이벤트가 발생한 요소가 돔에서 사라지면 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;oNpvygm&quot; data-user=&quot;imhyelim1209&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/imhyelim1209/pen/oNpvygm&quot;&gt; draggable false&lt;/a&gt; by ImHyeLim1209 (&lt;a href=&quot;https://codepen.io/imhyelim1209&quot;&gt;@imhyelim1209&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;script src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위 코드에서 드래그를 시작하면 다시는 '&lt;span style=&quot;color: #006dd7;&quot;&gt;nothing&lt;/span&gt;' 이라는 글자로 돌아오지 않는다. 그 이유는 당연히 dragend 이벤트가 발생하지 않기 때문이다. 왜 그럴까? 유저의 입장에서는 마우스를 눌렀다가 뗐으므로 dragend가 발생해야한다. 이벤트가 등록된 요소도&amp;nbsp; document이기 때문에 어디선가 dragend가 발생했다면 '&lt;span style=&quot;color: #006dd7;&quot;&gt;nothing&lt;/span&gt;' 글자를 볼 수 있어야 정상이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그 이유는 어쩌면 당연하게도, dragend 이벤트는 직전에 dragstart 이벤트가 발생한 요소에서 발생하기 때문이다. 그런데, DOM에 해당 요소가 없어져서 이벤트 버블링이 끊긴 것이다. 따라서 document에 dragend 이벤트가 도달하지 못하므로 텍스트가 변경되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N1VeF/btryV3oqtuJ/KJ0k9ni8Hd1iN2VC0UcQNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N1VeF/btryV3oqtuJ/KJ0k9ni8Hd1iN2VC0UcQNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N1VeF/btryV3oqtuJ/KJ0k9ni8Hd1iN2VC0UcQNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN1VeF%2FbtryV3oqtuJ%2FKJ0k9ni8Hd1iN2VC0UcQNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;557&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 예를 들어, 리액트 에서 사용자가 드래깅하는 도중 상태가 변경되어 드래깅 중인 원본 요소가 사라지는 등의 상황에선 나와 같은 당황스러움을 느낄 수 있을 것이다. 특히 React는 document 혹은 React Root Node에 이벤트를 바인딩하여 리액트 이벤트를 발생시키는데, 이와 같은 상황이 발생하면 React에서는 아예 이벤트 자체가 발생하지 않을 것이다(네이티브 dragend 이벤트는 발생하나, 리액트 dragend이벤트는 발생하지 않아, onDragEnd 와 같은 연결이 불가능하다). 이를 어떻게 처리해주어야 할까?&lt;/p&gt;
&lt;p class=&quot;codepen&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;VwyZdgv&quot; data-user=&quot;imhyelim1209&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/imhyelim1209/pen/VwyZdgv&quot;&gt; draggable improve&lt;/a&gt; by ImHyeLim1209 (&lt;a href=&quot;https://codepen.io/imhyelim1209&quot;&gt;@imhyelim1209&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;script src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;  내가 찾은 방법은 dragstart 이벤트 처리 함수에서, 드래그 이벤트의 타겟에 dragend 이벤트와 처리함수를 별도로 연결해주는 것이다. dragend 이벤트의 버블링이 끊긴 것이지, 해당 요소에서 dragend 이벤트가 발생하지 않는다는 의미가 이니기 때문에, 해당 요소의 dragend 이벤트는 수신 가능하기 때문이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 리액트에서도 위 코드와 같이 addEventListener를 이용하여 직접 이벤트를 수신하면 사라진 요소의 dragend 이벤트를 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/24537000/react-js-events-not-firing-for-the-last-rendered-element&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/24537000/react-js-events-not-firing-for-the-last-rendered-element&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/facebook/react/issues/1355&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/facebook/react/issues/1355&lt;/a&gt;&lt;/p&gt;</description>
      <category>ErrorLog</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/227</guid>
      <comments>https://study-ihl.tistory.com/227#entry227comment</comments>
      <pubDate>Sun, 13 Mar 2022 18:41:57 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해</title>
      <link>https://study-ihl.tistory.com/226</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3X5a/btrrKHszwzW/3cTjkKFxt2oluZpM25qFu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3X5a/btrrKHszwzW/3cTjkKFxt2oluZpM25qFu1/img.png&quot; data-alt=&quot;객체지향의 사실과 오해&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3X5a/btrrKHszwzW/3cTjkKFxt2oluZpM25qFu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3X5a%2FbtrrKHszwzW%2F3cTjkKFxt2oluZpM25qFu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;643&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체지향의 사실과 오해&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 많은 사람들이 객체 지향 언어를 배우고, 자신의 프로그램을 객체 지향적으로 구성하기 위해 노력한다. 오늘날의 개발자라면 객체 지향이라는 단어를 알고 있는 것이 당연하다. 나 역시 객체지향이라는 단어를 많이 들었고, 내가 단어를 사용하기도 하였다. 그런데, 이 책을 읽고 객체지향에 대해 잘못생각하고 있는 부분들이 있다는 점을 깨닫게 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 객체 지향의 대표적 오해는 객체지향이 현실 세계의 모방이라는 것이다. 예를 들어, 이상한 나라에 앨리스와 물병이라는 두 요소가 있다. 앨리스가 물병 안의 물을 먹는 행동을 취한다면, 물병 안의 물의 양이 줄어들 것이다. 반면, 객체 지향 나라의 앨리스와 물병에서 앨리스가 같은 행동을 한다면, 앨리스가 물병에게 물의 양을 줄이라는 요청을 보내고, 물병은 자신의 판단에 의해 물의 양을 줄인다. 즉, 객체가 현실 객체의 부분적인 특징을 모방하는 것이 아니라, 현실 객체가 갖지 못한 추가적인 능력을 보유하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이러한 소프트웨어 객체의 특징을 의인화라 부르기도 하고, 현실 세계와 객체지향 세계 사이의 관계를&lt;span&gt;&amp;nbsp;&lt;/span&gt;은유(metaphor)라고&lt;span&gt;&amp;nbsp;&lt;/span&gt;표현하기도 한다. 현실 속 전화기를 객체 전화기로 만들었을 때, 비록 현실 전화기는 스스로 전화를 걸 수 없어도, 현실의 전화기라는 개념을 통해 소프트웨어 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;묘사함으로써&lt;span&gt;&amp;nbsp;&lt;/span&gt;그 객체가 전화를 걸 수 있다는 사실을 쉽게 이해하고 기억할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 객체 지향의 또 다른 오해는 '객체 지향 = 클래스 기반' 라는 점이다. 사실 객체 지향의 개념은 1960 년대 발표된 '시뮬라 67'이라는 프로그래밍 언어에서 출발했으며, 그 후 C++, JAVA와 같은 클래스 기반의 프로그래밍 언어가 유행하면서 '객체 지향 = 클래스 기반'라는 식으로 과장된 것이다. 클래스가 객체 지향 프로그래밍 언어의 관점에서 매우 중요한 구성 요소이지만, 객체 지향의 핵심을 이루는 중심 개념이라고 말할 수는 없다. 당장 JS 만 봐도 클래스라는 요소 없이 객체 지향 프로그래밍을 충분히 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 훌륭한 객체지향 설계자가 되기 위해선, 코드를 담는 클래스의 관점에서 메시지를 주고받는 객체의 관점으로 사고의 중심을 전환해야 한다. 중요한 것은 어떤 클래스가 필요한가가 아니라, 어떤 객체들이 어떤 메시지를 주고받으며 협력하는가 이다. 클래스는 객체들의 협력관계를 코드로 옮기는 도구에 불과하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 즉, 객체지향설계를 수행할 때, 프로그램 내에서 어떤 메시지를 주고받을 것인지를 먼저 설계해야 한다. 메시지를 주고받는 객체들이 어떻게 메시지를 처리하는지가 중요하게 여겨져서는 안 된다. 각 객체들이 메시지를 구체적으로 어떻게 처리되어야 하는지는 가 중요해져서는 안 된다. 객체가 수신한 메시지를 스스로 정한 원칙에 따라 판단하고, 의지에 기반하여 자율적으로 처리하도록 만들어야 한다. 예를 들어 커피를 만드는 프로그램이 있을 때, 커피를 만들어라라는 메시지를 받는 객체가 초보 바리스타던, 베테랑 바리스타던 상관없이 동작하게 만들어야 한다는 것이다. 이렇게 자율적인 객체들이 모여야 유연하고 단순한 협력을 만들 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 이 책은 객체 지향에 대해 근본적인 부분부터 생각해보게해주는 책이다. 객체 지향과 객체 개념, 협력과 상태, 메시지와 메소드, 추상화 등이 왜 생겨나게 되었는지 하나씩 개념을 쌓아 나가면서 자연스럽게 객체 지향에 대한 오해를 풀고, 진짜 객체 지향이 무엇인지 알 수 있도록 유도해준다. 분량이 많은 것은 아니지만, 내용 하나하나가 이해력이 필요한 내용들이기 때문에 책을 한 번 읽었다고 바로 객체 지향이 무엇인지 통달할 수 있는 것은 아니었다. 완전히 이해하고 체화하기 위해선 몇 번 더 읽어봐야할 것 같다.&lt;/p&gt;</description>
      <category>감상문</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/226</guid>
      <comments>https://study-ihl.tistory.com/226#entry226comment</comments>
      <pubDate>Wed, 9 Feb 2022 23:33:34 +0900</pubDate>
    </item>
    <item>
      <title>Symbol Type</title>
      <link>https://study-ihl.tistory.com/225</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; JavaScript의 기본이 되는 6개의 원시 타입은 Number, String, Boolean, null, undefined, Symbol이다. 이 중 Symbol(심볼)에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Symbol과 기존 JS 객체의 문제점&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1643982293031&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. No Symbol
const arr = [1,2,3,4,5];
console.log(arr.length); // output: 5

arr.length = 10;
console.log(arr.length); // output: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼이란 ES6에서 도입된 원시 타입으로, 유일무이한 값, 고유한 값을 지정하기 위해 사용된다. 위 코드에 나타난 JS의 문제점은 무엇일까? 바로 객체의 내장 속성과 같은 이름으로 속성을 재정의 하면 속성의 값이 덮어쓰기 되어버린다는 점이다. 개발자가 객체의 모든 속성을 알고 있기 어렵고, 협업을 하기 때문에 JS에서 객체의 속성이 덮어쓰기 될 위험은 항상 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1643982561912&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const arr = [1,2,3,4,5];
const length = Symbol('length'); // Symbol Type 변수 length 선언
arr[length] = 10; // arr에 변수 length를 이용하여 property 추가

console.log(arr.length); // output: 5
console.log(arr[length]); // output: 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 지금까지 객체 속성(property)의 키는 문자열만 가능한 것으로 알려졌지만, ES6 이후 심볼도 객체 속성의 키로 사용할 수 있다. 위 코드처럼 심볼 타입인 키를 갖는 객체 속성을 추가할 수 있다. 심볼로 생성한 값은 유일무이하므로, 객체의 기존 속성이 수정될 위험 없이 객체에 새로운 속성을 추가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N2OP1/btrsswrwsff/gZQSDbILuHDCRLyFgNVk7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N2OP1/btrsswrwsff/gZQSDbILuHDCRLyFgNVk7K/img.png&quot; data-alt=&quot;arr 객체의 형태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N2OP1/btrsswrwsff/gZQSDbILuHDCRLyFgNVk7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN2OP1%2Fbtrsswrwsff%2FgZQSDbILuHDCRLyFgNVk7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;302&quot; height=&quot;164&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;arr 객체의 형태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Symbol을 이용하여 속성이 추가된 배열 객체는 위와 같은 형태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Symbol의 특징&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 생성&lt;/h3&gt;
&lt;pre id=&quot;code_1644122137324&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x = Symbol();
console.log(typeof x); // output: symbol&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼 타입의 변수는 Symbol()이라는 함수를 통해 생성할 수 있다. 생성 시 new 키워드를 사용하지 않으며, new를 사용하면 TypeError가 발생한다. 즉, Symbol Wrapper 객체를 생성하지 않고, 항상 심볼 값(primitive value)만 생성 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644123509325&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x1 = Symbol();
const x2 = Symbol('x');

console.log(x1.toString()); // output: symbol()
console.log(x2.toString()); // output: symbol(x)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼 생성 시, description이라는 인자를 넘길 수 있다. description은 심볼 값에 대한 설명이다. description 인자는 선택적으로 넘길 수 있으며, 값이 심볼 생성에 큰 영향을 주지는 않는다. 다만, 심볼을 명시적으로 문자열로 변환했을 때 description 인자 값이 함께 출력되므로 디버깅 용으로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644124206365&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x1 = Symbol('x');
const x2 = Symbol('x');

console.log(x1 === x2); // output: false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Symbol()은 항상 고유한 심볼 값을 리턴한다. 즉, 호출될 때마다 새로운 고유 심볼 값을 생성하여 리턴하는 것이다. 이 때문에 심볼을 객체 property key로 사용할 때, 이름 충돌이 발생하지 않는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 문자열 변환&lt;/h3&gt;
&lt;pre id=&quot;code_1644124630384&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x = Symbol('x');

console.log('var is ' + x); // TypeError : Cannot convert a Symbol value to a string
console.log(`var is ${x}`); // TypeError : Cannot convert a Symbol value to a string
console.log(`var is ${x.toString()}`); // output : var is Symbol(x)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼은 암시적인 문자열 변환이 불가능하다. 즉, 문자열과 심볼을 이어 붙이기 위해선 toString(), new String()을 사용하여 명시적으로 변환해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. share Symbol&lt;/h3&gt;
&lt;pre id=&quot;code_1644125956421&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x1 = Symbol.for('x');
const x2 = Symbol.for('x');
const x3 = Symbol('x');

console.log(x1 === x2); // true
console.log(x1 === x3); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Symbol.for() 메서드를 사용하면 전역 심볼 레지스트리를 이용하여 심볼을 공유할 수 있다. Symbol.for('x')라는 뜻은 'x'라는 키를 갖는 심볼을 새롭게 생성하거나, 이미 존재하는 경우 해당 심볼을 리턴하라는 의미이다. 따라서 위 코드에서 x1에는 새롭게 생성된 심볼이, x2에는 x1과 같은 심볼이 리턴된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644126284908&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x1 = Symbol.for('x');
const x2 = Symbol.for('x');
const x3 = Symbol('x');

Symbol.keyFor(x1); // 'x'
Symbol.keyFor(x3); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Symbol.keyFor() 메서드를 사용하면, 해당 심볼이 전역 심볼 레지스트리에 어떤 키로 등록되어있는지 확인할 수 있다. 등록되지 않은 경우(= Symbol.for()로 생성하지 않은 심볼)는 undefined가 리턴된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 객체 속성 키 Symbol의 특징&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1644125186533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const sumOfAngle = Symbol('sumOfAngle');

const triangle = {
  name: '삼각형',
  color: 'red',
  [sumOfAngle]: 180
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 객체에 심볼을 이용하여 새로운 객체 속성을 추가하였을 때, 새롭게 추가된 객체 속성은 어떤 특징이 있는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-1. get Keys without Symbol&lt;/h3&gt;
&lt;pre id=&quot;code_1644125338840&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Object.keys(triangle); // ['name', 'color']
for (const pr in triangle) { console.log(pr); }; // 'name' 'color'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼 타입을 키로 갖는 객체 속성은 Object.keys() 나, for-in 문법으로 접근할 수 없다. 즉, 속성을 은닉할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3-2. get Symbols&lt;/h3&gt;
&lt;pre id=&quot;code_1644126586407&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Object.getOwnPropertySymbols(triangle); // [Symbol(sumOfAngle)]
Reflect.ownKeys(triangle); // ['name', 'color', Symbol(sumOfAngle)]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼 타입을 키로 갖는 객체 속성은 Object.getOwnPropertySymbols()나, Reflect.ownKeys()로 접근 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Symbol 활용&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-1. 객체 프로퍼티 은닉 및 확장&lt;/h3&gt;
&lt;pre id=&quot;code_1644128358479&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String.prototype[Symbol.for('getVowel')] = function (target) {
  return target.match(/[aeiou]/g);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 내장 객체에 사용자 정의 프로퍼티를 추가해야 할 때 혹은 객체에 은닉되어야 하는 속성을 추가할 때 유용하다. 내장 객체에 심볼을 이용하여 속성을 추가하면, 추후 내장 객체에 새로운 속성들이 추가되어도 이름이 충돌되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4-2. Enum&lt;/h3&gt;
&lt;pre id=&quot;code_1644127408567&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const meta = {
  inspectable: Symbol('inspectable'),
  inspected: Symbol('inspected'),
  name: Symbol('name'),
  preview_long: Symbol('preview_long'),
  preview_short: Symbol('preview_short'),
  readonly: Symbol('readonly'),
  size: Symbol('size'),
  type: Symbol('type'),
  unserializable: Symbol('unserializable'),
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 심볼은 전역에서 유일한 값을 가지므로, enum을 구현하기 위해 사용되기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MDN : &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Symbol&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Symbol : &lt;a href=&quot;https://javascript.info/symbol&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://javascript.info/symbol&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Symbol을 사용하는 이유는 뭘까 : &lt;a href=&quot;https://another-light.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://another-light.tistory.com/105&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/[JS] Common</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/225</guid>
      <comments>https://study-ihl.tistory.com/225#entry225comment</comments>
      <pubDate>Sun, 6 Feb 2022 15:41:42 +0900</pubDate>
    </item>
    <item>
      <title>메타버스, NFT, P2E가 합쳐진 Web 3.0이란?</title>
      <link>https://study-ihl.tistory.com/224</link>
      <description>&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=bN-M-FBHrCU&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/lE3uw/hyNam8cxVD/xXO38Ge9GjxxRbtZ5wH7u1/img.jpg?width=480&amp;amp;height=360&amp;amp;face=61_92_411_208&quot; data-video-width=&quot;480&quot; data-video-height=&quot;360&quot; data-video-origin-width=&quot;480&quot; data-video-origin-height=&quot;360&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/bN-M-FBHrCU&quot; width=&quot;480&quot; height=&quot;360&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 발전사
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 1.0 : 초창기 인터넷 환경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구글, 야후, msn, 넷이스케이프,&amp;nbsp; 등&lt;/li&gt;
&lt;li&gt;PC 기반 + 읽기 위주의 컨텐츠(상호작용이 거의 X)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플랫폼이 제공하는 인프라를 사용자가 정해진 방법으로 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web 2.0 : 현재 SNS 중심의 참여형 플랫폼 위주의 인터넷 환경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS, twitter, facebook, chrome, dropbox, airbnb, 유튜브&lt;/li&gt;
&lt;li&gt;스마트폰의 등장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언제 어디서나, 인터넷이 가능하면 서비스에 참가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cloud Driven
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정해진 회사의 서버가 아니더라도, 동일한 서비스를 받을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;읽기 + 쓰기가 가능한 컨텐츠(상호작용 다수)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유저가 적극적으로 환경 안에 게시물을 작성하는 등의 참여&lt;/li&gt;
&lt;li&gt;사람들의 참여를 유도, 광고로 수익 창출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web 3.0 : 참여자들이 함께 소유하는 탈중앙화 웹 생태계(미래)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 2.0에서의 문제제기 : &lt;br /&gt;&amp;nbsp; &amp;nbsp; 유저의 참여로 생성된 컨텐츠로 기업이 왜 이득을 보는가, 내가 생성한 컨텐츠의 소유권은 나에게 있다!&lt;/li&gt;
&lt;li&gt;블록체인 기반&lt;/li&gt;
&lt;li&gt;읽기 + 쓰기 + 소유(나의 참여 결과로 생산된 결과물을 유저가 소유한다.)&lt;/li&gt;
&lt;li&gt;마이 데이터 : 개인 맞춤형 데이터&lt;/li&gt;
&lt;li&gt;Web 3.0의 목표
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 분산시켜 해킹으로 자유롭게한다.&lt;/li&gt;
&lt;li&gt;데이터 소유권을 플랫폼 기업이 아닌 개인에게 준다.&lt;/li&gt;
&lt;li&gt;참여자들에게 더 많은 혜택과 권한을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;어떤 느낌일지 유추해볼만한 서비스 예시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;P2E 게임
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게임 참여로 코인을 벌거나, 나의 게임 아이템을 수익화 가능&lt;/li&gt;
&lt;li&gt;ex. AXIE, MIR4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;블록체인 기반의 메타버스 플랫폼
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아이템을 모두 참여자가 만들고, 거래 가능하게 함&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ex. Decentraland, The SANDBOX&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DeFi
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;탈중앙 금융서비스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex1. 내가 암호 화폐를 넣어두면, 누군가 저장된 암호 화폐를 대출해갔을 때, 이자가 나에게 돌아온다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ex2. 내가 두 코인을 넣어두면, 누군가 코인 간의 환전을 할 때, 나에게 수수료가 돌아온다.&lt;/li&gt;
&lt;li&gt;특징&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 업무는 기업이 아닌, 블록체인 시스템이 수행한다.&lt;/li&gt;
&lt;li&gt;거래 이력이 분산 저장되므로, 수억원이 오고가더라도 시스템을 믿고 진행&lt;/li&gt;
&lt;li&gt;책임은 개인이 진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NFT(Non Fungible Token)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디지털 자산의 소유권, 거래 이력을 블록체인에 저장&lt;/li&gt;
&lt;li&gt;디지털 자산을 사고팔 수 있는 기술&lt;/li&gt;
&lt;li&gt;Web 3.0에서 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Coin
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 3.0은 탈중앙화로 거래가 관리되므로, 거래 내역을 계산해주는 것에 대한 보상&lt;/li&gt;
&lt;li&gt;플랫폼마다 사용되는 화폐의 역할&lt;/li&gt;
&lt;li&gt;플랫폼 참여에 대한 금전적 보상 역할
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좋아요 많으면 코인으로 보상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web 3.0에서 주식과 유사한 역할
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플랫폼의 인기에 코인의 가치가 영향을 받는다.&lt;/li&gt;
&lt;li&gt;문제 : 가치가 일정하지 않은 주식과 같은 코인을 화폐로 써도 될까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Stable Coin : 가치가 고정된 코인
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex. 1 달러 = 1 코인&lt;/li&gt;
&lt;li&gt;META 사에서 Diem 이라는 스테이블 코인을 준비 중&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코인이 플랫폼에 참여하고 있다는 증명이 되며, 나아가 플랫폼의 의사결정에 참여할 수 있는 참정권 역할 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DAO(Decentralized Autonomous Organization)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;탈중앙화된 자율화 조직&lt;/li&gt;
&lt;li&gt;코인 가진 사람들이 모든 이슈를 함께 결정(투표 등)한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ethereum System
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 3.0이 돌아가기 위한 대표적인 시스템(생태계)&lt;/li&gt;
&lt;li&gt;스마트 계약 기능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이더리움 시스템 위에 여러 앱이나 서비스를 런칭 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web 3.0의 극복 과제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템이 간편해질 수 있을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex. 카카오 in 암호화폐 지갑 Kilp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;느린 처리 속도와 비싼 수수료&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex. 이더리움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;각 플랫폼별 코인을 계속 환전해야하는 번거로움 + 환전 시 수수료 발생&lt;/li&gt;
&lt;li&gt;코인, NFT, 가상 부동산의 큰 가치 변동성&lt;/li&gt;
&lt;li&gt;상호 운용성 실현의 어려움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 플랫폼마다 가격과 가치의 차이 조정&lt;/li&gt;
&lt;li&gt;동일 플랫폼 내의 서비스간 가치 조정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;책임을 지는 주 기관의 부재와 개인 책임 증가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코인 지갑 비번 잃어버리면, 찾거나 보상받을 수 없다.&lt;/li&gt;
&lt;li&gt;코인을 잘못 송금했을 때 찾을 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web 3.0이 성공할 수 있을까?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일론 머스크 : Web 3.0은 현실 보단, 마케팅 용어 같고 이해할 수 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;블록체인 생태계는 기대감과 상상력에 의존하여 시장이 커지는 특징&lt;br /&gt;-&amp;gt; 참여하는 사람들이 많아져야 성공 / 줄어들면 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트위터 창업가 jack&amp;nbsp; : 당신은 Web 3.0을 소유할 수 없다. Web 3.0은 다른 이름으로 포장된 중앙화의 실체이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Web 3.0이 정말 개인들에게 혜택을 줄까? 의문&lt;/li&gt;
&lt;li&gt;소수 자본가의 영향력이 크다면, 진정한 탈중앙화가 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사람들이 Web 3.0에 관심을 갖는 이유?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FOMO(Fear of missing out) : 자신이 큰 돈을 벌 수 있는 기회를 놓칠까봐!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 요즘 웹 3.0이라는 것이 사람들 사이에서 많은 언급이 되고 있는데, 그 실체가 대체 무엇인지 도무지 알기 어려웠다. 이번 영상은 웹 3.0이라는 것이 어떤 것인지 기초를 알 수 있게 해주는 영상이다. Web 3.0이 가진 비전에 대해서는 매우 깊은 공감이 간다. 웹 2.0에서 플랫폼의 이익이 되었던 유저의 참가에 대한 이익은 대부분 플랫폼을 운영하는 회사가 가져갔기 때문이다. 그러나, 코인 활용의 번거로움과 개인의 책임이 커지는 것은 굉장한 스트레스다. 나도 최근 암호화폐를 선물받아서 이를 저장할 암호화폐 지갑을 만들었는데, 이 기회에 암호 화폐에 관심갖고 더 사볼까 생각이 들면서도, 비밀번호를 잊어버릴까 굉장히 불안하여, 결국 추가 구입을 하지 않은 경험이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 추가로 이&amp;nbsp;&lt;a title=&quot;영상&quot; href=&quot;https://www.youtube.com/watch?v=h9T0zBV7MMs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;영상&lt;/a&gt; 을 보았는데, 웹 3.0의 (아마도)찬성입장의 의견을 들어볼 수 있었다. 찬성 측에서도 웹 3.0의 번거로움에 대해 부정하지 않는다. 심지어 모든 것은 레거시 솔루션으로 가능하다는 말을 하며 웹 3.0이 완전 새로운 무언가가 아니라, 사실 기존의 솔루션으로 대체가능한 것처럼 말하기도 한다. 그러나, 탈중앙화라는 가치를 이루기 위해 사회적 비용을 치뤄 웹 3.0이 이루어져야한다는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 현재도 민주주의, 토의와 투표를 통해 의사결정이 결정되는 것처럼 보인다. 그러나 기업이든 나라든 어느정도 중앙집권화되어있는 구조이기 때문에 완전한 탈중앙화는 불가능하다는 것이다. 하다못해 임금협상을 할 때도, 진정으로 노사간 협의에 의해 임금협상이 이루어지는 기업이 우리나라에 많지 않으며, 회사는 직원에게 지속적으로 주인의식을 강조한다. 그러나, 내가 일한만큼 커뮤니티의 토큰의 가치가 상승한다면 진정한 주인의식도 생기고, 내가 이룬만큼의 성과를 얻을 수 있다. 이러한 구조가 기술, 사회문화적으로 가능해진다면, 웹 3.0이 대세가 되는 것은 시간 문제가 아닐까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 내 의견은... 글쎄 솔직히 아직까지도 잘 모르겠다. 웹 3.0의 비전은 이해하지만, 웹 3.0이라는 것은 결국 많은 사람들이 참여를 해야 힘을 얻을 수 있는 구조인데, 이상만으로 사람들을 끌어 모을 수 있을까? 모두가 환경을 보호해야한다는 생각은 하지만, 모든 사람이 환경보호를 위해 의식적인 환경보호 실천을 하진 아닌 것처럼, 이상을 위해 대다수의 사람들이 불편함을 감수할 수 있을까? 물론, 참여에 대한 보상을 받는다는 장점이 있지만 글쎄...? 참여라는 것이 항상 정량적으로 측정되어 평등한 보상을 줄 수 있는 것일까? 회의를 할 때, 발언을 많이하는 특정 몇 몇의 의견으로 쏠리는 것처럼, 웹 3.0이 정말 진정한 탈중앙화일까? 이것을 웹 3.0을 아예 모르는 사람에게도 설득할 수 있는가? 특정 국가나 집단에 의해 좌지우지되지 않는 화폐를 만들겠다던 비트코인이 현재 투기, 돈 세탁의 상징(?!)이 된 것처럼 웹 3.0은 이러한 부작용을 막을 수 있을까? 이제 막 암호화폐를 알게되서 그런지 아직 의문점이 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 웹 3.0의 시대가 진짜 올 것인지, 웹 3.0이 더 나은 사회를 만들어낼 수 있을지 많은 의문이 있지만, 굉장히 매력적이고 흥미로운 아이디어인 것은 틀림없는 것 같다. 이런 머리아픈 것을 내가 얻을 수 있는 금전적 이익에 초점을 맞추기 보다는 웹 3.0의 시대가 왔을 때 내가 얻을 수 있는 이익에 집중하기 보단, FE 개발자인 내가 알아야할 것, 할 수 있는 것은 무엇일지 생각하는 것이 좀 더 나을 것 같다. 웹 3.0 너무 어렵다...ㅠㅠ 앞으로는 웹 3.0과 개발자를 연결시킬 수 있는 그런 컨텐츠들이 많이 나왔으면 좋겠다.&lt;/p&gt;</description>
      <category>감상문</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/224</guid>
      <comments>https://study-ihl.tistory.com/224#entry224comment</comments>
      <pubDate>Sat, 22 Jan 2022 01:06:43 +0900</pubDate>
    </item>
    <item>
      <title>List Virtualization(Windowing)</title>
      <link>https://study-ihl.tistory.com/223</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0p4W1/btrrhGgFRDz/aKfhKldl07pPDXFMjoKuf0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0p4W1/btrrhGgFRDz/aKfhKldl07pPDXFMjoKuf0/img.jpg&quot; data-alt=&quot;A list with a lot of data&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0p4W1/btrrhGgFRDz/aKfhKldl07pPDXFMjoKuf0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0p4W1%2FbtrrhGgFRDz%2FaKfhKldl07pPDXFMjoKuf0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;480&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;A list with a lot of data&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 일반적으로 적은 양의 데이터는 모든 데이터를 화면에 렌더링 하는데 큰 리스크가 없지만, 너무 많은 양의 데이터가 있는 경우 데이터 전체를 렌더링 하기 위해 많은 시간이 걸려 사용자 경험을 해치는 상황이 발생한다. 이러한 상황을 극복하기 위한 대표적인 방법이 페이지네이션(Pagenation), 무한 스크롤(Infinity Scroll)과 가상화 목록(Virtualized List)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 가상화 목록은 전체 데이터를 모두 렌더링하는 대신, 유저 스크롤에 따라 현재 보이는 데이터만을 렌더링 하는 방법이다. 사용자가 볼 때 무한 스크롤과 유사할 수 있으나, 무한 스크롤은 스크롤이 발생할수록 화면에 렌더링 되는 항목도 많아지기 때문에 속도가 느려질 수 있으나, 가상화 목록은 현재 보이지 않는 항목은 unload 하므로 이러한 문제가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 가상화 목록 만들기&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm7qwH/btrrfJdJ8T7/kjF2duNlUbATQOm20qkSk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm7qwH/btrrfJdJ8T7/kjF2duNlUbATQOm20qkSk0/img.png&quot; data-alt=&quot;Scroll&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm7qwH/btrrfJdJ8T7/kjF2duNlUbATQOm20qkSk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm7qwH%2FbtrrfJdJ8T7%2FkjF2duNlUbATQOm20qkSk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;448&quot; height=&quot;293&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Scroll&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Inner Height&lt;/b&gt; : 목록 전체의 높이&lt;br /&gt;&amp;nbsp; = 각 항목의 높이 x 총 데이터 갯수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Window Height&lt;/b&gt; : 현재 보이는 영역 높이&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ScrollTop&lt;/b&gt; : 위부터 스크롤된 수직 거리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 가상화 목록의 구조는 위 그림과 같다. 위 그림에는 3가지 요소가 있는데, Inner Height, Window Height, SrollTop이다. 스크롤의 위치가 바뀔 때마다 3가지 요소 및 파생 값을 재계산하여 화면에 보여야 할 항목들을 추출하여 리스트를 재 렌더링 한다. &lt;a href=&quot;https://codesandbox.io/s/virtual-list-z9i8d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;코드&lt;/a&gt;로 함께 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-1. Outer Component&lt;/h3&gt;
&lt;pre id=&quot;code_1642657585708&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { VirtualizedList as List } from &quot;./VirtualListClass&quot;;
import &quot;./styles.css&quot;;

const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

export default class App extends React.Component {
  render() {
    return (
      &amp;lt;List
        numItems={10}
        windowHeight={120}
        itemHeight={40}
        renderItem={({ index, style }) =&amp;gt; {
          return (
            &amp;lt;div key={index} className=&quot;item&quot; style={style}&amp;gt;
              Hello {index} / {data[index]}
            &amp;lt;/div&amp;gt;
          );
        }}
      /&amp;gt;
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;numItems&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: List가 표현할 데이터의 총 개수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;windowHeight&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 리스트의 크기&lt;br /&gt;&amp;nbsp;= 화면에 보이는 영역의 크기&lt;br /&gt;&amp;nbsp;= itemHeight가 40, windowHeight가 120이므로, 위 리스트는 한 번에 3개의 항목이 보인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;itemHeight&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 각 항목의 Height&lt;/li&gt;
&lt;li&gt;&lt;b&gt;renderItem&lt;/b&gt; : 각 항목의 렌더링 로직 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; App 컴포넌트는 List Component(가상화 목록 구현 컴포넌트)의 상위 컴포넌트이다. 주목할만한 점은 &lt;a href=&quot;https://study-ihl.tistory.com/222&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;render props 패턴&lt;/a&gt;으로 App에서 List가 렌더링 해야 하는 데이터의 렌더링 로직을 구현하여 renderItem이라는 props로 넘겨준다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642659055936&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.scroll {
  width: 150px;
  height: 120px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; style.css는 위와 같은 내용이 담겨있다.. scroll은 가상 목록에서 스크롤이 포함되어있는 div를 의미하는 것으로 App에서 List 컴포넌트의 windowHeight prop을 120으로 넘겨주었기 때문에 css에서도 List 컴포넌트의 Height가 120이 되도록 설정해준 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1-2. List&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c12T9i/btrrh4IKAFP/Fur1A3qYg1o0krRK6iggnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c12T9i/btrrh4IKAFP/Fur1A3qYg1o0krRK6iggnk/img.png&quot; data-alt=&quot;Data of List Component&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c12T9i/btrrh4IKAFP/Fur1A3qYg1o0krRK6iggnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc12T9i%2Fbtrrh4IKAFP%2FFur1A3qYg1o0krRK6iggnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;291&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Data of List Component&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; List는 위와 같은 형태의 데이터들이 상호작용하는 구조로 되어있다. 코드를 보며 이들이 어떤 상호작용을 하는지 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642659567882&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class VirtualizedList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      scrollTop: 0
    };
  }

  onScroll = (e) =&amp;gt; {
    this.setState({ scrollTop: e.currentTarget.scrollTop });
  };

  render() {
    const { numItems, itemHeight, renderItem, windowHeight } = this.props;
    const scrollTop = this.state.scrollTop;

    // List Elements의 총 Height
    const innerHeight = numItems * itemHeight;
    // 현재 화면에 보여지는 List의 부분에서 가장 상위의 항목의 index
    const startIndex = Math.floor(scrollTop / itemHeight);
    // 현재 화면 바로 바깥에 있는 항목의 index
    // 가장 마지막 요소이거나, (스크롤한 부분 + 리스트에 한 번에 보여지는 부분) / 각 항목 Height
    const endIndex = Math.min(
      numItems - 1,
      Math.floor((scrollTop + windowHeight) / itemHeight)
    );

    // 렌더링할 새로운 items 배열을 만든다.
    const items = [];
    for (let i = startIndex; i &amp;lt;= endIndex; i++) {
      items.push(
        renderItem({
          index: i,
          style: {
            position: &quot;absolute&quot;,
            top: `${i * itemHeight}px`,
            width: &quot;100%&quot;
          }
        })
      );
    }

    return (
      &amp;lt;div
        className=&quot;scroll&quot;
        style={{ overflowY: &quot;scroll&quot; }}
        onScroll={this.onScroll}
      &amp;gt;
        &amp;lt;div
          className=&quot;inner&quot;
          style={{ position: &quot;relative&quot;, height: `${innerHeight}px` }}
        &amp;gt;
          {items}
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;innerHeight &lt;/b&gt;: 목록 전체의 높이. 전달된 props를 사용하여 결정되며, 스크롤이 변경돼도 변하지 않는 데이터이다.&lt;br /&gt;&amp;nbsp; = 각 항목의 높이 x 총 데이터 개수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;scrollTop&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 위부터 스크롤된 수직 거리를 의미하는 상태.&amp;nbsp; 스크롤 이벤트(onScroll)가 발생할 때마다 값이 변경된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;startIndex&lt;/b&gt; : 현재 화면에 보여야 하는 List의 항목 중 가장 상단 항목의 인덱스&lt;br /&gt;ex. itemHeight = 40, scrollTop = 80&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 스크롤이 80만큼 내려가면서, 리스트의 상단부가 80만큼 화면 바깥(상단)으로 나가게 된다.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 리스트의 각 항목의 높이는 40이므로, 총 2개의 아이템이 화면 밖으로 이동하였으므로, &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 현재 화면에 보이는 항목 중 가장 첫 번째 항목의 인덱스는 2 (80 / 2)이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;endIndex&lt;/b&gt; : 현재 화면 바로 바깥(하단)에 있는 항목의 인덱스&lt;br /&gt;&amp;nbsp; 가상 목록은 기본적으로 화면에 보이는 3가지만 렌더링 하도록 작성해야 하지만, 위 구현에서는 스크롤을 내릴 때 더 자연스럽게 보이기 위해 1개 항목을 추가로 렌더링(overscan)하여, 한 번에 총 4개 항목이 렌더링 된다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; List 컴포넌트는 전달받은 props와 스크롤 이벤트를 통해 startIndex, endIndex와 같은 값들을 계산하여, 현재 보여야 할 리스트 항목만으로 구성된 배열을 새롭게 작성한다. 그 후, 작성한 배열만을 렌더링 하여 업데이트하는 방식으로 현재 보여야 하는 항목들만을 렌더링 하고, 가려진 항목들은 unload 하는 것이다. 따라서 스크롤 이벤트가 얼마나 발생하던지 화면에는 항상 4개의 항목만이 그려져 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 코드의 또 다른 특징은 내부 목록은 position:relative와 계산된 innerHeight, 리스트의 각 항목은 position : absolute를 이용하여 렌더링 한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;virtuallist.gif&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxzxaH/btrrcItNqyf/L7gHYrJdDTS0moSKa88cC1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxzxaH/btrrcItNqyf/L7gHYrJdDTS0moSKa88cC1/img.gif&quot; data-alt=&quot;가상화 목록.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxzxaH/btrrcItNqyf/L7gHYrJdDTS0moSKa88cC1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bxzxaH/btrrcItNqyf/L7gHYrJdDTS0moSKa88cC1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;242&quot; data-filename=&quot;virtuallist.gif&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;가상화 목록.gif&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 가상화 목록 만들기 : &lt;a href=&quot;https://medium.com/ingeniouslysimple/building-a-virtualized-list-from-scratch-9225e8bec120&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/ingeniouslysimple/building-a-virtualized-list-from-scratch-9225e8bec120&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span&gt;가상화 목록 개발하며 배운 것 : &lt;a href=&quot;https://dev.to/nishanbajracharya/what-i-learned-from-building-my-own-virtualized-list-library-for-react-45ik&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev.to/nishanbajracharya/what-i-learned-from-building-my-own-virtualized-list-library-for-react-45ik&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web/[JS] FrontEnd</category>
      <author>ihl</author>
      <guid isPermaLink="true">https://study-ihl.tistory.com/223</guid>
      <comments>https://study-ihl.tistory.com/223#entry223comment</comments>
      <pubDate>Thu, 20 Jan 2022 21:11:43 +0900</pubDate>
    </item>
  </channel>
</rss>