<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Yeon&amp;rsquo;s Dev Log</title>
    <link>https://yeon-code.tistory.com/</link>
    <description>라인플러스에 재직중이며, 웹 프론트엔드 개발을 하고있습니다.</description>
    <language>ko</language>
    <pubDate>Thu, 13 Aug 2026 19:02:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Dev.yeon</managingEditor>
    <image>
      <title>Yeon&amp;rsquo;s Dev Log</title>
      <url>https://tistory1.daumcdn.net/tistory/4204825/attach/9368fc86e7514214851a88857ec9a5f3</url>
      <link>https://yeon-code.tistory.com</link>
    </image>
    <item>
      <title>리액트에서 컴포넌트를 작성하는 기준 (Feat. SOLID원칙)</title>
      <link>https://yeon-code.tistory.com/108</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;842&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcQeF6/btsDW4wL1XO/zv5mSL2yfYCtWBdHEcjlU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcQeF6/btsDW4wL1XO/zv5mSL2yfYCtWBdHEcjlU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcQeF6/btsDW4wL1XO/zv5mSL2yfYCtWBdHEcjlU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcQeF6%2FbtsDW4wL1XO%2Fzv5mSL2yfYCtWBdHEcjlU1%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;1191&quot; height=&quot;842&quot; data-origin-width=&quot;1191&quot; data-origin-height=&quot;842&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;리액트를 개발할때 컴포넌트를 어떤 기준으로 작성하시나요? SOLID원칙을 통해 어떻게 컴포넌트를 작성할지에 대해서 살펴보도록하겠습니다. 본격적으로 시작하기전에 리액트 가이드문서에서 계층을 분리하는 과정을 먼저 보고가겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;리액트 계층분리과정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;a href=&quot;https://react.dev/learn/thinking-in-react&quot;&gt;https://react.dev/learn/thinking-in-react&lt;/a&gt; 글을 요약하였습니다. 실제예시가 본문에 잘나와있으므로 참고하시기바랍니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. UI를 컴포넌트 계층으로 쪼개기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트를 하위 컴포넌트들로 쪼개야하는데 나누는 관점에는 차이가 있을수있습니다. 이미 디자인팀에서 정해놓은 계층이 있다면 그것을 기준으로 분리해도되고, 개발관점에서는 SRP원칙에따라 분리를 할수도있습니다. JSON이 잘구조화되어있다면, 응답값을 기준으로 컴포넌트 구조를 분리해볼수도있습니다. UI와 데이터는 같은 구조를 가지기때문입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 정적인 버전 구현하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 계층구조를 만들었다면, 실제로 리액트에서 개발을 해야합니다. 처음에는 상호작용기능은 추가하지않되, UI를 렌더링하는 버전을 먼저 만드는게 좋습니다. 재사용성을 고려해서 개발하게된다면 props를 이용하여 데이터를 넘겨주는 컴포넌트를 구현하게될것입니다. 이때 정적인 버전이기때문에 state는 고려하지않는것이 좋습니다. state는 시간이 지남에따라 데이터가 바뀌는것에 사용하기때문입니다.&lt;span&gt;&amp;nbsp; &lt;/span&gt;계층구조에따라 상층부에 있는 컴포넌트부터 하양식(top-down)으로 만들거나, 하층부에있는 컴포넌트부터 상향식(bottom-up)으로 만들수있지만 프로젝트가 클수록 탑다운방식이 더 좋습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 최소한의 데이터만 이용해서 완벽하게 UI State 표현하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI를 상호작용하기위헤서는 이제 state를 활용해야합니다. state를 구조화하는데 가장 중요한원칙은 DRY(Don't Repeat Yourself) 입니다. 가장 최소한의 state만을 가지게하고, 나머지는 필요에따라 실시간으로 계산하는게 좋습니다. 시간이 지나면서 변하지않거나, 부모로부터 props를 통해 전달되거나, 컴포넌트안의 다른 값을 이용해서 계산이 가능하다면 state가 아닙니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. state가 어디에있어야하는지 정하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state를 구조화했다면 어떤 컴포넌트가 이 state를 소유하고 변경할 책임을 지게할지 정해야합니다. 리액트애서는 항상 컴포넌트 게층을 따라 부모에서 자식으로 데이터를 전달하는 단방향 데이터 흐름을 사용한다는것을 기억하면 조금더 쉽게 정할수있습니다. state를 기반으로 렌더링하는 모든 컴포넌트를 찾은다음, 가장 가까운 공통되는 부모컴포넌트에 state를 두면됩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 역데이터 흐름 추가하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층구조 아래로 흐르는 props와 state를 구성했다면, 반대로 사용자의 입력을 상위로 전달하는 역데이터흐름을 추가해야합니다. 이때에는 이벤트핸들러를 추가하여 state를 변경하도록 구현합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&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;span&gt;아마도 실제 프로젝트를 진행하실때도&amp;nbsp;&lt;/span&gt;리액트에서&lt;span&gt; &lt;/span&gt;소개하고있는&lt;span&gt; &lt;/span&gt;계층분리과정순으로&lt;span&gt; &lt;/span&gt;개발을&lt;span&gt; &lt;/span&gt;많이&lt;span&gt; &lt;/span&gt;하실것이라고&lt;span&gt; &lt;/span&gt;생각됩니다&lt;span&gt;. 1, 2&lt;/span&gt;번에서&lt;span&gt; &lt;/span&gt;소개하고있는&lt;span&gt; &lt;/span&gt;컴포넌트를&lt;span&gt; &lt;/span&gt;쪼개고&lt;span&gt; &lt;/span&gt;실제&lt;span&gt; &lt;/span&gt;구현을&lt;span&gt; &lt;/span&gt;할때&lt;span&gt; &lt;/span&gt;컴포넌트&lt;span&gt; &lt;/span&gt;어떻게&lt;span&gt; &lt;/span&gt;구분할지에&lt;span&gt; &lt;/span&gt;대한&lt;span&gt; &lt;/span&gt;기준이&lt;span&gt; &lt;/span&gt;없다면&lt;span&gt; &lt;/span&gt;개발할때&lt;span&gt; &lt;/span&gt;상당히&lt;span&gt; &lt;/span&gt;난처할수있습니다&lt;span&gt;. &lt;/span&gt;개발을&lt;span&gt; &lt;/span&gt;진행하면서도&lt;span&gt; &lt;/span&gt;이&lt;span&gt; &lt;/span&gt;컴포넌트를&lt;span&gt; &lt;/span&gt;분리할지&lt;span&gt; &lt;/span&gt;합쳐서&lt;span&gt; &lt;/span&gt;작성할지에대해&lt;span&gt; &lt;/span&gt;고민하게되고&lt;span&gt;, &lt;/span&gt;그러다보면&lt;span&gt; &lt;/span&gt;프로젝트구조가&lt;span&gt; &lt;/span&gt;통일성없이&lt;span&gt; &lt;/span&gt;설계될수있습니다&lt;span&gt;. &lt;/span&gt;또한&lt;span&gt; &lt;/span&gt;개발후에&lt;span&gt; &lt;/span&gt;변경건이&lt;span&gt; &lt;/span&gt;발생하게되거나&lt;span&gt;, &lt;/span&gt;확장하게될경우&lt;span&gt; &lt;/span&gt;공수가&lt;span&gt; &lt;/span&gt;크게들수도있습니다&lt;span&gt;. &lt;/span&gt;따라서&lt;span&gt; &lt;/span&gt;실제&lt;span&gt; &lt;/span&gt;개발전에&lt;span&gt; &lt;/span&gt;팀원들과&lt;span&gt; &lt;/span&gt;컴포넌트를&lt;span&gt; &lt;/span&gt;나누는&lt;span&gt; &lt;/span&gt;기준을&lt;span&gt; &lt;/span&gt;정하고간다면&lt;span&gt;, &lt;/span&gt;리뷰할때나&lt;span&gt; &lt;/span&gt;유지보수할때에&lt;span&gt; &lt;/span&gt;편리할것입니다&lt;span&gt;.&lt;/span&gt;&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;&lt;span&gt;SOLID 원칙 &lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;SOLID원칙은&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt; 아키텍처 설계부터 코딩과 리뷰까지 사용되는 원칙입니다. 이 원칙을 하나하나 살펴보며, 리액트에서 컴포넌트를 작성할때 어떻게 작성하면 좋을까?에 대해서 탐구해보도록하겠습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;a href=&quot;https://fe-developers.kakaoent.com/2023/230330-frontend-solid/&quot;&gt;https://fe-developers.kakaoent.com/2023/230330-frontend-solid/&lt;/a&gt; 글을 참고하였습니다. 보다 자세하게 알고싶은분들은  원글을 꼭 읽어보시기바랍니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;SRP&lt;/b&gt;: Single Responsibility Principle&lt;br /&gt;&lt;b&gt;OCP&lt;/b&gt;: Open/Closed Principle&lt;br /&gt;&lt;b&gt;LSP&lt;/b&gt;: Liskov Substitution Principle&lt;br /&gt;&lt;b&gt;ISP&lt;/b&gt;: Interface Segregation Principle&lt;br /&gt;&lt;b&gt;DIP&lt;/b&gt;: Dependency Inversion Principle&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. SRP(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Single Responsibility Principle&lt;span style=&quot;color: #000000;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNmdAE/btsDZ3wPXCw/tXHsLFc7a2gL6vkCQXO5Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNmdAE/btsDZ3wPXCw/tXHsLFc7a2gL6vkCQXO5Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNmdAE/btsDZ3wPXCw/tXHsLFc7a2gL6vkCQXO5Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNmdAE%2FbtsDZ3wPXCw%2FtXHsLFc7a2gL6vkCQXO5Ak%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;554&quot; height=&quot;354&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SRP를 먼저논하기전에 콘웨이법칙을 알고가면좋습니다.&lt;b&gt; 콘웨이법칙&lt;/b&gt;은 &lt;i&gt;소프트웨어구조는 해당 소프트웨어를 개발한 조직의 커뮤니케이션 구조를 닮게된다 &lt;/i&gt;라는 법칙입니다. 즉 이말은 소프트웨어구조가 조직의 커뮤니케이션 구조와 다르다면 잘못된 구조이다 라는뜻을 내포하고있습니다. 코드를 변경해야하는 요구사항도 조직에서 비롯되기때문에, 이상적인 컴포넌트 구조는 변경된 요구사항이 전달되었을때 최대한 side-effect없이 원하는 부분만 변경할수있는 구조가 좋습니다. 응집도는 높고, 결합도는 낮은 구조로 구성해야한다는 뜻입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SRP를 직역하면 단일책임원칙입니다. 하지만 개발관점에서 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&quot;책임&quot;을 &quot;동작&quot;으로 해석하게되면&lt;/span&gt;&lt;/b&gt; 컴포넌트를 과하게 쪼갤수있습니다. 이렇게되면 전체로직을 한눈에 파악하기어렵고 코드 네이게이션에 들어가는 공수를 늘어나게 만듭니다. 관점을 다르게하여 R을 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;책임이 아닌 책무라고 이해&lt;/span&gt;&lt;/b&gt;해보면, R은 소프트웨어 내부의 동작이나 논리가 아니라 조직간 커뮤니케이션 영역으로 볼수있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 책무기반 컴포넌트 설계라고 볼수있습니다. 프로젝트별로 기획이나 디자인부서가 있을것이고, 요구사항이 있을것입니다. 컴포넌트 설계를 '요구사항을 전달하는 책무단위'로 진행하게되면, 변경에도 사이드이펙트없이 대처가 가능하며 커뮤니케이션 비용이 줄어들게됩니다. 실제업무에 대입해서 생각해본다면 다음과같이 원칙을 세울수있을것입니다.&lt;span&gt;&amp;nbsp;&lt;/span&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;별도의 변환없이 그대로&lt;/b&gt; 사용한다.&lt;/li&gt;
&lt;li&gt;디자인시스템이 구축되어있다면 &lt;b&gt;아토믹 디자인&lt;/b&gt;을 차용하여 그대로 사용한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;https://fe-developers.kakaoent.com/2022/220505-how-page-part-use-atomic-design-system/&quot;&gt;https://fe-developers.kakaoent.com/2022/220505-how-page-part-use-atomic-design-system/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;아토믹디자인: 컴포넌트를 atom, molecule, organism, template, page의 5가지 레벨로 나누어 생각하는 디자인시스템 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;아토믹디자인에서의 SRP를 생각해본다면, molecule단계를 잘 설계해야합니다. molecule은 쪼갤수없는 atom으로 구성되어 SRP에 따라 한가지의 책무를 지는것입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;molecule과 organism을 구분은, 작성한 컴포넌트에 컨텍스트가 있을경우에는 Organism으로, 컨텍스트없이 UI적인 요소라면 molecule로 한다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;범용적인 컴포넌트를 구성할때는 &lt;b&gt;특정 도메인과의 결합도를 낮추고&lt;/b&gt; 재사용성을 높이는것이 중요하며, 너무나 많은 역할을 수행하지 않도록 주의한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;https://fe-developers.kakaoent.com/2022/221020-component-abstraction/&quot;&gt;https://fe-developers.kakaoent.com/2022/221020-component-abstraction/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;범용적인 컴포넌트에서 특정도메인과 높은 의존성은 변경에 취약한 코드를 낳게되기때문에, 공통의 기능을 수행하게끔 구성해야한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;도메인과의 의존성과 별개로 컴포넌트자체가 수행하는 책임이 크다면 합성을 잘 이용해야한다. 하나의 컴포넌트가 가진 책임을 잘게 나누어 유연하게 대응할수있도록 한다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서&lt;span&gt; &lt;/span&gt;다음과같은&lt;span&gt; &lt;/span&gt;원칙을&lt;span&gt; &lt;/span&gt;정해놓고&lt;span&gt; &lt;/span&gt;개발을&lt;span&gt; &lt;/span&gt;하게된다면&lt;span&gt; &lt;/span&gt;굉장히&lt;span&gt; &lt;/span&gt;용이할것입니다&lt;span&gt;. &lt;/span&gt;정리하자면&lt;span&gt;, &lt;/span&gt;컴포넌트에는&lt;span&gt; SRP&lt;/span&gt;에&lt;span&gt; &lt;/span&gt;따라&lt;span&gt; &lt;/span&gt;단일책임을&lt;span&gt; &lt;/span&gt;부여하고&lt;span&gt;, &lt;/span&gt;특정도메인과의&lt;span&gt; &lt;/span&gt;결합도는&lt;span&gt; &lt;/span&gt;낮추자라고&lt;span&gt; &lt;/span&gt;볼수있습니다&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.&amp;nbsp; OCP(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Open/Closed Principle&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left;&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2723&quot; data-origin-height=&quot;1590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZbb0B/btsD0Fifotb/kgFwCJFsHdcEyG9mT5XGZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZbb0B/btsD0Fifotb/kgFwCJFsHdcEyG9mT5XGZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZbb0B/btsD0Fifotb/kgFwCJFsHdcEyG9mT5XGZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZbb0B%2FbtsD0Fifotb%2FkgFwCJFsHdcEyG9mT5XGZk%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;2723&quot; height=&quot;1590&quot; data-origin-width=&quot;2723&quot; data-origin-height=&quot;1590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;OCP&lt;/span&gt;는&lt;span&gt; &lt;/span&gt;요구사항이&lt;span&gt; &lt;/span&gt;변경될때&lt;span&gt; &lt;/span&gt;기존코드를&lt;span&gt; &lt;/span&gt;변경하는것이아니라&lt;span&gt; &lt;/span&gt;새롭게&lt;span&gt; &lt;/span&gt;코드를&lt;span&gt; &lt;/span&gt;추가하는&lt;span&gt; &lt;/span&gt;원칙입니다&lt;span&gt;. &lt;/span&gt;개방폐쇄원칙은&lt;span&gt; &lt;/span&gt;&lt;b&gt;객체는&lt;span&gt; &lt;/span&gt;확장에&lt;span&gt; &lt;/span&gt;개방되어있고&lt;span&gt;, &lt;/span&gt;변경에는&lt;span&gt; &lt;/span&gt;폐쇄되어있어야한다&lt;/b&gt;는&lt;span&gt; &lt;/span&gt;뜻을&lt;span&gt; &lt;/span&gt;내포합니다&lt;span&gt;. &lt;/span&gt;기획은&lt;span&gt; &lt;/span&gt;계속해서&lt;span&gt; &lt;/span&gt;변경되고&lt;span&gt;, &lt;/span&gt;새로운&lt;span&gt; &lt;/span&gt;스펙들이&lt;span&gt; &lt;/span&gt;추가되는&lt;span&gt; &lt;/span&gt;상황에서&lt;span&gt; &lt;/span&gt;닫혀있는&lt;span&gt; &lt;/span&gt;구조를&lt;span&gt; &lt;/span&gt;사용한다면&lt;span&gt; &lt;/span&gt;코드구조가&lt;span&gt; &lt;/span&gt;많이&lt;span&gt; &lt;/span&gt;변경되게됩니다&lt;span&gt;. &lt;a href=&quot;https://www.octobot.io/blog/solid-principles-react/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.octobot.io/blog/solid-principles-react/&lt;/a&gt;&amp;nbsp;에 작성된 코드예시를 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706178728649&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const RecipeCard = ({id, name, ingredients, type, onClick}) =&amp;gt; {
   return (
       &amp;lt;Card&amp;gt;
           &amp;lt;CardHeader&amp;gt;
               &amp;lt;CardTitle&amp;gt;{name}&amp;lt;/CardTitle&amp;gt;
           &amp;lt;/CardHeader&amp;gt;
           &amp;lt;CardBody&amp;gt;
               &amp;lt;p&amp;gt;Id: {id}&amp;lt;/p&amp;gt;
               &amp;lt;IngredientsFields&amp;gt;
                   {ingredients.map((ingredient) =&amp;gt; {
                       &amp;lt;Ingredient&amp;gt;{ingredient}&amp;lt;/Ingredient&amp;gt;
                   })}
               &amp;lt;/IngredientsFields&amp;gt;
               {type === 'byAuthor' &amp;amp;&amp;amp;
                   &amp;lt;button onClick={onClick}&amp;gt;Go to site&amp;lt;/button&amp;gt;
               }
               {type === 'byUs' &amp;amp;&amp;amp;
                   &amp;lt;button onClick={onClick}&amp;gt;Go to cook steps&amp;lt;/button&amp;gt;
               }
           &amp;lt;/CardBody&amp;gt;
       &amp;lt;/Card&amp;gt;
   )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecipeCard 컴포넌트는 type에 따라 다른 버튼을 렌더링합니다. 새로운 type을 추가하려면 컴포넌트를 수동으로 수정해야하므로 변경이 일어날수밖에 없습니다. 기존코드를 변경해야하기때문에 앞서 언급한 원칙에 위배됩니다. 따라서 다음과 같이 코드를 작성하는것이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706180777077&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// parent
