<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>chaeon1 님의 블로그</title>
    <link>https://chaeon1.tistory.com/</link>
    <description>chaeon1 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Mon, 13 Apr 2026 01:55:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>chaeon1</managingEditor>
    <item>
      <title>투 포인터</title>
      <link>https://chaeon1.tistory.com/31</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 투 포인터란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정렬된 배열이나 리스트에서 주로 사용되는 알고리즘 기법&lt;/li&gt;
&lt;li&gt;두 개의 포인터를 사용하여 효율적으로 문제 해결&lt;/li&gt;
&lt;li&gt;시간 복잡도를 &lt;b&gt;O(n&amp;sup2;) &amp;rarr; O(n)&lt;/b&gt; 으로 개선 가능&lt;/li&gt;
&lt;li&gt;전제 조건: 배열이 오름차순(또는 내림차순)으로 정렬되어 있어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  투 포인터의 종류&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;두 방향 포인터&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작(start)과 끝(end) 포인터가 중앙으로 이동하며 조건 탐색&lt;/li&gt;
&lt;li&gt;예시: 합이 k인 두 수 찾기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;한 방향 포인터&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한쪽 포인터 고정, 다른 포인터만 이동하며 모든 부분 배열 또는 쌍 순회&lt;/li&gt;
&lt;li&gt;예시: 두 수의 차가 k인 쌍 개수 세기&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;슬라이딩 윈도우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고정된 크기 혹은 조건을 만족하는 구간을 이동하며 탐색&lt;/li&gt;
&lt;li&gt;구간 길이가 고정인 경우와 조건 만족 시까지 크기가 가변적인 경우 존재&lt;/li&gt;
&lt;li&gt;예시: 고정 길이 k인 부분 배열의 최대 합&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❓ 두 수의 합이 특정 값이 되는 쌍 찾기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXRFge/btsPV3rvyxk/b7Ws4eP8hIu6tgVIkCFg30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXRFge/btsPV3rvyxk/b7Ws4eP8hIu6tgVIkCFg30/img.png&quot; data-alt=&quot;https://jojozhuang.github.io/algorithm/algorithm-two-pointers/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXRFge/btsPV3rvyxk/b7Ws4eP8hIu6tgVIkCFg30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXRFge%2FbtsPV3rvyxk%2Fb7Ws4eP8hIu6tgVIkCFg30%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;1366&quot; height=&quot;223&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://jojozhuang.github.io/algorithm/algorithm-two-pointers/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Brute Force (완전 탐색)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 쌍을 비교해 목표 값과 같은지 확인&lt;/li&gt;
&lt;li&gt;시간 복잡도: &lt;b&gt;O(n&amp;sup2;)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이진 탐색&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 원소에 대해 이진 탐색 수행&lt;/li&gt;
&lt;li&gt;시간 복잡도: &lt;b&gt;O(n log n)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;투 포인터 알고리즘&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열의 양 끝에서 포인터를 시작하여 조건에 따라 포인터 이동&lt;/li&gt;
&lt;li&gt;시간 복잡도: &lt;b&gt;O(n)&lt;/b&gt;&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;1366&quot; data-origin-height=&quot;970&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYT5SX/btsPUWfoRHl/mDZvkHN4sZ9OLF6KtVaFnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYT5SX/btsPUWfoRHl/mDZvkHN4sZ9OLF6KtVaFnk/img.png&quot; data-alt=&quot;https://jojozhuang.github.io/algorithm/algorithm-two-pointers/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYT5SX/btsPUWfoRHl/mDZvkHN4sZ9OLF6KtVaFnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYT5SX%2FbtsPUWfoRHl%2FmDZvkHN4sZ9OLF6KtVaFnk%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;1366&quot; height=&quot;970&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;970&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://jojozhuang.github.io/algorithm/algorithm-two-pointers/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;투 포인터 코드&lt;/h3&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;function findPairWithSum(nums, target) {
  let start = 0;
  let end = nums.length - 1;

  while (start &amp;lt; end) {
    const sum = nums[start] + nums[end];

    if (sum === target) {
      return [nums[start], nums[end]];
    }

    if (sum &amp;lt; target) {
      start++;
    }

    else {
      end--;
    }
  }

  return null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  예제&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;수들의 합 2 &lt;a href=&quot;https://www.acmicpc.net/problem/2003&quot;&gt;https://www.acmicpc.net/problem/2003&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;좋다 &lt;a href=&quot;https://www.acmicpc.net/problem/1253&quot;&gt;https://www.acmicpc.net/problem/1253&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;부분합 &lt;a href=&quot;https://www.acmicpc.net/problem/1806&quot;&gt;https://www.acmicpc.net/problem/1806&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;구명보트 &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42885&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42885&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;보석 쇼핑 &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67258&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/67258&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/31</guid>
      <comments>https://chaeon1.tistory.com/31#entry31comment</comments>
      <pubDate>Thu, 14 Aug 2025 21:44:13 +0900</pubDate>
    </item>
    <item>
      <title>시간 복잡도 (2)</title>
      <link>https://chaeon1.tistory.com/29</link>
      <description>&lt;h2&gt;✍️ 시간 복잡도 계산법&lt;/h2&gt;
&lt;h3&gt;1️⃣ 알고리즘 분석&lt;/h3&gt;
&lt;p&gt;알고리즘에서 반복되는 기본 연산 확인&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;반복문 (for, while)&lt;/li&gt;
&lt;li&gt;재귀 호출&lt;/li&gt;
&lt;li&gt;정렬, 탐색, 삽입 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2️⃣ 반복문 분석&lt;/h3&gt;
&lt;p&gt;반복문은 n번 실행되므로 시간 복잡도는 &lt;strong&gt;O(n)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;반복문이 중첩되었을 때는 반복 횟수를 서로 곱해서 계산&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;for i in range(n):          // n번
    for j in range(n):      // n번
        print(i, j)         // n * n = n²번 → O(n²)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3️⃣ 함수 호출 분석&lt;/h3&gt;
&lt;p&gt;함수 호출이 있을 경우 호출된 함수의 시간 복잡도를 분석하여 합산&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function a(n) {
  for (let i = 0; i &amp;lt; n; i++) {
    b(n);
  }
}

