<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>4_21ee.log</title>
        <link>https://velog.io/</link>
        <description>Life is all about timing.</description>
        <lastBuildDate>Sun, 08 Sep 2024 05:05:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>4_21ee.log</title>
            <url>https://images.velog.io/images/4_21ee/profile/2c941894-63eb-4be4-adeb-0e86acafdf98/123.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 4_21ee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/4_21ee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Discriminated Union]]></title>
            <link>https://velog.io/@4_21ee/Discriminated-Union</link>
            <guid>https://velog.io/@4_21ee/Discriminated-Union</guid>
            <pubDate>Sun, 08 Sep 2024 05:05:55 GMT</pubDate>
            <description><![CDATA[<h1 id="discriminated-union">Discriminated Union</h1>
<p>Discriminated Union은 번역하면 구별된 유니온이라는 뜻으로 리터럴 멤버 프로퍼티가 있는 클래스가 있다면, 그 프로퍼티로 유니온 타입을 구별할 수 있다는 개념이다.</p>
<p>흔하게 접할 수 있는 타입 코드를 하나 살펴보자.</p>
<pre><code class="language-tsx">interface RoundIcon {
  shape: &quot;circle&quot;;
  radius: number;
  color: string;
}

interface SquareIcon {
  shape: &quot;square&quot;;
  width: number;
  height: number;
  color: string;
}</code></pre>
<p><code>RoundIcon</code>과 <code>SquareIcon</code>은 <strong>리터럴 타입</strong>의 <code>shape</code>이라는 프로퍼티를 공통으로 가지고 있다.</p>
<p>이러한 경우 우리는 shape의 타입을 통해 특정 객체의 정확한 타입을 알아낼 수 있다.</p>
<pre><code class="language-tsx">type Icon = RoundIcon | SquareIcon;

const renderIcon = (icon: Icon) =&gt; {
    if (icon.shape === &#39;circle&#39;) {
      // icon은 RoundIcon 타입!
      icon.radius;
      // icon.width &lt;- X
    } else {
      // Icon 타입에서 shape가 circle이 아닌 타입이므로 여기서 icon은 SquareIcon 타입!
      icon.width
      // icon.radius &lt;- X
    }</code></pre>
<p>여기서 <code>shape</code>와 같이 특정한 리터럴을 가진 객체를 식별할 수 있는 프로퍼티를 <strong>구별 프로퍼티</strong>라 표현하고, <code>RoundIcon</code>과 <code>SquareIcon</code>을 유니온한 타입을 <strong>구별된 유니온(Discriminated Union)</strong>이라 표현한다.</p>
<h2 id="example">Example</h2>
<p>각각 여러 개의 타입이 <code>동일한 이름의 리터럴 타입 프로퍼티(구별 프로퍼티)</code>를 가지고 있다면, 그 여러 개의 타입을 구별해낼 수 있다는 점을 활용해 타입의 버전 관리를 할 수 있다.</p>
<pre><code class="language-tsx">type DTO = |
{
  version: undefined, // 버전 0
  name: string;
} | {
  version : 1,
  firstName: string;
  lastName: string;
} | {
  version : 2,
  firstName: string;
  middleName: string;
  lastName: string;
} | ...</code></pre>
<h2 id="real-world-usage">real-world usage</h2>
<p>이 구별된 유니온 타입을 활용하는 대표적인 예시가 Redux의 액션 객체이다.</p>
<p>액션 객체는 <code>type</code>이라는 구별 프로퍼티를 가지고 있고, switch문을 통해 이 프로퍼티를 기준으로 분기 처리를 한다. 즉, 타입이 좁혀진다.</p>
<pre><code class="language-tsx">function todosReducer(state = [], action) {
  switch (action.type) {
    case &quot;ADD_TODO&quot;: {
      return state.concat(action.payload);
    }
    case &quot;TOGGLE_TODO&quot;: {
      const { index } = action.payload;
      return state.map((todo, i) =&gt; {
        if (i !== index) return todo;

        return {
          ...todo,
          completed: !todo.completed,
        };
      });
    }
    case &quot;REMOVE_TODO&quot;: {
      return state.filter((todo, i) =&gt; i !== action.payload.index);
    }
    default:
      return state;
  }
}</code></pre>
<h1 id="exhaustive-check">Exhaustive Check</h1>
<pre><code class="language-tsx">interface RoundIcon {
  shape: &quot;circle&quot;;
  radius: number;
  color: string;
}

interface SquareIcon {
  shape: &quot;square&quot;;
  width: number;
  height: number;
  color: string;
}

export type Icon = RoundIcon | SquareIcon;</code></pre>
<pre><code class="language-tsx">function getIconArea(icon: Icon) {
  if (icon.shape === &quot;circle&quot;) {
    return icon.radius ** 2 * PI;
  }
  if (icon.shape === &quot;square&quot;) {
    return icon.width * icon.height;
  }
}</code></pre>
<p>위와 같이 유니온 타입의 <code>Icon</code>이 있고 유니온으로 묶인 각 타입들을 모두 대응하는 함수가 있는 상황이라 했을 때, 새로운 아이콘 타입을 추가하고 싶다면 <code>Icon</code>과 <code>getIconArea</code>를 모두 수정해 주어야 한다.</p>
<p>이때 <code>Icon</code>이 추가되었으면 <code>getIconArea</code>에도 조건문을 추가해 주어야 한다라는 일종의 가이드를 두고 싶은 경우, exhaustive 검사를 추가할 수 있다.</p>
<p>exhaustive 검사는 다음과 같이 해당 블록에서 추론한 타입이 never 타입과 호환되는 것처럼 작성하면 된다.</p>
<pre><code class="language-tsx">function getIconArea(icon: Icon) {
  if (icon.shape === &quot;circle&quot;) {
    return icon.radius ** 2 * PI;
  }
  if (icon.shape === &quot;square&quot;) {
    return icon.width * icon.height;
  }
  const _exhaustiveCheck: never = icon; // Here!
}</code></pre>
<p>새로운 타입을 추가한 상황이라면, 마지막 타입에서 추론되는 새로운 타입은 never 타입이 아닐 것이기 때문에 never 타입에 할당할 수 없어 에러가 발생한다.</p>
<pre><code class="language-tsx">// error: &#39;TriangleIcon&#39; is not assignable to &#39;never&#39;</code></pre>
<p>이렇게 에러를 발생시킴으로써 새로운 타입이 추가되었을 때 함께 변경되어야 하는 부분의 누락을 방지할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[requestIdleCallback]]></title>
            <link>https://velog.io/@4_21ee/requestIdleCallback</link>
            <guid>https://velog.io/@4_21ee/requestIdleCallback</guid>
            <pubDate>Mon, 12 Aug 2024 04:41:16 GMT</pubDate>
            <description><![CDATA[<h1 id="requestidlecallback이란">requestIdleCallback이란?</h1>
<p>브라우저가 <strong>유휴 상태(idle)일 때 실행할 콜백</strong>을 예약할 수 있는 메서드.</p>
<p>이 메서드를 사용하면 브라우저 메인 스레드가 바쁠 때는 해당 작업을 연기하고, 한가할 때 수행할 수 있다. 따라서 우선순위가 낮은 백그라운드 작업을 수행할 때 유용하다.</p>
<h2 id="usage">Usage</h2>
<pre><code class="language-jsx">var handle = window.requestIdleCallback(callback[, options])</code></pre>
<ul>
<li><code>callback</code>: 유휴 상태에 호출할 함수. <code>IdleDeadline</code> 객체를 인수로 받음</li>
<li><code>options</code>: 옵셔널 매개변수. 콜백이 반드시 호출되어야 하는 최대 시간을 나타내는 <code>timeout</code> 속성을 가짐</li>
</ul>
<h3 id="idledeadline-객체">IdleDeadline 객체</h3>
<p>callback 함수에게 전달되는 객체로, 다음과 같이 구성됩니다.</p>
<ul>
<li><code>timeRemaining()</code>: 브라우저가 다음 작업을 실행하기 전까지 얼만큼의 시간이 남았는지를 밀리초 단위로 반환</li>
<li><code>didTimeout</code>: 브라우저가 아직 유휴 상태가 되지 않았지만, 설정한 timeout 시간이 지나 콜백이 호출되었음을 나타내는 boolean 값</li>
</ul>
<h1 id="언제-사용할까">언제 사용할까?</h1>
<p>기존에는 필수적이지 않은 작업을 추후에 실행되도록 개발자가 직접 예약하는 것이 매우 번거로웠지만, 브라우저는 언제 유휴 상태가 되는지 알고 있기 때문에 <code>requestIdleCallback</code>라는 API가 등장하게 되었다.</p>
<p>요즘 웹사이트에서는 실행해야 할 스크립트가 매우 많다. 그래서 스크립트를 최대한 빨리 실행해야 하지만, 동시에 메인 스레드를 오래 점유하여 사용자에게 방해가 되지 않도록 하는 것이 중요하다. 따라서 자바스크립트의 실행에 있어서 최적화가 필요한 경우 <code>requestIdleCallback</code>을 사용하면 좋다.</p>
<h1 id="사용-예시">사용 예시</h1>
<p>유휴 상태에 실행할 콜백 함수를 <code>requestIdleCallback</code>에게 넘겨주면 된다.</p>
<pre><code class="language-jsx">function myNonEssentialWork(deadline) {
  // 유휴 시간 동안 실행하기
  while (deadline.timeRemaining() &gt; 0 &amp;&amp; tasks.length &gt; 0) {
    doWorkIfNeeded();
  }

  if (tasks.length &gt; 0) {
    // 해야 할 일이 남았다면
    requestIdleCallback(myNonEssentialWork); // 다음 유휴 때 마저 실행하기
  }
}

requestIdleCallback(myNonEssentialWork);</code></pre>
<p>단, 브라우저가 <strong>매우 바쁜 상황</strong>이라면 콜백이 호출되기 까지 오랜 시간이 걸릴 수 있다.</p>
<p>나중에 실행되어도 괜찮지만, 특정 시간 안에는 실행됐으면 하는 상황이라면 <code>timeout</code> 옵션을 주어 해결할 수 있다.</p>
<pre><code class="language-jsx">requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });</code></pre>
<p>2초라는 시간이 지나서 콜백이 실행되면, <code>deadline</code> 객체는 다음과 같이 구성된다.</p>
<ul>
<li><code>timeRemaining()</code>은 <code>0</code>을 반환함</li>
<li><code>didTimeout</code>은 <code>true</code>가 됨</li>
</ul>
<p>단, timeout 옵션을 주는 것은 사용자에게 중단이 발생(버벅거림)할 수 있어 주의가 필요하다. 가능하다면 브라우저가 콜백을 호출할 시점을 결정하도록 놔두는 것이 좋다.</p>
<h1 id="호환성-문제">호환성 문제</h1>
<p>이 메서드는 실험적 기능으로, <strong>현재 대부분의 브라우저에서 지원하지만 Safari(iOS)에서는 지원되지 않는다.</strong></p>
<p>따라서 메서드의 사용 가능 여부를 확인한 다음, 지원하지 않는다면 환경이라면 setTimeout으로 직접 구현하거나 <a href="https://www.npmjs.com/package/requestidlecallback-polyfill">폴리필</a>을 사용해야 한다</p>
<pre><code class="language-jsx">if (&quot;requestIdleCallback&quot; in window) {
  // Use requestIdleCallback to schedule work.
} else {
  // Do what you’d do today.
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[항해 플러스 프론트엔드 1기 후기 - 추천? 비추천? ]]></title>
            <link>https://velog.io/@4_21ee/%ED%95%AD%ED%95%B4-FE-%EB%82%B4%EB%8F%88%EB%82%B4%EC%82%B0-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@4_21ee/%ED%95%AD%ED%95%B4-FE-%EB%82%B4%EB%8F%88%EB%82%B4%EC%82%B0-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Thu, 23 May 2024 08:43:16 GMT</pubDate>
            <description><![CDATA[<h3 id="about-me">About Me</h3>
<p>우선 저는 타 부트캠프를 통해 개발을 시작했고, 일을 하다가 퇴사한지 이제 2달정도 되어가는 2년차 프론트엔드 개발자입니다. 현재는 항해 플러스 프로그램을 수료한지 1주도 채 지나지 않은 따끈따끈한 상태이고 약 2-3달 동안의 여정도 돌아볼겸 항해플러스를 고민하고 있는 다른 주니어 개발자 분들을 위해 후기를 작성해보려고 합니다.</p>
<h3 id="항해-플러스에-들어오기-전-갖고-있던-고민">항해 플러스에 들어오기 전 갖고 있던 고민</h3>
<p>주니어 개발자들이라면 대부분 비슷하겠지만 저 또한 프론트엔드 개발자로 일하면서 항상 최신 기술을 따라잡는 것과 실무에서의 깊이 있는 경험 부족이 고민이었습니다. 특히 React와 같은 프레임워크를 더 깊이 있게 공부하고, CI/CD, TDD와 같은 실무에서 중요하지만 경험하기 어려운 부분에 대해 더 배우고 싶었고 이러한 갈증을 해소하기 위해 방법을 알아보던 중에 항해플러스를 알게 되어 참여하게 되었습니다.</p>
<h3 id="왜-항해-플러스였나요">왜 항해 플러스였나요?</h3>
<p>항해 플러스 프로그램을 선택하게 된 결정적 계기는 현직자를 대상으로 한다는 점과 시니어 코치진의 멘토링이었습니다. 현업에서 활동 중인 전문가들의 멘토링을 통해 실무에서 바로 적용할 수 있는 기술과 노하우를 배우고 싶었고, 다른 동료 개발자들과 소통하며 서로의 고민을 공유할 수 있는 좋은 기회가 될 것이라고 생각했습니다.</p>
<h3 id="항해-플러스-fe-코스의-장점">항해 플러스 FE 코스의 장점</h3>
<ol>
<li><strong>React 심화 학습</strong>: 기본적인 사용법을 넘어, 고급 기능과 최적화 기법까지 배우며 실무 스킬을 레벨업 할 수 있었습니다.</li>
<li><strong>실전 프로젝트</strong>: CI/CD, 프론트 TDD, 디자인패턴, 성능 최적화 등 현직에서는 경험하기 어려운 다양한 주제를 다루는 프로젝트를 통해 실전 감각을 키울 수 있었습니다.</li>
<li><strong>시니어 코치진의 멘토링</strong>: 풍부한 경험을 가진 코치진의 멘토링을 통해 문제 해결 능력과 실무에 대한 이해도가 크게 향상되었습니다.
개발자 네트워킹: 동료 개발자들과의 협업을 통해 다양한 시각을 접하고, 현업 개발자들과의 네트워킹을 통해 넓은 인적 네트워크를 구축할 수 있었습니다.</li>
</ol>
<h3 id="항해-플러스-이전과-이후">항해 플러스 이전과 이후</h3>
<ol>
<li>기술적 성장: 심화된 React 학습과 다양한 실전 프로젝트를 통해 기술적 역량이 향상되었습니다.</li>
<li>마음가짐의 변화: 개발에 대한 자신감이 생기고, 새로운 도전에 대한 두려움이 줄어들었습니다.</li>
<li>개발자 네트워크: 동료들과의 협업과 네트워킹을 통해 다양한 인적 자원을 확보하게 되었습니다.</li>
</ol>
<h3 id="항해-플러스에-투자한-시간-돈이-아깝진-않은가요">항해 플러스에 투자한 시간, 돈이 아깝진 않은가요?</h3>
<p>분명 누군가는 항해플러스를 통해 얻는게 분명히 존재하지만 그래도 좀 비싼게 아니냐고 생각할 수 있다고 생각합니다. 그치만 항해 플러스에서의 기술적 성장, 실무 경험, 그리고 소중한 인맥을 통해 얻은 경험을 발판삼아 제가 개발자로서 한 단계 더 성장할 수 있는 시간이 되었다고 생각하기에, 투자한 시간과 돈이 전혀 아깝지 않습니다.</p>
<h3 id="항해-플러스-코스를-고민하고-있는-개발자들에게">항해 플러스 코스를 고민하고 있는 개발자들에게</h3>
<p>현업에서 새로운 자극을 원한다거나 이직을 생각하고 계시다거나 공부를 하려고 생각만 하고 시작하지 못하고 계신 저와 같은 주니어 프론트엔드 개발자분들이라면 여유가 되신다면 한번 항해플러스에 도전해보시는걸 추천드립니다. 하지만 내가 노력하는 만큼 얻어갈 수 있는곳이 항해플러스이기 때문에 자칫 가볍게 생각하고 오신다면 아무것도 얻어가지 못할 수도 있으니 단단히 각오하고 시작하시길 바랍니다,,, 화이팅~!🔥🔥🔥</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[테스트 전략 For FE]]></title>
            <link>https://velog.io/@4_21ee/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A0%84%EB%9E%B5-For-FE</link>
            <guid>https://velog.io/@4_21ee/%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%A0%84%EB%9E%B5-For-FE</guid>
            <pubDate>Thu, 25 Apr 2024 07:58:34 GMT</pubDate>
            <description><![CDATA[<h1 id="프론트엔드-개발에서의-테스트의-중요성">프론트엔드 개발에서의 테스트의 중요성</h1>
<p>프론트엔드 개발에서 테스트는 애플리케이션의 안정성과 품질을 보장하는 핵심요소이다. 사용자 인터페이스(UI)의 다양한 상호작용을 검증하고, 예상치 못한 버그를 사전에 발견하여 사용자 경험을 향상시키는 데 중요한 역할을 한다.
왜냐하면 테스트를 통해 코드의 신뢰성을 높이고, 개발 과정에서 발생할 수 있는 오류를 최소화할 수 있기 때문이다.</p>
<h2 id="테스트-종류와-적용시기">테스트 종류와 적용시기</h2>
<ul>
<li>단위 테스트(Unit Test)<ul>
<li>가장 작은 코드 단위의 기능을 검증</li>
</ul>
</li>
<li>통합 테스트(Integration Test)<ul>
<li>여러 컴포넌트 또는 시스템의 상호작용을 검증</li>
</ul>
</li>
<li>E2E 테스트(End-to-End Test)<ul>
<li>사용자의 관점에서 애플리케이션의 흐름을 전체적으로 검증</li>
</ul>
</li>
</ul>
<h2 id="테스트-도구-선택-기준">테스트 도구 선택 기준</h2>
<p>테스트 도구 선택은 프로젝트의 요구 사항, 개발 팀의 선호도, 그리고 기존 개발 환경과의 호환성을 고려해야한다. Jest, Mocha, Cypress 등 다양한 테스트 도구가 존재하며, 각 도구는 고유의 특징과 장단점을 가지고 있다.</p>
<p>왜냐하면 적절한 테스트 도구의 선택은 테스트 과정의 효율성과 효과성을 결정짓기 때문이다.</p>
<h2 id="테스트-자동화의-중요성">테스트 자동화의 중요성</h2>
<p>테스트 자동화는 개발 과정을 가속화하고, 반복적인 테스트 작업을 줄이며, 테스트의 일관성을 유지하는 데 중요하다. CI/CD 파이프라인에 테스트를 통합하여 코드 변경 사항마다 자동으로 테스트를 실행할 수 있다.</p>
<p>왜냐하면 테스트 자동화를 통해 개발자는 더 많은 시간을 품질 높은 코드 작성에 할애할 수 있으며, 신속한 피드백을 통해 개발 과정을 개선할 수 있기 때문이다.</p>
<h2 id="결론">결론</h2>
<p>프론트엔드 개발에서 테스트는 애플리케이션의 품질과 안정성을 보장하는 데 필수적이다. 적절한 테스트 종류의 선택, 테스트 도구의 적용, 그리고 테스트 자동화의 구현은 효과적인 테스트 전략의 핵심 요소이다.</p>
<p>왜냐하면 이를 통해 개발 과정의 효율성을 높이고, 최종 사용자에게 높은 품질의 애플리케이션을 제공할 수 있기 때문이다.</p>
<h2 id="좋은-테스트의-조건">좋은 테스트의 조건</h2>
<h3 id="1-실행-속도가-빨라야-한다">1. 실행 속도가 빨라야 한다.</h3>
<p>테스트의 실행 속도가 빠르다는 것은 코드를 수정할 때마다 빠른 피드백을 받을 수 있다는 의미이다. 이는 개발 속도를 빠르게 하고, 테스트를 더 자주 실행할 수 있도록 한다.</p>
<h3 id="2-내부-구현-변경-시-깨지지-않아야-한다">2. 내부 구현 변경 시 깨지지 않아야 한다.</h3>
<p>작은 리팩토링에도 테스트가 깨진다면 코드를 개선할때 믿고 의지할 수 없을 뿐 아니라, 오히려 테스트를 수정하는 비용을 발생시켜 코드 개선을 방해하는 결과를 낳게 된다.</p>
<h3 id="3-버그를-검출할-수-있어야-한다">3. 버그를 검출할 수 있어야 한다.</h3>
<p>테스트가 기대하는 결과를 구체적으로 명시하지 않거나 예상 가능한 시나리오를 모두 검증하지 않으면 제품 코드에 있는 버그를 발견하지 못할 수 있다. 그러므로 테스트 명세는 구체적이어야 하며, 모의 객체의 사용은 최대한 지양하는 것이 좋다.</p>
<h3 id="4-테스트의-결과가-안정적이어야-한다">4. 테스트의 결과가 안정적이어야 한다.</h3>
<p>테스트는 외부 환경의 영향을 최소화해서 언제 어디서 실행해도 동일한 결과를 보장해야 한다. 이러한 외부 환경은 현재 시간, 현재 기기의 OS, 네트워크 상태 등을 포함하며, 직접 조작할 수 있도록 모의 객체나 별도의 도구를 활용해야만 한다.</p>
<h3 id="5-의도가-명확히-드러나야-한다">5. 의도가 명확히 드러나야 한다.</h3>
<p>테스트 코드를 보고 한눈에 어떤 내용을 테스트하는지를 파악할 수 있어야 한다. 그렇지 않으면 추후에 해당 코드를 수정하거나 제거하기가 어려워져서 관리 비용이 늘어나게 된다. 테스트 준비를 위한 장황한 코드가 반복해서 사용되거나 결과를 검증하는 코드가 불필요하게 복잡하다면 별도의 함수 또는 단언문을 만들어서 추상화시키는 것이 좋다.</p>
<h2 id="테스트-전략의-중요성">테스트 전략의 중요성</h2>
<p>모든 요소를 100% 만족하는 테스트를 작성하는 것은 사실상 불가능하다. 그렇기에 프로젝트, 서비스 모듈 등의 특성에 따라 어떤 것을 포기하고 어떤 것을 얻을 것인가를 잘 판단해서 전략을 세워야 한다. 특히 프론트엔드 코드는 그래픽 사용자 인터페이스(GUI)와 밀접하게 관계되어 있고 사용자의 다양한 실행 환경을 고려해야 하기 때문에 다른 플랫폼에서 사용되는 전략을 그대로 사용할 수 없다. 시각적 요소, 서버와의 통신, 사용자 인터페이스(UI)를 통한 입력 등을 각각 어떻게 테스트 해야 할 지 고민하며 자신만의 전략을 세워야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[핵심 웹 지표]]></title>
            <link>https://velog.io/@4_21ee/%ED%95%B5%EC%8B%AC-%EC%9B%B9-%EC%A7%80%ED%91%9C-b57s4fvz</link>
            <guid>https://velog.io/@4_21ee/%ED%95%B5%EC%8B%AC-%EC%9B%B9-%EC%A7%80%ED%91%9C-b57s4fvz</guid>
            <pubDate>Mon, 25 Mar 2024 07:05:09 GMT</pubDate>
            <description><![CDATA[<h2 id="핵심-웹-지표란">핵심 웹 지표란?</h2>
<ul>
<li><p>구글에서 만든 지표로 웹사이트에서 뛰어난 사용자 경험을 제공하는 데 필수적인 지표를 일컫는 용어.</p>
</li>
<li><p>구글에서 핵심 웹 지표로 꼽는 지표</p>
<ul>
<li>최대 콘텐츠풀 페인트(LCP: Largest Contentful Paint)</li>
<li>최초 입력 지연(FID: First Input Delay)</li>
<li>누적 레이아웃 이동(CLS: Cumulative Layout Shift)</li>
</ul>
</li>
<li><p>이 외에 특정 문제를 진단하는 데 사용될 수 있는 지표</p>
<ul>
<li><p>최초 바이트까지의 시간(TTFB: Time To First Byte)
<img src="https://velog.velcdn.com/images/4_21ee/post/176e0ca7-cb6b-466d-85fd-802609d43379/image.png" alt=""></p>
</li>
<li><p>최초 콘텐츠풀 시간(FCP: First Contentful Paint)
<img src="https://velog.velcdn.com/images/4_21ee/post/3df8f33a-67fc-4b80-9b84-a1598c37047c/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h2 id="최대-콘텐츠풀-페인트lcp">최대 콘텐츠풀 페인트(LCP)</h2>
<ul>
<li>페이지가 처음으로 로드를 시작한 시점부터 뷰포트 내부에서 가장 큰 이미지 또는 텍스트를 렌더링하는 데 걸리는 시간<ul>
<li>뷰포트 내부에서 <code>큰 이미지와 텍스트</code>  는 다음과 같이 정의<ul>
<li><code>&lt;img&gt;</code></li>
<li><code>&lt;svg&gt;</code>  내부의 <code>&lt;image&gt;</code></li>
<li>poster 속성을 사용하는 <code>&lt;video&gt;</code></li>
<li>url()을 통해 불러온 배경 이미지가 있는 요소</li>
<li>텍스트와 같이 인라인 텍스트 요소를 포함하고 있는 블록 레벨 요소<ul>
<li>이 블록 레벨 요소에는 <code>&lt;p&gt;</code> , <code>&lt;div&gt;</code> 등이 포함된다.
<img src="https://velog.velcdn.com/images/4_21ee/post/b009a273-1ff5-4743-a9ab-81f990e616b1/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>개선방안<ul>
<li>텍스트는 언제나 옳다.</li>
<li>이미지를 불러오는 방법 변경.</li>
</ul>
</li>
</ul>
<h2 id="최초-입력-지연fid">최초 입력 지연(FID)</h2>
<ul>
<li><p>사용자가 페이지와 처음 상호 작용할 때부터 해당 상호 작용에 대한 응답으로 브라우저가 실제로 이벤트 핸들러 처리를 시작하기까지의 시간을 측정한다.</p>
</li>
<li><p>모든 입력에 대해 측정 X, 최초의 입력 하나에 대해서만 그 응답 지연이 얼마나 걸리는지 판단.</p>
</li>
<li><p>구글에서 정의하는 사용자 경험(RAIL)</p>
<ul>
<li><p>Response : 사용자의 입력에 대한 반응속도. 50ms 미만으로 이벤트를 처리할 것</p>
</li>
<li><p>Animation : 애니메이션의 각 프레임을 10ms 이하로 생성할 것</p>
</li>
<li><p>Idle : 유휴 시간을 극대화해 페이지가 50ms 이내에 사용자 입력에 응답하도록 할 것</p>
</li>
<li><p>Load : 5초 이내에 콘텐츠를 전달하고 인터랙션을 준비할 것</p>
<p>⇒ 이 가운데 최초 입력 지연은 R에 해당하는 응답에 초점을 맞추고 있다.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>최초 입력 지연이란 화면이 최초에 그려지고 난 뒤, 사용자가 웹페이지에서 클릭 등 상호작용을 수행했을 때 메인 스레드가 이 이벤트에 대한 반응을 할 수 있을 때까지 걸리는 시간을 의미한다. 그리고 이 시간은 메인 스레드가 처리해야 하는 다른 작업이 많을수록 느려진다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/4_21ee/post/c1e3ee89-6769-4cac-b7bf-a9ade1c96c11/image.png" alt=""></p>
<ul>
<li>개선방안<ul>
<li>실행에 오래 걸리는 긴 작업을 분리</li>
<li>자바스크립트 코드 최소화</li>
<li>타사 자바스크립트 코드 실행의 지연<ul>
<li>타사 스크립트는 대부분 웹페이지 로드에 중요한 자원이 아니므로 <code>&lt;script&gt;</code>  의 async와 defer를 이용해 지연 불러오기를 하는것이 좋다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="누적-레이아웃-이동cls">누적 레이아웃 이동(CLS)</h2>
<ul>
<li>페이지의 생명주기 동안 발생하는 모든 예기치 않은 이동에 대한 지표
<img src="https://velog.velcdn.com/images/4_21ee/post/663605dd-f398-4755-925b-9107f61e106d/image.png" alt=""></li>
</ul>
<ul>
<li>개선방안<ul>
<li>삽입이 예상되는 요소를 위한 추가적인 공간 확보</li>
<li>폰트 로딩 최적화</li>
<li>적절한 이미지 크기 설정</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CI/CD]]></title>
            <link>https://velog.io/@4_21ee/CICD</link>
            <guid>https://velog.io/@4_21ee/CICD</guid>
            <pubDate>Sun, 17 Mar 2024 15:53:18 GMT</pubDate>
            <description><![CDATA[<h2 id="ci">CI</h2>
<p>CI는 간단히 요약하자면 <code>빌드/테스트 자동화</code> 과정 CI는 개발자를 위한 자동화 프로세스인 <code>지속적인 통합(Continuous Integration)</code>을 의미한다. CI를 성공적으로 구현할 경우 애플리케이션에 대한 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 통합되므로 여러 명의 개발자가 <strong>동시에 애플리케이션 개발과 관련된 코드 작업을 할 경우 서로 충돌할 수 있는 문제를 해결</strong>할 수 있다.</p>
<ul>
<li>CI 단계에서 빌드와 테스트를 자동으로 진행해주면 아래와 같은 장점이 있다.<ul>
<li>여러 개발자가 관련된 코드를 작업하여 발생하는 충돌 문제를 해결할 수 있다.</li>
<li>커밋 할 때 마다 빌드와 자동 테스트가 이루어져 잘못된 merge를 예방할 수 있다.</li>
<li>코드 검증에 들어가는 시간이 줄어들며, 개발 편의성이 좋아진다.</li>
</ul>
</li>
</ul>
<p>개발자가 직접 코드를 병합하고 빌드, 테스트를 검증하는 것은 시간이 많이 소요될 뿐만 아니라 귀찮고 그 양도 프로젝트의 크기가 커질수록 많아질 수밖에 없다.</p>
<p>이를 자동화하면 개발자가 빌드와 테스트를 직접 하지 않고도 수정한 <strong>코드를 브랜치에 병합하기만 하면 자동으로 빌드와 테스트를 검증</strong>할 수 있다.</p>
<blockquote>
<p>CI의 간단한 순서</p>
<ul>
<li>개발자가 구현한 코드를 기존 코드와 병합한다.</li>
<li>병합된 코드가 올바르게 동작하고 빌드되는지 검증한다.</li>
<li>테스트 결과 문제가 있다면 수정하고 다시 1로 돌아간다. 문제가 없다면 배포를 진행한다.</li>
</ul>
</blockquote>
<h2 id="cd">CD</h2>
<p>CD는 간단히 말하면 배포 자동화 과정이다. CD는 <code>지속적인 서비스 제공(Continuous Delivery)</code> 또는 <code>지속적인 배포(Continuous Deployment)</code>를 의미하며 이 두 용어는 상호 교환적으로 사용된다.</p>
<p>지속적 배포는 빌드, 테스트 및 배포 단계를 자동화하는 DevOps 방식을 논리적 극한까지 끌어 올립니다. 코드 변경이 파이프라인의 <strong>이전 단계를 모두 성공적으로 통과하면 수동 개입 없이 해당 변경 사항이 프로덕션에 자동으로 배포됩니다.</strong> 지속적 배포를 채택하면 <strong>품질 저하 없이 최대한 빨리 사용자에게 새로운 기능을 제공</strong>할 수 있습니다.</p>
<blockquote>
<p>CD 단계에서</p>
<ul>
<li>지속적 제공 ( Continuous Delivery )<ul>
<li>CI를 마치고 릴리즈가 가능한 상태라면 배포까지 자동으로 해주는 것</li>
</ul>
</li>
<li>지속적 배포 ( Continuous Deployment )<ul>
<li>CI를 마치고 릴리즈가 가능한 상태라면 사람의 검증을 통해 수동으로 배포하는 것</li>
</ul>
</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/sju4486/post/cc8bf315-4723-45c2-a6ab-8ce9691446f2/image.png" alt=""></p>
<h2 id="cicd-종류">CI/CD 종류</h2>
<ul>
<li><code>Jenkins</code></li>
<li><code>CircleCI</code></li>
<li><code>TravisCI</code></li>
<li><code>Github Actions</code></li>
<li><code>etc</code></li>
</ul>
<h2 id="cicd-적용-전과후-비교">CI/CD 적용 전과후 비교</h2>
<p><strong><code>CI/CD를 적용하기 전</code></strong></p>
<ul>
<li>개발자들이 개발하여 코드를 수정</li>
<li>각자의 feature 브랜치에 코드를 push</li>
<li>각자의 코드를 git에 올리고 통합</li>
<li>에러가 발생했지만 어느 부분에서 에러가 났는지 모르므로 다시 어느 부분에 에러가 있는지 디버깅하고 코드를 수정</li>
<li>위의 과정을 반복</li>
<li>많은 시간을 할애하여 에러가 해결되었으면 배포를 시작 하지만 배포과정 또한, 개발자가 직접 배포과정을 거치므로 많은 시간을 소요</li>
</ul>
<p><strong><code>CI/CD를 적용 후</code></strong></p>
<ul>
<li>개발자들이 개발하여 feature브랜치에 코드를 push</li>
<li>git push를 통해 Trigger되어 CI서버에서 알아서 Build, Test, Lint를 실행하고 결과를 전송</li>
<li>개발자들은 결과를 전송받고 에러가 난 부분이 있다면 에러부분을 수정하고 코드를 master 브랜치에 merge</li>
<li>master 브랜치에 코드를 merge하고 Build, Test가 정상적으로 수행이 되었다면 CI서버에서 알아서 Deploy 과정을 수행</li>
</ul>
<p>Jenkins
<img src="https://velog.velcdn.com/images/4_21ee/post/d880d9db-4c2c-4a8e-a804-d4a3ce4ed3ea/image.png" alt=""></p>
<p>장점: Jenkins는 오픈 소스이며, 확장성이 뛰어나고 커뮤니티의 지원이 풍부합니다. 다양한 플러그인과 통합 가능한 도구들이 있어 다양한 시스템과 플랫폼에서 사용할 수 있습니다.</p>
<p>단점: 설정과 관리가 복잡할 수 있으며, 초기 설정에 시간이 걸릴 수 있습니다.</p>
<p>GitLab CI/CD
<img src="https://velog.velcdn.com/images/4_21ee/post/8f683367-a725-49aa-a7b1-adc045970973/image.png" alt="">
장점: GitLab은 코드 저장소와 CI/CD 기능을 한 플랫폼에서 제공하여 통합이 용이합니다. 코드 관리와 CI/CD 파이프라인을 단일 도구로 통합할 수 있으며, 사용이 간편하고 배포 설정을 쉽게 구성할 수 있습니다.
단점: 비교적 적은 플러그인이 있으며, 확장성 측면에서 다른 도구들에 비해 제한적일 수 있습니다.</p>
<p>CircleCI
<img src="https://velog.velcdn.com/images/4_21ee/post/33a219b4-2986-450e-a59d-5dc417e48378/image.png" alt="">
장점: CircleCI는 설정이 간단하며, 클라우드에서 호스팅되기 때문에 관리 부담이 적습니다. 빠른 빌드와 테스트 속도를 제공하며, 커뮤니티와의 통합이 잘 이루어져 있습니다.
단점: 무료 플랜이 제한적이며, 높은 트래픽이나 큰 규모의 프로젝트에는 추가 비용이 발생할 수 있습니다.</p>
<p>Travis CI
<img src="https://velog.velcdn.com/images/4_21ee/post/e496064f-25f6-44a6-9b45-996000e2e5b6/image.png" alt="">
장점: Travis CI는 깃허브와 연동이 원활하며, 사용이 간편합니다. 무료 플랜으로 시작할 수 있고, 프로젝트 설정이 간단하고 직관적입니다.
단점: 깃허브와의 연동에 의존하기 때문에 다른 소스 코드 관리 플랫폼과는 호환성이 제한될 수 있습니다. 무료 플랜에서는 제한적인 기능만 제공될 수 있습니다.</p>
<p>깃헙 액션(GitHub Actions)
<img src="https://velog.velcdn.com/images/4_21ee/post/b48fea6d-de02-498e-a517-599232a7d688/image.png" alt="">
깃헙 액션(GitHub Actions)은 깃허브에서 제공하는 자체 CI/CD 도구입니다. 깃헙 액션은 코드 저장소와 직접 통합되어 사용자가 작성한 워크플로우 파일을 기반으로 자동화된 빌드, 테스트, 배포 등의 작업을 수행할 수 있습니다.</p>
<hr>
<p>깃헙 액션(GitHub Actions) 장점:</p>
<p>깃헙 액션은 깃허브와의 강력한 통합을 제공합니다. 코드 저장소와 직접 연동되기 때문에 워크플로우를 쉽게 작성하고 관리할 수 있습니다.</p>
<p>설정이 간단하고 사용이 편리합니다. YAML 기반의 워크플로우 파일을 작성하여 필요한 작업을 정의할 수 있으며, 버전 관리도 손쉽게 할 수 있습니다.</p>
<p>다양한 이벤트와 트리거를 지원하여, 코드에 변경이 발생하거나 일정 시간마다 주기적으로 작업을 실행할 수 있습니다.</p>
<p>깃헙 액션 마켓플레이스에서 다른 사용자가 작성한 워크플로우 템플릿을 공유하고 활용할 수 있습니다.</p>
<p>깃헙 액션(GitHub Actions) 단점:</p>
<p>초보자에게는 초기 설정이 다소 복잡할 수 있습니다. 기본 개념과 YAML 문법을 이해해야 하며, 복잡한 워크플로우를 작성할 경우 학습 곡선이 존재할 수 있습니다.</p>
<p>실행 환경이 깃허브에서 호스팅되기 때문에, 프라이빗 환경에서 실행해야 하는 경우 추가적인 설정이 필요할 수 있습니다.</p>
<p>사용량에 따라 요금이 부과될 수 있습니다. 무료 플랜에서는 제한된 자원과 기능만을 제공하며, 대규모 프로젝트나 상업적 용도로 사용할 경우 요금을 지불해야 할 수 있습니다.</p>
<p>깃헙 액션은 깃허브와의 강력한 통합과 사용의 편의성을 제공하는 도구로, 특히 오픈 소스 프로젝트나 깃허브를 중심으로 개발하는 경우에는 매우 유용합니다. 하지만 프로젝트의 규모와 요구 사항에 따라 다른 CI/CD 도구들과 비교하여 선택하는 것이 좋습니다.</p>
<p>가장 훌륭한 선택은 사용자의 요구 사항과 프로젝트의 특성에 따라 다를 수 있습니다. 그러나 현재 시장에서 가장 널리 사용되고 커뮤니티의 지원이 많은 Jenkins와 GitLab CI/CD는 많은 사람들에게 추천되고 있습니다. Jenkins는 다양한 플러그인과 확장성을 제공하며, GitLab CI/CD는 코드 저장소와 통합된 단일 플랫폼으로 편의성을 제공합니다. 이러한 도구들은 대규모 프로젝트에서도 안정적으로 사용되고 있으며, 사용자 경험과 개발 팀의 선호도에 따라 선택할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 51 | redux-observable]]></title>
            <link>https://velog.io/@4_21ee/TIL-51-redux-observable</link>
            <guid>https://velog.io/@4_21ee/TIL-51-redux-observable</guid>
            <pubDate>Wed, 26 Jan 2022 02:36:48 GMT</pubDate>
            <description><![CDATA[<h1 id="redux-observable란">Redux Observable란?</h1>
<p>RxJS 기반의 Redux Middleware이다.
<em>Redux Middleware는 dispatch가 호출되었을 때, Action을 가로채, 작업을 처리하고 다음 Middleware에게 Action을 전달한다.</em>
dispatch 가 호출 되었을때, 구독하고 있는 Epic 들이 원하는 Action 이 있다면, Action 을 Observable 로 작업을 처리하고, 다시 store.dispatch 로 Action 을 호출하는 방법으로 구성되어 있다.</p>
<pre><code class="language-js">epic(action$, state$).subscribe(store.dispatch)</code></pre>
<h2 id="redux-observable-구현-과정">redux-observable 구현 과정</h2>
<ol>
<li>set up</li>
<li>epic 생성</li>
<li>export epic : combineEpics 사용(epic이 두개 이상일때)</li>
<li>store 등록
5-1. createEpicMiddelware() : epicMiddleware 생성
5-2. store에 middleware 추가
5-3. epicMiddleware.run()<h2 id="set-up">SET UP</h2>
<pre><code class="language-bash">npm install --save redux-observable@1.2.0
npm install rxjs
npm install rxjs-operators</code></pre>
<h2 id="epic-생성">Epic 생성</h2>
<h3 id="epic이란">Epic이란?</h3>
Epic이란 reducer의 action 하나하나에 매칭되는 middleware이다.
epic내의 구현 흐름은 특정 action이 dispatch 되었을 경우 그것과 매칭되는 epic이 발동하고, epic 내의 순수함수들의 일련의 절차를 거치고 나서, 다시 특정 action을 반환한다. 따라서 epic은 action in, action out 형식이라고 생각할 수 있다.<h3 id="epic-생성-1">Epic 생성</h3>
epic(increment_plus3_epic)에 increment라는 action이 들어오면 incrementByValue()라는 액션의 parameter로 3을 넣어 action을 반환하는 과정으로 예를 들어보면<pre><code class="language-js">import { Action, Observable } from &quot;redux&quot;;
import { ActionObservable, StateObservable, ofType, combineEpics } from &quot;redux-observable&quot;;
import { map, mergeMap } from &quot;rxjs/operators&quot;;
import { incrementByValue, increment } from &quot;./counter&quot;;
</code></pre>
</li>
</ol>
<p>const increment_plus3_epic = (action$, state$) =&gt; {
  return action$
  .pipe(
    ofType(increment),
    map((result) =&gt; {
      return incrementByValue(3)
    })
    )
}</p>
<p>export const exampleEpic = combineEpics(increment_plus3_epic)</p>
<pre><code>### epic export
위의 epic들을 store에 등록하기 위해 export한다. 이때 epic은 action 당 하나씩 만들어지기 때문에 하나 이상일 수 있다. 따라서 combineEpic을 통해 묶어서 export한다.
```js
export const exampleEpic = combineEpics(increment_plus3_epic)</code></pre><h2 id="store-등록">Store 등록</h2>
<h3 id="createepicmiddelware">createEpicMiddelWare()</h3>
<p>만들어 놓은 epic을 store에 middleware로 등록하기 위해서, 여러 미들웨어들을 담을 대표가 필요하다. 이를 위해, createEpicMiddleware()를 이용한다.</p>
<pre><code class="language-js">const epicMiddleWare = createEpicMiddleware()</code></pre>
<h3 id="store-등록-1">store 등록</h3>
<p>앞에서 만든 대표 미들웨어를 store에 등록한다.</p>
<pre><code class="language-js">export const store = configureStore({
  reducer: {
    counter: CounterReducer,
  },
  // 밑의 한 줄을 추가한다.
  middleware: (getDefaultMiddleware) =&gt; getDefaultMiddleware().concat(epicMiddleWare),
})</code></pre>
<h3 id="epic-등록">epic 등록</h3>
<p>편의상 대표 미들웨어라고 부른 것이 store에 등록되었기 때문에, 그 대표 미들웨어에 여러 epic들이 등록되며 자동으로 store에 등록된다. 미리 만들어 놓은 epic을 대표 미들웨어에 등록한다.</p>
<pre><code class="language-js">epicMiddleware.run(exampleEpic)</code></pre>
<h3 id="store의-전체-코드">store의 전체 코드</h3>
<pre><code class="language-js">import { configureStore } from &quot;@reduxjs/toolkit&quot;;
import { createEpicMiddleware } from &quot;redux-observable&quot;;
import CounterReducer from &quot; ../features/counter/counter&quot;;
import { exampleEpic } from &quot;../features/counter/counterEpic&quot;;

const epicMiddleWare = createEpicMiddleware();

export const store = configureStore({
  reducer: {
    counter: CounterReducer,
  },
  middleware: (getDefaultMiddleware) =&gt; getDefaultMiddleware().concat(epicMiddleWare),
})

epicMiddleWare.run(exampleEpic)</code></pre>
<h4 id="결과">결과</h4>
<p>increment 액션을 보내면 epic이 받아서 incrementByValue(3)을 리턴하고 다시 increment와 incrementByValue(3)이 모두 reducer로 가서 각각 1, 3씩 state를 증가시킨다. 총 4씩 증가하는 것이다.
epic은 mniddleware로 주로 사용되기 때문에 네트워크 통신이나 비동기 처리에 사용하면 좋을 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 50 | Redux - Ducks pattern]]></title>
            <link>https://velog.io/@4_21ee/TIL-50-Redux-Ducks-pattern</link>
            <guid>https://velog.io/@4_21ee/TIL-50-Redux-Ducks-pattern</guid>
            <pubDate>Fri, 14 Jan 2022 01:39:32 GMT</pubDate>
            <description><![CDATA[<h2 id="리덕스-모듈이란">리덕스 모듈이란?</h2>
<ul>
<li>액션 타입(Actions), 액션 생성 함수(Action Creators), 리듀서(Reducer)가 모두 들어있는 자바스크립트 파일을 의미.</li>
<li>이렇게 하나의 파일에 모두 작성하는 것을 <strong>덕스(Ducks) 패턴</strong>이라고 한다.</li>
<li>리덕스 모듈에서 리듀서는 default export하고, 액션 생성 함수는 그냥 export한다.<h1 id="ducks-pattern">Ducks pattern</h1>
</li>
<li>덕스 패턴은 자바스크립트 개발자인 Erik Rasmussen이 리덕스 사용 방법과 관련하여 제안한 패턴이다.</li>
<li>액션 타입, 액션 생성 함수, 리듀서를 각각 별도의 파일(심지어는 별도의 폴더)에 분리하여 작성하기 보다는 그 셋을 하나의 모듈처럼 한 파일 안에 작성하자는 제안이다.</li>
<li>덕스 패턴을 이용하여 리덕스를 모듈화하는 것의 이점은 코드를 작성하는 사람도 왔다갔다 하지 않고 하나의 파일 안에서 <em>액션 타입 =&gt; 액션 생성 함수 =&gt; 리듀서</em> 이런 식으로 순서대로 작성하기만 하면 되기 때문에 코드 작성하기가 더 용이하고, 다른 사람들이 보기에도 코드가 깔끔 명료하고 가독성이 좋다는 것이다.</li>
</ul>
<h2 id="ducks-pattern의-규칙">Ducks pattern의 규칙</h2>
<ul>
<li>MUST <strong>export default</strong> a function called <strong>reducer()</strong>
반드시 리듀서 함수를 default export 해야한다.</li>
<li>MUST <strong>export</strong> its action creators as functions
반드시 액션 생성 함수를 export 해야한다.</li>
<li>MUST have action types in the form <strong>npm-module-or-app/reducer/ACTION_TYPE</strong>
반드시 접두사를 붙인 형태로 액션 타입을 정의해야 한다. (아래 예제 코드 참고)</li>
<li>MAY <strong>export</strong> its action types as <strong>UPPER_SNAKE_CASE</strong>, if an external <strong>reducer</strong> needs to listen for them, or if it is a published reusable library
(필수는 아니지만) 외부 리듀서가 모듈 내 액션 타입을 바라보고 있거나, 모듈이 재사용 가능한 라이브러리로 쓰이는 것이라면 액션 타입을 UPPER_SNAKE_CASE 형태로 이름 짓고 export 하면 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 49 | SCSS & Styled-components]]></title>
            <link>https://velog.io/@4_21ee/TIL-49-SCSS-Styled-components</link>
            <guid>https://velog.io/@4_21ee/TIL-49-SCSS-Styled-components</guid>
            <pubDate>Thu, 13 Jan 2022 01:01:58 GMT</pubDate>
            <description><![CDATA[<h2 id="기본-css-문제점">기본 CSS 문제점</h2>
<p>웹 문서의 스타일을 담당하는 CSS 문법은 작성하는 데에 있어서 몇몇 문제점이 있다.</p>
<ol>
<li>클래스명에 대한 고민.</li>
<li>정해진 가이드가 없으면 구조가 복잡해짐.</li>
<li>방대한 스타일 정보로 인한 파일의 크기.
이러한 문제점을 해결하기 위해 나온 문법으로 scss, styled-components가 출시되었다.</li>
</ol>
<h1 id="scss">SCSS</h1>
<ul>
<li>SASS 버전3에서 나온 SCSS 문법은 이전에 나왔던 SASS 문법과는 달리 기존 CSS 문법과의 호환성을 지키면서도 SASS 기능까지 활용할 수 있다.</li>
<li>css preprocessing(css 전처리)로서, scss 문법으로 스타일 정보를 작성할시 컴파일러를 거쳐 css 문법으로 전환되는 과정을 거친다.</li>
<li>방대한 스타일 정보의 구조를 Nesting 기능을 활용하여 가독성있게 전환할 수 있으며 이외에도 다양한 기능을 갖고 있다.</li>
<li>변수를 활용하거나 Mixin 기능과 여러 selector 기능이 존재한다.
<em>but, 구조에 있어서 가독성이 보완되고 디버깅이 용이해졌지만 여전히 클래스명에 대한 고민 존재.</em></li>
</ul>
<h1 id="styled-components">Styled-components</h1>
<ul>
<li>클래스명에 대해 고민하는 문제를 덜어주면서 기존의 컴포넌트라는 개념이 지니고 있는 재사용성이라는 장점 또한 갖고 있다.</li>
<li>css 문법을 js 파일에 넣어 변수처럼 활용하면 컴파일 되었을때, html 태그별로 클래스명이 자동으로 부여된다.</li>
<li>컴포넌트의 속성인 props 기능을 활용할 수 있어, jsx에서 넘겨주는 값을 css 문법에서 활용 가능하다.
<em>but, 스타일 정보가 많아지거나 프로젝트의 규모가 커지면 js 파일 자체가 굉장히 방대해질 수 있어 또다시 가독성과 디버깅의 문제가 발생할 수 있다.</em></li>
</ul>
<h2 id="css-in-css-css-in-js">CSS in CSS, CSS in JS</h2>
<h3 id="scss-1">scss</h3>
<ul>
<li>css in css 문법은 기본적으로 js 파일과는 분리되어 있는 구조이기 때문에 어떤 컴포넌트의 상태값이 변하더라도 이에 반응하기 쉽지 않으며, 처음에 렌더링될 때에도 브라우저에 보이지 않는 컴포넌트까지 웹문서의 스타일 정보로 읽히기 때문에 불필요한 컴파일 과정이 추가된다.<h3 id="styled-components-1">styled-components</h3>
</li>
<li>css in js 방식이기에 해당 컴포넌트가 렌더링될 때에만 해당 스타일 정보를 읽는다. 이 부분이 장점처럼 보일 수 있지만 한편으로는 해당 컴포넌트가 렌더링 될 때마다 스타일 정보를 가져와야 한다는 의미이다.</li>
<li>만약, 굉장히 동적인 이벤트가 많은 웹사이트가 있다면 그만큼 컴포넌트의 상태값 전환도 활발하며, 컴포넌트 인터렉션이 활발할수록 자주 렌더링될 것이다. 그만큼 스타일 정보도 그때그때 다시 읽어와야 한다는 것이다. 그에 반해 css in css는 html문서에서 이미 읽혀져있는 상태이기 때문에 처음에는 스타일 정보를 가져오는 양이 많더라도 그 이후에 추가적인 렌더링은 상대적으로 적다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 48 | RxJS]]></title>
            <link>https://velog.io/@4_21ee/TIL-48-RxJS</link>
            <guid>https://velog.io/@4_21ee/TIL-48-RxJS</guid>
            <pubDate>Wed, 12 Jan 2022 01:46:51 GMT</pubDate>
            <description><![CDATA[<h1 id="rxjs란">RxJS란?</h1>
<p>Observable을 사용하여 비동기 및 이벤트 기반 프로그램을 작성하기 위한 라이브러리</p>
<h2 id="rxjs를-사용하는-이유">RxJS를 사용하는 이유</h2>
<p>RxJS는 ReactiveX의 자바스크립트 버전의 라이브러리이다.
RxJS는 입력오류, 상태오류, 로직오류로 인해 발생하는 오류들을 효과적으로 처리하기 위한 최적의 라이브러리이다. 
궁극적으로는 일관된 방식으로 안전하게 데이터 흐름의 처리를 도와주는 라이브러리이며 한마디로 정리하자면 범용데이터의 흐름을 제어하는 솔루션이다.
상태 전파를 하기 위해 리액티브 프로그래밍의 패러다임도 녹아있고, 로직오류를 방지하기 위한 함수형 퓨ㅡ로그래밍의 패러다임 기법도 사용하고 있다.</p>
<h3 id="설치">설치</h3>
<pre><code class="language-bash">npm install rxjs
npm install @reactivex/rxjs    // Typescript와 같이 사용하려면 설치</code></pre>
<h3 id="시작">시작</h3>
<h4 id="click-이벤트를-통해-consolelog를-실행하는-코드">Click 이벤트를 통해 console.log를 실행하는 코드</h4>
<ul>
<li>JavaScript<pre><code class="language-js">const eventHandler = event =&gt; {
console.log(event.currentTarget);
}
</code></pre>
</li>
</ul>
<p>document.addEventListener(&#39;click&#39;, eventHandler);</p>
<pre><code>- RxJS
```js
import { fromEvent } from &#39;rxjs&#39;;
const click$ = fromEvent(document, &#39;click&#39;);    // observable
const observer = event =&gt; {
  console.log(event.currentTarget);
}
click$.subscribe(observer);</code></pre><p>fromEvent를 통해 이벤트 Observable로 생성하고 observer가 Observable 객체를 구독한다.</p>
<p>Observable는 어떠한 행위를 하는 객체 또는 데이터로써 어떠한 동작을 하기 위해 데이터 또는 이벤트를 Observable로 생성하고, 이를 구독하여 어떠한 observer 행위를 하여 개발을 진행하는 방식이 RxJS의 개발 패턴이다.</p>
<p>=&gt; 그렇기 때문에 RxJS 개발 패턴에서 가장 먼저 해야하는 것이 Observable을 생성하는 것이다.</p>
<h2 id="rxjs의-중요개념">RxJS의 중요개념</h2>
<h3 id="observable">Observable</h3>
<p>시간을 축으로 연속적인 데이터를 저장한 객체.
이러한 Observable 객체를 observer에 전달하여 처리하는 과정을 스트림이라고 한다.</p>
<h3 id="오퍼레이터">오퍼레이터</h3>
<p>filter와 같이 Observable 객체를 생성 또는 조작하는 함수를 오퍼레이터라고 한다. 이러한 오퍼레이터를 통해 Observable 객체를 생성하기도 하고, 각각의 Observable 객체를 서로 연결 또는 분리, 합치기도 한다. 오퍼레이터는 현재의 Observable의 인스턴스를 기반으로 항상 새로운 Observable 인스턴스를 반환한다. RxJS는 다양한 오퍼레이터들을 제공하고 있고, 상황에 맞는 오퍼레이터를 사용해야 한다.</p>
<p>과거에는 오퍼레이트 사용시 도트체이닝을 사용하여 개발하였으나, RxJS 6.0부터 지원 도트체이닝을 제공하지 않고, pipe 오퍼레이터만 제공한다.
도트체이닝 사용 시 Observable 객체가 모든 오퍼레이터를 가지고 있어야 하는데, 이는 불필요한 오퍼레이터도 모두 가지고 있어야 하기에 파일 사이즈가 증가한다.
pipe 오퍼레이터 사용시 webpack을 통해 트리쉐이킹(사용하지 않는 모듈을 번들링 할 때 제거)하여 사용된다.</p>
<h3 id="observer">Observer</h3>
<p>Observable에 전달된 데이터를 소비하는 주체이며, next, error, complete 함수를 가진 객체이다.</p>
<pre><code class="language-js">const observer = {
  next: x =&gt; console.log(`Observer가 Observable로 받은 데이터: ${x}`),
  error: err =&gt; console.log(`Observer가 Observable로 받은 에러 데이터: ${error}`),
  complete: () =&gt; console.log(`Observer가 Observable로 부터 종료 되었다는 알림 메시지`)
}

click$.subscribe(observer)</code></pre>
<h3 id="subscription">Subscription</h3>
<p>Observable.prototype.subscribe의 반환값이다.
Subscription 객체는 자원의 해제를 담당하고 더이상 데이터를 전달받고 싶지 않은 경우 unsubscribe 메소드를 호출하여 자원을 해제해야한다.
유한한 데이터의 경우 Observable의 자원을 해지할 필요가 없다.
하지만 이벤트 핸들러 또는 interval을 통해 데이터를 계속 전달 받는 경우 자원해제가 필요하다.</p>
<pre><code class="language-js">const subscription = currentTarget$.subscribe(observer);

subscription.unsubscribe();</code></pre>
<h2 id="rxjs-개발방법">RxJS 개발방법</h2>
<p>이벤트를 Observable로 변환하고 filter 등의 오퍼레이터를 이용하여 변경데이터를 처리할 Observer를 만들고 subscribe 메소드를 통해 Observable를 구독한다.</p>
<ul>
<li><ol>
<li>데이터를 Observable로 변경</li>
</ol>
</li>
<li><ol start="2">
<li>오퍼레이터를 통해 변경 또는 추출 또는 여러 개의 Observable을 결합 또는 분리</li>
</ol>
</li>
<li><ol start="3">
<li>원하는 데이터를 처리할 Observer를 생성</li>
</ol>
</li>
<li><ol start="4">
<li>Observable의 subscribe를 통해 Observer를 등록</li>
</ol>
</li>
<li><ol start="5">
<li>Observable의 구독을 정지하고 자원을 해제</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 47 | AG - Grid 사용하기]]></title>
            <link>https://velog.io/@4_21ee/TIL-47-AG-Grid-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@4_21ee/TIL-47-AG-Grid-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 11 Jan 2022 01:58:56 GMT</pubDate>
            <description><![CDATA[<h1 id="ag-grid란">AG-Grid란?</h1>
<p>자바스크립트 기반의 오픈 소스 그리드.
서버사이드 렌더링, 엑셀 추출, Master-Detail 구조, Tree, Pivot 등을 지원하며 무료버전과 유료버전으로 나뉘어 있지만 무료 버전만으로도 많은 기능을 제공하고 있다.</p>
<h2 id="ag-grid-사용">AG-Grid 사용</h2>
<p>JS 스크립트 기반으로 어떤 플랫폼에서도 사용할 수 있다. 
복잡한 그리드를 Ag-grid를 통해 손쉽게 그릴 수 있으며 수많은 데이터를 한눈에 보기 쉽게 정리할 수 있다는 장점이 있다.</p>
<h3 id="ag-grid-설치하기">AG-Grid 설치하기</h3>
<pre><code class="language-bash">npm install ag-grid-community ag-grid-react --save</code></pre>
<h3 id="column-생성">Column 생성</h3>
<pre><code class="language-js">import React from &#39;react&#39;;
import { render } from &#39;react-dom&#39;;
import {AgGridColumn, AgGridReact} from &#39;ag-grid-react&#39;;

import &#39;ag-grid-community/dist/styles/ag-grid.css&#39;;
import &#39;ag-grid-community/dist/styles/ag-theme-alpine.css&#39;;

const App = () =&gt; {
   const rowData = [
       {make: &quot;Toyota&quot;, model: &quot;Celica&quot;, price: 35000},
       {make: &quot;Ford&quot;, model: &quot;Mondeo&quot;, price: 32000},
       {make: &quot;Porsche&quot;, model: &quot;Boxter&quot;, price: 72000}
   ];

   return (
       &lt;div className=&quot;ag-theme-alpine&quot; style={{height: 400, width: 600}}&gt;
           &lt;AgGridReact
               rowData={rowData}&gt;
               &lt;AgGridColumn field=&quot;make&quot;&gt;&lt;/AgGridColumn&gt;
               &lt;AgGridColumn field=&quot;model&quot;&gt;&lt;/AgGridColumn&gt;
               &lt;AgGridColumn field=&quot;price&quot;&gt;&lt;/AgGridColumn&gt;
           &lt;/AgGridReact&gt;
       &lt;/div&gt;
   );
};

render(&lt;App /&gt;, document.getElementById(&#39;root&#39;));</code></pre>
<p>AgGridReact와 필요한 CSS를 import한다.
그리드의 두 가지 필수 구성 속성인 열 정의(columnDefs)와 데이터(rowData)는 필수로 들어가야 한다.</p>
<h2 id="ag-grid의-기능">AG-Grid의 기능</h2>
<h3 id="검색-및-정렬">검색 및 정렬</h3>
<p>ColumnDefs에 저장된 여러개의 컬럼들을 공통의 기본값으로 정의하기 위해서는 defaultColDef 속성을 사용해야 한다. 
defaultColDef에 정의 된 속성들을 살펴보면</p>
<ul>
<li>sortable : 열 머리글을 클릭하여 그리드를 정렬할 수 있는 기능으로, 머리글을 클릭하면 오름차순, 내림차순 및 정렬 기본으로 전환된다. 실제 응용 프로그램에서 많은 열과 수많은 행이 있을 경우 정렬해주는 기능은 필수이다.</li>
<li>filter : 검색 기능. 머리글을 가리키면 그리드에 작은 열 메뉴 아이콘이 표시된다. 그것을 누르면 필터의 종류와 필터링할 텍스트를 선택할 수 있는 필터링 UI가 있는 팝업이 표시된다.</li>
<li>floatingFilter : 검색을 하기 위해 머리글을 한 번 클릭하고 검색하는 것은 불편하다. header 밑행에 바로 검색할 수 있게 설정한다.</li>
<li>resizeable : header의 사이즈 간격 조절이 가능하게 해 준다. <h3 id="axios를-통한-crud">Axios를 통한 CRUD</h3>
<h3 id="treedata">TreeData</h3>
treeData는 부모와 자식 관계로 이루어진 상위/하위 데이터로 상위 폴더 한 개에 여러 개의 자식을 넣을 수 있다. 
비슷한 성격을 가진 rowGroup은 행을 그룹화를 하여 여러 개의 열을 표현할 수 있다.<h2 id="ag-grid의-장단점">AG-Grid의 장단점</h2>
<h3 id="장점">장점</h3>
</li>
<li>무료지만 막강한 기능 제공을 하며 상용버전도 저렴하다.</li>
<li>자바스크립트 기반으로 어떤 플랫폼에서도 사용이 가능하다. </li>
<li>설치가 쉽다. </li>
<li>사용하기 쉽다. </li>
<li>자세한 레퍼런스와 샘플, 코드들을 제공한다.</li>
<li>확장성이 좋기 때문에 사용하는 개발자의 역량에 따라 서비스에 맞는 컴포넌트 등을 추가 개발하여 이용하기 쉽다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>그리드만 제공하기 때문에 차트와 그래프는 적당한걸 찾아서 별도로 이용해야 한다.</li>
<li>한글 가이드문서가 없다.</li>
<li>참고 레퍼런스가 부족하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 46 | useRef]]></title>
            <link>https://velog.io/@4_21ee/TIL-46-useRef</link>
            <guid>https://velog.io/@4_21ee/TIL-46-useRef</guid>
            <pubDate>Mon, 10 Jan 2022 13:36:17 GMT</pubDate>
            <description><![CDATA[<h1 id="useref란">useRef란?</h1>
<p>useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환한다. 
반환된 객체는 컴포넌트의 전 생애주기를 통해 유지된다.
본직적으로 useRef는 .current 프로퍼티에 변경 가능한 값을 담고 있는 상자와 같다.</p>
<h2 id="useref를-언제-사용할까">useRef를 언제 사용할까?</h2>
<h3 id="특정-dom-선택하기">특정 DOM 선택하기</h3>
<p>JavaScript를 사용할 때는, 특정 DOM을 선택해야 하는 상황에 getElementById, querySelector, 같은 DOM Selector 함수를 사용해서 DOM을 선택한다.</p>
<p>리액트에서는 DOM을 선택할 때 ref를 사용한다. 
함수형 컴포넌트에서 ref를 사용할 때는 useRef라는 Hook 함수를 사용하고 클래스형 컴포넌트에서는 콜백 함수를 사용하거나 React.createRef 함수를 사용한다.</p>
<h3 id="컴포넌트-안의-변수-만들기">컴포넌트 안의 변수 만들기</h3>
<p>컴포넌트 안에서 조회 및 수정할 수 있는 변수를 관리할 수 있다.</p>
<p>useRef로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않는다. 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그다음 렌더링 이후로 업데이트된 상태를 조회할 수 있지만, useRef로 관리하는 변수는 설정 후 바로 조회할 수 있다.</p>
<p>이 변수를 사용하여 관리할 수 있는 값</p>
<ul>
<li>setTimeout, setInterval을 통해서 만들어진 id</li>
<li>외부 라이브러리를 사용하여 생성된 인스턴스</li>
<li>scroll 위치</li>
</ul>
<h3 id="리렌더링-방지하기">리렌더링 방지하기</h3>
<p>컴포넌트가 렌더링 된다는 것은 함수(컴포넌트)를 호출하여 실행되는 것을 말한다. 함수가 실행될 때마다 내부에 선언되어 있던 표현식(변수나 또 다른 함수 등)도 매번 다시 선언되어 사용한다.</p>
<p>컴포넌트는 자신의 state가 변경되거나, 부모에게서 받는 props가 변경되었을 때마다 리렌더링 된다.</p>
<p>심지어 하위 컴포넌트에 최적화 설정을 해주지 않으면 부모에게서 받는 props가 변경되지 않았더라도 리렌더링 된다.</p>
<p>useRef로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않으므로 리렌더링 방지에 활용할 수 있다.</p>
<h2 id="useref로-dom-선택하는-방법">useRef로 DOM 선택하는 방법</h2>
<p>useRef()를 사용하여 Ref 객체를 만들고, 이 객체를 선택하고 싶은 DOM에 ref 값으로 설정한다. 그러면 Ref 객체의 .current 값은 DOM을 가리키게 된다.</p>
<h2 id="useref로-컴포넌트-안의-변수-만드는-방법">useRef로 컴포넌트 안의 변수 만드는 방법</h2>
<p>useRef()를 사용할 때 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 된다. 그리고 이값을 수정할 때는 .current 값을 수정하면 되고 조회할 때는 .current를 조회하면 된다.</p>
<h2 id="리렌더링-방지하기-1">리렌더링 방지하기</h2>
<p>onChange 구현 부분을 ref 값으로 대체해서 리렌더링을 방지할 수 있다. state 로 event의 value에 접근하지 않고 refObject.current.value를 사용하는 방법이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 45 | TS - 열거 타입(Enum)과 제네릭(Generic)]]></title>
            <link>https://velog.io/@4_21ee/TIL-45-TS-%EC%97%B4%EA%B1%B0-%ED%83%80%EC%9E%85Enum%EA%B3%BC-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</link>
            <guid>https://velog.io/@4_21ee/TIL-45-TS-%EC%97%B4%EA%B1%B0-%ED%83%80%EC%9E%85Enum%EA%B3%BC-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</guid>
            <pubDate>Sun, 09 Jan 2022 07:45:38 GMT</pubDate>
            <description><![CDATA[<h1 id="열거-타입enum">열거 타입(Enum)</h1>
<p>열거 타입은 일정 수의 상수로 구성된 집합을 만든다. 상수로는 숫자나 문자열을 사용할 수 있다.
높은 가독성이 필여하고 일정 집합에만 값을 배정하고 싶으며, 데이터 저장을 효율적으로 하고 싶은 상황에선 열거 타입을 사용하는 것이 좋다.
타입스크립트는 enum 키워드로 일정 수의 상수로 구성된 집합을 만든다. 열거를 이용해 요일을 표시하는 타입을 선언해보면</p>
<pre><code class="language-ts">enum Weekdays {
  Monday = 1,
  Tuesday = 2,
  Wednesday = 3,
  Thursday = 4,
  Friday = 5,
  Saturday = 6,
  Sunday = 7,
}</code></pre>
<p>Weekdays 타입이 가질 수 있는 값은 수가 정해져 있다. 각 enum 멤버를 숫자값으로 초기화하고, 각 요일은 점 표기법으로 참조할 수 있다.</p>
<pre><code class="language-ts">enum Weekdays {
  Monday = 1,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday,
}</code></pre>
<p>다음과 같이 월요일을 1로 초기화하고 나머지 값을 따로 할당해주지 않으면 자동으로 1씩 증가된 값이 할당된다.</p>
<h2 id="열거-타입을-사용해-리팩토링하기">열거 타입을 사용해 리팩토링하기</h2>
<pre><code class="language-ts">function convertTemperature(temp: number, fromTo: string): number {
  return &#39;FtoC&#39; === fromTo
  (temp - 32) * 5.0 / 9.0:    //    화씨에서 섭씨로 변환
  temp * 9.0 / 5.0 + 32;    //    섭씨에서 화씨로 변환
}</code></pre>
<p>convertTemperature()는 화씨 온도를 섭씨 온도로 또는 그 반대로 변환하는 함수다. 이 함수를 열거 타입을 이용하여 리팩토링하면</p>
<pre><code class="language-ts">enum Direction {
  FtoC,
  CtoF,
}
function convertTemperature(temp: number, fromTo: Direction): number{
  return Direction.FtoC === fromTo ? ((temp - 32) * 5.0) / 9.0 : (temp * 9.0) / 5.0 + 32;
}</code></pre>
<h1 id="제네릭generic">제네릭(Generic)</h1>
<p>타입스크립트 제네릭을 사용하면 다양한 타입을 지원하는 함수를 작성할 수 있다. 즉 제네릭을 사용해 함수를 선언하면, 함수의 호출자가 나중에 구체적인 타입을 지정할 수 있다. 타입스크립트는 제네릭 함수, 클래스 또는 인터페이스를 작성할 수 있다. 제네릭 타입은 T in Array&lt;T&gt;와 같이 임의의 문자로 표시한다. 배열 내 요소의 타입을 선언할 때 &lt;&gt; 기호 안에 해당 타입을 작성한다.</p>
<pre><code class="language-ts">let lotteryNumbers: Array&lt;number&gt;;</code></pre>
<p>제네릭은 코드를 사용할 때 타입을 선언함으로써 여러 종류의 타입 값을 처리할 수 있게 해준다.</p>
<ul>
<li>배열 요소의 타입을 정의한다<pre><code class="language-ts">const someValues: number[];</code></pre>
</li>
<li>제네릭 Array&lt;&gt; 키워드로 &lt;&gt; 기호 안에 타입 파라미터를 작성한다.<pre><code class="language-ts">const someValues: Array&lt;number&gt;;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 44 | Redux Toolkit]]></title>
            <link>https://velog.io/@4_21ee/TIL-44-Redux-Toolkit</link>
            <guid>https://velog.io/@4_21ee/TIL-44-Redux-Toolkit</guid>
            <pubDate>Sun, 02 Jan 2022 17:18:08 GMT</pubDate>
            <description><![CDATA[<h1 id="redux의-문제점들">Redux의 문제점들</h1>
<p>리덕스는 리액트의 상태 관리 라이브러리 중 대표로서 굳게 자리매김하고 있었지만, 사용하기 너무 복잡하고 배우기 어렵다는 의견이 많았다. (나또한 그렇게 느껴서 여러번 좌절할뻔했다...) 
리덕스가 높은 러닝 커브와 복잡성을 가지는 원인들을 리덕스 측에서 문서로 공식적으로 발표한 것을 보면서 어떤 것들이 있는지 확인해보자.</p>
<h3 id="1-store-configuration-복잡성">1. store configuration 복잡성</h3>
<p>우선, 리덕스는 스토어(store)를 설정하는게 너무 복잡하다. 리덕스는 앱 전체에 단 하나의 스토어를 가지며 이 스토어는 리액트 앱에서 사용할 상태(state)들을 저장하고 관리한다. 따라서 스토어는 상태 값들을 사용하고 관리하는 모든 API를 가지며 이것을 설정해주는 것은 복잡한 작업이었다.</p>
<h3 id="2-redux를-사용하기-위해선-다른-라이브러리들의-추가설치가-너무-많이-필요했다">2. redux를 사용하기 위해선 다른 라이브러리들의 추가설치가 너무 많이 필요했다.</h3>
<p>redux를 제대로 사용하려면 다음과 같은 패키지들을 추가 설치해줘야 한다.</p>
<ul>
<li>react-redux : react와 바인딩</li>
<li>immutable/immer : 불변성 유지</li>
<li>redux-thunk/redux-saga/redux-pender : 비동기 통신</li>
<li>redux-actions : 액션 생성
심지어 리액트와 리덕스 특유의 높은 자유도로 인해 프로젝트마다, 혹은 개발자 취향마다 설치하는 패키지들이 다 제각각일 수 있다.</li>
</ul>
<p>따라서 매번 프로젝트마다 다른 패키지를 학습해야 하는 상황이 발생하게 될 수 있는 것이다.</p>
<h3 id="3-너무-많은-양의-보일러플레이트를-파일마다-반복-작성해야-했다">3. 너무 많은 양의 보일러플레이트를 파일마다 반복 작성해야 했다.</h3>
<p>리덕스 액션과 리듀서들을 도메인마다 분리를 하고, 또 리액트 각 컴포넌트마다 바인딩을 하면, 엄청나게 많은 수의 파일에서 리덕스 코드를 사용하게 된다. 그런데 그 많은 파일에서 많은 양의 보일러 플레이트 코드를 반복해서 사용해줘야 해서 코드가 지저분해지고 관리포인트가 많다는 단점이 있다.</p>
<p>또한 추가적으로 설치하는 패키지에 따라 보일러플레이트 코드가 천차만별이어서 정형화된 보일러 플레이트를 바로 작성하기도 어렵다. </p>
<h2 id="redux-toolkit을-통한-문제점-해결">Redux Toolkit을 통한 문제점 해결</h2>
<p>리덕스 툴킷(Redux Toolkit)은 리덕스에서 공식적으로 내놓은 위에서 언급한 단점들을 제거한 패키지이다.
리덕스 공식 문서도 리덕스를 사용할때 이 리덕스 툴킷을 사용하는 것이 좋다고 적극 권장하고 있다.</p>
<h3 id="1-store-configuration">1. store configuration</h3>
<p>먼저 스토어 생성은 configureStore 함수를 실행하여 할 수 있다. 이 안에서 리듀서(reducer)들을 바인딩 해주면 된다.</p>
<pre><code class="language-js">import { configureStore } from &#39;@reduxjs/toolkit&#39;;

export const store = configureStore({
  reducer: {},
});</code></pre>
<p>그리고 리액트 앱에서는 이 store를 import해서 Provider로 제공해준다.</p>
<pre><code class="language-js">ReactDOM.render(
  &lt;Provider store={store}&gt;
  &lt;App /&gt;
  &lt;/Provider&gt;
document.getElementById(&#39;root&#39;)
)</code></pre>
<h3 id="2-너무-많은-패키지들-추가-설치">2. 너무 많은 패키지들 추가 설치</h3>
<p>리덕스 툴킷은 딴 두 가지 패키지만 설치해서 사용할 수 있다.</p>
<pre><code class="language-bash">yarn add @reduxjs/toolkit react-redux</code></pre>
<p>리덕스 툴킷은 내부적으로 불변성을 지키기 위해 immer 라이브러리를 사용하고 비동기 통신을 위해 redux-thunk를 사용한다. 리덕스 툴킷은 이렇게 내부적으로 의존 라이브러리들을 사용해서 개발자는 툴킷만 설치하면 다른 패키지를 뭘 설치할지 고민하지 않아도 된다. 그러므로 리덕스 툴킷 사용시 추가 라이브러리를 설치하지 않고 공식문서의 가이드대로 두 가지만 설치를 해서 사용하는 것이 패키지 사용 통일성을 지킬 수 있어 좋다.</p>
<h3 id="3-너무-많은-양의-보일러-플레이트">3. 너무 많은 양의 보일러 플레이트</h3>
<p>리덕스 툴킷을 보면 보일러 플레이트 코드량을 최소화하도록 노력한 것을 알 수 있다. flux 패턴 중에 액션 생성 함수, 리듀서 코드는 다음과 같이 작성할 수 있다.</p>
<ul>
<li><strong>type.d.ts</strong><pre><code class="language-ts">type ToDo = {
id: number;
content: string;
checked: boolean;
};
</code></pre>
</li>
</ul>
<p>type ToDoList = ToDo[] | [];</p>
<p>interface IToDoListState {
  toDoList: IToDoList;
}</p>
<p>interface IAction {
  type?: string;
}</p>
<p>interface IToggleToDoPayload {
  id: number;
  checked: boolean;
}</p>
<p>interface IToggleToDoAction extends IAction {
  payload: IToggleToDoPayload;
}</p>
<p>interface IDeleteToDoPayload {
  id: number;
}</p>
<p>interface IDeleteToDoAction extends IAction {
  payload: IDeleteToDoPayload;
}</p>
<pre><code>- **src/store/toDoList/index.ts**
```ts
import { createAction, createReducer } from &quot;@reduxjs/toolkit&quot;;

export const action = {
  toggleToDo: createAction&lt;IToggleToDoPayload&gt;(&quot;TOGGLE/TO_DO&quot;),
  deleteToDo: createAction&lt;IDeleteToDoPayload&gt;(&quot;DELETE/TO_DO&quot;),
};

const initialState: IToDoListState = {
  toDoList: [],
};

export const reducer = {
  toggleToDo: (state: IToDoListState, action: IToggleToDoAction) =&gt; {
    state.toDoList.find((todo: ToDo) =&gt; todo.id === action.payload.id).checked = action.payload.checked;
  },
  deleteToDo: (state: IToDoListState, action: IDeleteToDoAction) =&gt; {
    state.toDoList = state.toDoList.filter((todo: ToDo) =&gt; todo.id !== action.payload.id);
  },
};

const toDoListReducer = createReducer(initialState, builder =&gt; {
  builder
    .addCase(action.toggleToDo, reducer.toggleToDo)
    .addCase(action.deleteToDo, reducer.deleteToDo);
});

export default toDoListReducer;</code></pre><p>이처럼 리듀서 툴킷에서 제공하는 createAction, createReducer만 있으면 리덕스를 사용할 수 있다. 
빌더 패턴을 사용하여 리듀서 함수들을 추가하기 때문에 createReducer 함수를 사용하는 코드가 매우 간결하다.</p>
<p>또한 리듀서는 내부적으로 immer 라이브러리를 사용하기 때문에 불변성에 대해서 신경쓰지 않고 state를 변경시켜주어도 내부적으로 불변성을 지켜준다.</p>
<p>만든 리듀서는 스토어에 다음과 같이 추가해준다.</p>
<ul>
<li><strong>src/store/index.ts</strong><pre><code class="language-ts">import { configureStore } from &quot;@reduxjs/toolkit&quot;;
</code></pre>
</li>
</ul>
<p>import toDoListReducer from &quot;src/store/toDoList&quot;;</p>
<p>export const store = configureStore({
  reducer: {
    toDoList: toDoListReducer,
  },
});</p>
<p>// Infer the <code>RootState</code> and <code>AppDispatch</code> types from the store itself
export type RootState = ReturnType<typeof store.getState>;</p>
<p>export type AppDispatch = typeof store.dispatch;</p>
<pre><code>이제 보일러 플레이트가 얼마나 단순해졌는 확인해기 위해 List와 Item이라는 컴포넌트를 만들어서 확인해보자.
- **src/components/toDoList/List.tsx**
```ts
import { useSelector } from &quot;react-redux&quot;;

import Item from &quot;src/components/toDoList/item&quot;;
import { RootState } from &quot;src/store&quot;;

function List() {
  const toDoList: ToDoList = useSelector((state: RootState) =&gt; state.toDoList.toDoList);

  return (
    &lt;div&gt;
      {toDoList &amp;&amp; toDoList.map(toDo =&gt; &lt;Item key={toDo.id} toDo={toDo} /&gt;)}
    &lt;/div&gt;
  );
}

export default List;</code></pre><p>store에 있는 state를 가져오기 위해서는 react-redux가 제공하는 useSelect를 사용한다. 이때 타입스크립트를 사용한다면 store에서 만든 RootState 타입을 사용하여야 한다.</p>
<ul>
<li>** src/components/toDoList/Item.tsx**<pre><code class="language-ts">import { useDispatch } from &quot;react-redux&quot;;
</code></pre>
</li>
</ul>
<p>import { action } from &quot;src/store/toDoList&quot;;</p>
<p>interface IProps {
  toDo: ToDo;
}</p>
<p>function Item({ toDo }: IProps) {
  const { id, content, checked } = toDo;
  const dispatch = useDispatch();</p>
<p>  const onToggle = (event: any) =&gt; {
    dispatch(action.toggleToDo({ id, checked: event.target.checked as boolean }));
  };</p>
<p>  const onDeleteToDo = () =&gt; {
    dispatch(action.deleteToDo({ id }));
  };</p>
<p>  return (
    <div>
      <div>{id}</div>
      <p>{content}</p>
      <input type="checkbox" defaultChecked={checked} onChange={onToggle} />
      <button onClick={onDeleteToDo}>삭제</Button>
    </div>
  );
}</p>
<p>export default Item;</p>
<p>```
액션을 디스패치(dispatch)하기 위해서는 react-redux에서 제공하는 useDispatch를 사용한다.</p>
<p>컴포넌트 단에서도 useSelect와 useDispatch를 이용하면 보일러 플레이트가 많이 간결하다는 것을 확인할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 43 | async & await]]></title>
            <link>https://velog.io/@4_21ee/TIL-43-async-await</link>
            <guid>https://velog.io/@4_21ee/TIL-43-async-await</guid>
            <pubDate>Fri, 31 Dec 2021 08:05:28 GMT</pubDate>
            <description><![CDATA[<h1 id="async--await">async &amp; await</h1>
<h2 id="asyncawait-키워드를-통한-비동기-코딩">async/await 키워드를 통한 비동기 코딩</h2>
<p>Promise의 불편한 점들을 해결하기 위해 ES7에서 async/await 키워드가 추가되었다. async/await 키워드를 사용하면 비동기 코드를 마치 동기 코드처럼 보이게 작성할 수 있다.</p>
<p>함수 선언부를 보면 async 키워드가 function 앞에 붙는다는 것과 Promise를 리턴하는 모든 비동기 함수 호출부 앞에는 await 키워드가 추가되었다는 것을 확인할 수 있다.</p>
<p>await 키워드는 async 키워드가 붙어있는 함수 내부에서만 사용할 수 있으며 비동기 함수가 리턴하는 promise로부터 결과값을 추출해준다. 즉 await 키워드를 사용하면 일반 비동기처리처럼 바로 실행이 다음 라인으로 넘어가는 것이 아니라 결과값을 얻을 수 있을 때까지 기다려 준다. 따라서 일반적인 동기 코드 처리와 동일한 흐름으로 (함수 호출 후 결과값을 변수에 할당하는 식으로) 코드를 작성할 수 있으며, 따라서 코드를 읽기도 한결 수월해진다.</p>
<p>한가지 주의할점은 async 키워드가 붙어있는 함수를 호출하면 명시적으로 promise 객체를 생성하여 리턴하지 않아도 promise 객체가 리턴된다. 하지만 만약 이 호출부가 또 다른 async 키워드가 붙어있는 함수의 내부에 있다면 동일한 방식으로 await 키워드를 사용하여 promise가 제공할 값에 바로 접근할 수 있다.</p>
<h2 id="예외-처리">예외 처리</h2>
<p>동기/비동기 구분없이 try/catch로 일관되게 예외 처리를 할 수 있는 부분도 async/await를 사용해서 코딩했을 때의 큰 이점 중 하나이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 42 | Libraries vs Frameworks]]></title>
            <link>https://velog.io/@4_21ee/TIL-42-Libraries-vs-Frameworks</link>
            <guid>https://velog.io/@4_21ee/TIL-42-Libraries-vs-Frameworks</guid>
            <pubDate>Mon, 27 Dec 2021 10:00:45 GMT</pubDate>
            <description><![CDATA[<h1 id="libraries-vs-frameworks">Libraries vs Frameworks</h1>
<h2 id="라이브러리library란">라이브러리(Library)란?</h2>
<p><em>집을 직접 짓는 것과 같다. 당신이 원하는 구조를 선택하여 원하는 방식으로 방을 정렬할 수 있다.</em></p>
<p>프로그래밍에서의 라이브러리란 <strong>필요한 기능들이 모여있는 코드의 묶음</strong>이라고 생각할 수 있다.
자주 사용되는 기능들을 라이브러리(객체나 함수등의 형태)로 만들어두면, 필요할 때마다 <strong>직접 호출</strong>하여 사용할 수 있다.</p>
<p>물론 남들이 만들어둔 외부 라이브러리도 가져다 사용할 수 있다.</p>
<ol>
<li>Browser 환경에서 script src 로 불러들이는 js파일(JQuery 등).</li>
<li>node.js 환경에서 npm으로 설치한 모듈.</li>
<li>Python 환경에서 pip로 설치한 패키지/모듈.</li>
<li>Java 환경에서 설치한 jar.</li>
</ol>
<h3 id="라이브러리의-장점">라이브러리의 장점</h3>
<p>라이브러리는 어떻게 사용할 것인가에만 집중되어 있다. 즉 HTTP, 라우팅 등의 상태 관리를 위한 라이브러리는 지원하지 않는다. 이러한 특징 덕분에 사용자는 자신이 필요한 라이브러리만 직접 선택할 수 있다.
즉, 라이브러리를 사용하면 애플리케이션에 대한 통제권을 가질 수 있으며, 원하는 부분만 추가하면 되므로 제작과정이 더욱 원활해진다.</p>
<h3 id="라이브러리의-단점">라이브러리의 단점</h3>
<p>특정 아키텍처를 직접 제작하다 보면 애플리케이션이 망가질 수 있으므로 주의해야 한다. 일부 사람들이 Angular 또는 Vue를 선택하는 이유는 자신만의 규칙을 꾸축하는 데 시간과 돈을 투자하고 싶지 않기 때문이다. 이러한 프레임워크를 사용하면 단순히 규칙을 배운 뒤, 실제 제작에만 집중할 수 있다.</p>
<h2 id="프레임워크framework란">프레임워크(Framework)란?</h2>
<p><em>새집을 사는 것과 같아서 구조를 직접 다룰 필요가 없지만, 집은 이미 지어져 있기 때문에 방을 정렬하는 방식을 선택할 수 없다.</em></p>
<p>프레임워크는 작업(work)의 구조(frame)가 정해져 있는 라이브러리라고 볼 수 있다.
단, <strong>프레임워크가 원하는 방식</strong>대로 다양한 기능을 제공한다.</p>
<p>앱/서버 등의 구동, 메모리 관리, 이벤트 루프 등의 공통된 부분은 프레임워크가 알아서 관리하며, 개발자는 서비스별로 다른 부분만 프레임워크가 정해준 방식대로 클래스, 메서드 등에 구현해두면 된다.</p>
<p>유명한 프레임워크로는 아래와 같은 것들이 있다.</p>
<ol>
<li>Java 서버 개발에 사용되는 Spring.</li>
<li>Python 서버 개발에 사용되는 Django, Flask.</li>
<li>안드로이드 앱 개발에 사용되는 Android.</li>
<li>아이폰 앱 개발에 사용되는 Cocoa Touch.</li>
<li>웹 개발에 사용되는 React, Angular, Vue.js 등.</li>
</ol>
<h3 id="프레임워크의-장점">프레임워크의 장점</h3>
<p>일반적으로 프레임워크는 우리가 무엇을 해야 할지 알려준다. 프레임워크는 사용에 관한 모범 사례(best practice)를 가지고 있으며, 사용자를 지원하는 도구를 제공한다.
전담 팀에 의해 만들어진 이러한 프레임워크는 대규모 애플리케이션을 구축하는 데 필요한 모든 것들이 제공된다. 프레임워크의 개발팀은 모범 사례를 따르는 공식 스타일 가이드를 제공한다. 이러한 가이드를 통해 사용자는 빠르게 생산성을 높이고, 다른 팀원에 대한 교육도 쉽게 할 수 있다.</p>
<h3 id="프레임워크의-단점">프레임워크의 단점</h3>
<p>프레임 워크는 많은 코드를 작성하여 구축된다. 즉, 로딩 시간이 길어지곡 성능이 저하된다. 확장 가능한 아키텍처(Scalable architecture)는 수 많은 기능들을 제공한다. 일부 애플리케이션은 매우 간단하므로, 이러한 프레임워크의 사용이 자칫 개발 과정을 더욱 복잡하게 만들 수도 있다.
프레임워크를 사용하려면 지속해서 공부해야 한다. 새로운 버전이 나올 때마다 항목이 추가되고, 어떤 항목들은 제거되거나 더는 사용되지 않으므로 최신 지식을 유지해야 한다.</p>
<h2 id="라이브러리-vs-프레임워크">라이브러리 vs 프레임워크</h2>
<p>가장 큰 차이점은 <strong>코드 흐름의 제어권</strong>이 누구에게 있느냐이다.</p>
<h3 id="라이브러리">라이브러리</h3>
<p>라이브러리의 객체나 함수를 개발자가 직접 호출하여 사용한다.</p>
<h3 id="프레임워크">프레임워크</h3>
<p>개발자가 구현한 메서드가 프레임워크에 의해 호출된다.
이를 제어의 역전(IoC: Inversion of Control)이라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 41 | Promise]]></title>
            <link>https://velog.io/@4_21ee/TIL-38-Callback</link>
            <guid>https://velog.io/@4_21ee/TIL-38-Callback</guid>
            <pubDate>Mon, 13 Dec 2021 18:28:09 GMT</pubDate>
            <description><![CDATA[<h1 id="promise">Promise</h1>
<ul>
<li>자바스크립트 비동기 처리에 사용되는 객체<blockquote>
<h4 id="비동기-처리">비동기 처리</h4>
<p>특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미한다.</p>
</blockquote>
<h2 id="promise의-3가지-상태states">Promise의 3가지 상태(states)</h2>
상태는 프로미스의 처리과정을 의미.</li>
</ul>
<ol>
<li>Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태.</li>
<li>Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태.</li>
<li>Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태.<h2 id="producer">Producer</h2>
</li>
</ol>
<ul>
<li>새로운 Promise가 만들어질때는 우리가 전달한 executor라는 함수가 자동적으로 실행이 된다.<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
// doing some heavy work (network, read files)
setTimeout(() =&gt; {
    resolve(&#39;yonghyun&#39;); // 성공한 경우
     reject(new Error(&#39;에러 발생 이유&#39;)); // 실패한 경우
}, 2000);
});</code></pre>
=&gt; 어떤 일을 2초정도 하다가 resolve라는 콜백함수를 호출하면서 yonghyun이라는 값을 전달해주는 Promise</li>
</ul>
<h2 id="consumers--then-catch-finally">Consumers : then, catch, finally</h2>
<h3 id="then">then</h3>
<p>Promise가 정상적으로 잘 수행이 되어서 마지막에 최종적으로 resolve라는 콜백함수를 통해서 전달한 값이 value에 parameter로 전달된다.</p>
<pre><code class="language-js">promise
    .then((value) =&gt; { // 성공한 값
    console.log(value); // yonghyun이 출력
})
    .catch(error =&gt;{ // 실패한 에러
    console.log(error);
})
    .finally(() =&gt; { // 성공, 실패 여부에 상관없이 무조건 실행
      console.log(&#39;finally&#39;);
});</code></pre>
<h2 id="promise-chaining">Promise chaining</h2>
<pre><code class="language-js">const fetchNumber = new Promise((resolve, reject) =&gt; {
  setTimeout(() =&gt; resolve(1), 1000);
});

fetchNumber
.then(num =&gt; num * 2)
.then(num =&gt; num * 3)
.then(num =&gt; {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; resolve(num - 1), 1000);
  });
})
.then(num =&gt; console.log(num));</code></pre>
<h2 id="error-handling">Error Handling</h2>
<pre><code class="language-js">const getHen = () =&gt;
    new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(&#39;닭&#39;), 1000);
    });
const getEgg = hen =&gt;
    new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(`${hen} =&gt; 계란`), 1000);
    });
const cook = egg =&gt;
    new Promise((resolve, reject) =&gt; {
      setTimeout(() =&gt; resolve(`${egg} =&gt; 사탕`), 1000);
    });

getHen()
  .then(getEgg)
  .catch(error =&gt; {
      return &#39;빵&#39;;
}) // 에러가 발생한 걸 바로 잡아낼 수 있다.
  .then(cook)
  .then(console.log)
  .catch(console.log);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 40 | JS - 원시값(Primitive Type)과 참조값(Reference Type)]]></title>
            <link>https://velog.io/@4_21ee/TIL-40-JS-%EC%9B%90%EC%8B%9C%EA%B0%92Primitive-Type%EA%B3%BC-%EC%B0%B8%EC%A1%B0%EA%B0%92Reference-Type</link>
            <guid>https://velog.io/@4_21ee/TIL-40-JS-%EC%9B%90%EC%8B%9C%EA%B0%92Primitive-Type%EA%B3%BC-%EC%B0%B8%EC%A1%B0%EA%B0%92Reference-Type</guid>
            <pubDate>Fri, 10 Dec 2021 00:18:56 GMT</pubDate>
            <description><![CDATA[<h2 id="자바스크립트의-원시값과-참조값">자바스크립트의 원시값과 참조값</h2>
<p>자바스크립트는 원시타입과 참조타입 두가지의 자료형이 제공된다.</p>
<ul>
<li>원시 타입 - null, undefined, string, number, boolean, symbol</li>
<li>참조 타입 - Array, Object, Function</li>
</ul>
<h2 id="원시-타입-데이터는">원시 타입 데이터는?</h2>
<ul>
<li>변수에 할당될 때 메로리 상에 고정된 크기로 저장되고 해당 변수가 원시 데이터의 값을 보관한다.</li>
<li>원시 타입 자료형은 모두 변수 선언, 초기화, 할당시 값이 저장된 메모리 영역에 직접적으로 접근한다. 즉 변수에 새 값이 할당 될 때 변수에 할당된 메모리 블럭에 저장된 값을 바로 변경한다는 뜻이다.</li>
<li>변수에 새로운 값을 할당하면 변수가 참조하는 메모리 공간의 주소가 바뀌게된다.</li>
<li>값을 복사</li>
</ul>
<pre><code class="language-js">// ex
var x = 100;
var y = x;
x = 99;
y; // 100;</code></pre>
<h2 id="참조-타입-데이터는">참조 타입 데이터는?</h2>
<ul>
<li>자바스크립트는 객체의 메모리를 직접 조작하지 않고, 해당 객체에 대한 &#39;참조&#39;를 조작한다. 따라서 객체를 가리키는 값은 &#39;참조로 접근한다&#39;라고 한다.</li>
<li>크기가 정해져 있지 않고 변수에 할당될 때 값이 직접 해당 변수에 저장될 수 없으며, 변수에는 데이터에 대한 참조만 저장된다. 참조 타입은 변수의 값이 저장된 메모리 블럭의 주소를 가지고 있고, 자바스크립트 엔진이 변수가 가지고 있는 메모리 주소를 이용해서 변수의 값에 접근한다.</li>
<li>값을 참조</li>
</ul>
<pre><code class="language-js">// ex
var x = {const: 100};
var y = x;
x.count = 99;
y.count; // 99</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 40 | JS - ES5 그리고 ES6]]></title>
            <link>https://velog.io/@4_21ee/TIL-40-JS-ES5-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ES6</link>
            <guid>https://velog.io/@4_21ee/TIL-40-JS-ES5-%EA%B7%B8%EB%A6%AC%EA%B3%A0-ES6</guid>
            <pubDate>Wed, 08 Dec 2021 16:47:54 GMT</pubDate>
            <description><![CDATA[<h2 id="es란">ES란?</h2>
<p>JavaScript가 넷스케이프 커뮤니케이션즈로부터 개발되고 나서, MS에서 JScript를 개발하였다. 두 언어는 서로 호환되지 못하는 경우가 있어 크로스 브라우징 이슈가 발생하였는데 이 크로스브라우징 이슈를 해결하기 위해 JavaScript를 표준화하였는데 이게 바로 ECMAScript이다. ES는 ECMAScript를 줄여쓰는 말이다. 뒤에 나오는 숫자는 버전을 뜻하는데 <strong>ES5</strong>는 2009년 발표되었고, <strong>ES6</strong>는 2015년 발표되었다.</p>
<h2 id="es6에서-달라진점">ES6에서 달라진점</h2>
<h3 id="1-let-const-키워드-추가">1. let, const 키워드 추가</h3>
<p>기존의 var 키워드에 비해 블록 레벨 스코프를 가지며 재할당이 가능한 let, const 키워드가 추가되었다. 변수의 생명주기에 영향을 끼치며 키워드만 보고도 변수의 성격을 파악할 수 있게 되었다.</p>
<h3 id="2-arrow-function-추가">2. Arrow Function 추가</h3>
<p>화살표 함수가 추가되어 함수를 간결하게 나타낼 수 있게 되었다. 이로 인해 코드의 가독성 및 유지 보수성이 상승하였다. </p>
<h3 id="3-default-parameter-추가">3. Default Parameter 추가</h3>
<p>기존에 함수의 매개변수에 초기값을 작성하려면 함수 내부에서 로직이 필요했지만 ES6 이후 default parameter가 추가되었다.</p>
<h3 id="4-template-literal">4. Template literal</h3>
<p>ES6부터 새롭게 등장한 템플릿 리터럴 덕분에 문자열 표현이 훨씬 간단해졌다. 템플릿 리터럴이란 작은 따옴표나 큰 따옴표 대신 백틱(`)으로 문자열을 감싸 표현하는 기능을 말한다. 템플릿 리터럴을 사용하면 플레이스홀더(${variable})를 사용하여 백틱 내부에 문자열과 함께 표현식을 넣을 수 있다.</p>
<h3 id="5-multi-line-string">5. Multi-line string</h3>
<p>문자열이 라인을 넘어가게 되면 \n 줄바꿈과 덧셈연산자를 사용해야 하기 때문에 관리가 불편했다. 하지만 백 틱(`)을 사용하게 되면 여러 라인의 문자열도 문제없이 사용할 수 있게 되었다.</p>
<h3 id="6-클래스">6. 클래스</h3>
<p>ES5에서는 class라는 키워드는 없었지만 프로토타입을 통해 실현 가능했다. ES6에서는 class 키워드를 사용해서 선언할 수 있게 되었다.</p>
<h3 id="7-모듈">7. 모듈</h3>
<p>ES5 이전에는 각 기능별로 JS 파일을 나누고 개발 및 관리하는 것이 불가능했다. ES5에서는 require를 통해 모듈화를 할 수 있었다. ES6 부터는 import/export로 모듈을 관리할 수 있다. 모듈을 실현가능한 특정 프로그램의 그룹이다. 그리고 이것은 다른 파일의 변수, 함수를 참조한다. 클래스와 같은 모듈이 로딩될 때, import와 export를 이용해 사용될 수 있다.</p>
<h3 id="8-디스트럭처링-할당">8. 디스트럭처링 할당</h3>
<p>디스트럭처링이란 비구조화, 파괴를 뜻하는 단어로 크게 객체나 배열에서 개별 변수에 할당할 때 사용하는 방법이다.디스트럭처링 할당을 통해 자료구조에서 일부 또는 전체를 편리하게 사용할 수 있다.</p>
<h3 id="9-promise">9. Promise</h3>
<p>비동기 통신에 있어 기존에는 콜백 함수를 사용한 콜백 패턴을 사용했다. 이는 결과론적으로 콜백헬을 발생시켰다. 이를 해결하기 위해 프로미스가 도입되었고, 프로미스 후속처리 메서드를 통해 에러 처리를 효과적으로 할 수 있게 되었다.</p>
<h3 id="10-string-메서드includes-startswith-endswith">10. string 메서드(includes, startsWith, endsWith)</h3>
<p>includes, startsWith, endsWith의 문자열 메서드가 추가되었다. true/false 값을 리턴하며 문자열 메스드들로 검사 로직을 수행할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 39 | JS - var, let, const]]></title>
            <link>https://velog.io/@4_21ee/TIL-39-JS-var-let-const</link>
            <guid>https://velog.io/@4_21ee/TIL-39-JS-var-let-const</guid>
            <pubDate>Tue, 07 Dec 2021 08:10:32 GMT</pubDate>
            <description><![CDATA[<h1 id="var-let-const의-차이점">var, let, const의 차이점</h1>
<ol>
<li>var는 function-scoped이고 let, const는 block-scoped이다.</li>
<li>var로 선언한 변수는 선언하기 전에 사용해도 에러가 나지 않지만 let, const는 에러가 발생한다.</li>
<li>var는 이미 선언되어 있는 이름과 같은 이름으로 변수를 또 선언해도 에러가 나지 않지만 let, const는 이미 존재하는 변수와 같은 이름의 변수를 선언하면 에러가 난다.</li>
<li>var, let은 변수 선언시 초기 값을 주지 않아도 되지만 const는 반드시 초기값을 할당해야 한다.</li>
<li>var, let은 값을 재할당할 수 있지만 const는 한번 할당한 값을 변경할 수 없다.(but, 객체안에 프로퍼티는 변경할 수 있다.)</li>
</ol>
<h2 id="var">var</h2>
<p>변수 선언을 여러 번해도 에러 없이 각기 다른 값을 출력할 수 있다.
이러한 점은 필요할 때마다 변수를 사용할 수 있기때문에 편리하다는 장점이 있지만 같은 이름의 변수명을 남용하는 문제가 발생할 수도 있기 때문에 장점보다 단점이 더 크다고 할 수 있다.
이러한 단점을 보완하기 위해 ES6부터 let, const가 추가되었다.</p>
<h2 id="let">let</h2>
<p>let은 변수의 재할당은 가능하지만 var처럼 재선언은 되지 않는다.</p>
<h2 id="const">const</h2>
<p>const의 경우 constant(상수)의 의미 그대로 한 번만 선언이 가능하고 한번 선언된 값은 재할당을 통해 바꿀 수 없다.</p>
<h2 id="호이스팅">호이스팅</h2>
<p>호이스팅이란 함수 안에 있는 선언을 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 의미한다. var로 선언한 변수의 경우 호이스팅이 발생해 최상위로 변수 선언이 옮겨졌지만 let의 경우에는 호이스팅이 발생하지 않는다.
때문에 var로 코드를 작성하는 경우에는 호이스팅이 발생해서 같은 이름의 변수나 함수로 값이 변질될 수 있다. 호이스팅이 자주 일어나는 코드의 경우 유지보수가 어려워지며, 쓸모없는 코드가 생길 수 있다.</p>
<h2 id="스코프">스코프</h2>
<p>스코프는 범위라는 뜻을 갖고 있다. 즉 변수에 접근할 수 있는 범위를 의미하며, 전역 스코프(global scope)와 지역 스코프(local scope)가 있다. </p>
<h3 id="전역-스코프global-scope">전역 스코프(Global Scope)</h3>
<p>브라우저를 기준으로 변수가 함수 바깥이나 중괄호 바깥에 선언되었다면 전역 스코프에 정의된다고 볼 수 있다. 전역 스코프에 정의된 변수를 전역 변수라고 한다. 전역 변수를 선언하면 코드 모든 곳에서 해당 변수를 사용할 수 있다.</p>
<h3 id="지역-스코프local-scope">지역 스코프(Local Scope)</h3>
<p>전역 스코프와는 다르게 특정 부분에서만 사용 가능한 변수는 지역 스코프 내에 포함되어 있다고 할 수 있고 이런 변수를 지역 변수라 칭한다. 자바스크립트에는 함수 스코프와 블록 스코프 두 개의 지역 스코프가 존재한다. 여기서 말하는 블록은 {...}을 의미하며, 이 블록을 벗어난다면 블록 내부에 선언된 변수를 참조할 수 없다.</p>
<h4 id="함수-스코프function-scope">함수 스코프(Function scope)</h4>
<p>선언된 함수의 내부 어느 곳에서라도 접근이 가능하다.</p>
<h4 id="블록-스코프block-scope">블록 스코프(Block Scope)</h4>
<p>블록 스코프는 블록 내부에서 선언한 변수는 블록 외부에서 사용할 수 없다.</p>
]]></description>
        </item>
    </channel>
</rss>