const RecipeCard = ({id, name, ingredients}) =&amp;gt; {
   return (
       &amp;lt;Card&amp;gt;
           &amp;lt;CardHeader&amp;gt;
               &amp;lt;CardTitle&amp;gt;{name}&amp;lt;/CardTitle&amp;gt;
           &amp;lt;/CardHeader&amp;gt;
           &amp;lt;CardBody&amp;gt;
               &amp;lt;p&amp;gt;Id: {id}&amp;lt;/p&amp;gt;
               &amp;lt;IngredientsFields&amp;gt;
                   {ingredients.map((ingredient) =&amp;gt; {
                       &amp;lt;Ingredient&amp;gt;{ingredient}&amp;lt;/Ingredient&amp;gt;
                   })}
               &amp;lt;/IngredientsFields&amp;gt;
               {children}
           &amp;lt;/CardBody&amp;gt;
       &amp;lt;/Card&amp;gt;
   )
}


// children
const AuthorRecipeCard = ({id, name, ingredients, onClick}) =&amp;gt; {
   return (
       &amp;lt;RecipeCard id={id} name={name} ingredients={ingredients}&amp;gt;
           &amp;lt;button onClick={onClick}&amp;gt;Go to site&amp;lt;/button&amp;gt;
       &amp;lt;/RecipeCard&amp;gt;
   )
}

const OwnRecipeCard = ({id, name, ingredients, onClick}) =&amp;gt; {
   return (
       &amp;lt;RecipeCard id={id} name={name} ingredients={ingredients}&amp;gt;
           &amp;lt;button onClick={onClick}&amp;gt;Go to cook steps&amp;lt;/button&amp;gt;
       &amp;lt;/RecipeCard&amp;gt;
   )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이디, 이름, 재료와같이 공통적인 부분은 유지를 하되, type별로 &lt;b&gt;나눠지는 부분은 특정컴포넌트를 만들어서 children으로 렌더링&lt;/b&gt;하게됩니다. 새로운 type이 추가되더라도 새 컴포넌트를 추가하고 children으로 전달하면되기때문에 확장성이 높아졌습니다. 즉, 확장에 개방되어있고, 변경에는 폐쇄되어있는 원칙을 잘 지켰다고 볼수있습니다. 또한, 앞서 설명한 SRP에서 특정도메인과의 결합도를 낮추는것과도 부합한다고 볼수있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.&amp;nbsp; LSP(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Liskov Substitution Principle&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left;&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbULk5/btsDVnRlyhj/yTryedrW4sHB9V124rYFok/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbULk5/btsDVnRlyhj/yTryedrW4sHB9V124rYFok/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbULk5/btsDVnRlyhj/yTryedrW4sHB9V124rYFok/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbULk5%2FbtsDVnRlyhj%2FyTryedrW4sHB9V124rYFok%2Fimg.webp&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;1024&quot; height=&quot;619&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LSP는 리스코프 치환법칙입니다. 주로 객체지향언어에서 아용되는 원칙이기때문에 보통 &quot;&lt;b&gt;클래스 A가 클래스 B의 하위유형인 경우, 프로그램에서 오류를 일으키지않고 클래스 B의 객체를 클래스 A의 객체로 대체해야한다&lt;/b&gt;&quot; 라고 설명합니다. 자식부모관계는 클래스 상속을 통해 설정되지만, 더 넓은 맥락에서 상속이란 비슷한 구현을 유지하면서 한 객체를 다른객체 위에 구축하는것을 의미합니다. &lt;a href=&quot;https://www.octobot.io/blog/solid-principles-react/&quot;&gt;https://www.octobot.io/blog/solid-principles-react/&lt;/a&gt; 에 작성된 코드예시를 보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706222675312&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const RecipeCard = ({children, color, size}) =&amp;gt; {
   return (
       &amp;lt;Card style={{color, fontSize: size === 'xl' ? '32px' : '16px'}}&amp;gt;
           {children}
       &amp;lt;/Card&amp;gt;
   )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 자식컴포넌트, 색상, 크기를 props로 받는 RecipeCard component입니다. 여기에 나중에 다크모드가 기획상 추가되어서 새로운 DarkRecipeCard 컴포넌트를 만들어야한다고 가정해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1706222949449&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const DarkRecipeCard = ({children, isBig}) =&amp;gt; {
   return (
       &amp;lt;RecipeCard color='dark' size={isBig ? 'xl' : 'tb'}&amp;gt;
           {children}
       &amp;lt;/RecipeCard&amp;gt;
   )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 언뜻보면 문제가 없어보입니다. 렌더링할때도 제대로 동작하는것을 볼수있습니다. 하지만 리스코프 치환법칙을 준수하지는 않습니다. 왜냐하면 DarkRecipeCard를 다른 레시피 카드로 대체하고싶어도 상속되는 props의 동작을 수정해서 이름을 변경하였기때문에 대체하지 못하기때문입니다. 따라서 이 리스코프 치환법칙을 지키기위해서는 아래와같이 코드를 작성하는편이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706223134684&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const DarkRecipeCard = ({children, size}) =&amp;gt; {
   return (
       &amp;lt;RecipeCard color='dark' size={size}&amp;gt;
           {children}
       &amp;lt;/RecipeCard&amp;gt;
   )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링상 문제는 없지만 아무생각없이 개발하다보면 놓칠수 있는 부분입니다. 이 원칙을 코드레벨말고 아키텍쳐레벨 관점에서 본다면 더 넓은 의미로 적용이 가능합니다. 리스코프 치환법칙은 다시말하자면 &lt;b&gt;&lt;i&gt;상속으로 이어진 관계에서 예상못할 행동을 하지말라&lt;/i&gt;는 것&lt;/b&gt;입니다. 타입스크립트 인터페이스정의를 아무생각없이 상속관계로 만든다거나, `ApiErrorBoudary` 를 작성해놓고 API와 관련없는 에러처리를 한다거나 등의 위반을 저지를수있습니다. 실제로 &lt;b&gt;SOLID원칙중 장애상황과 가장 밀접한 부분&lt;/b&gt;은 LSP이기때문에 실제개발단계에서 이원칙을 지켰나 생각하면서 개발을 하는것이 좋습니다. 상위정의된부분과 실제 구현된 부분이 다르가면 장애상황이 일어날 확률이 커지게되고, 나중에 원인을 찾기도 힙들게됩니다. 따라서 개발단계에서부터 조심해서 쓰는것이 좋습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.&amp;nbsp; ISP(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Interface Segregation Principle&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left;&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dB1WCX/btsD1mbNBdJ/Dm8clAoDsrH4awLpGhsQLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dB1WCX/btsD1mbNBdJ/Dm8clAoDsrH4awLpGhsQLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dB1WCX/btsD1mbNBdJ/Dm8clAoDsrH4awLpGhsQLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdB1WCX%2FbtsD1mbNBdJ%2FDm8clAoDsrH4awLpGhsQLk%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;811&quot; height=&quot;302&quot; data-origin-width=&quot;811&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;ISP는 인터페이스 분리원칙입니다. &lt;b&gt;어떤 코드도 &quot;사용하지 않는 메서드/인터페이스&quot;에 의존하도록 해서는 안된다&lt;/b&gt;라는 원칙입니다. 리액트에서 ISP는 컴포넌트를 작성할때 정확하고 최소한의 인터페이스를 만드는것에 대한 중요성을 강조하고있습니다. 즉, 불필요한 부피를 피하면서 특정요구에 맞는 컴포넌트 인터페이스를 설계하도록 권장하는 것입니다. 이러한 접근방식은 컴포넌트가 작아지고 집중화되어 가독성과 확장성이 개선된 모듈로 기능을 하게됩니다. &lt;a href=&quot;https://www.octobot.io/blog/solid-principles-react/&quot;&gt;https://www.octobot.io/blog/solid-principles-react/&lt;/a&gt;&amp;nbsp;에 작성된 코드예시를 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706225512746&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const RecipeCard = ({ recipeData }) =&amp;gt; {
   return (
     &amp;lt;Card&amp;gt;
       &amp;lt;Title&amp;gt;{recipeData.name}&amp;lt;/Title&amp;gt;
       &amp;lt;TypeLabel&amp;gt;{recipeData.type}&amp;lt;/TypeLabel&amp;gt;
       {recipeData.ingredients.map((ingredient) =&amp;gt;
       (&amp;lt;Ingredient&amp;gt;{ingredient}&amp;lt;/Ingredient&amp;gt;))}
       &amp;lt;Photo src={recipeData.img} /&amp;gt;
     &amp;lt;/Card&amp;gt;
   );
}
RecipeCard.propTypes = {
   recipeData: PropTypes.object.isRequired,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;RecipeCard는 recipeData를 받아서 렌더링하는 컴포넌트입니다. 만약 recipeData에서 특정 데이터만 필요하다면 이 부분은 쪼개어 props를 받는것이 좋습니다. 컴포넌트에 불필요한 정보를 제공하는것은 컴포넌트의 클라이언트가 사용하지않는 인터페이스에 의존하도록 강요하는것이기 때문입니다. 따라서 다음과같이 코드를 수정하는것이 좋습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706225686579&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const RecipeCard = ({ name, type, ingredients, photo }) =&amp;gt; {
   return (
     &amp;lt;Card&amp;gt;
       &amp;lt;Title&amp;gt;{name}&amp;lt;/Title&amp;gt;
       &amp;lt;TypeLabel&amp;gt;{type}&amp;lt;/TypeLabel&amp;gt;
       {ingredients.map((ingredient) =&amp;gt;
       (&amp;lt;Ingredient&amp;gt;{ingredient}&amp;lt;/Ingredient&amp;gt;))}
       &amp;lt;Photo src={photo} /&amp;gt;
     &amp;lt;/Card&amp;gt;
   );
}
RecipeCard.propTypes = {
   name: PropTypes.string.isRequired,
   type: PropTypes.string.isRequired,
   ingredients: PropTypes.array.isRequired,
   photo: PropTypes.string.isRequired,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게함으로써 컴포넌트가 사용하지않는 props에 의존하지않게되었습니다. 컴포넌트간의 종속성을 최소하하고, 한 컴포넌트에서 다른 컴포넌트로 전달되는 props를 최소화하여 결합도를 낮췄습니다. 이렇게하면 코드를 유지보수할때나, 장애상황 발생시 빠르게 파악이 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. DIP(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;Dependency Inversion Principle&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left;&quot;&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceopZl/btsDZZanRCC/2iIdrjwGQx1VVa1lUMoWd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceopZl/btsDZZanRCC/2iIdrjwGQx1VVa1lUMoWd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceopZl/btsDZZanRCC/2iIdrjwGQx1VVa1lUMoWd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceopZl%2FbtsDZZanRCC%2F2iIdrjwGQx1VVa1lUMoWd0%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;814&quot; height=&quot;424&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;DIP는 의존성역전법칙으로 그 개념이 다소 어렵습니다. 클린아키텍처저자인 Martin, Robert C의 말씀을 빌리면 DIP는 다음과같습니다. &lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 고차원모듈은 저차원 모듈에 의존하면안된다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 이 모듈 모두 다른 추상화된것에 의존해야한다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 추상화된것은 구체적인 것에 의존하면안된다. 구체적인것이 추상화된것에 의존해야한다.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 리액트에 대입해서 생각해보자면, 상위 컴포넌트가 하위 컴포넌트에 직접적으로 의존하게 하는것이 아닌, props나 context와 같은 추상화에 의존하여 유연성과 유지보수를 강화하자는 말로 이해할수있습니다. 이렇게되면 모듈화하기에도 좋고, 테스트하기에도 쉬우며 코드유지관리가 쉬워집니다. &lt;a href=&quot;https://fe-developers.kakaoent.com/2023/230330-frontend-solid/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fe-developers.kakaoent.com/2023/230330-frontend-solid/&lt;/a&gt;에 작성된 예시를 보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706226523179&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function TicketInfoContainer(){
  const { isLoading, data:ticketInfo, error } = useTicketInfoQuery();
  const { data:commentInfo, error:commentApiError } = useCommentInfoQuery();
  const { data:keywordInfo } = useKeywordInfoQuery();
  
  if(isLoading){
    return &amp;lt;Loading /&amp;gt;
  }

  if(error){
    return &amp;lt;Error /&amp;gt;
  }

  return (
    &amp;lt;TicketInfo
      waitfreePeriod={ticketInfo.waitfreePeriod}
      waitfreeChargedDate={ticketInfo.waitfreeChargedDate}
      rentalTicketCount={ticketInfo.rentalTicketCount}
      ownTicketCount={ticketInfo.ownTicketCount}
      commentCount={commentInfo.commentCount}
      commentError={commentApiError}
      keywordInfo={keywordInfo}
    /&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 &lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;DIP원칙으로 개선해본다면 다음과같은 개선점이 있을수있습니다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Loading과 Error 처리가 &lt;span style=&quot;background-color: #f0f0f0; color: #444444; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;TicketInfoContainer&lt;/span&gt;&amp;nbsp;&lt;/span&gt;컴포넌트 내부에 강하게 결합되어있기때문에 의존성을 반전시켜주는게 좋습니다. 리액트 ErrorBoundary와 Suspense를 사용하면 상위레벨에서 해당처리를 할수있습니다. &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;또한&amp;nbsp;&lt;/span&gt;ErrorBoundary와 Suspense는 여러부분에서 공통으로 사용되므로 응집도는 높이고 결합도는 낮추는 결과를 가져오게됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;TicketInfo&lt;/span&gt; 컴포넌트가 너무많은 props를 가지고있습니다. 의존되는곳이 많기때문에 한번에 파악이 어렵고 테스트를 작성하기도 어렵습니다. 원글에서는 합성컴포넌트를 사용하여 컴포넌트를 분리하였습니다. 선호하는 방향에따라 각각의 컴포넌트를 폴더구조 하위에 만들어서 사용하는 방법도 있을것입니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여기서 IoC라는 개념을 잠깐 살피고 넘어가자면, &lt;b&gt;IoC&lt;/b&gt;(Inversion of Control)는 제어역전으로,&lt;b&gt; 컴포넌트를 사용하는 개발자에게 컴포넌트 제어권을 넘겨줌&lt;/b&gt;으로써 개발자가 원하는대로 컨트롤하도록하는 개념입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;컴포넌트가 특정조건에서 다른 렌더링결과물을 만들어내야하는데, 전달되는 props도 많고 렌더링조건이 많아지게된다면 컴포넌트 복잡도는 증가할것입니다. 이때 여러 IoC패턴들을 사용해서 쉽게 쪼개볼수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fe-developers.kakaoent.com/2022/221110-ioc-pattern/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://fe-developers.kakaoent.com/2022/221110-ioc-pattern/&lt;/a&gt; 글을 참고하시기 바랍니다.&amp;nbsp;&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에 SOLID원칙을 적용하면 프로젝트에서 발생할수있는변화, 장애상황시에 조금 더 유연한 대처가 가능합니다. 응집도는 높고 결합도는 낮은, 확장에는 개방되어있고 변경에는 폐쇄되어있는 컴포넌트를 만들어내는것이 중요한것같습니다. 여태까지는&amp;nbsp;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;나중에 어떤 결과를 가져올지는 생각안하고&amp;nbsp;&lt;/span&gt;대충느낌상 쪼개야할때 컴포넌트를 분리하곤했었습니다. SOLID원칙을 정리하고나니, 이젠 근거를 가지고 컴포넌트구조를 설계할수있을것같습니다. 더 나은 의견이 있다면 댓글로 알려주세요! 긴글 읽어주셔서 감사합니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>FYI/FE</category>
      <category>react</category>
      <category>solid</category>
      <category>SRP</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/108</guid>
      <comments>https://yeon-code.tistory.com/108#entry108comment</comments>
      <pubDate>Thu, 25 Jan 2024 18:53:00 +0900</pubDate>
    </item>
    <item>
      <title>TanStack Query v5 변경사항, 마이그레이션 가이드</title>
      <link>https://yeon-code.tistory.com/107</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH8GsM/btsy8avL1OY/i2GQPHpQb6hFP3YTnTfvCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH8GsM/btsy8avL1OY/i2GQPHpQb6hFP3YTnTfvCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH8GsM/btsy8avL1OY/i2GQPHpQb6hFP3YTnTfvCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH8GsM%2Fbtsy8avL1OY%2Fi2GQPHpQb6hFP3YTnTfvCK%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;1752&quot; height=&quot;994&quot; data-origin-width=&quot;1752&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 TanStack Query v5가 릴리즈되었습니다! v4보다 용량은 더작게, 하지만 더 직관적이게 변화했는데요, 변경사항과 마이그레이션시의 주의사항을 살펴보도록 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1.&amp;nbsp; Breaking Change&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 변화에는 코드베이스로부터의 overload를 제거하여 &lt;i&gt;useQuery&lt;/i&gt;와같은 훅을 더 직관적으로 만들었다는 것입니다. 사실 v4부터 하려고 기획했던것이지만 &lt;a href=&quot;https://github.com/microsoft/TypeScript/issues/43371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;타입스크립트에서의 제약&lt;/a&gt;으로 인해 할수가없었는데요, TS 4.7에서 이부분이 보완되었고, 훅을 호출할때의 다양한 매개변수를 이제는 신경쓰지 않아도되게 변화하였습니다. v5에서는 객체만을 지원합니다. 이 부분은 DX측면에서 큰 성과라고 할수있습니다. 일일히 overload를 고려하지않아도되며, 하나의 객체만을 전달하면되기때문에 일관성이 높아졌습니다. 당연히 새로운 API를 사용할수있도록 &lt;a href=&quot;https://tanstack.com/query/v4/docs/react/eslint/prefer-query-object-syntax&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;eslint 패키지&lt;/a&gt;에 자동수정가능한 규칙도 배포되었습니다.&amp;nbsp; 또한 v5로 마이그레이션하는데에 도움이되는&lt;a href=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; codemod&lt;/a&gt;도 추가되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도, 기존 &lt;i&gt;cacheTime&lt;/i&gt;을 &lt;i&gt;gcTime&lt;/i&gt;으로 이름을 변경하여 직관성을 높였고, &lt;i&gt;keepPrevioudsData&lt;/i&gt; 옵션을 &lt;i&gt;placeholderData&lt;/i&gt; 옵션과 통합하여 비슷한 기능을 하던 두가지의 옵션을 하나로 재정의하였습니다. 또한 &lt;i&gt;loading&lt;/i&gt;으로 표시되던 상태값을 &lt;i&gt;pending&lt;/i&gt;이라는 이름으로 변경되었고, &lt;i&gt;useQuery&lt;/i&gt;에서의 콜백을 제거하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2.&amp;nbsp; New Features&amp;nbsp;&lt;/b&gt;&lt;/h2&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;Simplified optimistic updates&lt;/b&gt;: cache를 수동적으로 업데이트하는 코드대신, &lt;i&gt;useMutation&lt;/i&gt;에서 반환된 'variables'를 사용하여 업데이트를 수행할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sharable mutation state&lt;/b&gt;: &lt;i&gt;useMutation&lt;/i&gt;&amp;nbsp;훅을 통해 컴포넌트 간에 공유되는 모든 상태에 접근할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1st class 'suspense' support&lt;/b&gt;: suspense를 완전히 지원하며, &lt;i&gt;useSuspenseQuery&lt;/i&gt;나 &lt;i&gt;useSuspenseInfiniteQuery&lt;/i&gt;와 같은 훅을 사용할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Improved Infinite Queries&lt;/b&gt;: infinite query는 이제 한번에 여러페이지를 prefetch할수있으며, 옵션으로 최대페이지의 개수까지 지정할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;New Devtools&lt;/b&gt;: Query devtools는 모든 어댑터, 프레임워크에 사용될수있도록 다시 개발되었습니다. UI개선과함께 cache 인라인 편집이나 light mode같은 기능도 추가되었습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fine-grained persistense&lt;/b&gt;: PersistQueryClient 플러그인에 기존에는 없었던 복원기능이 추가되었습니다. experimental_createPersister를 사용하면 storage를 전달할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&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.&amp;nbsp; Migration Guide&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) Supports a single signature, one object&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;i&gt;useQuery&lt;/i&gt;, &lt;i&gt;useInfiniteQuery&lt;/i&gt;등 훅을 호출할때 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;객체만을 지원&lt;/span&gt;&lt;/b&gt;합니다. TS에 많은 오버로드를 가지는것과 매개변수 유형을 확인하기위해 runtime 검사를 해야하는 수고로움이 사라졌습니다. 타입스크립트 4.7 이전버전에서는 &lt;a href=&quot;https://github.com/microsoft/TypeScript/issues/43371&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;함수인수가 unknown으로 추론되는 이슈&lt;/a&gt;가 있었고, 이 때문에 useQuery등의 훅에서 매개변수를 사용할때 많은 타입스크립트 에러를 만나야만했습니다. 하지만 이 부분이 TS 4.7에서 해결이되면서 오버로드가 모두 제거되었기때문에 단일객체로 사용이 가능합니다. 그렇기때문에 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;최소한 TS 버전은 4.7이상&lt;/span&gt;&lt;/b&gt;으로 설정해주어야합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698256761036&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- useQuery(key, fn, options)
+ useQuery({ queryKey, queryFn, ...options })

- useInfiniteQuery(key, fn, options)
+ useInfiniteQuery({ queryKey, queryFn, ...options })

- useMutation(fn, options)
+ useMutation({ mutationFn, ...options })

- useIsFetching(key, filters)
+ useIsFetching({ queryKey, ...filters })

- useIsMutating(key, filters)
+ useIsMutating({ mutationKey, ...filters })&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) &lt;i&gt;getQueryData&lt;/i&gt;, &lt;i&gt;getQueryState&lt;/i&gt; now accepts queryKey only as an Argument&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;getQueryData&lt;/i&gt;와 &lt;i&gt;getQueryState&lt;/i&gt;는 이제부터 queryKey만을 인자로 받습니다. 기존에는 filters 인자도 optional하게 받아서, stale이나 exact 등의 필터를 설정할수있었지만, v5에서는 filters 설정기능이 사라졌습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698258096256&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- queryClient.getQueryData(queryKey, filters)
+ queryClient.getQueryData(queryKey)

- queryClient.getQueryState(queryKey, filters)
+ queryClient.getQueryState(queryKey)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) Callbacks on useQuery have been removed&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;useQuery&lt;/i&gt;에서의 콜백이 제거되었습니다(&lt;i&gt;useMutation&lt;/i&gt;에서의 콜백은 사라지지않았습니다). 따라서 onSuccess, onError, onSettled는 이제 사용하지 못합니다. &lt;i&gt;useQuery&lt;/i&gt;의 콜백이 제거된 이유는 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;예상대로 동작하지 않을 가능성이 높기때문&lt;/b&gt;&lt;/span&gt;입니다. 기존에는 쿼리가 성공적으로 실행되었을때 / 오류가 발생했을때 / 두 경우모두 해당할때 호출되는 3가지 콜백함수 onSuccess / onError / onSettled가 있었습니다. 하지만 이러한 콜백들이 일어나지않을수도, 중복으로 호출될수도 있습니다. (자세한 사례는 &lt;a href=&quot;https://tkdodo.eu/blog/breaking-react-querys-api-on-purpose&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;본글&lt;/a&gt;을 참조하세요) 따라서 이 콜백들은 직관적이지 못합니다. v5에서는 이러한 콜백을 사용하지 못하기때문에 다른 대안법을 찾아야합니다. onError대신 meta필드를 사용한다든지, onSuccess대신 value값 자체를 반환한다던지의 대안을 사용해야합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698258937013&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//AS-IS
export function useTodos() {
  return useQuery({
    queryKey: ['todos', 'list'],
    queryFn: fetchTodos,
    onError: (error) =&amp;gt; {
      toast.error(error.message)
    },
  })
}



// To-BE
const queryClient = new QueryClient({
  queryCache: new QueryCache({
    onError: (error, query) =&amp;gt; { 
      if (query.meta.errorMessage) {
        toast.error(query.meta.errorMessage)
      }
    },
  }),
})

export function useTodos() {
  return useQuery({
    queryKey: ['todos', 'list'],
    queryFn: fetchTodos,
    meta: { 
      errorMessage: 'Failed to fetch todos',
    },
  })
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1698259057718&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//AS-IS
export function useTodos() {
  const [todoCount, setTodoCount] = React.useState(0)
  const { data: todos } = useQuery({
    queryKey: ['todos', 'list'],
    queryFn: fetchTodos,
    //  please don't
    onSuccess: (data) =&amp;gt; {
      setTodoCount(data.length)
    },
  })

  return { todos, todoCount }
}

//TO-BE
export function useTodos() {
  const { data: todos } = useQuery({
    queryKey: ['todos', 'list'],
    queryFn: fetchTodos,
  })

  const todoCount = todos?.length ?? 0

  return { todos, todoCount }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4) &lt;i&gt;refetchInterval&lt;/i&gt; callback function only gets 'query' passed&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;refetchInterval, refechOnWindowFocus, refetchOnMount, refetchOnReconnect&lt;/i&gt;와 같은 훅들에서 더이상 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;data를 select하여 변환하지 못합니다.&lt;/span&gt;&lt;/b&gt; 기존에 변환된 데이터를 가져올때 발생하던 typing issue를 해결하기위해서 수정되었습니다. 하지만 여전히 query.state.date를 사용하여 데이터에 접근할수있기때문에 refetch한 후에 데이터변환을 시도하면됩니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698259951378&quot; class=&quot;scala&quot; data-ke-language=&quot;scala&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- refetchInterval: number | false | ((data: TData | undefined, query: Query) =&amp;gt; number | false | undefined)
+ refetchInterval: number | false | ((query: Query) =&amp;gt; number | false | undefined)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5) 'remove' method has been removed from &lt;i&gt;useQuery&lt;/i&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;remove는 기존에 옵저버에게 알리지않고 쿼리를 제거하는데 사용되는 메서드였으나, 쿼리가 아직 활성화되지 않은 상태에서 remove를 수행하는 것은 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;리렌더링시에 로딩상태를 불러오기때문에 합리적이지 못하다&lt;/span&gt;&lt;/b&gt;는 이유로 사라졌습니다. v5에서는 removeQueries 메서드를 통해 쿼리 삭제가 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698260355431&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const queryClient = useQueryClient();
 const query = useQuery({ queryKey, queryFn });
 
- query.remove()
+ queryClient.removeQueries({ queryKey })&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6) `isDataEqual` option has been removed from useQuery&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 isDataEqual 옵션은 이전데이터를 사용할지 새로운데이터를 사용할지에 대해 판단하는데 사용되었으나 structuralSharing 옵션과 비슷한 기능을 하기에 제거되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698260690531&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { replaceEqualDeep } from '@tanstack/react-query'

- isDataEqual: (oldData, newData) =&amp;gt; customCheck(oldData, newData)
+ structuralSharing: (oldData, newData) =&amp;gt; customCheck(oldData, newData) ? oldData : replaceEqualDeep(oldData, newData)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7) Supported Broswers&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능과 번들크기를위해 지원되는 브라우저 범위를 업데이트하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Chrome &amp;gt;= 91&lt;br /&gt;Firefox &amp;gt;= 90&lt;br /&gt;Edge &amp;gt;= 91&lt;br /&gt;Safari &amp;gt;= 15&lt;br /&gt;iOS &amp;gt;= 15&lt;br /&gt;opera &amp;gt;= 77&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8) Rename `cacheTime` to `gcTime`&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 cacheTime은 마치 &quot;데이터가 캐시로 유지되는시간&quot;이라는 뜻을 나타내는것처럼 보이지만 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;사실은 &quot;쿼리가 사용되지않을때 캐시가 제거되기까지의 시간&quot;&lt;/span&gt;&lt;/b&gt;입니다. 쿼리가 계속사용될때 cacheTime은 아무일도하지않다가 쿼리가 사용되지않는 순간부터 일정시간 이후에 garbage colletor가 수집해서 버려버리기 때문입니다. 따라서 gcTime으로 이름을 변경하여 가비지로 수집되기까지의 시간이라는 뜻을 더 잘 나타내게하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698261095159&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const MINUTE = 1000 * 60;

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
-      cacheTime: 10 * MINUTE,  //AS-IS
+      gcTime: 10 * MINUTE, 	//TO-BE
    },
  },
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&amp;nbsp;9) `useErrorBoundary` option has been renamed to `throwOnError`&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 리액트 훅의 use와 혼동되는것을 방지하기위해 useErrorBoundary 옵션의 이름이 throwErrors로 변경되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;10) TS: `Error` is now the default type for errors instead of `unknown`&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러의 기본타입이 unknown에서 Error로 변경되었습니다. 커스텀에러나 에러가 아닌 타입을 지정하고싶다면 다음과 같이 지정할수있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698261395184&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;declare module '@tanstack/react-query' {
  interface Register {
    defaultError: AxiosError
  }
}