function b(n) {
  for (let j = 0; j &amp;lt; n; j++) {
    console.log(j);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 함수 b는 O(n), 함수 a는 함수 b를 n번 호출하므로 총 시간 복잡도는 &lt;strong&gt;O(n²)&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;4️⃣ 분할 정복 구조 분석&lt;/h3&gt;
&lt;p&gt;분할 정복 알고리즘의 시간 복잡도는 재귀식으로 표현됨&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// 병합 정렬
function mergeSort(arr) {
  if (arr.length &amp;lt;= 1) return arr;
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));  // 왼쪽 절반 정렬
  const right = mergeSort(arr.slice(mid));    // 오른쪽 절반 정렬
  return merge(left, right);                  // 정렬된 두 배열 병합
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;재귀식: &lt;code&gt;T(n) = 2T(n/2) + O(n)&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;배열을 반으로 나누어 &lt;code&gt;mergeSort&lt;/code&gt;를 두 번 호출하므로 &lt;code&gt;2T(n/2)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;두 정렬된 배열을 병합하는 시간 &lt;code&gt;O(n)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;마스터 정리에 따라 &lt;strong&gt;O(n log n)&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;5️⃣ 최악의 경우 고려&lt;/h3&gt;
&lt;p&gt;조건문이 있을 경우 가장 오래 걸리는 조건을 기준으로 분석&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function findTarget(arr, target) {
  for (let i = 0; i &amp;lt; arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이때 최악의 경우 끝까지 탐색하므로 &lt;strong&gt;O(n)&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;6️⃣ 최종 계산&lt;/h3&gt;
&lt;p&gt;알고리즘 내 모든 연산의 시간 복잡도를 합산하여 가장 영향력 있는 항(가장 큰 항)만 남기고 나머지는 제거&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;T(n) = 3n² + 5n + 7&lt;/code&gt; → &lt;strong&gt;O(n²)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;T(n) = n log n + n&lt;/code&gt; → &lt;strong&gt;O(n log n)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/29</guid>
      <comments>https://chaeon1.tistory.com/29#entry29comment</comments>
      <pubDate>Mon, 30 Jun 2025 00:36:08 +0900</pubDate>
    </item>
    <item>
      <title>시간 복잡도 (1)</title>
      <link>https://chaeon1.tistory.com/28</link>
      <description>&lt;h2&gt;시간 복잡도&lt;/h2&gt;
&lt;h3&gt;  정의&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;알고리즘이 문제를 해결하는 데 걸리는 시간을 입력 크기(n)와 비교하여 표현한 것&lt;/li&gt;
&lt;li&gt;알고리즘의 실행 시간을 수학적으로 분석하여 입력 크기가 커졌을 때 실행 시간이 어떻게 변화하는지 예측&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;  기본 개념&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;입력 크기(n)&lt;/strong&gt;: 알고리즘에 주어지는 데이터의 크기&lt;ul&gt;
&lt;li&gt;예: 배열의 크기, 그래프의 노드 수 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;최악의 경우 시간 복잡도&lt;/strong&gt;: 입력 크기 n에 대해 알고리즘이 가장 많은 시간을 소요하는 경우&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;평균 시간 복잡도&lt;/strong&gt;: 입력 데이터가 일반적으로 어떻게 분포하는지에 따른 평균적인 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;  문제 해결 전략&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;분할 정복&lt;/strong&gt;: 문제를 작은 문제로 나누어 해결한 후 합치는 방법 (예: 퀵 정렬, 병합 정렬)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;동적 계획법&lt;/strong&gt;: 문제를 작은 하위 문제로 나누고, 그 결과를 재사용하는 방식 (예: 피보나치 수 계산)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그리디 알고리즘&lt;/strong&gt;: 매 순간 최적의 선택을 하는 방식 (예: 다익스트라 알고리즘)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;탐색 방법 개선&lt;/strong&gt;: 비효율적인 탐색을 개선 (예: 이진 탐색)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;  무조건 시간 복잡도가 낮은 알고리즘을 사용하는 것이 좋은가?&lt;/h3&gt;
&lt;p&gt;일반적으로는 시간 복잡도가 낮은 알고리즘이 유리하지만 예외가 존재할 수 있음&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;입력 크기가 작을 때&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;입력 데이터가 작으면 O(n²) 알고리즘도 충분히 빠르게 실행됨&lt;/li&gt;
&lt;li&gt;이럴 경우 구현이 더 간단한 알고리즘 선택 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;상수 계수가 클 때&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;시간 복잡도는 입력 크기가 무한히 커질 때의 추세를 보는 것이므로 실제 성능은 구현의 상수 계수(숨겨진 비용)에 영향을 받음&lt;/li&gt;
&lt;li&gt;예시: O(n) 알고리즘이지만 내부 연산이 무거우면 O(n log n)보다 느릴 수 있음 (상수 계수나 내부 연산의 복잡도 고려)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;메모리 사용량 고려&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;어떤 알고리즘은 시간 복잡도는 낮지만 메모리를 많이 사용할 수도 있음&lt;/li&gt;
&lt;li&gt;예시: 재귀적으로 호출되는 알고리즘은 메모리 스택을 많이 소모할 수 있음&lt;/li&gt;
&lt;li&gt;제한된 환경에서는 시간보다 메모리가 더 중요할 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;  빅오 표기법 (Big-O Notation)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boOPLm/btsOLE8XivG/C6nSBjkUo4erPraKPRFGeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boOPLm/btsOLE8XivG/C6nSBjkUo4erPraKPRFGeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boOPLm/btsOLE8XivG/C6nSBjkUo4erPraKPRFGeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboOPLm%2FbtsOLE8XivG%2FC6nSBjkUo4erPraKPRFGeK%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3&gt;입력 n값에 따른 시간 복잡도 &lt;a href=&quot;https://blog.chulgil.me/algorithm/&quot;&gt; &lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(log n)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(n log n)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;461&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(n²)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(2ⁿ)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;td&gt;1267650600228229401496703205376&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;O(n!)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3628800&lt;/td&gt;
&lt;td&gt;화면에 표현 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2&gt;  주요 빅오 표기법&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(1)&lt;/strong&gt;: 상수 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;입력 크기와 관계 없이 실행 시간이 일정함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 배열 인덱스 접근&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const element = array[index];&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(log n)&lt;/strong&gt;: 로그 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;입력 크기가 커질수록 실행 시간은 느리게 증가함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 이진 탐색&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const binarySearch = (arr, target) =&amp;gt; {
  let start = 0, end = arr.length - 1;
  while (start &amp;lt;= end) {
      const mid = Math.floor((start + end) / 2);
      if (arr[mid] === target) return mid;
      if (arr[mid] &amp;lt; target) start = mid + 1;
      else end = mid - 1;
  }
  return -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(n)&lt;/strong&gt;: 선형 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;입력 크기에 비례하여 실행 시간 증가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 배열 순회&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const sum = arr.reduce((acc, val) =&amp;gt; acc + val, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(n log n)&lt;/strong&gt;: 로그 선형 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;효율적인 정렬 알고리즘에서 나타남&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 병합 정렬, 퀵 정렬&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function mergeSort(arr) {
  if (arr.length &amp;lt;= 1) return arr;
  const mid = Math.floor(arr.length / 2);
  const left = mergeSort(arr.slice(0, mid));
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);
}

function merge(left, right) {
  let result = [], i = 0, j = 0;
  while (i &amp;lt; left.length &amp;amp;&amp;amp; j &amp;lt; right.length) {
      if (left[i] &amp;lt; right[j]) result.push(left[i++]);
      else result.push(right[j++]);
  }
  return result.concat(left.slice(i), right.slice(j));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(n²)&lt;/strong&gt;: 이차 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;입력 크기가 커지면 매우 느려짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 버블 정렬, 선택 정렬&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function bubbleSort(arr) {
  for (let i = 0; i &amp;lt; arr.length - 1; i++) {
      for (let j = 0; j &amp;lt; arr.length - 1 - i; j++) {
          if (arr[j] &amp;gt; arr[j + 1]) {
              [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
          }
      }
  }
  return arr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;O(2ⁿ)&lt;/strong&gt;: 지수 시간 복잡도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;입력 크기 증가에 따라 매우 빠르게 증가함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;예: 피보나치 수열의 재귀적 계산&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;function fibonacci(n) {
  if (n &amp;lt;= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/28</guid>
      <comments>https://chaeon1.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 22 Jun 2025 23:06:12 +0900</pubDate>
    </item>
    <item>
      <title>프로젝트 세팅 - Git, Prettier, Husky</title>
      <link>https://chaeon1.tistory.com/27</link>
      <description>&lt;h1&gt;  Git&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  GitHub 저장소 연동&lt;/h3&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;cd read-on&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Git 초기화&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;git init&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;원격 저장소 연결&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;git remote add origin https://github.com/user/repository.git&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브랜치 이름 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;git branch -M main&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;첫 푸시&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;git push -u origin main&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Lint &amp;amp; Format&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  사용 도구&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ESLint&lt;/b&gt; &amp;ndash; 코드 문법 검사&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Prettier&lt;/b&gt; &amp;ndash; 코드 포맷 자동 정리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;lint-staged&lt;/b&gt; &amp;ndash; 변경된 파일만 lint/format&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Husky&lt;/b&gt; &amp;ndash; Git Hook 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  설치&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier lint-staged husky&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚙️ 설정&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;.eslintrc.json&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;extends&quot;: [&quot;next/core-web-vitals&quot;, &quot;plugin:prettier/recommended&quot;],
  &quot;plugins&quot;: [&quot;prettier&quot;],
  &quot;rules&quot;: {
    &quot;prettier/prettier&quot;: &quot;error&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;.prettierrc&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;singleQuote&quot;: true,
  &quot;semi&quot;: true,
  &quot;useTabs&quot;: false,
  &quot;tabWidth&quot;: 2,
  &quot;trailingComma&quot;: &quot;all&quot;,
  &quot;printWidth&quot;: 80,
  &quot;bracketSpacing&quot;: true,
  &quot;arrowParens&quot;: &quot;always&quot;,
  &quot;endOfLine&quot;: &quot;auto&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;.prettierignore&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;node_modules
.next
dist
out
public
*.log&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;lint-staged&lt;/code&gt; 설정 (&lt;code&gt;package.json&lt;/code&gt; 내부에 추가)&lt;/h3&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;&quot;lint-staged&quot;: {
  &quot;*.{js,jsx,ts,tsx}&quot;: [
    &quot;eslint --fix&quot;,
    &quot;prettier --write&quot;
  ],
  &quot;*.{json,css,md}&quot;: [
    &quot;prettier --write&quot;
  ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Husky 설정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;초기화&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;npx husky init&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pre-commit 설정 (&lt;code&gt;.husky/pre-commit&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/bin/sh
. &quot;$(dirname &quot;$0&quot;)/_/husky.sh&quot;

npx lint-staged&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;commit-msg 설정&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;패키지 설치&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm install --save-dev @commitlint/cli @commitlint/config-conventional&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;commitlint.config.js&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;ceylon&quot;&gt;&lt;code&gt;module.exports = {
  extends: ['@commitlint/config-conventional'],
};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;.husky/commit-msg&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/bin/sh
. &quot;$(dirname &quot;$0&quot;)/_/husky.sh&quot;

npx commitlint --edit &quot;$1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;커밋 타입 예시&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;타입&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;build:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빌드 시스템, 의존성 관련 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chore:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;설정, 패키지 등 개발환경 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ci:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CI 관련 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docs:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;문서 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feat:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새로운 기능 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fix:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;perf:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;성능 개선&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;refactor:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;리팩토링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;revert:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;커밋 되돌리기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;style:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;스타일 변경 (공백, 세미콜론 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;test:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;테스트 코드 추가 및 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  참고&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;***&lt;a href=&quot;https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories&quot;&gt;https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Husky&lt;/li&gt;
&lt;li&gt;***&lt;a href=&quot;https://typicode.github.io/husky/&quot;&gt;https://typicode.github.io/husky/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;lint-staged&lt;/li&gt;
&lt;li&gt;***&lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;https://github.com/lint-staged/lint-staged&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;commitlint&lt;/li&gt;
&lt;li&gt;***&lt;a href=&quot;https://commitlint.js.org/guides/getting-started.html&quot;&gt;https://commitlint.js.org/guides/getting-started.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>ReadOn/Git</category>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/27</guid>
      <comments>https://chaeon1.tistory.com/27#entry27comment</comments>
      <pubDate>Sun, 15 Jun 2025 23:59:35 +0900</pubDate>
    </item>
    <item>
      <title>프로젝트 세팅 - Next.js, Storybook, Jest</title>
      <link>https://chaeon1.tistory.com/26</link>
      <description>&lt;h1&gt;  프론트엔드&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; ️ Next.js&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작업 디렉토리로 이동&lt;/h3&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;cd /Projects&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로젝트 생성&lt;/h3&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;npx create-next-app@latest&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 응답:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;&amp;radic; What is your project named? ... read-on
&amp;radic; Would you like to use TypeScript? ... No / Yes
&amp;radic; Would you like to use ESLint? ... No / Yes
&amp;radic; Would you like to use Tailwind CSS? ... No / Yes
&amp;radic; Would you like your code inside a `src/` directory? ... No / Yes
&amp;radic; Would you like to use App Router? (recommended) ... No / Yes
&amp;radic; Would you like to use Turbopack for `next dev`? ... No / Yes
&amp;radic; Would you like to customize the import alias (`@/*` by default)? ... No / Yes
&amp;radic; What import alias would you like configured? ... @/*&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  참고&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Next.js&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/getting-started/installation&quot;&gt;https://nextjs.org/docs/app/getting-started/installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;  테스트 및 문서화 도구&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Storybook&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 설치 및 초기화&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm create storybook@latest&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동으로 Vite 기반 preset(@storybook/nextjs-vite)으로 설치됨&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@storybook/addon-a11y&lt;/code&gt;, &lt;code&gt;@storybook/addon-vitest&lt;/code&gt; 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;▶️ 실행&lt;/h3&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;npm run storybook&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Jest&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 설치&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm init jest@latest&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 예시:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;radic; Would you like to use Jest when running &quot;test&quot; script in &quot;package.json&quot;? ... yes      
&amp;radic; Would you like to use Typescript for the configuration file? ... yes
&amp;radic; Choose the test environment that will be used for testing &amp;raquo; jsdom (browser-like)      
&amp;radic; Do you want Jest to add coverage reports? ... no
&amp;radic; Which provider should be used to instrument code for coverage? &amp;raquo; babel                
&amp;radic; Automatically clear mock calls, instances, contexts and results before every test? ... yes&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;⚙️ 설정 파일&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;jest.config.ts&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import type { Config } from 'jest';

const config: Config = {
  clearMocks: true,
  testEnvironment: 'jsdom',
  testMatch: [
    '**/__tests__/**/*.test.[jt]s?(x)',
    '**/?(*.)+(spec|test).[jt]s?(x)',
  ],
  moduleNameMapper: {
    '^@/(.*)$': '&amp;lt;rootDir&amp;gt;/src/$1',
  },
  setupFilesAfterEnv: ['&amp;lt;rootDir&amp;gt;/jest.setup.ts'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
};

export default config;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;jest.setup.ts&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;import '@testing-library/jest-dom';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  참고&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Storybook&lt;br /&gt;&lt;a href=&quot;https://storybook.js.org/docs/get-started/frameworks/nextjs?renderer=react&quot;&gt;https://storybook.js.org/docs/get-started/frameworks/nextjs?renderer=react&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Next.js&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/guides/testing/jest&quot;&gt;https://nextjs.org/docs/app/guides/testing/jest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>ReadOn/FE</category>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/26</guid>
      <comments>https://chaeon1.tistory.com/26#entry26comment</comments>
      <pubDate>Sun, 15 Jun 2025 23:58:23 +0900</pubDate>
    </item>
    <item>
      <title>[React] Toast 컴포넌트 구현하기</title>
      <link>https://chaeon1.tistory.com/25</link>
      <description>&lt;h3&gt;✨ 핵심 기능&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;재사용 가능한 &lt;code&gt;useToast()&lt;/code&gt; 훅&lt;/li&gt;
&lt;li&gt;Framer Motion 적용&lt;/li&gt;
&lt;li&gt;&lt;code&gt;React Portal&lt;/code&gt;을 사용해 DOM 트리 외부에 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;1️⃣ Toast 컴포넌트&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ReactDOM.createPortal&lt;/code&gt;을 이용해 Toast를 document.body에 직접 렌더링&lt;/p&gt;
&lt;p&gt;이렇게 하면 부모 컴포넌트의 CSS나 위치에 영향을 받지 않고 자유롭게 위치 지정 가능&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return ReactDOM.createPortal(
  &amp;lt;div className=&amp;quot;...&amp;quot;&amp;gt;
    &amp;lt;div className={`...`}&amp;gt;
      {message}
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;,
  document.body,
);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2️⃣ useToast Hook&lt;/h2&gt;
&lt;p&gt;컴포넌트 어디서든 Toast 메시지를 쉽게 트리거할 수 있도록 커스텀 훅 작성&lt;/p&gt;
&lt;p&gt;필요한 곳에서 &lt;code&gt;showToast(message)&lt;/code&gt;만 호출하여 사용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import { useState, useCallback } from &amp;#39;react&amp;#39;;

export default function useToast() {
  const [message, setMessage] = useState(&amp;#39;&amp;#39;);

  const showToast = useCallback((msg: string) =&amp;gt; {
    setMessage(msg);
    setTimeout(() =&amp;gt; setMessage(&amp;#39;&amp;#39;), 2000);
  }, []);

  return { message, showToast };
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useToast()&lt;/code&gt; 훅은 상태(&lt;code&gt;message&lt;/code&gt;) + 제어 함수 (&lt;code&gt;showToast&lt;/code&gt;를 제공하는 컨트롤러 역할&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Toast&lt;/code&gt;는 그 상태를 뷰로 표현하는 컴포넌트&lt;/li&gt;
&lt;li&gt;토스트를 띄우는 로직과 실제 UI를 분리함으로써 독립적으로 유지 → 재사용성, 유지보수성 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3️⃣ 실제 사용 예시&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const { message, showToast } = useToast();

const handleCopy = async () =&amp;gt; {
  await navigator.clipboard.writeText(`https://...`);
  showToast(&amp;#39;클립보드에 복사되었습니다.&amp;#39;);
};

...

{message &amp;amp;&amp;amp; &amp;lt;Toast key={message} message={message} /&amp;gt;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;동일한 메시지를 여러 번 연속으로 보여주기 위해 &lt;code&gt;key={message}&lt;/code&gt; 사용&lt;/p&gt;
&lt;p&gt;React에서는 동일한 key를 가진 컴포넌트를 재사용하려 하기 때문에 메시지가 바뀌지 않으면 Toast가 재렌더링되지 않음&lt;/p&gt;
&lt;p&gt;이를 방지하고자 메시지 변경 시 강제 리마운트하도록 적용&lt;/p&gt;
&lt;h2&gt;4️⃣ 최종 코드&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;//Toast.tsx
import { AnimatePresence, motion } from &amp;#39;framer-motion&amp;#39;;
import { useEffect, useState } from &amp;#39;react&amp;#39;;
import ReactDOM from &amp;#39;react-dom&amp;#39;;

interface ToastProps {
  message: string;
  duration?: number;
}

export default function Toast({ message, duration = 2000 }: ToastProps) {
  const [show, setShow] = useState(true);

  useEffect(() =&amp;gt; {
    const timer = setTimeout(() =&amp;gt; setShow(false), duration);
    return () =&amp;gt; clearTimeout(timer);
  }, [duration]);

  return ReactDOM.createPortal(
    &amp;lt;AnimatePresence&amp;gt;
      {show &amp;amp;&amp;amp; (
        &amp;lt;motion.div
          className=&amp;quot;fixed bottom-6 inset-x-0 mx-auto z-50 w-fit&amp;quot;
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 20 }}
          transition={{ duration: 0.5 }}
        &amp;gt;
          &amp;lt;div className=&amp;quot;bg-black text-white text-sm px-4 py-2 rounded-lg shadow-lg text-center&amp;quot;&amp;gt;
            {message}
          &amp;lt;/div&amp;gt;
        &amp;lt;/motion.div&amp;gt;
      )}
    &amp;lt;/AnimatePresence&amp;gt;,

    document.body,
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;// useToast.tsx
import { useState, useCallback } from &amp;#39;react&amp;#39;;

export default function useToast() {
  const [message, setMessage] = useState(&amp;#39;&amp;#39;);

  const showToast = useCallback((msg: string, duration: number = 2000) =&amp;gt; {
    setMessage(msg);
    setTimeout(() =&amp;gt; setMessage(&amp;#39;&amp;#39;), duration);
  }, []);

  return { message, showToast };
}&lt;/code&gt;&lt;/pre&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/25</guid>
      <comments>https://chaeon1.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 9 Jun 2025 00:01:02 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript] 코딩테스트 기본 문법 정리</title>
      <link>https://chaeon1.tistory.com/24</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;  1. 입출력 처리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 콘솔 입력 (Node.js 기준)&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;const fs = require('fs');
const input = fs.readFileSync('/dev/stdin').toString().trim().split('\n');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;✅ 예제 입력&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;const input = `31 2
 3`.split('\n');
 const N = Number(input[0]);
 const arr = input[1].split(' ').map(Number);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;✅ 출력&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;console.log(answer);&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  2. 기본 자료형&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;숫자형 변환&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;Number(&quot;123&quot;);        // 123
parseInt(&quot;123&quot;, 10);  // 123&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문자열&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;let str = &quot;hello&quot;;
str.length;           // 문자열 길이
str.split('');        // ['h','e','l','l','o']&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  3. 배열&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;생성 및 초기화&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let arr = [1, 2, 3];
let newArr = new Array(5).fill(0); // [0, 0, 0, 0, 0]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;순회&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;for (let i = 0; i &amp;lt; arr.length; i++ { ... }
arr.forEach((v) =&amp;gt; console.log(v));
for (let x of arr) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정렬&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;arr.sort((a, b) =&amp;gt; a - b); // 오름차순
arr.sort((a, b) =&amp;gt; b - a); // 내림차순&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기타 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;arr.push(4);       // 뒤에 추가
arr.pop();         // 마지막 제거
arr.shift();       // 첫 요소 제거
arr.unshift(0);    // 앞에 추가
arr.includes(2);   // 요소 포함 여부&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  4. 문자열 처리&lt;/b&gt;&lt;/h1&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;let s = &quot;hello world&quot;;s.split(' ');           // ['hello', 'world']
s.replace('l', 'x');    // 첫 번째 'l'만 변경
s.replaceAll('l', 'x'); // 전체 'l' 변경
s.toUpperCase();        // 대문자 변환
s.toLowerCase();        // 소문자 변환&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  5. Set / Map&lt;/b&gt;&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Set&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let set = new Set([1, 2, 2, 3]);
set.has(2); // true&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Map&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;let map = new Map();
map.set('a', 1);
map.get('a'); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  6. 조건문 &amp;amp; 반복문&lt;/b&gt;&lt;/h1&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;if (a &amp;gt; b) {
  ...
} else {
  ...
}

for (let i = 0; i &amp;lt; 10; i++) { ... }

while (조건) { ... }

do {
  ...
} while (조건);&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  7. 함수&lt;/b&gt;&lt;/h1&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function add(a, b) {
  return a + b;
}

const sub = (a, b) =&amp;gt; a - b; // 화살표 함수&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  8. 객체&lt;/b&gt;&lt;/h1&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;let obj = { name: &quot;Tom&quot;, age: 25 };
obj.name;       // &quot;Tom&quot;
obj[&quot;age&quot;];     // 25

for (let key in obj) {
  console.log(key, obj[key]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;b&gt;  9. 기타 유용한 메서드&lt;/b&gt;&lt;/h1&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Math.max(...arr);   // 배열 최댓값
Math.min(...arr);   // 배열 최솟값
Math.abs(-10);      // 절댓값
Math.floor(3.7);    // 내림
Math.ceil(3.1);     // 올림
Math.round(3.5);    // 반올림&lt;/code&gt;&lt;/pre&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/24</guid>
      <comments>https://chaeon1.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 2 Jun 2025 02:56:08 +0900</pubDate>
    </item>
    <item>
      <title>[React/TypeScript + tailwindCSS] Tiptap 에디터 적용</title>
      <link>https://chaeon1.tistory.com/23</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✉️ 기술 스택&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React, TypeScript, Zustand, Tiptap, DOMPurify, tailwindCSS, Flowbite&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Tiptap Editor&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tiptap.dev/product/editor&quot;&gt;Tiptap Rich Text Editor - the Headless WYSIWYG Editor&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔️ 쉽게 확장 가능&lt;br /&gt;✔️ ProseMirror 기반: 구조적 편집 가능&lt;br /&gt;✔️ 확장 기능 커스터마이징 가능&lt;br /&gt;✔️ 공식 문서 설명이 잘 되어 있어서 따라하기 편함&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;커스터마이징 에디터 구성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✏️ 에디터 설정&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요한 extension (StarterKit, Underline, Highlight) 선택적으로 추가&lt;/li&gt;
&lt;li&gt;prose 기반 스타일링 적용&lt;/li&gt;
&lt;li&gt;debounce 적용으로 입력 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;const editor = useEditor({
  editorProps: {
    attributes: {
      class:
        'prose prose-sm dark:prose-invert prose-headings:my-2 prose-p:m-0 min-h-[120px] focus:outline-none',
    },
  },
  extensions: [StarterKit, Underline, Highlight],
  content,
  onUpdate({ editor }) {
    debouncedOnChange(editor.getHTML());
  },
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✏️ 툴바 기능&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Format: Paragraph, Heading 1, Heading 2&lt;/li&gt;
&lt;li&gt;Bold, Italic, Underline, Highlight&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;{/* Bold */}
&amp;lt;button
  type=&quot;button&quot;
  onClick={() =&amp;gt; editor.chain().focus().toggleBold().run()}
  className={`...`}
&amp;gt;
  &amp;lt;BoldIcon /&amp;gt;
  &amp;lt;span className=&quot;sr-only&quot;&amp;gt;Bold&amp;lt;/span&amp;gt;
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HTML 렌더링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성된 HTML 콘텐츠는 &lt;code&gt;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;텍스트&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt; 형식으로 저장됨&lt;br /&gt;이를 안전하게 보여주기 위해 &lt;code&gt;DOMPurify.sanitize&lt;/code&gt; 적용&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const photoTalkMessage = DOMPurify.sanitize(photoTalk.message);

&amp;lt;p dangerouslySetInnerHTML={{ __html: photoTalkMessage }} /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;: WYSIWYG 작성 콘텐츠를 그대로 표현&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DOMPurify.sanitize&lt;/code&gt;: script injection과 같은 보안 문제 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에디터 구조 및 확장 적용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터를 다른 영역에도 재사용 가능하도록 설계했으며, 교통 안내 입력 등에서도 동일한 에디터 UI 활용&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt; components
 ┣  common
 ┃ ┣  Editor
 ┃ ┃ ┣  MenuBar.tsx
 ┃ ┃ ┗  TiptapEditor.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// TiptapEditor.tsx
return (
  &amp;lt;div className=&quot;border rounded-md bg-white dark:bg-gray-800&quot;&amp;gt;
    {editor &amp;amp;&amp;amp; (
      &amp;lt;&amp;gt;
        &amp;lt;MenuBar editor={editor} /&amp;gt;
        &amp;lt;div className=&quot;p-4 h-[160px] overflow-y-auto&quot;&amp;gt;
          &amp;lt;EditorContent editor={editor} /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/&amp;gt;
    )}
  &amp;lt;/div&amp;gt;
);


// PhotoTalkEditor.tsx
import TipTapEditor from '@/components/common/Editor/TiptapEditor';

&amp;lt;TipTapEditor
  content={form.message}
  onChange={(value) =&amp;gt; {
    setForm((prev) =&amp;gt; ({ ...prev, message: value }));
  }}
/&amp;gt;


// TransportationItem.tsx
import TipTapEditor from '@/components/common/Editor/TiptapEditor';

&amp;lt;TipTapEditor
  content={transportationInputs[inputKey] || ''}
  onChange={(value) =&amp;gt; {
    updateTransportationInput(inputKey, value);
  }}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/23</guid>
      <comments>https://chaeon1.tistory.com/23#entry23comment</comments>
      <pubDate>Sat, 24 May 2025 17:05:03 +0900</pubDate>
    </item>
    <item>
      <title>[모던 자바스크립트 Deep Dive] 46장 ~ 49장</title>
      <link>https://chaeon1.tistory.com/22</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;46장 제너레이터와 async/await&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.1 제너레이터란?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;제너레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있다.&lt;/li&gt;
&lt;li&gt;제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.&lt;/li&gt;
&lt;li&gt;제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.2 제너레이터 함수의 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;function*&lt;/code&gt; 키워드로 선언, &lt;code&gt;yield&lt;/code&gt; 표현식 포함&lt;/li&gt;
&lt;li&gt;선언문, 표현식, 메서드, 클래스 메서드 형태&lt;/li&gt;
&lt;li&gt;화살표 함수로 정의 불가&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; 생성자로 호출 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.3 제너레이터 객체&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 함수: 호출 시 코드 블록 실행&lt;/li&gt;
&lt;li&gt;제너레이터 함수: 호출 시 제너레이터 객체 생성 후 반환&lt;/li&gt;
&lt;li&gt;제너레이터 객체는 이터러블이면서 동시에 이터레이터
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Symbol.iterator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next&lt;/code&gt;: 호출 시 &lt;code&gt;yield&lt;/code&gt;까지 실행하고 &lt;code&gt;{ value, done }&lt;/code&gt; 객체 반환&lt;/li&gt;
&lt;li&gt;&lt;code&gt;return&lt;/code&gt;: 호출 시 &lt;code&gt;{ value, done: true }&lt;/code&gt; 반환 후 종료&lt;/li&gt;
&lt;li&gt;&lt;code&gt;throw&lt;/code&gt;: 호출 시 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.4 제너레이터의 일시 중지와 재개&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;yield&lt;/code&gt; 키워드로 실행 중지, &lt;code&gt;next()&lt;/code&gt;로 재개&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next(value)&lt;/code&gt;: 값을 제너레이터 내부로 전달&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yield&lt;/code&gt; 연속 호출 구조: &lt;code&gt;generator.next() -&amp;gt; yield -&amp;gt; generator.next() -&amp;gt; yield -&amp;gt; ... -&amp;gt; generator.next() -&amp;gt; return&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.5 제너레이터의 활용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이터러블의 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무한 이터러블 간결하게 생성 가능 (무한 피보나치 수열 등)&lt;/li&gt;
&lt;li&gt;기존 이터레이션 프로토콜 구현보다 간단&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비동기 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;yield&lt;/code&gt; 표현식을 통해 비동기 흐름을 동기처럼 표현 가능&lt;/li&gt;
&lt;li&gt;제너레이터 실행기 필요 (co 라이브러리)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;46.6 async/await&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;async 함수
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;async&lt;/code&gt; 키워드로 정의, 항상 프로미스 반환&lt;/li&gt;
&lt;li&gt;명시적 &lt;code&gt;return&lt;/code&gt; 없이도 암묵적으로 프로미스 resolve&lt;/li&gt;
&lt;li&gt;클래스의 &lt;code&gt;constructor&lt;/code&gt; 메서드는 사용 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;await 키워드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt;: 프로미스가 완료될 때까지 대기&lt;/li&gt;
&lt;li&gt;반드시 &lt;code&gt;async&lt;/code&gt; 함수 내부에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에러 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;try...catch&lt;/code&gt;문을 사용해 에러 처리 가능&lt;/li&gt;
&lt;li&gt;에러 전파 및 처리 명확&lt;/li&gt;
&lt;li&gt;&lt;code&gt;catch&lt;/code&gt;문을 사용하지 않고 에러가 발생하면 reject된 프로미스 반환&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 data-ke-size=&quot;size26&quot;&gt;47장 에러 처리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;47.1 에러 처리의 필요성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러 방치하면 프로그램 강제 종료&lt;/li&gt;
&lt;li&gt;&lt;code&gt;try...catch&lt;/code&gt;문으로 적절히 대응하면 종료 없이 실행 가능&lt;/li&gt;
&lt;li&gt;예외 상황(DOM 조작 등)도 에러로 이어질 수 있으므로 방어 코드 필요
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;null 체크, &lt;code&gt;?.&lt;/code&gt; 옵셔널 체이닝 사용 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;47.2 try...catch...finally 문&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;try&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, &lt;code&gt;finally&lt;/code&gt; 세 블록으로 구성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;try&lt;/code&gt;: 실행할 코드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;catch&lt;/code&gt;: 에러 발생 시 실행, 에러 객체가 인자로 전달&lt;/li&gt;
&lt;li&gt;&lt;code&gt;finally&lt;/code&gt;: 에러 발생과 상관 없이 무조건 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;catch&lt;/code&gt; 생략 불가, &lt;code&gt;finally&lt;/code&gt; 생략 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;47.3 Error 객체&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Error&lt;/code&gt; 생성자 함수로 에러 객체 생성 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;const error = new Error('invalid');&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt;: 전달된 에러 메시지&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stack&lt;/code&gt;: 콜스택 정보 (디버깅 목적)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;생성자 함수&lt;/th&gt;
&lt;th&gt;인스턴스&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Error&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;일반적인 에러&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SyntaxError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;문법 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ReferenceError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정의되지 않은 변수 참조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TypeError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;타입 불일치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RangeError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;허용 범위를 벗어난 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;URIError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URI 처리 함수 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EvalError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;eval&lt;/code&gt; 함수 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;47.4 throw 문&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러 객체 생성만으로는 에러가 발생하지 않음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;throw&lt;/code&gt;문으로 명시적 에러 발생 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;throw&lt;/code&gt;: &lt;code&gt;catch&lt;/code&gt; 블록 실행 트리거&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;47.5 에러의 전파&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;콜 스택을 따라 호출자 방향(아래 방향)으로 전파&lt;/li&gt;
&lt;li&gt;catch되지 않으면 프로그램 강제 종료&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;Promise.then&lt;/code&gt; 등 비동기 콜백 함수 내부에서 throw한 에러는 전파되지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역에서 uncaught되어 종료될 수 있음, 내부에서 &lt;code&gt;try/catch&lt;/code&gt;로 직접 처리 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에러는 호출자 쪽에서만 처리 가능, 적절한 위치에 &lt;code&gt;catch&lt;/code&gt; 구문 필요&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;48장 모듈&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;48.1 모듈의 일반적 의미&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모듈: 재사용 가능한 코드 조각, 일반적으로 기능 단위로 파일 분리&lt;/li&gt;
&lt;li&gt;자신만의 파일 스코프(모듈 스코프)를 가지며, 내부 자산은 기본적으로 비공개&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export&lt;/code&gt; 키워드로 선택적 공개 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt;를 통해 &lt;code&gt;export&lt;/code&gt;된 자산 재사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;48.2 자바스크립트와 모듈&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과거 자바스크립트는 파일 스코프 없이 전역 공유, 모듈 시스템 미지원&lt;/li&gt;
&lt;li&gt;여러 &lt;code&gt;script&lt;/code&gt; 태그를 사용해도 전역 스코프 공유, 변수 충돌 가능성&lt;/li&gt;
&lt;li&gt;문제 해결을 위해 CommonJS(Node.js 기반), AMD 방식 등장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;48.3 ES6 모듈(ESM)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;type = &quot;module&quot;&lt;/code&gt; 속성을 가진 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 태그로 ESM 로드&lt;/li&gt;
&lt;li&gt;ESM: 기본적으로 strict mode 적용&lt;/li&gt;
&lt;li&gt;모듈 스코프
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ESM 내부 변수는 전역 스코프에 등록되지 않음&lt;/li&gt;
&lt;li&gt;동일한 식별자를 다른 모듈에서 선언해도 충돌 없이 동작&lt;/li&gt;
&lt;li&gt;외부 모듈에서 ESM 내 식별자에 접근 불가 -&amp;gt; &lt;code&gt;export&lt;/code&gt; 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;export&lt;/code&gt; 키워드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변수, 함수, 클래스 등을 외부에 공개 가능&lt;/li&gt;
&lt;li&gt;선언 앞에 export 키워드 사용&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;export const pi = Math.PI;

export function square(x) {
  return x * x;
}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;하단에서 객체처럼 한 번에 export&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;const pi= Math.PI;

function square(x) {
  return x * x;
}

export { pi, square };&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt; 키워드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 모듈이 export한 식별자를 현재 모듈 스코프 내부로 불러오기&lt;/li&gt;
&lt;li&gt;기본 사용&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;import { pi, square } from './lib.mjs';&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;전체 import (&lt;code&gt;as&lt;/code&gt; 구문)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;import * as lib from './lib.mjs';

lib.square(2);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;이름 변경 후 import (&lt;code&gt;as&lt;/code&gt; 구문)&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-js&quot;&gt;import { square as sq } from './lib.mjs';

sq(2);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;default&lt;/code&gt; export
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모듈에서 하나의 값만 export할 때 사용&lt;/li&gt;
&lt;li&gt;이름 없이 export, import 시 임의의 이름 사용
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;// lib.mjs
export default x =&amp;gt; x * x;

&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;  // app.mjs
  import square from './lib.mjs';

  square(3); // 9
  ```&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;49장 Babel과 Webpack을 이용한 ES6+/ES.NEXT 개발 환경 구축&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;49.1 Babel&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Babel: ES6+/ES.NEXT 코드를 ES5 코드로 변환하여 구형 브라우저 호환성 확보&lt;/li&gt;
&lt;li&gt;브라우저가 지원하지 않는 최신 문법 자동 변환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화살표 함수, 지수 연산자 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;브라우저에서 &lt;code&gt;require&lt;/code&gt; 함수 미지원
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Babel은 기본적으로 CommonJS 방식으로 트랜스파일링 (&lt;code&gt;require&lt;/code&gt;, &lt;code&gt;exports&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;브라우저는 이를 지원하지 않으므로 브라우저 실행 시 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;49.2 Webpack&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Webpack: 여러 JS 모듈, 이미지, CSS 등을 하나의 번들 파일로 묶음&lt;/li&gt;
&lt;li&gt;모듈 로더 없이 브라우저에서 실행 가능&lt;/li&gt;
&lt;li&gt;Babel과 함께 사용하여 트랜스파일링 + 번들링&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study/모던 자바스크립트 Deep Dive</category>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/22</guid>
      <comments>https://chaeon1.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 11 May 2025 01:08:16 +0900</pubDate>
    </item>
    <item>
      <title>[모던 자바스크립트 Deep Dive] 40장 ~ 45장</title>
      <link>https://chaeon1.tistory.com/21</link>
      <description>&lt;h2&gt;41장 타이머&lt;/h2&gt;
&lt;h3&gt;41.1 호출 스케줄링&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;함수 호출 지연, 반복 예약 가능&lt;/li&gt;
&lt;li&gt;타이머 함수: 호스트 객체&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;: 일정 시간 후 한 번만 실행&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setInterval&lt;/code&gt;: 일정 시간 간격으로 반복 실행&lt;/li&gt;
&lt;li&gt;자바스크립트는 싱글 스레드로 동작하므로 타이머는 비동기 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;41.2 타이머 함수&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;setTimeout / clearTimeout&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;const timeoutId = setTimeout(func|code[, delay, param1, param2, ...]);&lt;/code&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;매개변수&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;func&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;타이머가 만료된 뒤 호출될 콜백 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delay&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;타이머 만료 시간(ms). &lt;code&gt;setTimeout&lt;/code&gt; 함수는 &lt;code&gt;delay&lt;/code&gt; 시간으로 단 한 번 동작하는 타이머를 생성한다. 인수 전달을 생략한 경우 기본값 0이 지정된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;param1&lt;/code&gt;, &lt;code&gt;param2&lt;/code&gt;, ...&lt;/td&gt;
&lt;td&gt;호출 스케줄링된 콜백 함수에 전달해야 할 인수가 존재하는 경우 세 번째 이후의 인수로 전달할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;setInterval / clearInterval&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const timerId = setInterval(func|code[, delay, param1, param2, ...]);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;일정 간격마다 콜백 반복 실행&lt;/li&gt;
&lt;li&gt;반복 횟수 조건으로 제한 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;41.3 디바운스와 스로틀&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;디바운스&lt;ul&gt;
&lt;li&gt;짧은 시간 간격으로 이벤트가 발생하면 이벤트 핸들러를 호출하지 않음&lt;/li&gt;
&lt;li&gt;일정 시간이 경과한 이후에 콜백 한 번 호출&lt;/li&gt;
&lt;li&gt;최종 상태 반영에 적합: 입력 완료 후 한 번만 Ajax 요청&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;clearTimeout&lt;/code&gt; 사용&lt;/li&gt;
&lt;li&gt;resize 이벤트, 자동완성 UI, 중복 클릭 방지 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스로틀&lt;ul&gt;
&lt;li&gt;이벤트가 연속 발생해도 일정 시간 간격마다 한 번씩만 콜백 실행&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt; 사용, 일정 간격마다 타이머 초기화&lt;/li&gt;
&lt;li&gt;scroll 이벤트, 무한 스크롤 UI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;

&lt;h2&gt;42장 비동기 프로그래밍&lt;/h2&gt;
&lt;h3&gt;42.1 동기 처리와 비동기 처리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;싱글 스레드 기반: 한 번에 하나의 태스크 처리 가능&lt;/li&gt;
&lt;li&gt;함수 호출 시 실행 컨텍스트 스택에 푸시되어 순차적 실행&lt;/li&gt;
&lt;li&gt;실행 중인 함수가 종료되어야 다음 함수 실행 가능 -&amp;gt; 동기 처리 -&amp;gt; 블로킹 발생&lt;/li&gt;
&lt;li&gt;비동기 처리&lt;ul&gt;
&lt;li&gt;실행 순서에 상관 없이 다음 태스크 실행 가능&lt;/li&gt;
&lt;li&gt;실행 순서 보장 어려움&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, HTTP 요청, 이벤트 핸들러&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;콜백 패턴&lt;ul&gt;
&lt;li&gt;비동기 처리 방식&lt;/li&gt;
&lt;li&gt;콜백 헬, 예외 처리 어려움, 복잡한 비동기 흐름 처리 한계&lt;/li&gt;
&lt;li&gt;해결책: 프로미스(Promise)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;42.2 이벤트 루프와 태스크 큐&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;이벤트 루프: 자바스크립트의 동시성 지원&lt;/li&gt;
&lt;li&gt;자바스크립트 엔진 구성 요소&lt;ul&gt;
&lt;li&gt;콜 스택(call stack): 실행 컨텍스트 저장 및 실행&lt;/li&gt;
&lt;li&gt;힙(heap): 객체 저장 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비동기 작업 처리: 브라우저, Node.js&lt;ul&gt;
&lt;li&gt;태스크 큐(task queue): 비동기 콜백 함수, 이벤트 핸들러 저장&lt;/li&gt;
&lt;li&gt;마이크로태스크 큐: 프로미스의 후속 처리용 콜백 저장&lt;/li&gt;
&lt;li&gt;이벤트 루프 동작 원리&lt;ol&gt;
&lt;li&gt;콜 스택이 비었는지 확인&lt;/li&gt;
&lt;li&gt;비어 있으면 태스크 큐에서 콜백 함수를 꺼내 콜 스택에 푸시하여 실행&lt;/li&gt;
&lt;li&gt;FIFO(First In First Out) 방식으로 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;자바스크립트는 싱글 스레드, 브라우저는 멀티 스레드&lt;/li&gt;
&lt;li&gt;브라우저와 자바스크립트 엔진이 협력하여 비동기 처리 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;

&lt;h2&gt;43장 Ajax&lt;/h2&gt;
&lt;h3&gt;43.1 Ajax란?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;브라우저와 서버 간 비동기 통신을 가능하게 하는 프로그래밍 방식&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XMLHttpRequest&lt;/code&gt; 객체 사용하여 HTTP 요청 비동기 처리&lt;/li&gt;
&lt;li&gt;기존 방식 단점&lt;ul&gt;
&lt;li&gt;매 요청마다 HTML을 다시 받아와 불필요한 데이터 전송과 렌더링 발생&lt;/li&gt;
&lt;li&gt;화면 깜빡임 등 사용자 경험 저하&lt;/li&gt;
&lt;li&gt;서버 응답 전까지 블로킹 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ajax 장점&lt;ul&gt;
&lt;li&gt;필요한 데이터만 요청, 네트워크 부하 감소&lt;/li&gt;
&lt;li&gt;변경된 부분만 렌더링하여 UX 향상&lt;/li&gt;
&lt;li&gt;비동기 통신으로 블로킹 없는 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;43.2 JSON&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JSON 표기 방식&lt;ul&gt;
&lt;li&gt;자바스크립트 객체와 유사한 텍스트 기반 포맷&lt;/li&gt;
&lt;li&gt;배열과 객체 모두 표현 가능&lt;/li&gt;
&lt;li&gt;키와 문자열은 반드시 &lt;code&gt;&amp;quot;&lt;/code&gt; 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JSON.stringify&lt;ul&gt;
&lt;li&gt;객체나 배열을 JSON 문자열로 직렬화&lt;/li&gt;
&lt;li&gt;선택적 들여쓰기 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replacer&lt;/code&gt;: 특정 속성 제외 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JSON.parse&lt;ul&gt;
&lt;li&gt;JSON 문자열을 객체나 배열로 역직렬화&lt;/li&gt;
&lt;li&gt;서버에서 받은 JSON 데이터를 자바스크립트에서 사용할 수 있도록 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;43.3 XMLHttpRequest&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;XMLHttpRequest 객체 생성&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const xhr = new XMLHttpRequest()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HTTP 요청 전송&lt;ol&gt;
&lt;li&gt;&lt;code&gt;XMLHttpRequest.prototype.open&lt;/code&gt; 메서드로 HTTP 요청 초기화&lt;/li&gt;
&lt;li&gt;필요에 따라 &lt;code&gt;XMLHttpRequest.prototype.setRequestHeader&lt;/code&gt; 메서드로 특정 HTTP 요청의 헤더 값 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XMLHttpRequest.prototype.send&lt;/code&gt; 메서드로 HTTP 요청 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;HTTP 응답 처리&lt;ul&gt;
&lt;li&gt;&lt;code&gt;onreadystatechange&lt;/code&gt; 이벤트: &lt;code&gt;readyState === 4&lt;/code&gt; (DONE) &amp;amp;&amp;amp; &lt;code&gt;status === 200&lt;/code&gt;일 때 응답 처리&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onload&lt;/code&gt; 이벤트: 성공 시 자동 호출, &lt;code&gt;readyState&lt;/code&gt; 체크 불필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;

&lt;h2&gt;44장 REST API&lt;/h2&gt;
&lt;h3&gt;44.1 REST API의 구성&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구성 요소&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;th&gt;표현 방법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;자원 (resource)&lt;/td&gt;
&lt;td&gt;자원&lt;/td&gt;
&lt;td&gt;URI(엔드포인트)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;행위 (verb)&lt;/td&gt;
&lt;td&gt;자원에 대한 행위&lt;/td&gt;
&lt;td&gt;HTTP 요청 메서드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;표현 (representations)&lt;/td&gt;
&lt;td&gt;자원에 대한 행위의 구체적 내용&lt;/td&gt;
&lt;td&gt;페이로드&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;44.2 REST API의 설계 원칙&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;URI는 리소스를 표현해야 한다.&lt;ul&gt;
&lt;li&gt;명사 사용: &lt;code&gt;GET /todos/1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리소스에 대한 행위는 HTTP 요청 메서드로 표현한다.&lt;ul&gt;
&lt;li&gt;GET: 조회&lt;/li&gt;
&lt;li&gt;POST: 생성&lt;/li&gt;
&lt;li&gt;PUT: 전체 수정&lt;/li&gt;
&lt;li&gt;PATCH: 부분 수정&lt;/li&gt;
&lt;li&gt;DELETE: 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;br/&gt;

&lt;h2&gt;45장 프로미스&lt;/h2&gt;
&lt;h3&gt;45.1 비동기 처리를 위한 콜백 패턴의 단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;콜백 헬&lt;ul&gt;
&lt;li&gt;비동기 함수는 결과가 준비되기 전 종료, 반환값 외부 사용 불가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;XMLHttpRequest&lt;/code&gt;: 콜백 실행이 호출 시점 이후에 발생&lt;/li&gt;
&lt;li&gt;콜백에서 상위 스코프의 변수에 값을 할당해도 순서 보장이 안 되므로 예상대로 동작하지 않음&lt;/li&gt;
&lt;li&gt;후속 처리는 콜백 함수로 처리, 콜백 중첩 시 콜백 헬 현상 발생&lt;ul&gt;
&lt;li&gt;가독성 저하&lt;/li&gt;
&lt;li&gt;유지보수 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;에러 처리의 한계&lt;ul&gt;
&lt;li&gt;&lt;code&gt;try...catch&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;동기 코드에만 유효&lt;/li&gt;
&lt;li&gt;비동기 콜백에서 발생한 에러는 잡을 수 없음&lt;/li&gt;
&lt;li&gt;비동기 콜백은 호출 스택 상에서 &lt;code&gt;try&lt;/code&gt; 블록과 연결되어 있지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;콜백 기반 비동기 처리에서는 에러 처리를 위한 일관된 매커니즘 부재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.2 프로미스의 생성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;등장 배경&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;콜백 패턴의 한계 해결&lt;/li&gt;
&lt;li&gt;비동기 처리 결과 명확하게 표현&lt;/li&gt;
&lt;li&gt;가독성 및 에러 처리 용이성 향상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;생성 방법&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const promise = new Promise((resolve, reject) =&amp;gt; {...});&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;executor 함수: 생성 시 전달되는 콜백, 비동기 작업 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;프로미스의 상태 정보&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;상태 변경 조건&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;비동기 처리가 아직 수행되지 않은 상태&lt;/td&gt;
&lt;td&gt;프로미스가 생성된 직후 기본 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fulfilled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;비동기 처리가 수행된 상태 (성공)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;resolve&lt;/code&gt; 함수 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rejected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;비동기 처리가 수행된 상태 (실패)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;reject&lt;/code&gt; 함수 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.3 프로미스의 후속 처리 메서드&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Promise.prototype.then&lt;ul&gt;
&lt;li&gt;두 개의 콜백 함수를 인수로 전달받음&lt;ul&gt;
&lt;li&gt;첫 번째: &lt;code&gt;fulfilled&lt;/code&gt;, 프로미스의 비동기 처리 결과&lt;/li&gt;
&lt;li&gt;두 번째: &lt;code&gt;rejected&lt;/code&gt;, 프로미스의 에러&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;언제나 프로미스 반환&lt;ul&gt;
&lt;li&gt;반환값이 프로미스인 경우 그대로 반환&lt;/li&gt;
&lt;li&gt;반환값이 프로미스가 아닐 경우 암묵적으로 프로미스를 생성해 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Promise.prototype.catch&lt;ul&gt;
&lt;li&gt;한 개의 콜백 함수를 인수로 전달받음&lt;ul&gt;
&lt;li&gt;프로미스가 &lt;code&gt;rejected&lt;/code&gt; 상태일 경우 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;then(undefined, onRejected)&lt;/code&gt;과 동일하게 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Promise.prototype.finally&lt;ul&gt;
&lt;li&gt;한 개의 콜백 함수를 인수로 전달받음&lt;ul&gt;
&lt;li&gt;성공/실패 여부와 무관하게 무조건 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리소스 정리, 로딩 종료 등 공통 처리 시 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.4 프로미스의 에러 처리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;catch&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;비동기 처리에서 발생한 에러 처리 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;then&lt;/code&gt; 내부에서 발생한 에러 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;then&lt;/code&gt;의 두 번째 인자보다는 &lt;code&gt;catch&lt;/code&gt; 사용 권장&lt;ul&gt;
&lt;li&gt;&lt;code&gt;then&lt;/code&gt;: 두 번째 콜백은 첫 번째 콜백에서 발생한 에러 캐치 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.5 프로미스 체이닝&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;then&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, &lt;code&gt;finally&lt;/code&gt;는 모두 프로미스 반환, 연속 호출 가능 -&amp;gt; 체이닝&lt;/li&gt;
&lt;li&gt;체이닝을 통해 비동기 처리 순차적 연결 가능 -&amp;gt; 콜백 헬 방지&lt;/li&gt;
&lt;li&gt;&lt;code&gt;async/await&lt;/code&gt;: 체이닝 없이도 동기처럼 프로미스 처리 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.6 프로미스의 정적 메서드&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Promise.resolve / Promise.reject&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resolve&lt;/code&gt;: 값을 즉시 resolve한 프로미스 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reject&lt;/code&gt;: 에러 등을 즉시 reject한 프로미스 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.all&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;여러 프로미스 병렬 처리, 모두 성공 시 배열로 결과 반환&lt;/li&gt;
&lt;li&gt;하나라도 실패하면 즉시 reject&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.race&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;가장 먼저 완료된 프로미스의 결과/오류를 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.allSettled&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;모든 프로미스의 성공/실패 결과를 객체 배열로 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.7 마이크로태스크 큐&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;마이크로태스크 큐는 태스크 큐보다 우선순위가 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;45.8 fetch&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fetch()&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;XMLHttpRequest&lt;/code&gt;를 대체하는 HTTP 요청 API&lt;/li&gt;
&lt;li&gt;Promise 기반&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Response 객체: HTTP 응답 표현&lt;/li&gt;
&lt;li&gt;에러 처리&lt;ul&gt;
&lt;li&gt;&lt;code&gt;404&lt;/code&gt;, &lt;code&gt;500&lt;/code&gt; 등의 HTTP 오류는 reject되지 않음 -&amp;gt; &lt;code&gt;ok: false&lt;/code&gt;인 Response로 resolve&lt;/li&gt;
&lt;li&gt;네트워크 에러나 CORS 오류만 reject 처리&lt;/li&gt;
&lt;li&gt;명시적 에러 처리 필요&lt;/li&gt;
&lt;li&gt;&lt;code&gt;axios&lt;/code&gt;: 모든 HTTP 에러를 자동으로 reject 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Study/모던 자바스크립트 Deep Dive</category>
      <author>chaeon1</author>
      <guid isPermaLink="true">https://chaeon1.tistory.com/21</guid>
      <comments>https://chaeon1.tistory.com/21#entry21comment</comments>
      <pubDate>Sun, 11 May 2025 01:07:25 +0900</pubDate>
    </item>
  </channel>
</rss>