const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;11) Removed `keepPreviousData` in favor of `placeholderData` idenify function&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;keepPreviousData&lt;/i&gt;와 &lt;i&gt;isPreviousData&lt;/i&gt; 플래그는 &lt;i&gt;placeholderData&lt;/i&gt; 혹은 &lt;i&gt;isPlaceholderData&lt;/i&gt;플래그와 비슷한 기능을 하므로 제거되었습니다. 다만 몇가지 다른점은&lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt; placeholderData는 항상 success상태를 반환할것이며, dataUpdatedAt은 항상 0으로 유지될것&lt;/span&gt;&lt;/b&gt;이라는점입니다. 기존 keepPreviousData는 이전 쿼리의 상태를 나타냈지만, 에러 자체가 다음 쿼리로 공유되지는 않으므로 placeholderData의 동작(success로 반환되는것)을 그대로 사용하기로 하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698262030977&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useQuery({
  queryKey,
  queryFn,
  placeholderData: (previousData, previousQuery) =&amp;gt; previousData, // identity function with the same behaviour as `keepPreviousData`
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;12) Window focus refetching no longer listends to the `focus` event&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;focus 이벤트 대신에 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;visibilityChange&lt;/span&gt;&lt;/b&gt; 이벤트를 전적으로 사용합니다. visibilityChange이벤트를 지원하는 브라우저만을 지원하고 있으며, 기존에 &lt;a href=&quot;https://github.com/TanStack/query/pull/4805&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;focus로 인한 이슈&lt;/a&gt;는 해결되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;13) Network status no longer relies on the `navigator.onLine` property&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;navigator.onLine은 chromium 기반 브라우저에서 제대로 작동하지않기때문에 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;online:true로 가정하고 온라인/오프라인 이벤트를 수신&lt;/span&gt;&lt;/b&gt;하였을때만 상태를 업데이트합니다. 이때 인터넷 연결없이도 작동이 가능한 서비스워커를 통해 로드되는 오프라인 앱에서는 오탐이 있을수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;14) Removed custom `context` prop in favor of custom `queryClient` instance&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;v4에서는 모든 리액트 쿼리 훅에 custom context를 전달할수있는 기능을 도입했으나, 이는 리액트 전용 기능이므로 quert client를 직접 전달하게함으로써 모든 프레임워크에서 사용가능하도록 변경하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698262717279&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { queryClient } from './my-client'

const { data } = useQuery(
  {
    queryKey: ['users', id],
    queryFn: () =&amp;gt; fetch(...),
-   context: customContext //AS-IS
  },
+  queryClient, //To-BE
)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;15) Infinite queries now need a `initialPageParam`&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 pageParam으로 undefined를 지정할수도 있었지만 이는 query cache에 정의되지않은 상태로 존재한다는 허점이 있었습니다. v5에서는 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;명시적으로 initialPageParam을 지정&lt;/span&gt;&lt;/b&gt;하여 첫페이지의 pageParam을 정해주어야합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1698263002129&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useInfiniteQuery({
   queryKey,
-  queryFn: ({ pageParam = 0 }) =&amp;gt; fetchSomething(pageParam), //AS-IS
+  queryFn: ({ pageParam }) =&amp;gt; fetchSomething(pageParam), //TO-BE
+  initialPageParam: 0, //TO-BE
   getNextPageParam: (lastPage) =&amp;gt; lastPage.next,
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;16) No retries on the server&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 서버 요청 실패시 재시도 기본값은 3번이였으나 이제는 &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;0으로 변경&lt;/span&gt;&lt;/b&gt;되었습니다. prefetch의 경우 항상 기본값이 0이였지만, suspense가 활성화된 쿼리는 직접 서버에서 실행할수있기때문에 재시도를 전혀 하지않는것으로 변경되었습니다.&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. Conclusion&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 변경된 사항이 있으므로 자세한 내용은 &lt;a href=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;원글&lt;/a&gt;을 참조하시길 바랍니다. v5로 마이그레이션 할때 &lt;a href=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;codemod&lt;/a&gt;를 지원해주므로 같이 사용한다면 훨씬 빠르게 가능할것으로 보입니다. 1년전 &lt;a href=&quot;https://github.com/TanStack/query/discussions/4252&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;v5 로드맵&lt;/a&gt; 발표이후 많은 우려와 논의가 이루어졌었는데요, 기존에 문제되던 이슈들이 많이해결되었고, '직관성'을 강조하는 철학이 담겨 더 탄탄한 Tanstack query가 되었다라는 생각이 들었습니다. v4 -&amp;gt; v5에서 엄청난 변화가 있다고 느껴지진않지만, DX가 향상된 확고한 API들은 더 매력적으로 보이는것같습니다. 긴글 읽어주셔서 감사합니다.&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;size18&quot;&gt;&lt;b&gt;Reference.&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698301759393&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;Migrating to TanStack Query v5 | TanStack Query Docs&quot; data-og-description=&quot;Breaking Changes v5 is a major version, so there are some breaking changes to be aware of:&quot; data-og-host=&quot;tanstack.com&quot; data-og-source-url=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; data-og-url=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7qhqi/hyUkjjtnrU/8rkOwlkN0caADdCkqYuwok/img.png?width=3000&amp;amp;height=1704&amp;amp;face=0_0_3000_1704,https://scrap.kakaocdn.net/dn/b75V5b/hyUltTBkbH/QMFkeINoT2eWJ3jFaQxwYK/img.png?width=3000&amp;amp;height=1704&amp;amp;face=0_0_3000_1704&quot;&gt;&lt;a href=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tanstack.com/query/v5/docs/react/guides/migrating-to-v5#codemod&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7qhqi/hyUkjjtnrU/8rkOwlkN0caADdCkqYuwok/img.png?width=3000&amp;amp;height=1704&amp;amp;face=0_0_3000_1704,https://scrap.kakaocdn.net/dn/b75V5b/hyUltTBkbH/QMFkeINoT2eWJ3jFaQxwYK/img.png?width=3000&amp;amp;height=1704&amp;amp;face=0_0_3000_1704');&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;Migrating to TanStack Query v5 | TanStack Query Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Breaking Changes v5 is a major version, so there are some breaking changes to be aware of:&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tanstack.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tanstack.com/blog/announcing-tanstack-query-v5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tanstack.com/blog/announcing-tanstack-query-v5&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698301781559&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;Announcing TanStack Query v5 | TanStack Blog&quot; data-og-description=&quot;About one year ago, we announced the TanStack Query v5 roadmap, and the whole team has been working hard on that version ever since. So we're super happy to announce that today is the day: After 91 alpha releases, 35 betas and 16 release candidates, TanSta&quot; data-og-host=&quot;tanstack.com&quot; data-og-source-url=&quot;https://tanstack.com/blog/announcing-tanstack-query-v5&quot; data-og-url=&quot;https://tanstack.com/blog/announcing-tanstack-query-v5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oqvX0/hyUkfVFF7Q/D86XUnd2XrK2HNxBSqG9ok/img.png?width=1200&amp;amp;height=629&amp;amp;face=0_0_1200_629&quot;&gt;&lt;a href=&quot;https://tanstack.com/blog/announcing-tanstack-query-v5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tanstack.com/blog/announcing-tanstack-query-v5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oqvX0/hyUkfVFF7Q/D86XUnd2XrK2HNxBSqG9ok/img.png?width=1200&amp;amp;height=629&amp;amp;face=0_0_1200_629');&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;Announcing TanStack Query v5 | TanStack Blog&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;About one year ago, we announced the TanStack Query v5 roadmap, and the whole team has been working hard on that version ever since. So we're super happy to announce that today is the day: After 91 alpha releases, 35 betas and 16 release candidates, TanSta&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tanstack.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;</description>
      <category>FYI/FE</category>
      <category>query</category>
      <category>react</category>
      <category>tanstack</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/107</guid>
      <comments>https://yeon-code.tistory.com/107#entry107comment</comments>
      <pubDate>Thu, 26 Oct 2023 14:01:55 +0900</pubDate>
    </item>
    <item>
      <title>'unload' 이벤트는 이제 사용하지마세요</title>
      <link>https://yeon-code.tistory.com/106</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceutGL/btsy4rWTXQn/5Ns9wO0XtIb6Zt3KZsadN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceutGL/btsy4rWTXQn/5Ns9wO0XtIb6Zt3KZsadN0/img.png&quot; data-alt=&quot;Never use unload event&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceutGL/btsy4rWTXQn/5Ns9wO0XtIb6Zt3KZsadN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceutGL%2Fbtsy4rWTXQn%2F5Ns9wO0XtIb6Zt3KZsadN0%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;1538&quot; height=&quot;574&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Never use unload event&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'unload' 이벤트는 이제 크롬에서 점차 실행되지 않도록 변경된다고 합니다. 도대체 왜 사라지는것이며, unload 이벤트를 대체할수있는 이벤트에는 무엇이 있을까요?&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Background&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unload 이벤트는 말그대로 페이지가 unload 될때 실행되도록 설계되었습니다. 이론적으로 사용자가 페이지에서 다른페이지로 이동할때마다 실행되었습니다. unload 이벤트가 가장 일반적으로 사용되는 시나리오는 다음과 같습니다.&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;&amp;nbsp;Saving user data: 페이지에서 나가기전에 데이터를 저장한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Performing cleanup tasks: 페이지를 끝내기전에 열려있는 리소스를 제거한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;Sending analytics: 페이지 종료시 사용자 상호작용과 관련된 데이터를 전송한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 unload 이벤트는 매우 불안정합니다. 데스크탑 Chrome 및 firefox에서의 unload 이벤트는 안정적이지만, bfcache의 사용을 방지하여 사이트 성능에 부정적인 영향을 미칩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 모바일 브라우저에서는 탭이 백그라운드에서 실행되다가 종료되는 경우가 많기때문에 unload 이벤트 자체가 실행되지 않는 경우가 많습니다. 이러한 이유때문에 모바일에서는 unload보다 bfcache의 우선순위를 높게 책정하여 더더욱 unload 이벤트를 불안정하게 만듭니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 크롬팀에서는 unload 이벤트를 완전히 제거하는것을 목표로 하고있습니다. 당장 이벤트를 없애는 것은 아니지만, unload 이벤트 자체를 명시적으로 다시 활성화하지않는한 unload 이벤트의 실행을 중지하도록 기본값을 변경하여 점진적으로 없애겠다고합니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;※ bfcache(Back/forward cache)&lt;br /&gt;사용자가 이동하는 동안 페이지의 전체 스냅샷을 저장하는 in-memory 캐시. 전체페이지가 저장되어있기때문에 사용자가 다시 페이지로 돌아올경우에 빠르게 복원을 가능하게 한다.&amp;nbsp;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. &lt;/b&gt;&lt;b&gt;Page LifeCyle&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 unload 이벤트 대신에 사용할수있는 이벤트에는 무엇이 있을까요? 그전에 Page Lifecycle을 한번 간략하게 살펴보고 가도록 하겠습니다.&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;2292&quot; data-origin-height=&quot;1276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6cOdP/btsyUKRukov/feixVcGKgTzqUBlB4iQg4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6cOdP/btsyUKRukov/feixVcGKgTzqUBlB4iQg4k/img.png&quot; data-alt=&quot;Page Lifecycle&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6cOdP/btsyUKRukov/feixVcGKgTzqUBlB4iQg4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6cOdP%2FbtsyUKRukov%2FfeixVcGKgTzqUBlB4iQg4k%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;2292&quot; height=&quot;1276&quot; data-origin-width=&quot;2292&quot; data-origin-height=&quot;1276&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Page Lifecycle&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&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;Active&lt;/b&gt;: 페이지가 표시되고, 입력이 활성화된 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passive&lt;/b&gt;: 페이지가 표시되어있지만, 입력포커스는 없는상태&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hidden&lt;/b&gt;: 페이지가 표시되지않고 숨겨진상태. 종료된것은 아닌상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Terminated&lt;/b&gt;: 페이지가 브라우저에서 사라지면서 메모리에서 지워진 상태.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Alternatives to 'unload' events&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unload 이벤트를 대신해서 쓸 수있는 이벤트는 visibilitychange와 pagehide가 있습니다.&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;visibilitychange&lt;/b&gt;: 페이지의 가시성이 변경되는 시점을 파악합니다. 사용자가 탭을 전환하거나, 브라우저 창을 최소화하거나, 새 페이지를 열때 발생합니다. 숨겨진 상태를 마지막으로 신뢰할수있는 이벤트라고 할수있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;pagehide&lt;/b&gt;: 사용자가 페이지에서 벗어난 시점을 파악합니다. 사용자가 페이지에서 다른곳으로 이동하거나, 페이지를 다시 로드하거나, 브라우저 창을 닫을때 발생합니다. 페이지가 단순히 최소화되거나 다른탭으로 전환된 경우에는 발생하지 않습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bERQV1/btsy4s2z2NT/339bDQwZpVzrYjkOmAphpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bERQV1/btsy4s2z2NT/339bDQwZpVzrYjkOmAphpK/img.png&quot; data-alt=&quot;beforeunload event caution&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bERQV1/btsy4s2z2NT/339bDQwZpVzrYjkOmAphpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbERQV1%2Fbtsy4s2z2NT%2F339bDQwZpVzrYjkOmAphpK%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;1510&quot; height=&quot;552&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;beforeunload event caution&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;beforeunload 이벤트도 페이지가 언로드되기 이전에 일어나기는하지만, unload이벤트와 마찬가지로 bfcache의 사용을 방지한다는 문제가 있습니다. 하지만 beforeunload는 unload와는 다르게 취소가능한 이벤트라는 점에 주목할 필요가 있는데요, 이때문에 저장되지않는 변경사항을 사용자에게 경고하는데에 사용됩니다. 크롬에서도 오직 이 용례에 한해서만 사용하라 라고 가이드하고있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Detect usage of 'unload'&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;unload 이벤트핸들러를 사용하고있는지는 lighthouse와 chrome devtools를 통해 확인이 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Lighthouse: 라이트하우스 테스트를 실행한후 결과를 보면, 페이지의 자바스크립트가 unload이벤트 리스너를 추가하는경우 경고문구를 확인할수있습니다.&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;1440&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RJHm6/btsyV0sJzq6/ogK8mD1DE7UiGEpaKEAfKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RJHm6/btsyV0sJzq6/ogK8mD1DE7UiGEpaKEAfKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RJHm6/btsyV0sJzq6/ogK8mD1DE7UiGEpaKEAfKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRJHm6%2FbtsyV0sJzq6%2FogK8mD1DE7UiGEpaKEAfKK%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;1440&quot; height=&quot;236&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) Chrome Devtools: Application tab의 &quot;Test back/forward cache&quot;를 이용하여 테스트를 하면, 경고문구를 확인할수있습니다.&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;1068&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxBoOX/btsy3gn21Bl/8wecx6fDOr2Z8lcsckKj31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxBoOX/btsy3gn21Bl/8wecx6fDOr2Z8lcsckKj31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxBoOX/btsy3gn21Bl/8wecx6fDOr2Z8lcsckKj31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxBoOX%2Fbtsy3gn21Bl%2F8wecx6fDOr2Z8lcsckKj31%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;1068&quot; height=&quot;172&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://developer.chrome.com/blog/deprecating-unload/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.chrome.com/blog/deprecating-unload/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698080805087&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;Deprecating the unload event - Chrome for Developers&quot; data-og-description=&quot;The unload event will be gradually deprecated starting from Chrome 117. Learn what this means and how sites and enterprises can prepare for this&quot; data-og-host=&quot;developer.chrome.com&quot; data-og-source-url=&quot;https://developer.chrome.com/blog/deprecating-unload/&quot; data-og-url=&quot;https://developer.chrome.com/blog/deprecating-unload/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cbrXZv/hyUlrt5NMX/Q5r8l5z4McaZmUXaOjClH1/img.jpg?width=1521&amp;amp;height=1010&amp;amp;face=0_0_1521_1010,https://scrap.kakaocdn.net/dn/b0k9Fi/hyUgJDuIGZ/5APjWc8ZRXMDtkdjWeDuK1/img.jpg?width=1521&amp;amp;height=1010&amp;amp;face=0_0_1521_1010,https://scrap.kakaocdn.net/dn/bPwHQJ/hyUkfnc6xz/XtDfwvUqnaEfsmTNSVjrvK/img.jpg?width=4288&amp;amp;height=2848&amp;amp;face=0_0_4288_2848&quot;&gt;&lt;a href=&quot;https://developer.chrome.com/blog/deprecating-unload/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.chrome.com/blog/deprecating-unload/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cbrXZv/hyUlrt5NMX/Q5r8l5z4McaZmUXaOjClH1/img.jpg?width=1521&amp;amp;height=1010&amp;amp;face=0_0_1521_1010,https://scrap.kakaocdn.net/dn/b0k9Fi/hyUgJDuIGZ/5APjWc8ZRXMDtkdjWeDuK1/img.jpg?width=1521&amp;amp;height=1010&amp;amp;face=0_0_1521_1010,https://scrap.kakaocdn.net/dn/bPwHQJ/hyUkfnc6xz/XtDfwvUqnaEfsmTNSVjrvK/img.jpg?width=4288&amp;amp;height=2848&amp;amp;face=0_0_4288_2848');&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;Deprecating the unload event - Chrome for Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The unload event will be gradually deprecated starting from Chrome 117. Learn what this means and how sites and enterprises can prepare for this&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.chrome.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://developer.chrome.com/articles/page-lifecycle-api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.chrome.com/articles/page-lifecycle-api/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698080812502&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;Page Lifecycle API - Chrome for Developers&quot; data-og-description=&quot;The Page Lifecycle API brings app lifecycle features common on mobile operating systems to the web. Browsers are now able to safely freeze and discard background pages to conserve resources, and developers can safely handle these interventions without affe&quot; data-og-host=&quot;developer.chrome.com&quot; data-og-source-url=&quot;https://developer.chrome.com/articles/page-lifecycle-api/&quot; data-og-url=&quot;https://developer.chrome.com/articles/page-lifecycle-api/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/od5cm/hyUj82GK9A/HYY5xHMc2m5BHm48IvJzf0/img.png?width=1521&amp;amp;height=1521&amp;amp;face=0_0_1521_1521,https://scrap.kakaocdn.net/dn/edksFk/hyUgF8WzFE/22KsiC231Efq3MoE5rBj2K/img.png?width=1521&amp;amp;height=1521&amp;amp;face=0_0_1521_1521&quot;&gt;&lt;a href=&quot;https://developer.chrome.com/articles/page-lifecycle-api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.chrome.com/articles/page-lifecycle-api/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/od5cm/hyUj82GK9A/HYY5xHMc2m5BHm48IvJzf0/img.png?width=1521&amp;amp;height=1521&amp;amp;face=0_0_1521_1521,https://scrap.kakaocdn.net/dn/edksFk/hyUgF8WzFE/22KsiC231Efq3MoE5rBj2K/img.png?width=1521&amp;amp;height=1521&amp;amp;face=0_0_1521_1521');&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;Page Lifecycle API - Chrome for Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The Page Lifecycle API brings app lifecycle features common on mobile operating systems to the web. Browsers are now able to safely freeze and discard background pages to conserve resources, and developers can safely handle these interventions without affe&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.chrome.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;a href=&quot;https://web.dev/articles/bfcache?hl=ko#never_use_the_unload_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://web.dev/articles/bfcache?hl=ko#never_use_the_unload_event&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1698080835745&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;뒤로-앞으로 캐시 &amp;nbsp;|&amp;nbsp; Articles &amp;nbsp;|&amp;nbsp; web.dev&quot; data-og-description=&quot;브라우저의 뒤로 및 앞으로 버튼을 사용할 때 페이지가 즉시 로드되도록 최적화하는 방법을 알아보세요.&quot; data-og-host=&quot;web.dev&quot; data-og-source-url=&quot;https://web.dev/articles/bfcache?hl=ko#never_use_the_unload_event&quot; data-og-url=&quot;https://web.dev/articles/bfcache?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b7P4pd/hyUj8uRE7F/IiuqUc6B3D8vypxXQbFbWK/img.png?width=3200&amp;amp;height=900&amp;amp;face=0_0_3200_900,https://scrap.kakaocdn.net/dn/bKc8xe/hyUgJcsXHZ/EAt8keKh24j2ZFTaM7HWUk/img.png?width=2420&amp;amp;height=948&amp;amp;face=0_0_2420_948,https://scrap.kakaocdn.net/dn/cmfob0/hyUgJKe7kx/LaH8CGfdPt6RmF0H91A7g0/img.png?width=2420&amp;amp;height=948&amp;amp;face=0_0_2420_948&quot;&gt;&lt;a href=&quot;https://web.dev/articles/bfcache?hl=ko#never_use_the_unload_event&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://web.dev/articles/bfcache?hl=ko#never_use_the_unload_event&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b7P4pd/hyUj8uRE7F/IiuqUc6B3D8vypxXQbFbWK/img.png?width=3200&amp;amp;height=900&amp;amp;face=0_0_3200_900,https://scrap.kakaocdn.net/dn/bKc8xe/hyUgJcsXHZ/EAt8keKh24j2ZFTaM7HWUk/img.png?width=2420&amp;amp;height=948&amp;amp;face=0_0_2420_948,https://scrap.kakaocdn.net/dn/cmfob0/hyUgJKe7kx/LaH8CGfdPt6RmF0H91A7g0/img.png?width=2420&amp;amp;height=948&amp;amp;face=0_0_2420_948');&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;뒤로-앞으로 캐시 &amp;nbsp;|&amp;nbsp; Articles &amp;nbsp;|&amp;nbsp; web.dev&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;브라우저의 뒤로 및 앞으로 버튼을 사용할 때 페이지가 즉시 로드되도록 최적화하는 방법을 알아보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;web.dev&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;</description>
      <category>FYI/FE</category>
      <category>Chrome</category>
      <category>pagehide</category>
      <category>unload</category>
      <category>visibilitychange</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/106</guid>
      <comments>https://yeon-code.tistory.com/106#entry106comment</comments>
      <pubDate>Tue, 24 Oct 2023 01:53:09 +0900</pubDate>
    </item>
    <item>
      <title>2022년 상반기 하이닉스 IT 최종합격 수기</title>
      <link>https://yeon-code.tistory.com/104</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1762&quot; data-origin-height=&quot;1318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1fJbO/btrKknwNpbc/NkF8ktJfoyToF6UbFkuKKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1fJbO/btrKknwNpbc/NkF8ktJfoyToF6UbFkuKKk/img.png&quot; data-alt=&quot;면접합격 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1fJbO/btrKknwNpbc/NkF8ktJfoyToF6UbFkuKKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1fJbO%2FbtrKknwNpbc%2FNkF8ktJfoyToF6UbFkuKKk%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;693&quot; height=&quot;518&quot; data-origin-width=&quot;1762&quot; data-origin-height=&quot;1318&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;&lt;span style=&quot;color: #000000;&quot;&gt;2022년 상반기 하이닉스 신입 공개체용에 ✨&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;최종합격&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;✨ 했습니다. 제가 지원했던 직무는 IT 직무이며, 이천에 위치하고 있습니다. 당시 자격요건에는 4년제 학사 이상 졸업(예정)자이며, 전산/컴퓨터/산업공학/경영정보학/전기/전자/반도체 등 관련전공자라는 조건이 있었습니다. 채용 전형은 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;서류전형 -&amp;gt; SKCT ( IT는 코딩테스트와 인성검사) -&amp;gt; 면접전형&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;으로 3가지의 단계로 진행되었습니다. 비록 최종적으로 하이닉스에 입사하지는 않았지만, 각 단계에 대한 후기와 꿀팁을 적어보려합니다. 지원하고자하는 많은 분들께 도움이 되길 바라며, 혹시 궁금하신점이 있다면 댓글로 달아주시면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. 서류전형 &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1128&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd434K/btrKkLc7wcI/VXNcmSkH6ewYJR2DWJiu71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd434K/btrKkLc7wcI/VXNcmSkH6ewYJR2DWJiu71/img.png&quot; data-alt=&quot;서류합격메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd434K/btrKkLc7wcI/VXNcmSkH6ewYJR2DWJiu71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd434K%2FbtrKkLc7wcI%2FVXNcmSkH6ewYJR2DWJiu71%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;615&quot; height=&quot;401&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1128&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;&lt;span style=&quot;color: #000000;&quot;&gt;서류전형에는 기본인적사항, 학력, 경력, 학부전공이수내역, 외국어능력사항과 함께 4가지 자소서 질문 문항에 대한 답변을 적게 됩니다. 하이닉스의 서류전형에서 가장 중요한점은 개인적으로 &lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;학점, 학력, 자소서문항&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이라는 생각이 들었습니다. '서류전형만 통과해도 반절은 왔다' 라는 생각이 들만큼 하이닉스에서는 서류에서 많이 필터를 거치기 때문에 3단계의 전형 중 가장 중요하다고 생각합니다. 또한 자소서를 기반으로 면접이 이루어지기 때문에 많은 시간을 들여 작성하는 것을 추천드립니다. 학점, 학력과 같은 사항은 자소서를 쓸 당시에는 바꿀수 없는 사항이기 때문에 많은 분들이 걱정하시는 부분중 하나입니다. 하지만 여러명의 최종합격자 분들과 대화했을때 제가 느낀 점은 물론 학력도 하이닉스 합격에 있어서 중요한 지표중 하나지만, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;본인의 직무에 대해 이해도가 높고, 대학생활때 열심히 하신분들이 붙는다는 점&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입니다. 참고를 위해 저의 스펙을 말씀드리자면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;이화여대 컴퓨터공학과 4.1 / 2번의 인턴경험 (SKT, LG전자) / 토익스피킹 LV7 / 2번의 개발동아리(교내, 교외) / 프로젝트 4개(전공팀플젝 제외)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정도의 스펙을 보유하고 있습니다. 실제로 면접전형에서 받은 질문 중 70%가 인턴경험, 동아리활동 에서 나온만큼, 본인이 했던 활동에 대해 충분히 설명이 가능한경우에 쓰는 것이 좋다고 생각합니다. 특별한 자격증이나 동아리활동이 있는 경우에도 적는 것이 좋다고 느꼈는데, 직무와 관련이 없는 자격증이였지만, 면접때 자소서에 기재한 저의 열정과 자격증을 얻는 과정을 연결지어 답변했더니 면접분위기가 아주좋았습니다. 직무와 관련이 없더라도 본인의 성향을 잘 나타낼수있는 활동이라면 적으시는 것을 추천드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자소서 문항은 4가지입니다. &lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자발적으로 최고수준의 목표를 세우고 끈질기게 성취한 경험 / 새로운것을 접목하거나 남다른 아이디어를 통해 문제를 개선했던 경험 / 지원분야의 전문성을 키우기 위해 꾸준히 노력한경험 / 팀워크를 발휘하여 공동의 목표달성에 기여한 경험&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에 대한 질문입니다. 글자수 제한은 모두 1000자 이내인데, 저는 거의 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1000자를 꽉 채워서 제출&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하였습니다. 4가지 문항모두 개발과 관련지어 작성하였고, 선택질문에 대한 답변은 추가적으로 하지 않았기 때문에 결과적으로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;필수였던 4개의 답변만 제출&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하였습니다. 하이닉스는 특이하게 질문이 굉장히 길고 상세합니다. 괄호안에 친절하게 어떤 내용이 들어가면 좋다라는 것을 명시해주는데, 이 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;괄호안의 조건들을 순서대로 연결&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지어 글을 쓰시는것을 추천드립니다. 전문가 분들께 자소서 첨삭을 받을때 항상 칭찬을 받은 점이, 괄호안의 조건들이 모두 답변에 녹아있기때문에 자소서 점수가 높을 것이다 라는 점이였습니다. 추가적으로 꿀팁을 알려드리자면, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;소제목&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;을 꼭 달아주시는것이 좋습니다. 평가자분들이 한눈에 알아볼수 있게끔 키워드를 중심으로 궁금하게 작성한다면 더 높은 점수를 받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2월 28일 접수마감 후, 3월 11일 금요일 5시 17분에 합격메일을 수신하였습니다. 합격메일을 기다리는 순간이 가장 떨렸는데요, 전형마다 메일 수신 날짜와 시각을 작성해놓을테니 참고하시면 좋을것 같습니다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. SKCT ( 코딩테스트와 인성검사) &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;962&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/comiHE/btrKl2MgXSC/KreJLccTjkFLE6Pkx0cEU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/comiHE/btrKl2MgXSC/KreJLccTjkFLE6Pkx0cEU0/img.png&quot; data-alt=&quot;SKCT 합격메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/comiHE/btrKl2MgXSC/KreJLccTjkFLE6Pkx0cEU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcomiHE%2FbtrKl2MgXSC%2FKreJLccTjkFLE6Pkx0cEU0%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;677&quot; height=&quot;374&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;962&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;SKCT 합격메일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;IT직무는 코딩테스트를 보게 됩니다. 3월 19일 토요일에 온라인으로 진행되었으며,&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;카메라를 연결해야하고 검색은 불가능&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;합니다. 오전 10시부터 12시까지&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; 2시간동안 4문제를 풀어야하며, 언어는 C++ 고정&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입니다. 저는 원래 코딩테스트 주언어를 파이썬으로 사용하고 있었기 때문에 3월 11일 합격메일을 수신한 후, 일주일동안 C언어를 공부하였습니다. 밥먹고 자는 시간빼고 C언어를 공부하였고, 주로 백준과 프로그래머스를 사용하여 공부하였습니다. 하이닉스 코딩테스트의 경우, 타기업에 비해 난이도가 높은 편은 아닙니다만, 예전에 비해 점점 더 어려워지고있고, 언어가 한정적이라는 점때문에 어렵게 느껴집니다. 제가 봤던 코딩테스트에서는 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;완전탐색, BFS/DFS, DP, 구현&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;과 관련된 문제가 나왔습니다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;문제순서가 난이도 순서는 아니기 때문&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에, 문제를 잘 살펴보시고 자신있는 문제서부터 푸는것을 추천드립니다. 저는 따로 면접에서 코드리뷰는 실시하지 않았으나, 면접방식이 어떻게 바뀔지 모르기 때문에 코딩테스트 후에 복기를 해놓는 것을 추천드립니다. 당시 코딩테스트 문제와 유사했던 문제의 링크를 하단에 첨부해둘테니 참고하시기 바랍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1시부터는 따로 인성검사를 실시하게 됩니다. 소요시간은 약 40~50분 사이이며, 시간내에 인성 질문에 대해 답변을 체크하는 형식입니다. 이 부분은 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;솔직하게 답변&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하는 것이 좋다고 생각합니다. 물론 SK하이닉스의 인재상에 맞게 답변하는 것도 중요하지만, 본인이 답변한 내용이 면접에서의 본인과 다를 경우에는 면접결과에 좋지 않은 영향을 미칠 것이라는 생각이 듭니다. 저는 인성검사에서 솔직하게 열정적이고 매사에 진중한 모습으로 답변하였고, 그 모습그대로를 면접장에서 보여드렸습니다. 또한 문항수가 굉장히 많은데, 앞에서의 답변과 뒤에서의 답변이 일치하는 것도 중요하므로, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;앞에서의 답변을 기억하고 넘어가는것&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 좋습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3월 19일 코딩테스트 실시 후에, 3월 25일 금요일 오후 5시 27분에 합격메일을 수신하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;* 코딩테스트전에 아래의 문제들을 풀어보세요 * &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/81302&quot; target=&quot;_self&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/81302&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1913&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/1913&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11005&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://www.acmicpc.net/problem/11005&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/12983&quot; target=&quot;_self&quot;&gt;&lt;span&gt;https://programmers.co.kr/learn/courses/30/lessons/12983&lt;/span&gt;&lt;/a&gt;&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. 면접전형 &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;828&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HtUu7/btrKlqfyTTp/yKpQUkcm9qCHYdj9agHdp1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HtUu7/btrKlqfyTTp/yKpQUkcm9qCHYdj9agHdp1/img.jpg&quot; data-alt=&quot;건강검진까지 통과 후 받은 입사선물&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HtUu7/btrKlqfyTTp/yKpQUkcm9qCHYdj9agHdp1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHtUu7%2FbtrKlqfyTTp%2FyKpQUkcm9qCHYdj9agHdp1%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;544&quot; height=&quot;708&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;1078&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;&lt;span style=&quot;color: #000000;&quot;&gt;면접전형은 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4월 4일 ~ 19일 사이에 온라인으로 진행&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;되었습니다. 저는 상대적으로 늦게 면접 일정이 잡혔지만, 같은 직무여도 굉장히 빠르게 보시는 분들도 계셨습니다. 또한 최종합격자 분들과 대화를 나눠본 결과,&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;면접 일정이 최종합불에는 영향을 미치지 않는다&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;는 생각이 들었습니다. 따라서 일정신경쓰시지 마시고 준비하시면 될것같습니다. 지원자마다 면접 시간이 상이한데, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;평균적으로 약 25~30분&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;동안 면접을 봅니다. 이때 인성질문과 직무질문에 대한 질문을 쉴새없이 받는다고 생각하시면 됩니다. 저는 인성질문을 대체로 받았는데, 다른 분들께서는 직무질문도 많이 받았다라고 하시니 골고루 준비를 하시면 될 것 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 질문이 나왔는지에 대해서 말씀드릴수는 없지만 제가 준비한 질문들을 공유해보자면, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;인성질문&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에서는 1분 자기소개, 지원 이유, 불화 해결방법, 되고싶은 개발자, 존경하는 사람, 나의 장단점, 인턴경험, 동아리활동 등에 대한 질문을 약 30개정도 만들었고 그에 대한 답변을 연습했습니다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;직무질문&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;에서는 반도체, 펌웨어, 지원직무가 정확히 무슨일을 하는지, ESG에 대한 질문을 약 30개 정도 만들었고 그에 대한 답변을 연습했습니다. 이렇게 연습했던것이 면접에 도움이 되었다고 생각하고, 하이닉스에 대한 기업조사는 기본이라고 생각합니다. 하이닉스 공식 홈페이지를 참고하여 답변을 만들어나가시길 바랍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4월 19일 모든 지원자분들의 면접이 끝난후에, 최종합격메일은 5월 3일 화요일 5시 50분에 수신하였습니다.&lt;/span&gt;&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. 최종합격 후기 &lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;건강검진, OT까지 모두 참여했지만 최종적으로는 입사하지 않았습니다. 너무나 좋은 회사지만 제가 좀더 하고싶은 일을 하는 것이 맞다라는 생각이들어 입사를 포기하게 되었습니다. 오랜기간동안 전형이 진행되는 만큼, 개인적으로 마음을 다잡기가 힘든순간이 여러차례 왔습니다. 결과메일이 언제올까 노심초사하게되고, 다른 지원자 분들과의 비교를 통해 나의 답변이 틀렸나 라는 생각도 들었습니다. 하지만 그럴때마다, 조금 더 직무에 대한 이해도를 높이려 공부를 하였고, &quot;지금 할 수 있는 일을 하자&quot; 라는 마인드로 마음을 다잡으려 노력하였습니다. 채용과정을 거치면서, 반도체 산업과 IT직무에 대한 부분도 자세히 알게되었지만, 정신적으로 더 성숙해졌다는 생각이 듭니다. 후배가 하이닉스 하반기 지원 시작했는데 막막하다라는 말을 듣고 최종합격수기를 작성해보았습니다. 제글이 도움이 되길 바라며, 궁금하신 점은 댓글로 남겨주시면 아는선에서 답변해드리도록 하겠습니다. 감사합니다. &lt;/span&gt;&lt;/p&gt;</description>
      <category>Yeon`s Diary/취준일기</category>
      <category>hynix</category>
      <category>sk</category>
      <category>최종합격</category>
      <category>하이닉스</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/104</guid>
      <comments>https://yeon-code.tistory.com/104#entry104comment</comments>
      <pubDate>Mon, 22 Aug 2022 23:05:09 +0900</pubDate>
    </item>
    <item>
      <title>2022년 상반기 LINE 라인 최종 합격 수기</title>
      <link>https://yeon-code.tistory.com/103</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2022-06-03 오후 10.32.13.png&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;1150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csnEJE/btrKhkACI92/GQ8wAbqjFS1fUjvOcEc3jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csnEJE/btrKhkACI92/GQ8wAbqjFS1fUjvOcEc3jk/img.png&quot; data-alt=&quot;언제봐도 짜릿한 최종합격 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csnEJE/btrKhkACI92/GQ8wAbqjFS1fUjvOcEc3jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsnEJE%2FbtrKhkACI92%2FGQ8wAbqjFS1fUjvOcEc3jk%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;634&quot; height=&quot;507&quot; data-filename=&quot;edited_스크린샷 2022-06-03 오후 10.32.13.png&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;1150&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;2022년 상반기 라인 신입 공개 채용에 ✨&lt;b&gt;최종합격&lt;/b&gt;✨ 했습니다. 제가 지원했던 직무는 &lt;b&gt;Web FrontEnd Engineer&lt;/b&gt; 이며, 라인플러스 법인 소속입니다. 지원서접수, 코딩테스트, 필기테스트, 1차 면접, 2차면접의 채용과정을 거쳤는데, 각 단계에 대한 후기와 지원꿀팁을 순서대로 적어보려 합니다. 제글이 도움이 되길 바라며, 궁금하신 점은 언제든지 댓글로 달아주시면 됩니다!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-03 오후 10.37.35.png&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N7PeK/btrDVmSkQd6/BFmMyPt9qKqp27nZTjHuI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N7PeK/btrDVmSkQd6/BFmMyPt9qKqp27nZTjHuI0/img.png&quot; data-alt=&quot;2022년 라인 상반기 채용과정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N7PeK/btrDVmSkQd6/BFmMyPt9qKqp27nZTjHuI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN7PeK%2FbtrDVmSkQd6%2FBFmMyPt9qKqp27nZTjHuI0%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;2156&quot; height=&quot;670&quot; data-filename=&quot;스크린샷 2022-06-03 오후 10.37.35.png&quot; data-origin-width=&quot;2156&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2022년 라인 상반기 채용과정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 지원서 접수&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지원서에는 기본인적, 학력, 경력, 어학사항과 함께 3가지의 자소서 질문 문항에 대한 답변을 적게됩니다. 지원서 접수단계의 경우 적혀있는 것처럼 지원자격만을 확인하기 때문에 자격만 갖춘다면 코딩테스트를 응시할 수 있지만, 필기테스트의 지원자격을 판단할때는 지원서 + 코딩테스트 결과를 같이 고려하여 합격여부가 나오기 때문에 열심히 작성을 하는 것이 좋습니다. 또한, 자소서 기반으로 면접이 진행되기때문에 최대한 상세하게 적는 것이 좋습니다. 참고를 위해 저의 서류 스펙을 말씀드리자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;이화여대 컴퓨터공학과 4.1 / 2번의 인턴경험 (SKT, LG전자) / 토익스피킹 LV7 / 2번의 개발동아리(교내, 교외) / 프로젝트 4개(전공팀플젝 제외)&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정도의 스펙을 보유하고 있습니다. 자소서 문항은 3가지로, 의미있었던 개발경험 / CS지식과 기술적역량 / 협업 경험에 대한 질문입니다. 글자수 제한은 딱히 없었어서 1000자 내외정도로 작성하였고, 한 문항당 2개의 프로젝트 경험을 서술하였습니다. 배포까지 했던 프로젝트는 실제 서비스 링크를 첨부하였습니다. 자소서를 적을때는 실제 기술명과 함께 최대한 자세하게 서술하였고, 자세하게 서술했던점이 후에 면접 과정에서도 그것과 관련된 질문에 답변하는데에 도움이 되었다고 생각합니다. 프로젝트를 2개이상 언급할 경우 번호를 달아 구분되게 하였고, 소제목을 달아 어떤 줄거리인지 한눈에 파악하게끔 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첨부자료항목에 포트폴리오 파일과 깃허브링크를 첨부할 수 있습니다. 빈항목으로 두는 것보단 파일과 링크 모두 첨부하는 것을 추천드립니다! 포트폴리오는 20장정도로 작성하였고, 작성법에 대해선 추후에 게시글을 업로드할 예정입니다. 블로그 링크또한 포르폴리오에 첨부하여서 채용담당자분께서 확인하실 수 있도록 하였고, 실제 면접장에서 블로그 관련 질문또한 받았습니다. 자소서와함께 첨부자료도 모두 확인하여 면접질문이 정해지므로, 자세하게 작성하여 첨부하시면 좋을 것 같습니다.&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;&lt;b&gt;2. 코딩테스트&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.13.19.png&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dt2OE3/btrDVCU3lyl/Gf5IuxXaZgk0JvGFLtK0Fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dt2OE3/btrDVCU3lyl/Gf5IuxXaZgk0JvGFLtK0Fk/img.png&quot; data-alt=&quot;코딩테스트 합격 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dt2OE3/btrDVCU3lyl/Gf5IuxXaZgk0JvGFLtK0Fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdt2OE3%2FbtrDVCU3lyl%2FGf5IuxXaZgk0JvGFLtK0Fk%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;279&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.13.19.png&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;586&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;3월 26일 토요일 오전 10시부터 1시까지, 총 &lt;span style=&quot;color: #ee2323;&quot;&gt;3시간동안 6문제&lt;/span&gt;를 풀었습니다. &lt;b&gt;오픈인터넷, IDE사용가능&lt;/b&gt;인 시험이므로 따로 카메라를 설치하진 않았습니다. 체감상 난이도는 백준티어로 표현하면 &lt;b&gt;실버4, 골드 5, 실버 1, 골드 3, 골드 4, 골드2&lt;/b&gt; 이렇게 여섯문제가 나왔다고 생각합니다. 저는 다섯문제를 풀었지만 끝나고 생각해보니 한문제는 효율성에서 오류날 것이라 생각하여 정확하게는 4문제정도 정확하게 풀었다고 볼 수 있을 것 같습니다. 통상적으로 6문제중에 4문제는 맞춰야 필기테스트를 볼 수 있는 자격이 주어지는 것 같습니다. 저는 전략적으로 다섯문제만 정확하게 풀어내자라는 마인드로 1개의 문제는 아예 풀지 않았고, 다섯문제를 푼 후 남은 1시간 동안은 엣지케이스를 생각해보며 검토하고 주석을 달았습니다. 테스트케이스는 3개정도 주어지고, 본인이 케이스를 추가하여 테스트를 돌려볼 수는 있습니다. 나중에 히든케이스로 채점하기 때문에 테스트 케이스가 다 맞았다고 하여, 그 문제가 맞았다고 확답할 수 없습니다. 라인 코딩테스트를 잘풀기 위해서는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;구현 / 문자열 조작(문자열 나누기, 대소문자 등) / 완전탐색 / 스택, 큐, 집합 자료구조 / BFS, DFS&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에 대한 문제에 대해서는 확실히 익히고 들어가면 좋을 것 같습니다. 프로그래머스의 LV2 문제나 백준의 실버 문제들에 대해선 15분 이내에 빠르게 풀 수 있는 실력은 무조건 갖추고, 프로그래머스의 LV3문제나 백준의 골드4정도의 문제에 대해서는 45분 이내에 풀어내는 정도의 실력을 갖춘다면 라인 코딩테스트는 무난하게 통과할 수 있을 것이라 생각합니다.&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;&lt;b&gt;3. 필기테스트&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.21.29.png&quot; data-origin-width=&quot;1576&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXwT4I/btrDXnWBXUW/czIbkiPR8Pu7mBz5eU4z9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXwT4I/btrDXnWBXUW/czIbkiPR8Pu7mBz5eU4z9K/img.png&quot; data-alt=&quot;필기테스트 합격메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXwT4I/btrDXnWBXUW/czIbkiPR8Pu7mBz5eU4z9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXwT4I%2FbtrDXnWBXUW%2FczIbkiPR8Pu7mBz5eU4z9K%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;700&quot; height=&quot;336&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.21.29.png&quot; data-origin-width=&quot;1576&quot; data-origin-height=&quot;756&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;필기테스트는 코딩테스트 일주일 후에 4월 2일 토요일 오전 10시부터 11시 30분까지 &lt;span style=&quot;color: #ee2323;&quot;&gt;총 90분&lt;/span&gt;동안 진행하였습니다. 다만, 코딩테스트 결과는 수요일 오후에 발표되었기 때문에 결과를 보고 공부를 시작하신다면 늦을거라 생각합니다. 만약 코딩테스트를 4문제정도 정확하게 풀어냈다라고 생각이 드신다면, 바로 필기테스트에 대해 공부를 하셔야 할것같습니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;약 30~40문항&lt;/span&gt;정도 나오기 때문에 한문항당 쓸 수 있는 시간은 2~3분정도 입니다. 필기테스트 범위는 4년간 컴퓨터공학 에서 배우는 전공과목입니다. 중요한 순으로 추려보자면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;네트워크 / 운영체제 / 데이터베이스 / 보안 / 자료구조와 알고리즘 /&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;C 언어&lt;/span&gt;&lt;/b&gt;&amp;nbsp; / 컴퓨터구조 / OOP / 오토마타 / 디자인패턴&lt;/span&gt;&lt;/b&gt;&amp;nbsp;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학부시절 열심히 정리를 해놓았다면 도움이 될 것 같습니다! 자세하고 꼼꼼하게 계산법까지 공부를 한다기 보다는, 해당 전공에 등장하는 분야와 용어에 대한 정의를 정확하게 알아놓자 라는 식으로 공부를 하시면 좋을 것 같습니다. 또한 필기테스트에서는 &lt;b&gt;오픈인터넷이 불가&lt;/b&gt;하며 카메라를 설치해야하는 시험이기 때문에 누가누가더 많이 암기하냐의 싸움입니다. 코딩테스트가 끝난후 일주일동안 시간을 잘 배분하여 여러 분야의 범위를 커버할 수 있도록 계획을 잘 세우는 것이 중요할 것 같습니다. 만약 비전공자이시거나 학교수업시간에 정리를 하지 않으셨다면, 케이묵 사이트에서 해당 전공과목에 대한 수업을 들으시거나, 한재엽님의 깃허브를 참고하시면 좋을 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.kmooc.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.kmooc.kr/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654269559641&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;| K-MOOC&quot; data-og-description=&quot;K-MOOC 소개 K-MOOC는 온라인을 통해서누구나, 어디서나 원하는 강좌를 무료로 들을 수 있는온라인 공개강좌 서비스로 2015년에 시작된한국형 무크입니다. more 강좌찾기 K-MOOC의 다양한 강좌를 통해 &quot; data-og-host=&quot;www.kmooc.kr&quot; data-og-source-url=&quot;http://www.kmooc.kr/&quot; data-og-url=&quot;http://www.kmooc.kr/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://www.kmooc.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://www.kmooc.kr/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;| K-MOOC&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;K-MOOC 소개 K-MOOC는 온라인을 통해서누구나, 어디서나 원하는 강좌를 무료로 들을 수 있는온라인 공개강좌 서비스로 2015년에 시작된한국형 무크입니다. more 강좌찾기 K-MOOC의 다양한 강좌를 통해&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.kmooc.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654269570191&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - JaeYeopHan/Interview_Question_for_Beginner: Technical-Interview guidelines written for those who started studying progr&quot; data-og-description=&quot;:boy: :girl: Technical-Interview guidelines written for those who started studying programming. I wish you all the best. :space_invader: - GitHub - JaeYeopHan/Interview_Question_for_Beginner: Techn...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot; data-og-url=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/U0JWE/hyOCDhUfsc/BGPKnXsEWC4VZuQijtTtU1/img.png?width=721&amp;amp;height=458&amp;amp;face=0_0_721_458&quot;&gt;&lt;a href=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/JaeYeopHan/Interview_Question_for_Beginner&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/U0JWE/hyOCDhUfsc/BGPKnXsEWC4VZuQijtTtU1/img.png?width=721&amp;amp;height=458&amp;amp;face=0_0_721_458');&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;GitHub - JaeYeopHan/Interview_Question_for_Beginner: Technical-Interview guidelines written for those who started studying progr&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;:boy: :girl: Technical-Interview guidelines written for those who started studying programming. I wish you all the best. :space_invader: - GitHub - JaeYeopHan/Interview_Question_for_Beginner: Techn...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 1차면접&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.29.49.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O51k5/btrDUNJxId6/SLsMoGLxbZKsM74YgKcTM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O51k5/btrDUNJxId6/SLsMoGLxbZKsM74YgKcTM1/img.png&quot; data-alt=&quot;1차 면접 합격메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O51k5/btrDUNJxId6/SLsMoGLxbZKsM74YgKcTM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO51k5%2FbtrDUNJxId6%2FSLsMoGLxbZKsM74YgKcTM1%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;717&quot; height=&quot;327&quot; data-filename=&quot;스크린샷 2022-06-04 오전 12.29.49.png&quot; data-origin-width=&quot;859&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1차 면접 합격메일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차면접은 4월 18일 월요일부터 5월 2일 월요일까지 진행되었습니다. 그 중 저는 4월 21일에 면접을 보았고, 약&lt;span style=&quot;color: #ee2323;&quot;&gt; 60분동안&lt;/span&gt; 기술면접을 보았습니다. 총 2명의 면접관분들과 함께 진행하였고, 여러 분야에 걸친 기술문제를 받았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;인성질문(5분정도) / 프로젝트 질문(5분정도) / 리액트 질문 / 돔과 가상돔 / CSR SSR / SEO / 시맨틱마크업 / 네트워크 계층 / 마크업 최적화 / JS엔진 / 프로세스와 스레드 / 자료구조&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에 대한 질문을 50분동안 쉴새없이 받았습니다. 프론트엔드에 관련한 질문부터 시작해서 네트워크, 운영체제 등 CS와 관련된 질문들도 받았기 때문에, 필기테스트에서 준비했던 것과 별개로 답변하는 연습을 많이 하셔야합니다. 본인이 수행했던 프로젝트에 대해서는 막힘없이 술술 이야기 할 수 있어야하며, 그외의 기술질문에 대해서는 &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;정말 깊이&lt;/b&gt; 공부&lt;/span&gt;하셔야 합니다. 저는&lt;b&gt; 200문항에 대한 질문과 답변&lt;/b&gt;을 준비하였고, 그외에도 노트정리를 통해 각 전공과목에 대한 공부를 하였습니다. 정말 간단한 예를 들어보자면,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;브라우저 동작과정에 대해서 말해보세요 -&amp;gt; HTML을 파싱하여 어쩌구 -&amp;gt; 파싱의 뜻이 무엇인가요? -&amp;gt; 자바스크립트엔진이 어쩌구 -&amp;gt; 자바스크립트 엔진은 어떤 동작과정을 가지나요? -&amp;gt; 이벤트루프와 콜스택 어쩌구 -&amp;gt; 그럼 이벤트루프와 콜스택은 어디에 존재하나요?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 같은 과정을 통해 정말 모를때까지 깊게 질문을 하십니다. 위의 예시는 제가 방금 만들어낸거라 허접하지만, 실제 면접에서는 정말 논리적이고 타당한 과정으로 깊게 탐구하게 됩니다. 1차면접을 거치면서 정말 공부를 많이 했고, 면접 50분동안에 질문들을 들으면서 감탄이 나올정도로 질문들이 너무 좋았습니다. 이런 면접 경험을 거쳤다는 것이 영광이고 큰 교훈이였습니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;30여정도의 질문중에 대답을 못한건 4개정도&lt;/span&gt;라고 생각하며, 그외의 질문들은 제가 아는것을 정확히 전달하려고 노력하였습니다. 50분동안의 기술면접이 끝난후에 나머지 10분동안에는 제가 면접관 분들께 질문할 수 있는 시간이 주어집니다. 저는 라인 기술블로그에서 해당 직무와 관련된 글은 모두 읽었고, 그중에서 궁금한 점에 대해서 여쭈어 보았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://engineering.linecorp.com/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://engineering.linecorp.com/ko/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654271041043&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;Main - LINE ENGINEERING&quot; data-og-description=&quot;LINE의 미션은 사람과 사람, 정보,&amp;nbsp;서비스 사이의 거리를 좁히는 것입니다. TAKE OWNERSHIP LINE 개발자들은 자신의 프로젝트에 오너십을 가지고 최고의 결과물을 만들어냅니다 BE OPEN LINE 엔지니어들&quot; data-og-host=&quot;engineering.linecorp.com&quot; data-og-source-url=&quot;https://engineering.linecorp.com/ko/&quot; data-og-url=&quot;https://engineering.linecorp.com/ko/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bKhQcO/hyOEkVjhGS/0vZ8jUiq25bFT5lsvK7KF1/img.jpg?width=360&amp;amp;height=200&amp;amp;face=0_0_360_200,https://scrap.kakaocdn.net/dn/bo0eU4/hyOEoXHUhS/rLZnuy0zewaxr3iroi6JOK/img.jpg?width=360&amp;amp;height=200&amp;amp;face=0_0_360_200,https://scrap.kakaocdn.net/dn/0WJty/hyOEdBSnTM/PPHTdcb368KcUSKGBalg01/img.jpg?width=360&amp;amp;height=200&amp;amp;face=220_66_243_91&quot;&gt;&lt;a href=&quot;https://engineering.linecorp.com/ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://engineering.linecorp.com/ko/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bKhQcO/hyOEkVjhGS/0vZ8jUiq25bFT5lsvK7KF1/img.jpg?width=360&amp;amp;height=200&amp;amp;face=0_0_360_200,https://scrap.kakaocdn.net/dn/bo0eU4/hyOEoXHUhS/rLZnuy0zewaxr3iroi6JOK/img.jpg?width=360&amp;amp;height=200&amp;amp;face=0_0_360_200,https://scrap.kakaocdn.net/dn/0WJty/hyOEdBSnTM/PPHTdcb368KcUSKGBalg01/img.jpg?width=360&amp;amp;height=200&amp;amp;face=220_66_243_91');&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;Main - LINE ENGINEERING&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;LINE의 미션은 사람과 사람, 정보,&amp;nbsp;서비스 사이의 거리를 좁히는 것입니다. TAKE OWNERSHIP LINE 개발자들은 자신의 프로젝트에 오너십을 가지고 최고의 결과물을 만들어냅니다 BE OPEN LINE 엔지니어들&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;engineering.linecorp.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 2차 면접&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bM2Guy/btrDV1twlsQ/8hLz1SLP9NXtLKR1FxH2rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bM2Guy/btrDV1twlsQ/8hLz1SLP9NXtLKR1FxH2rk/img.png&quot; data-alt=&quot;최종합격메일에 실린 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bM2Guy/btrDV1twlsQ/8hLz1SLP9NXtLKR1FxH2rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbM2Guy%2FbtrDV1twlsQ%2F8hLz1SLP9NXtLKR1FxH2rk%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;167&quot; height=&quot;143&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;143&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;2차면접은 5월 16일 월요일부터 5월 26일 목요일까지 진행되었습니다. 그 중 저는 5월 16일에 면접을 보았고, &lt;span style=&quot;color: #ee2323;&quot;&gt;약 60분&lt;/span&gt;정도 진행되었습니다. 저는 2차면접에서는 여러&lt;b&gt; 인성질문과 프로젝트 관련질문을 7:3 비율&lt;/b&gt;로 받았습니다. 하지만 다른 분들중에서는 1차면접보다도 더 어려운 기술면접을 보셨다는 분들고 계셨고, 인성질문만 받았다는 분들고 계셨습니다. 따라서 일단 1차면접에서 준비한 면접 문항들은 다시 처음부터 공부하면서 혹시나 빠트린것이 있지는 않은지 확인하셔야하며, 1차면접에서 대답하지 못했던 것들에 대해서는 따로 적어두었다가 공부를 하셔야합니다. 또한 본인이 작성한 지원서를 다시 보면서 프로젝트 관련하여 제대로 알고있는지, 관련 기술들에 대해 최신기술 현황을 공부하고, 코드를 다시 보면서 복습하시는 것을 추천드립니다. 인성질문에 대한 대비를 하실때에는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;나는 어떤 개발자가 되고싶은가?&amp;nbsp; / 나라는 사람은 어떤 사람이지? / 나의 장단점 / 내가 개발자가 되고싶은 이유 / 나의 개발 가치관 / 내가 라인에서 하고싶은 일 / 내가 라인에 가고싶은 이유 / 마지막으로 정말 드리고 싶은 말&amp;nbsp;&lt;/span&gt;&lt;/b&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 최종합격 후기&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라인의 채용과정을 거치면서 제 자신이 정말 성장했다라는 생각이 듭니다. 여러 분야에 걸쳐서 공부하는 과정에서 제가 그간 얕게 알고있던 내용에 대해서 깊이 공부할 수 있었고, 정말 대단하신 면접관 분들과 질문과 답변을 주고받으며 많은 지식 뿐만 아니라 개발자가 가져야할 자세에 대해 생각해볼 수 있어서 영광이었습니다. 라인에 입사하기까지 약 3주정도의 시간이 남았는데, 입사를 기다리며 라인에서 발간한 책을 읽어보려 합니다. 라인 개발자 분들의 개발이야기를 들으며, 신입 개발자가 가져야할 자세와 앞으로 어떤 개발자가 될 것인지에 대해서 깊게 생각해보는 시간을 가지려고 합니다. 긴글 읽어주셔서 감사하며, 라인에서 동료개발자로 만나뵙길 기원하겠습니다! 궁금하신점은 댓글로 남겨주세요. 감사합니다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2022-06-04-01-06-24.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5RviI/btrDWLKc0Z6/kHwtrPoMBLRVjSnYjX8rik/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5RviI/btrDWLKc0Z6/kHwtrPoMBLRVjSnYjX8rik/img.jpg&quot; data-alt=&quot;오늘 온 따끈따끈한 새책&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5RviI/btrDWLKc0Z6/kHwtrPoMBLRVjSnYjX8rik/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5RviI%2FbtrDWLKc0Z6%2FkHwtrPoMBLRVjSnYjX8rik%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;288&quot; height=&quot;384&quot; data-filename=&quot;KakaoTalk_Photo_2022-06-04-01-06-24.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오늘 온 따끈따끈한 새책&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Yeon`s Diary/취준일기</category>
      <category>LiNE</category>
      <category>라인</category>
      <category>취뽀</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/103</guid>
      <comments>https://yeon-code.tistory.com/103#entry103comment</comments>
      <pubDate>Sat, 4 Jun 2022 00:46:07 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 콜백함수, 콜백지옥</title>
      <link>https://yeon-code.tistory.com/102</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1.&amp;nbsp; 콜백함수란?&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수&lt;/span&gt;이다. 예를들면 A와 B는 토요일 오전 7시에 만나기로 하였다. 둘은 만나기위해 5시에 기상하여야 한다. A는 알람을 5시에 맞춰 푹자다가 기상하였다. 하지만 B는 알람이 고장나서 편히 잠들지 못하고 수시로 일어나서 시간을 확인하다가 기상하였다. 여기서&amp;nbsp;콜백함수를 쓴 사람은 A이다. B는 수시로 시간을 구하는 함수를 직접 호출하였지만 A는 알람을 울리는 함수를 호출할 당시에는 아무것도 하지 않다가 정해진 시간이 되었을때 함수를 호출하였다. B는 함수를 호출하는 제어권을 자신이 가지고 있으면서 함수를 호출하였고, A는 제어권을 알람에게 넘겨주고 취침이라는 다른일을 하다가 함수가 호출되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여기서 콜백함수의 중요한 키워드는&amp;nbsp;제어권이다.&amp;nbsp;콜백함수는 다른 코드에게 인자와 제어권을 함께 넘겨주게 된다. 콜백함수를 위임받은 코드는 자체적인 내부로직에 의해 이 콜백함수를 적절한 시점에 실행한다. 제어권을 넘겨받은 코드는&lt;b&gt; (1)호출하는 시점 (2) 인자의 순서 (3)this 지정&lt;/b&gt;에 대한 제어권을 획득한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1) 호출하는 시점:&lt;/b&gt;&amp;nbsp;setInterval이라고 하는 '다른 코드'에 첫번째 인자로 ex1func 함수를 넘겨주자 제어권을 넘겨받은 setInterval이 스스로 판단에 따라 적절한 시점(0.3)에 익명함수를 실행했다. 따라서 콜백함수의 제어권을 넘겨받은 코드는&amp;nbsp;콜백함수 호출시점에 대한 제어권을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.38.10.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsY2I8/btrB4LSPB05/5zQnqwX4n5JDhKFKoVfuTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsY2I8/btrB4LSPB05/5zQnqwX4n5JDhKFKoVfuTK/img.png&quot; data-alt=&quot;호출시점에 대한 제어권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsY2I8/btrB4LSPB05/5zQnqwX4n5JDhKFKoVfuTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsY2I8%2FbtrB4LSPB05%2F5zQnqwX4n5JDhKFKoVfuTK%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;300&quot; height=&quot;196&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.38.10.png&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;196&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2) 인자의 순서:&lt;/b&gt; 밑의 예시를 보면 첫번째 예시에서는 첫번째 인덱스 0 에 대한 콜백함수는 currnetValue에는 10, index에는 0이 담기고 15를 반환한다. 두번째 인덱스 1에 대한 콜백함수는 currentValue에는 20, index에는 1이 담기고 25를 반환한다. 두번째 예시에서 컴퓨터는 순서에 의해서만 각각을 구분하고 인식한다. map 메서드에 정의된 규칙에 따라 함수를 작성해야하며, map메서드에는 콜백함수를 호출할 때 인자의 순서에 대한 정보가 들어있다. 따라서 콜백함수의 제어권을 넘겨받은 코드는 콜백함수를 호출할 때&amp;nbsp;인자에 어떤값들을 어떤 순서로 넘길 것인지에 대한 제어권을 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.40.40.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPog2S/btrB2YyRhh6/dxiKo0bKjtP9zD2jlJt3Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPog2S/btrB2YyRhh6/dxiKo0bKjtP9zD2jlJt3Dk/img.png&quot; data-alt=&quot;인자의 순서에 대한 제어권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPog2S/btrB2YyRhh6/dxiKo0bKjtP9zD2jlJt3Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPog2S%2FbtrB2YyRhh6%2FdxiKo0bKjtP9zD2jlJt3Dk%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;416&quot; height=&quot;323&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.40.40.png&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;323&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3) this 지정:&lt;/b&gt; 밑의 예시에서 마지막인자에 담긴 userData는 call함수의 첫번째 인자로 넘어가게 되어서&amp;nbsp;this객체가 매핑된다. 콜백함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다. 따라서 call/ apply 함수를 이용하여 첫번째 인자에 콜백함수 내부에서의&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;this가 될 대상을 명시적으로 바인딩&lt;/span&gt;해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.49.26.png&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSkMNx/btrB1nMHZ5i/ovTLcrcYAQHEvJw0Xkzwjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSkMNx/btrB1nMHZ5i/ovTLcrcYAQHEvJw0Xkzwjk/img.png&quot; data-alt=&quot;this 지정에 대한 제어권&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSkMNx/btrB1nMHZ5i/ovTLcrcYAQHEvJw0Xkzwjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSkMNx%2FbtrB1nMHZ5i%2FovTLcrcYAQHEvJw0Xkzwjk%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;411&quot; height=&quot;251&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.49.26.png&quot; data-origin-width=&quot;411&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;this 지정에 대한 제어권&lt;/figcaption&gt;
&lt;/figure&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;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 콜백지옥이란?&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;콜백함수를 익명함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상&lt;/span&gt;을 말한다. 현대의 자바스크립트는 웹의 복잡도가 높아진 만큼 비동기적인 코드의 비중이 예전보다 훨씬 높아진 상횡이며, 비동기적인 코드는 별도의 요청, 실행 대기, 보류 등으로 콜백지옥에 빠지기 훨씬 쉽다.&lt;/span&gt;&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;스크린샷 2022-05-13 오후 3.52.37.png&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/etZhrW/btrB44knCqy/lVkGOMCwiTIvo4O92RDvIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/etZhrW/btrB44knCqy/lVkGOMCwiTIvo4O92RDvIk/img.png&quot; data-alt=&quot;콜백지옥 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/etZhrW/btrB44knCqy/lVkGOMCwiTIvo4O92RDvIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FetZhrW%2FbtrB44knCqy%2FlVkGOMCwiTIvo4O92RDvIk%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;306&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.52.37.png&quot; data-origin-width=&quot;302&quot; data-origin-height=&quot;306&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;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;해결방법 1) 기명함수로 전환&lt;/b&gt;: 기명함수로의 변환은 코드의 가독성을 높인다는 장점이 있지만, 일회성 함수를 전부 변수에 할당해야 하는 것이 반복되고 복잡하여 좋은 방법은 아니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.53.55.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b01yxW/btrB2X04igc/3ZZ7lTw6nQQpR02GQaPaK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b01yxW/btrB2X04igc/3ZZ7lTw6nQQpR02GQaPaK0/img.png&quot; data-alt=&quot;기명함수로 전환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b01yxW/btrB2X04igc/3ZZ7lTw6nQQpR02GQaPaK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb01yxW%2FbtrB2X04igc%2F3ZZ7lTw6nQQpR02GQaPaK0%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;325&quot; height=&quot;440&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.53.55.png&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;440&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;&lt;b&gt;해결방법 2) promise 사용&lt;/b&gt;: ES6에 등장한 promise를 사용할 수도 있다. new연산자와 함께 호출한 promise의 인자로 넘겨주는 콜백함수는 호출할때 바로 실행되지만 그 내부에 resolve 또는 rejected 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 다음으로 넘어가지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.59.14.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/436g0/btrB2Y6MkRj/BwK3knLSl0WuctyS7hYz11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/436g0/btrB2Y6MkRj/BwK3knLSl0WuctyS7hYz11/img.png&quot; data-alt=&quot;promise 사용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/436g0/btrB2Y6MkRj/BwK3knLSl0WuctyS7hYz11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F436g0%2FbtrB2Y6MkRj%2FBwK3knLSl0WuctyS7hYz11%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;495&quot; height=&quot;309&quot; data-filename=&quot;스크린샷 2022-05-13 오후 3.59.14.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;promise 사용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결방법 3) promise + async/await:&lt;/b&gt; ES2017에는 가독성이 뛰어나면서도 작성법이 간단한 async/await 기능이 추가되었다. &lt;span style=&quot;color: #333333;&quot;&gt;비동기작업을 하고자하는 함수앞에 async를 표시하고 함수 내부에서 실질적으로 비동기 작업이 필요한 위치마다 await를 표기하면&amp;nbsp;자동적으로 await 뒤의 내용을 promise로 전환하고 해당내용이 resolve된 이후에야 다음으로 진행한다. promise then과 같은 원리이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-13 오후 4.01.43.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6dOP7/btrB5paLdRm/PXX9IpuAqycKPlIqiI3RM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6dOP7/btrB5paLdRm/PXX9IpuAqycKPlIqiI3RM0/img.png&quot; data-alt=&quot;promise + async/await&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6dOP7/btrB5paLdRm/PXX9IpuAqycKPlIqiI3RM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6dOP7%2FbtrB5paLdRm%2FPXX9IpuAqycKPlIqiI3RM0%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;420&quot; height=&quot;397&quot; data-filename=&quot;스크린샷 2022-05-13 오후 4.01.43.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;promise + async/await&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;✨ 이 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정재남님의 코어자바스크립트&lt;/b&gt;를 참고하여 작성된 글입니다. 프론트엔드 개발자라면 꼭 사서 읽어보시는 것을 추천드립니다. &lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yqEF2/btrBN5kx6t7/a9oWrBnMrZ7hKVPVH6Aji0/img.jpg&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buNgmo/btrB4AqyZ6w/fE8Ku5Fa5ZvszCMaVtVLZ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buNgmo/btrB4AqyZ6w/fE8Ku5Fa5ZvszCMaVtVLZ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buNgmo/btrB4AqyZ6w/fE8Ku5Fa5ZvszCMaVtVLZ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuNgmo%2FbtrB4AqyZ6w%2FfE8Ku5Fa5ZvszCMaVtVLZ0%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;850&quot; height=&quot;478&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JS</category>
      <category>자바스크립트</category>
      <category>정재남</category>
      <category>코어자바스크립트</category>
      <category>콜백지옥</category>
      <category>콜백함수</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/102</guid>
      <comments>https://yeon-code.tistory.com/102#entry102comment</comments>
      <pubDate>Fri, 13 May 2022 16:03:09 +0900</pubDate>
    </item>
    <item>
      <title>[JS] This, Binding</title>
      <link>https://yeon-code.tistory.com/101</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. This 란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서의 this는 상황에 따라 바라보는 대상이 달라진다. 즉, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;실행컨텍스트가 생성될때, 함수가 호출될때 결정&lt;/span&gt;된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 전역공간에서의 This:&lt;/b&gt; 전역공간에서는 &lt;b&gt;전역객체&lt;/b&gt;를 가리키게된다. 브라우저 환경에서 전역객체는 window이고, Node.js에서는 global 이다. 자바스크립트에서 모든 변수는 특정객체의 프로퍼티로서 동작하게되는데, 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.17.21.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZPJEr/btrBUGSGif2/UPURR3ObcgahDPRZwYEhc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZPJEr/btrBUGSGif2/UPURR3ObcgahDPRZwYEhc1/img.png&quot; data-alt=&quot;전역변수와 전역객체&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZPJEr/btrBUGSGif2/UPURR3ObcgahDPRZwYEhc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZPJEr%2FbtrBUGSGif2%2FUPURR3ObcgahDPRZwYEhc1%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;348&quot; height=&quot;220&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.17.21.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;248&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;&lt;b&gt;2) 메서드 내부에서의 this:&lt;/b&gt; 메서드 내부에서는 &lt;b&gt;호출한 주체&lt;/b&gt;에 대한 정보가 담긴다. 어떤함수를 메서드로서 호출하는 경우 호출주체는 함수명앞의 객체가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.21.53.png&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ypAEG/btrBVBQ7ina/gJgvMHA6ci3BPgdt4YxLcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ypAEG/btrBVBQ7ina/gJgvMHA6ci3BPgdt4YxLcK/img.png&quot; data-alt=&quot;메서드로서 호출&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ypAEG/btrBVBQ7ina/gJgvMHA6ci3BPgdt4YxLcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FypAEG%2FbtrBVBQ7ina%2FgJgvMHA6ci3BPgdt4YxLcK%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;449&quot; height=&quot;241&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.21.53.png&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;348&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;&lt;b&gt;3) 함수내부에서의 this:&lt;/b&gt; 함수내부에서는 &lt;b&gt;전역객체를&lt;/b&gt; 바라보게 된다. ES6에서는 함수내부에서 this가 전역객체를 바라보는 문제를 보완하고자&amp;nbsp; this를 바인딩하지 않는 화살표함수를 새로 도입하였고, 그외에도 call, apply, bind의 메서드를 통해 명시적으로 this를 지정할수도 있다. ES5환경에서는 var self 를 선언하여 객체를 바라보게끔 우회해줄수도 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.37.27.png&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOs57f/btrBSMMpU0L/wlko8EItT7AbtmxRm3DPiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOs57f/btrBSMMpU0L/wlko8EItT7AbtmxRm3DPiK/img.png&quot; data-alt=&quot;함수내부에서의 this&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOs57f/btrBSMMpU0L/wlko8EItT7AbtmxRm3DPiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOs57f%2FbtrBSMMpU0L%2Fwlko8EItT7AbtmxRm3DPiK%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;711&quot; height=&quot;267&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.37.27.png&quot; data-origin-width=&quot;1442&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;함수내부에서의 this&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 콜백함수 호출시 함수내부에서의 this:&lt;/b&gt; 콜백함수에서는 제어권을 다른함수에게 넘겨주므로,&lt;b&gt; 제어권을 가진함수&lt;/b&gt;에서의 내부로직에서 정한 규칙에 따라 값이 결정되게 된다. 콜백함수도 함수이기 때문에 기본적으로 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백함수에 별도로 this가 지정된 경우라면 그 대상을 참조하게 된다. 해당 내용은 콜백함수 게시글에서 자세히 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yeon-code.tistory.com/102&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.05.13 - [FrontEnd] - [JS] 콜백함수, 콜백지옥&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1652425529054&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JS] 콜백함수, 콜백지옥&quot; data-og-description=&quot;1. 콜백함수란? 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다. 예를들면 A와 B는 토요일 오전 7시에 만나기로 하였다. 둘은 만나기위해 5시에 기상하&quot; data-og-host=&quot;yeon-code.tistory.com&quot; data-og-source-url=&quot;https://yeon-code.tistory.com/102&quot; data-og-url=&quot;https://yeon-code.tistory.com/102&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bunxAz/hyOoI2Q4zt/lJ4d1CFWeDOWy19Nz5kGrk/img.jpg?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/cIgoNj/hyOoFLPdTZ/kJyugWcP1VJ3oNM51s1aZk/img.jpg?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bxgRwx/hyOnUqi1yT/FdivdIE2ecybakCu6MD9aK/img.jpg?width=850&amp;amp;height=478&amp;amp;face=0_0_850_478&quot;&gt;&lt;a href=&quot;https://yeon-code.tistory.com/102&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yeon-code.tistory.com/102&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bunxAz/hyOoI2Q4zt/lJ4d1CFWeDOWy19Nz5kGrk/img.jpg?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/cIgoNj/hyOoFLPdTZ/kJyugWcP1VJ3oNM51s1aZk/img.jpg?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/bxgRwx/hyOnUqi1yT/FdivdIE2ecybakCu6MD9aK/img.jpg?width=850&amp;amp;height=478&amp;amp;face=0_0_850_478');&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;[JS] 콜백함수, 콜백지옥&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. 콜백함수란? 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다. 예를들면 A와 B는 토요일 오전 7시에 만나기로 하였다. 둘은 만나기위해 5시에 기상하&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yeon-code.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) 생성자 함수 내부에서의 this:&lt;/b&gt; 생성자 함수를 호출하면 생성자의 프로토타입 프로퍼티를 참조하는 __proto__라는 프로퍼티가 있는 객체를 만들고, 미리 준비된 속성을 해당 객체에 부여하게 된다. 즉, &lt;b&gt;인스턴스를&lt;/b&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;스크린샷 2022-05-12 오후 2.43.07.png&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYHbCD/btrBYDUBVf5/cpl7uBOalFG8oDqKfzGGw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYHbCD/btrBYDUBVf5/cpl7uBOalFG8oDqKfzGGw1/img.png&quot; data-alt=&quot;생성자함수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYHbCD/btrBYDUBVf5/cpl7uBOalFG8oDqKfzGGw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYHbCD%2FbtrBYDUBVf5%2Fcpl7uBOalFG8oDqKfzGGw1%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;211&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.43.07.png&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;406&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 명시적으로 this를 바인딩 하는법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) call 메서드:&lt;/b&gt; 메서드의 호출주체인 함수를 즉시 실행하도록 하는 명령이다. 첫번째 인자를 this로 바인딩하고, 이후 인자들은 호출한 함수의 매개변수로 쓰인다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.48.29.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vm0VS/btrBUGSPJKg/SK1JnGdWa1QcmfLvGBdRF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vm0VS/btrBUGSPJKg/SK1JnGdWa1QcmfLvGBdRF1/img.png&quot; data-alt=&quot;call 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vm0VS/btrBUGSPJKg/SK1JnGdWa1QcmfLvGBdRF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVm0VS%2FbtrBUGSPJKg%2FSK1JnGdWa1QcmfLvGBdRF1%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;666&quot; height=&quot;117&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.48.29.png&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;call 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) apply 메서드:&lt;/b&gt; call과 기능적인 측면에서 거의동일하나, apply는 두번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정을 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.51.47.png&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg0vcu/btrBUGkXQQE/L7qP1ASte8k4THLikYRUl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg0vcu/btrBUGkXQQE/L7qP1ASte8k4THLikYRUl1/img.png&quot; data-alt=&quot;apply 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg0vcu/btrBUGkXQQE/L7qP1ASte8k4THLikYRUl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg0vcu%2FbtrBUGkXQQE%2FL7qP1ASte8k4THLikYRUl1%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;693&quot; height=&quot;116&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.51.47.png&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;apply 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) bind 메서드&lt;/b&gt;: call과 비슷하지만 즉시 호출하지는 않고 새로운 함수를 반환하기만 하는 메서드이다. 새로운 함수를 호출할때 인수를 넘기면 그 인수든 기존 bind메서드를 호출할때 전달했던 인수들 뒤에 이어서 등록되므로 부분적용함수를 구현할수도 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.56.53.png&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PsePq/btrBYEsuMte/Qb4ekUoSp7h8wmXn4NzqZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PsePq/btrBYEsuMte/Qb4ekUoSp7h8wmXn4NzqZK/img.png&quot; data-alt=&quot;bind 메서드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PsePq/btrBYEsuMte/Qb4ekUoSp7h8wmXn4NzqZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPsePq%2FbtrBYEsuMte%2FQb4ekUoSp7h8wmXn4NzqZK%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;663&quot; height=&quot;192&quot; data-filename=&quot;스크린샷 2022-05-12 오후 2.56.53.png&quot; data-origin-width=&quot;1584&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;bind 메서드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 화살표함수&lt;/b&gt;: ES6에서 새롭게 도입된 화살표함수는 실행컨텍스트 생성시에 this를 바인딩 하지않는다. 따라서 함수 내부에서는 this가 아예 없고, 접근하려면 스코프체인상 가장 가까운 this에 접근하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-12 오후 3.00.31.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lOQrg/btrBWPPf7qD/Ccan6edRfXU6gMLVvy8DOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lOQrg/btrBWPPf7qD/Ccan6edRfXU6gMLVvy8DOk/img.png&quot; data-alt=&quot;화살표함수&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lOQrg/btrBWPPf7qD/Ccan6edRfXU6gMLVvy8DOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOQrg%2FbtrBWPPf7qD%2FCcan6edRfXU6gMLVvy8DOk%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;323&quot; height=&quot;188&quot; data-filename=&quot;스크린샷 2022-05-12 오후 3.00.31.png&quot; data-origin-width=&quot;484&quot; data-origin-height=&quot;282&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;p data-ke-size=&quot;size16&quot;&gt;✨ 이 글은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정재남님의 코어자바스크립트&lt;/b&gt;를&lt;span&gt;&amp;nbsp;&lt;/span&gt;참고하여 작성된 글입니다. 프론트엔드&lt;span&gt;&amp;nbsp;&lt;/span&gt;개발자라면 꼭 사서 읽어보시는 것을 추천드립니다.&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JqvLo/btrBNl2UBJH/JvNBlrDEZRamK40wkvZYQK/img.jpg&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uwlIF/btrBYp3p4OJ/FiEx7rHLxTczNnlWCUVp5k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uwlIF/btrBYp3p4OJ/FiEx7rHLxTczNnlWCUVp5k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uwlIF/btrBYp3p4OJ/FiEx7rHLxTczNnlWCUVp5k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuwlIF%2FbtrBYp3p4OJ%2FFiEx7rHLxTczNnlWCUVp5k%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;850&quot; height=&quot;478&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JS</category>
      <category>This</category>
      <category>바인딩</category>
      <category>자바스크립트</category>
      <category>정재남</category>
      <category>코어자바스크립트</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/101</guid>
      <comments>https://yeon-code.tistory.com/101#entry101comment</comments>
      <pubDate>Thu, 12 May 2022 15:01:55 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 실행컨텍스트, 호이스팅, 스코프체인</title>
      <link>https://yeon-code.tistory.com/100</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 실행컨텍스트란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;실행컨텍스트는 실행할 코드에 제공할 환경정보를 모아놓은 객체&lt;/span&gt;로, 자바스크립트는 실행컨텍스트가 활성화되는 시점에 선언된 변수를 호이스팅하고, 외부환경정보를 구성하고, this값을 설정하는 등의 동작을 수행하게된다. 자바스크립트는 동일한 환경에 있는 코드들을 실행할때 필요한 환경정보들을 모아 컨텍스트를 구성하고, 이를 콜스택에 쌓아올렸다가 가장 위에서부터 실행하여 전체코드의 환경과 순서를 보정하게 된다. 어떤 실행컨텍스트가 활성화될때, 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는데 필요한 환경정보를 수집해서 실행컨텍스트 객체에 저장하게되는데, 이때 수집하는 정보는 &lt;b&gt;variavle environment, lexical environment, this binding&lt;/b&gt; 3가지이다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.9535%; height: 36px;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;Variable Environment&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.0465%; height: 18px;&quot;&gt;Environment Record: 식별자 정보&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 76.0465%; height: 18px;&quot;&gt;Outer Environment Reference: 선언될 당시의 Lexical 참조&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.9535%; height: 18px;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;Lexical Environment&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.0465%; height: 18px;&quot;&gt;Environment Record: 식별자 정보&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 76.0465%; height: 18px;&quot;&gt;Outer Environment Reference: 선언될 당시의 Lexical 참조&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.9535%; height: 18px;&quot;&gt;&lt;b&gt;This Binding&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 76.0465%; height: 18px;&quot;&gt;this로 지정된 객체&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Variable Environment는 현재 컨텍스트 내의 식별자들에 대한 정보와 외부환경정보를 담고있고, 선언시점의 스냅샷이여서 변경사항은 반영되지 않는다. 그에 비해 Lexical Environment는 변경사항이 실시간으로 반영된다. This Binding은 this식별자가 바라봐야할 대상 객체에 대한 정보를 갖게된다.&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;&lt;b&gt;2. 호이스팅&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Environment Record에는 현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장되게되는데, 컨텍스트 내부전체를 처음부터 끝까지 순서대로 수집하게된다. 이때, 코드가 실행되기 전임에도 불구하고 자바스크립트엔진은 식별자에 대한 정보를 갖게되는것이고, 이는&lt;span style=&quot;background-color: #f6e199;&quot;&gt; '식별자들을 최상단으로 끌어올려놓은다음 실제코드를 실행한다'라고 할수있는데 이 개념이 호이스팅&lt;/span&gt;이다. 호이스팅에서는 변수명만 끌어올리고 할당과정은 그대로 남겨두게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 7.55.06.png&quot; data-origin-width=&quot;203&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4yaHu/btrBPf2HDWM/gNhaBzkcXGLkkvlgkvoIR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4yaHu/btrBPf2HDWM/gNhaBzkcXGLkkvlgkvoIR1/img.png&quot; data-alt=&quot;호이스팅 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4yaHu/btrBPf2HDWM/gNhaBzkcXGLkkvlgkvoIR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4yaHu%2FbtrBPf2HDWM%2FgNhaBzkcXGLkkvlgkvoIR1%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;203&quot; height=&quot;203&quot; data-filename=&quot;스크린샷 2022-05-11 오후 7.55.06.png&quot; data-origin-width=&quot;203&quot; data-origin-height=&quot;203&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;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;스크린샷 2022-05-11 오후 8.02.32.png&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yxPvM/btrBSG5Rt8f/u27kR4AEVRzKRMzNjJHQp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yxPvM/btrBSG5Rt8f/u27kR4AEVRzKRMzNjJHQp1/img.png&quot; data-alt=&quot;함수선언문과 함수표현식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yxPvM/btrBSG5Rt8f/u27kR4AEVRzKRMzNjJHQp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyxPvM%2FbtrBSG5Rt8f%2Fu27kR4AEVRzKRMzNjJHQp1%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;369&quot; height=&quot;186&quot; data-filename=&quot;스크린샷 2022-05-11 오후 8.02.32.png&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;186&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 스코프체인&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프란 식별자에 대한 유효범위로, ES5까지는 스코프는 오직 함수에 의해 생성이 되었었다. 식&lt;span style=&quot;background-color: #f6e199;&quot;&gt;별자의 유효범위를 안에서부터 바깥으로 차례대로 탐색해 나가는 것을 스코프체인&lt;/span&gt;이라고 한다. Outer Environment Reference는 현재 호출된 함수가 선언될 당시의 Lexical Environment를 참조하게 된다. 즉 A함수 내부에 B함수를 선언했다면, B함수의 Lexical Environment에 존재하는 Outer Environment Reference는 A의 Lexical Environment를 참조하게 되는 것이다. 만약 여러 스코프에서 동일한 식별자를 선언한 경우에는 스코프체인상에서 가장 먼저 발견된 식별자에만 접근 가능하게된다. 여기서&lt;b&gt; 변수은닉화&lt;/b&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;스크린샷 2022-05-11 오후 8.25.29.png&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL0WCE/btrBS1on4xK/rlInhoW2FWSsOIcu1fv840/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL0WCE/btrBS1on4xK/rlInhoW2FWSsOIcu1fv840/img.png&quot; data-alt=&quot;스코프체인 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL0WCE/btrBS1on4xK/rlInhoW2FWSsOIcu1fv840/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL0WCE%2FbtrBS1on4xK%2FrlInhoW2FWSsOIcu1fv840%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;263&quot; height=&quot;218&quot; data-filename=&quot;스크린샷 2022-05-11 오후 8.25.29.png&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;218&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;자바스크립트에서 &lt;b&gt;전역변수란&lt;/b&gt; 전역컨텍스트의 Lexical Environment에 담긴 변수를 말하며, &lt;b&gt;지역변수는&lt;/b&gt; 그밖의 함수에 의해 생성된 실행컨텍스트의 변수를 말한다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;코드의 안전성을 위해서는 가급적 전역변수의 사용을 최소화&lt;/span&gt;하는 것이 좋은데, 그 이유는 전역공간에 같은 변수명의 함수를 선언하더라도 이미 지역변수로 선언을 했다면 코드 대부분이 함수내부에서 동작하게되어 전역공간에서 접근할 수 없게 되기때문이다. ES6에서는 let, const, class, strict와 같은 블록에 의해서도 스코프 경계가 발생한다.&amp;nbsp;&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정재남님의 코어자바스크립트&lt;/b&gt;를&lt;span&gt;&amp;nbsp;&lt;/span&gt;참고하여 작성된 글입니다. 프론트엔드&lt;span&gt;&amp;nbsp;&lt;/span&gt;개발자라면 꼭 사서 읽어보시는 것을 추천드립니다. &lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yqEF2/btrBN5kx6t7/a9oWrBnMrZ7hKVPVH6Aji0/img.jpg&quot; data-lightbox=&quot;lightbox&quot; data-alt=&quot;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JqvLo/btrBNl2UBJH/JvNBlrDEZRamK40wkvZYQK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JqvLo/btrBNl2UBJH/JvNBlrDEZRamK40wkvZYQK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JqvLo/btrBNl2UBJH/JvNBlrDEZRamK40wkvZYQK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJqvLo%2FbtrBNl2UBJH%2FJvNBlrDEZRamK40wkvZYQK%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;850&quot; height=&quot;478&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JS</category>
      <category>스코프체인</category>
      <category>실행컨텍스트</category>
      <category>자바스크립트</category>
      <category>정재남</category>
      <category>코어자바스크립트</category>
      <category>호이스팅</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/100</guid>
      <comments>https://yeon-code.tistory.com/100#entry100comment</comments>
      <pubDate>Wed, 11 May 2022 20:35:39 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 자바스크립트 데이터 타입</title>
      <link>https://yeon-code.tistory.com/99</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 자바스크립트의 데이터 타입: 기본형과 참조형&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 데이터 타입에는 2가지가 있다. 기본형(prototype)과 참조형(refrence type)이다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.9069%;&quot;&gt;&lt;b&gt;기본형&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.0931%;&quot;&gt;Number, String, Boolean, null, undefined, Symbol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.9069%;&quot;&gt;&lt;b&gt;참조형&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 82.0931%;&quot;&gt;Array, Function, Date, Map, Set, RegExp&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형은 불변값이고, 참조형은 보통 가변값이다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;컴퓨터는 데이터를 늘릴경우를 대비하기 위해, 중복데이터에 대해 효율성을 높이기 위해 변수영역과 데이터 영역을 분리하게 된다.&lt;/span&gt; 기본형이 불변값인 이유는 기본값에서의 변경이 새로 만드는 동작을 통해서만 이루어지기 때문이다. 반면에 참조형은 기본형과는 달리 객체의 변수영역이 별도로 존재하여 다른값을 얼마든지 대입할수있고, 데이터 영역에 저장된 값은 모두 불변값이다. 따라서 가변값이라고 부르는것이고, 재할당 명령을 내릴시에 참조카운트가 0인 이전 메모리 주소는 가비지 콜렉터가 수거해가게된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.11.56.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv2HoU/btrBR9sQTsw/jlz1q4VDykbfgUGH0q9nD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv2HoU/btrBR9sQTsw/jlz1q4VDykbfgUGH0q9nD1/img.png&quot; data-alt=&quot;참조형 데이터의 할당&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv2HoU/btrBR9sQTsw/jlz1q4VDykbfgUGH0q9nD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv2HoU%2FbtrBR9sQTsw%2Fjlz1q4VDykbfgUGH0q9nD1%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;628&quot; height=&quot;265&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.11.56.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;458&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 기본형과 참조형의 변수복사&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본형은 복사를 할때 값이 담긴 주소값을 바로 복제하게되지만, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;참조형은 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제하게된다.&lt;/span&gt; 따라서 기본형은 객체의 프로퍼티를 변경시에 서로 다른 주소를 바라보게 되지만, 참조형데이터는 여전히 같은 주소를 바라보게 된다. 참조형데이터를 불변객체로 만들기 위해서, 얕은복사와 깊은복사의 개념에 대해 알아야한다. 얕은 복사는 바로 아래단계의 값만을 복사하는 방법이고, 깊은 복사는 내부의 모든값을 모두 찾아서 전부 복사하는 방법이다. 얕은 복사를 시행할 경우 깊이가 1인 기본형 프로퍼티만 있다면 문제가 되지 않겠지만, 참조형 데이터가 프로퍼티로 있을 경우에는 다시 재귀적으로 내부의 프로퍼티까지 모두 복사를 해주는 깊은 복사를 해주어야 문제가 생기지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.25.39.png&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bha4nj/btrBMFUEOeJ/lkFiIpcsAcTgioWh7u7yI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bha4nj/btrBMFUEOeJ/lkFiIpcsAcTgioWh7u7yI0/img.png&quot; data-alt=&quot;기본형과 참조형의 복사 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bha4nj/btrBMFUEOeJ/lkFiIpcsAcTgioWh7u7yI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbha4nj%2FbtrBMFUEOeJ%2FlkFiIpcsAcTgioWh7u7yI0%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;547&quot; height=&quot;267&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.25.39.png&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;444&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;&lt;b&gt;얕은복사&lt;/b&gt;를 하기 위해서는 1) assign함수이용 2) 전개연산자 이용 이렇게 2가지의 방법이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.31.32.png&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b36oqz/btrBNTSpog1/fsnI0etzhHf9QowXY7ixz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b36oqz/btrBNTSpog1/fsnI0etzhHf9QowXY7ixz0/img.png&quot; data-alt=&quot;얕은복사 방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b36oqz/btrBNTSpog1/fsnI0etzhHf9QowXY7ixz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb36oqz%2FbtrBNTSpog1%2FfsnI0etzhHf9QowXY7ixz0%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;294&quot; height=&quot;411&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.31.32.png&quot; data-origin-width=&quot;294&quot; data-origin-height=&quot;411&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;&lt;b&gt;깊은 복사&lt;/b&gt;를 하기위해서는 1) 깊은복사를 시행하는 재귀함수를 생성 2)String을 Json으로 변환 3) loadash 라이브러리를 사용 이렇게 3가지 방법이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.46.24.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zMYGF/btrBR9s1UPj/vhXwHBWlUdQ4nrLofCwmZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zMYGF/btrBR9s1UPj/vhXwHBWlUdQ4nrLofCwmZK/img.png&quot; data-alt=&quot;깊은복사방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zMYGF/btrBR9s1UPj/vhXwHBWlUdQ4nrLofCwmZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzMYGF%2FbtrBR9s1UPj%2FvhXwHBWlUdQ4nrLofCwmZK%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;380&quot; height=&quot;525&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.46.24.png&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;깊은복사방법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. undefined 와 null&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에는 '없음'을 나타내는 값에 undefined와 null 2가지가 있다. &lt;b&gt;undefined&lt;/b&gt;는 사실 사용자가 지정할수도 있겠지만, 보통 자바스크립트 엔진이 값이 존재하지 않을 때 자동으로 부여하게 된다. 값을 대입하지 않아서 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할때, 객체 내부에 존재하지 않는 프로퍼티에 접근하려할때, return문이 없거나 호출되지 않는 함수의 실행결과에는 undefined가 부여된다. &lt;b&gt;null&lt;/b&gt;은 '비어있음'을 명시적으로 나타내고 싶을때 사용자가 할당하는 값이다. 이 두가지를 혼용하지 않기 위해서는 undefined를 명시적으로 할당하지 않기만하면된다. 다만, null을 쓸때 주의할점은 typeof(null)은 object라는 결과를 반환하는 자바스크립트 버그있기때문에 어떤 변수값이 null인지 확인하기 위해서는 동등연산자가 아닌 일치연산자로 비교를 해주어야한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.55.53.png&quot; data-origin-width=&quot;230&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vOUyl/btrBQE1pdXC/FCXbgOemiMldjueIXHXJE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vOUyl/btrBQE1pdXC/FCXbgOemiMldjueIXHXJE0/img.png&quot; data-alt=&quot;null과 undefined 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vOUyl/btrBQE1pdXC/FCXbgOemiMldjueIXHXJE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvOUyl%2FbtrBQE1pdXC%2FFCXbgOemiMldjueIXHXJE0%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;230&quot; height=&quot;279&quot; data-filename=&quot;스크린샷 2022-05-11 오후 2.55.53.png&quot; data-origin-width=&quot;230&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;null과 undefined 비교&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;✨ 이 글은 &lt;b&gt;정재남님의 코어자바스크립트&lt;/b&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;850&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yqEF2/btrBN5kx6t7/a9oWrBnMrZ7hKVPVH6Aji0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yqEF2/btrBN5kx6t7/a9oWrBnMrZ7hKVPVH6Aji0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yqEF2/btrBN5kx6t7/a9oWrBnMrZ7hKVPVH6Aji0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyqEF2%2FbtrBN5kx6t7%2Fa9oWrBnMrZ7hKVPVH6Aji0%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;850&quot; height=&quot;478&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JS</category>
      <category>데이터타입</category>
      <category>자바스크립트</category>
      <category>정재남</category>
      <category>코어자바스크립트</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/99</guid>
      <comments>https://yeon-code.tistory.com/99#entry99comment</comments>
      <pubDate>Wed, 11 May 2022 15:01:22 +0900</pubDate>
    </item>
    <item>
      <title>[python] BOJ 백준 21610: 마법사상어와 비바라기</title>
      <link>https://yeon-code.tistory.com/98</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;1. 문제&amp;nbsp;&lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마법사 상어는&amp;nbsp;&lt;a href=&quot;https://www.acmicpc.net/problem/20056&quot;&gt;파이어볼&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.acmicpc.net/problem/20057&quot;&gt;토네이도&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/20058&quot;&gt;파이어스톰&lt;/a&gt;, 물복사버그&amp;nbsp;마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기를 크기가 N&amp;times;N인 격자에서 연습하려고 한다. 격자의 각 칸에는 바구니가 하나 있고, 바구니는 칸 전체를 차지한다. 바구니에 저장할 수 있는 물의 양에는 제한이 없다. (r, c)는 격자의 r행 c열에 있는 바구니를 의미하고, A[r][c]는 (r, c)에 있는 바구니에 저장되어 있는 물의 양을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격자의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫&amp;nbsp;칸은 (N, N)이다. 마법사 상어는 연습을 위해 1번 행과 N번 행을 연결했고, 1번 열과 N번 열도 연결했다. 즉, N번 행의 아래에는 1번 행이,&amp;nbsp;1번 행의 위에는 N번 행이 있고, 1번 열의 왼쪽에는 N번 열이, N번 열의 오른쪽에는 1번 열이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비바라기를&amp;nbsp;시전하면 (N, 1), (N, 2), (N-1, 1), (N-1, 2)에 비구름이 생긴다. 구름은 칸 전체를 차지한다. 이제 구름에 이동을 M번 명령하려고 한다. i번째 이동 명령은 방향 di과 거리 si로 이루어져 있다. 방향은 총 8개의 방향이 있으며, 8개의 정수로 표현한다. 1부터 순서대로&amp;nbsp;&amp;larr;,&amp;nbsp;↖,&amp;nbsp;&amp;uarr;,&amp;nbsp;↗,&amp;nbsp;&amp;rarr;,&amp;nbsp;↘,&amp;nbsp;&amp;darr;,&amp;nbsp;↙ 이다.&amp;nbsp;이동을 명령하면 다음이 순서대로 진행된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 구름이 di&lt;span&gt;&amp;nbsp;&lt;/span&gt;방향으로 si칸 이동한다.&lt;/li&gt;
&lt;li&gt;각 구름에서 비가 내려&amp;nbsp;구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가한다.&lt;/li&gt;
&lt;li&gt;구름이 모두 사라진다.&lt;/li&gt;
&lt;li&gt;2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면, 대각선 방향으로 거리가 1인&amp;nbsp;칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.&lt;/li&gt;
&lt;li&gt;예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고, (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다. 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 구해보자.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7; color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. 입력&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 N, M이 주어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째 줄부터 N개의 줄에는 N개의 정수가 주어진다. r번째 행의 c번째 정수는 A[r][c]를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 M개의 줄에는 이동의 정보 di, si가 순서대로 한 줄에 하나씩 주어진다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&lt;b&gt;3. 출력&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에 M번의 이동이 모두 끝난 후 바구니에 들어있는 물의 양의 합을 출력한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&lt;b&gt;4. 해결방법&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 문제는&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구현, 시뮬레이션 문제&lt;/b&gt;이다. 구름배열과 바구니 격자배열을 계속해서 업데이트 해주면서 각 단계를 진행하면된다. 다만 각 단계에서 구름이 이미 생성된 칸에 대해서 정보를 계속해서 가지고 있어야하므로 &lt;span style=&quot;color: #ee2323;&quot;&gt;방문배열 visited&lt;/span&gt;를 생성해서 관리를 해주어야한다. 기존 배열에서 들어있는지를 확인하는 in 함수를 쓰게된다면 O(n)의 시간이 걸려서 시간초과가 일어나게되기 때문이다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;1) move함수:&lt;/b&gt; 방향 d에 대해서 s만큼 이동한다. 다만 행과열을 각각 이어져있다고 하였으므로 범위가 넘어가다면 각 끝점으로 다시 이어주어야한다. 또한 여기서 방문체크를 해주는 배열을 같이 계산하여 리턴을 해주어야 5단계의 구름생성에서 활용할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;2) rain 함수:&lt;/b&gt;&lt;span&gt; 구름이 있는 곳에 대해서 물의 양을 1씩 증가시켜준다. 그 후에 물복사를 실시하여 대각선을 탐색해준다. &lt;span style=&quot;color: #ee2323;&quot;&gt;이때 임시배열을 만들고 증가시킬 물의양을 따로 저장해주어야 계산오류가 나지않는다.&lt;/span&gt; 한번에 적용시켜준다면 동시성에 어긋나므로 계산오류가 일어나게 된다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;b&gt;3) make_cloud 함수&lt;/b&gt;: 물이 2이상이고 move함수에서 리턴한 방문배열에서 체크가 안되어있다면 구름이 생성가능한 부분이다. 새로운 배열에 저장해주고 리턴해준다음, 메인함수에서 원래의 구름배열에 저장해주면된다.&amp;nbsp;&lt;/span&gt;&lt;/span&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;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5) 구현코드&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1651242479752&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n,m=map(int,input().split())
a=[list(map(int,input().split()))for _ in range(n)] #격자 
commands=[list(map(int,input().split())) for _ in range(m)] #명령
cloud=[(n-1,0),(n-1,1),(n-2,0),(n-2,1)] #구름배열 

#8가지 방향 
dx=[0,-1,-1,-1,0,1,1,1]
dy=[-1,-1,0,1,1,1,0,-1]

#1단계: 구름이동 
def move(d,s):
  #5단게를 위해 저장할 방문여부 배열 
  visited=[[0]*n for _ in range(n)]
  d-=1 #방향 
  for i in range(len(cloud)):
    x,y=cloud[i] #구름좌표 
    for _ in range(s): #s만큼이동 
      x,y=x+dx[d],y+dy[d]
      #경계를 넘어가는건 이어주기 
      if x&amp;lt;0: x=n-1
      if x&amp;gt;=n: x=0
      if y&amp;lt;0: y=n-1
      if y&amp;gt;=n : y=0 
    cloud[i]=(x,y) #구름좌표 업데이트 
    visited[x][y]=1 #방문체크 
  return visited #방문배열 리턴 

#2,4단계: 물증가, 물복사버그 
def rain():
  temp=[]
  #2단계: 비오기 
  for x,y in cloud:
    a[x][y]+=1#물증가 

  #4단계: 물복사마법 실시   
  for x,y in cloud:
    cnt=0 #대각선 물개수  
    for i in [1,3,5,7]: #대각선 
      nx,ny=x+dx[i],y+dy[i] 
      if 0&amp;lt;=nx&amp;lt;n and 0&amp;lt;=ny&amp;lt;n:#범위안 
        if a[nx][ny]&amp;gt;0: #물있으면 
          cnt+=1 #개수증가 
    temp.append((x,y,cnt)) #임시배열에 저장 
  for x,y,cnt in temp:
      a[x][y]+=cnt #물복사

#3,5단게: 새로운 구름생성 
def make_cloud(cloud,visited):
  temp=[] #새로운 구름배열 
  for i in range(n):
    for j in range(n):
      #물이 2이상이고 예전에 구름이 아닌칸
      if a[i][j]&amp;gt;=2 and visited[i][j]==0:
        temp.append((i,j)) #구름생성 
        a[i][j]-=2 #물의양 줄기 
  return temp 


for d,s in commands:
  visited=move(d,s) 
  rain()
  cloud=make_cloud(cloud,visited)

answer=0
for i in range(n):
  answer+=sum(a[i])
print(answer)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;⭐️난이도:&amp;nbsp; 골드 5 ⭐️&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/21610&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/21610&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651242968395&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;21610번: 마법사 상어와 비바라기&quot; data-og-description=&quot;마법사 상어는&amp;nbsp;파이어볼,&amp;nbsp;토네이도, 파이어스톰, 물복사버그&amp;nbsp;마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/21610&quot; data-og-url=&quot;https://www.acmicpc.net/problem/21610&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/czh2ND/hyOdENtkE7/UR2CKPoVLSFMFjaqu9OEo0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/21610&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/21610&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/czh2ND/hyOdENtkE7/UR2CKPoVLSFMFjaqu9OEo0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&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;21610번: 마법사 상어와 비바라기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;마법사 상어는&amp;nbsp;파이어볼,&amp;nbsp;토네이도, 파이어스톰, 물복사버그&amp;nbsp;마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&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;</description>
      <category>Algorithms/Samsung</category>
      <category>구현</category>
      <category>삼성</category>
      <category>시뮬레이션</category>
      <category>코테</category>
      <author>Dev.yeon</author>
      <guid isPermaLink="true">https://yeon-code.tistory.com/98</guid>
      <comments>https://yeon-code.tistory.com/98#entry98comment</comments>
      <pubDate>Fri, 29 Apr 2022 23:42:41 +0900</pubDate>
    </item>
  </channel>
</rss>