<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>faith_coder_lab.log</title>
        <link>https://velog.io/</link>
        <description>Turning Vision into Reality.</description>
        <lastBuildDate>Thu, 05 Feb 2026 08:00:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>faith_coder_lab.log</title>
            <url>https://velog.velcdn.com/images/faith_coder_lab/profile/35be4382-371d-4a69-88b6-051af0180a2a/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. faith_coder_lab.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/faith_coder_lab" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[알고리즘 | 크루스칼 메소드]]></title>
            <link>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%AC%EB%A3%A8%EC%8A%A4%EC%B9%BC-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%AC%EB%A3%A8%EC%8A%A4%EC%B9%BC-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Thu, 05 Feb 2026 08:00:33 GMT</pubDate>
            <description><![CDATA[<h2 id="질문에서-시작하기">질문에서 시작하기</h2>
<h3 id="우리는-단일-상품만-등록하는데">우리는 단일 상품만 등록하는데,,</h3>
<table>
<thead>
<tr>
<th>상품등록</th>
<th>그룹상품등록</th>
</tr>
</thead>
<tbody><tr>
<td><img src="https://velog.velcdn.com/images/faith_coder_lab/post/8922ccfd-5a30-4fb6-98b0-716aa2f9de26/image.png" alt=""></td>
<td><img src="https://velog.velcdn.com/images/faith_coder_lab/post/77ae2687-a99e-4539-927f-6782ab0e3fea/image.png" alt=""></td>
</tr>
</tbody></table>
<p>네이버 솔루션 API 전환을 하다가 문득 그룹 상품 등록이 눈에 띄었다.
우리는 단일 상품만 쓰고 있는데,, 흠.
그룹 상품은 뭐지?</p>
<hr>
<h2 id="등록과-추천은-다른-이야기일지도">등록과 추천은 다른 이야기일지도</h2>
<ul>
<li><strong>상품 등록</strong> = 시스템에 상품을 넣는 기준</li>
<li><strong>상품 추천</strong> = 어떤 상품을, 어떤 기준으로 묶어서 보여줄지</li>
</ul>
<p>셀파트너는 지금 <strong>단일 상품</strong>을 기준으로 상품을 추천해주고 있다.</p>
<p>그렇다면, 그룹 상품 등록은 우리에게 필요한 기능일까?</p>
<hr>
<h2 id="상품을-아주-단순하게-표현해보자면">상품을 아주 단순하게 표현해보자면,,</h2>
<ul>
<li><p>상품 → 점</p>
</li>
<li><p>상품 추천의 단위 → 선</p>
</li>
<li><p>A 상품과 B 상품이 자주 같이 팔린다면</p>
</li>
<li><p>A와 B 사이에는 <strong>굵은 선</strong>이 하나 생긴다</p>
</li>
</ul>
<p>그렇다면 상품 추천은 결국 <strong>점과 점을 어떻게 연결하느냐</strong>의 문제가 된다.
마치 그래프,, 라 할 수 있다.</p>
<hr>
<h2 id="문제는">문제는</h2>
<h3 id="다-연결하면-너무-복잡함">다 연결하면 너무 복잡함</h3>
<p>그럼 모든 상품을 전부 연결하면?</p>
<ul>
<li>A도 B랑 연결</li>
<li>A도 C랑 연결</li>
<li>B도 C랑 연결</li>
<li>C도 D랑 연결</li>
</ul>
<p>셀러 입장에서는</p>
<blockquote>
<p>그래서 어쩌라고?,,,</p>
</blockquote>
<p>모든 관계를 다 보여주는 건 판단을 오히려 어렵게 만들 것 같다.
그럼 정말 필요한 연결만 남길 수는 없을까?</p>
<hr>
<h2 id="mst-꼭-필요한-연결만-남긴다는-생각">MST: 꼭 필요한 연결만 남긴다는 생각</h2>
<p>여기서 오늘 공부했던 개념이 <strong>최소 신장 트리(MST)</strong>.
이름은 어렵지만,, 개념은 꽤 직관적이다.</p>
<blockquote>
<p>모든 점을 연결하되, 가장 작은 연결만으로 설명하자</p>
</blockquote>
<p>상품 추천으로 치환해보자면,,</p>
<ul>
<li>다 묶을 필요는 없고,</li>
<li>가장 의미 있는 연결 몇 개면 충분하다는 것.</li>
</ul>
<p>&quot;왜 이 상품들이 추천 대상인지&quot;</p>
<hr>
<h2 id="그럼-어떤-연결부터-남겨야-하는데">그럼 어떤 연결부터 남겨야 하는데?</h2>
<p>연결은 줄이겠는데... 그럼 뭘 기준으로 남겨야 하나ㅏ,,
그래서 한 단계 더 들어가면 <strong>Kruskal 알고리즘</strong>이 등장한다.</p>
<hr>
<h2 id="kruskal-제일-확실한-것부터">Kruskal: 제일 확실한 것부터</h2>
<ol>
<li>제일 확실한 관계부터 보기</li>
<li>하나씩 연결해보기</li>
<li>이미 충분히 연결된 경우는 넘어가기</li>
</ol>
<p>&quot;일단 잘 팔리는 조합부터 보자&quot;</p>
<hr>
<h2 id="union-find-이미-같은-묶음일까">Union-Find: 이미 같은 묶음일까?</h2>
<p>Kruskal이 제대로 동작하기 위해서는 <em>이 두 상품이 이미 같은 그룹인지</em> 확인이 필수다.
이걸 확인하는 게 <strong>Union-Find</strong>.</p>
<p>Union-Find는</p>
<ul>
<li>상품이 어떤 그룹에 속해 있는지 관리하고</li>
<li>이미 묶인 상품을 또 묶지 않게 해준다</li>
</ul>
<p>이게 없으면</p>
<ul>
<li>비슷한 그룹이 계속 생기고</li>
<li>구조는 금방 복잡해짐</li>
</ul>
<hr>
<h2 id="path-compression">Path Compression</h2>
<h3 id="한-번-확인한-건-다음엔-더-빠르게">한 번 확인한 건, 다음엔 더 빠르게</h3>
<p>Union-Find의 최적화 <strong>Path Compression</strong></p>
<p>처음에는</p>
<ul>
<li>A랑 D가 같은 그룹인지 확인하려면</li>
<li>A → B → C → D 여러 단계를 거쳐야 할 가능성이 높음</li>
</ul>
<p>한 번 확인하고 나면</p>
<ul>
<li>A, B, C가 전부 바로 D를 가리키게 되는 것.</li>
</ul>
<blockquote>
<p>한 번 검증된 상품 묶음은 다음엔 훨씬 빠르게 판단할 수 있다.</p>
</blockquote>
<p>데이터가 쌓이면 판단은 가벼워진다.</p>
<hr>
<h2 id="그래서">그래서</h2>
<ul>
<li><strong>MST</strong>: 꼭 필요한 만큼만 묶고</li>
<li><strong>Kruskal</strong>: 가장 신뢰할 수 있는 관계부터 선택하고</li>
<li><strong>Union-Find + Path Compression</strong>: 중복 없이, 점점 더 빠르게 판단</li>
</ul>
<p>이긴 한데,, 결국 처음의 질문으로 돌아와서
그룹 상품 API 필요하다고?
라고 하면 아아직은,,,, 안필요한듯,, 그냥 공부에 의의를 두기로 ㅎ</p>
<hr>
<h2 id="나는">나는</h2>
<p>개발을 하다 보면 기능을 만드는 데만 집중하게 된다.
오늘도 스터디를 앞두고 시작하지 못한 쿠팡이 눈앞에 아른거렸다..</p>
<p>그렇지만,,
좋은 기능은 잠시 쉬었다 가는 것,
또 좋은 질문에서 시작한다고 생각한다.</p>
<ul>
<li>이 기능은 왜 필요할까</li>
<li>이 구조는 누구를 위한 것일까</li>
<li>더 단순하게 설명할 방법을 없을까</li>
</ul>
<p>계속 공부하고 질문하는 개발자 되기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘 | 다익스트라]]></title>
            <link>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</link>
            <guid>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</guid>
            <pubDate>Sat, 15 Nov 2025 13:05:51 GMT</pubDate>
            <description><![CDATA[<p>백트래킹에 이어서,,
다익스트라 알고리즘(Dijkstra&#39;s Algorithm)을 공부했었다.
코테 준비할 때 그래프 문제가 그렇게 싫었었지.</p>
<hr>
<h2 id="다익스트라-알고리즘">다익스트라 알고리즘</h2>
<p>한 지점에서 다른 지점까지 가는 최단 경로를 찾는 알고리즘.</p>
<p>네이버 지도나 구글 지도가 길 안내할 때 여러 개의 경로를 보여주는데,
그 밑바탕에 깔린 기본 알고리즘이 바로 이 다익스트라 알고리즘이라고 한다.</p>
<hr>
<h3 id="핵심-아이디어">핵심 아이디어</h3>
<p>가장 짧은 길을 하나씩 확정시키며 탐색해 나간다.</p>
<p>처음 시작 지점에서
&quot;현재까지 가장 가까운 지점&quot;을 하나씩 확정해 나가는 구조다.</p>
<ul>
<li>&#39;지금 당장 최적&#39;인 선택을 하고</li>
<li>그 선택이 전체적으로도 최적이라는 성질을 이용하는 것</li>
</ul>
<p>일명 <strong>그리디(Greedy)</strong> 방식이다.</p>
<p>한 스텝씩, 한 노드 씩,
&quot;지금 계산된 것 중에 제일 짧은 길&quot;을 선택하고 확정하고,
그 확정된 노드를 바탕으로 또 다른 노드를 업데이트한다.</p>
<p>이걸 반복하면
어느 순간 &quot;모든 최단 거리&quot;가 구해진다.</p>
<hr>
<p>백트래킹은 조합을 찾는 데 좋고,
다익스트라는 &#39;최적의 한 경로&#39;를 찾는 데 강하다.</p>
<p>근래 데이터 파이프라인과 AI 작업의 시간 단축에 대해서 고민하고 있는데,
&quot;가장 효율적인 수집 경로&quot;,,,, 이게 곧 다익스트라 아닌가?</p>
<hr>
<p>백트래킹도 그렇고 알고리즘을 다시 보다 보니
괜히 이름 붙은 알고리즘이 아니다.
하나의 코딩 테스트 문제를 해결하려고 만들어진 게 아니라
여러 실생활 문제에 응용될 수 있도록 설계되어 있다는 게 확 체감되는,,</p>
<p>&quot;가장 빠른 길&quot;을 찾아주는 알고리즘이 있다면
개발자에게도 셀러에게도 너무 좋쟈나..</p>
<p>끊임 없이 고민하는 직원 되기.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘 | 백트래킹]]></title>
            <link>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9</link>
            <guid>https://velog.io/@faith_coder_lab/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9</guid>
            <pubDate>Sat, 15 Nov 2025 12:57:22 GMT</pubDate>
            <description><![CDATA[<p>오랜만에 알고리즘 공부를 했다.
사실 알고리즘을 깊게 파서 사용할 일은 많지 않은데도,
가끔 이렇게 기본기를 다시 들여다보면 &quot;아 맞다, 이런 게 있었지&quot; 싶다.
실무에서는 cursor나 GPT를 쓰는 데에 익숙해져 있다 보니,
내 사고를 확장하기 위해서는 앞으로도 중간중간 공부가 필요할 듯 하다.</p>
<p>오늘 리마인드한 개념은 바로 <strong>백트래킹(backtracking)</strong>.</p>
<p>이름만 들을 때는 뭔가 거창하고 어려운 알고리즘 같지만,
실제로 이해해보면 굉장히 단순하다.</p>
<hr>
<h3 id="막다른-길이면-다시-돌아가기">막다른 길이면 다시 돌아가기</h3>
<p>백트래킹은 미로에 비유하면 제일 이해가 잘 되는 것 같다.</p>
<p>길을 걷다가</p>
<ul>
<li>막다른 길을 만나면 뒤로 돌아가고,</li>
<li>다른 길을 탐색해보고,</li>
<li>또 막히면 돌아오고,,</li>
</ul>
<p>이걸 컴퓨터가 반복하는 것이 바로 백트래킹이다.</p>
<p>문제 해결에 적용해보면
&quot;모든 가능한 선택을 해보되,
조건에 맞지 않으면 즉시 포기하고
되돌아가 다른 선택을 시도하는 방식&quot;이 된다.</p>
<p>사람스러운(?) 방식 같기도,,</p>
<hr>
<p>셀파트너는 오픈마켓 셀러가 해야 하는 복잡한 작업을 
AI로 자동화해주는 서비스다.
셀러의 업무에 대해서는 아직 알아가는 중이긴 하지만,
업무의 절반이 <strong>여러 조합 중에서 좋은 조합을 찾는 일</strong>인 것 같다.</p>
<blockquote>
<p><strong>백트래킹 아이디어 기록해두기</strong></p>
</blockquote>
<ul>
<li>상품명 키워드 조합 찾기</li>
<li>카테고리 추천 자동 필터링</li>
</ul>
<p>셀러 본인이 하면 몇 시간씩 걸리겠지만
백트래킹 알고리즘을 쓴다면
조건에 맞지 않는 조합을 즉시 버려가면서
훨씬 빠르게 최적 조합에 도달할 수 있다.</p>
<p>아직 등록 시스템만 출시되었고,
이후 솔루션화시켜가는 과정 중에 있지만,
백트래킹이라는 알고리즘을 AI 안에 잘 접목 시켜보면,
생각보다 깔끔하고 똑똑한 시스템이 될 듯 하다.
개발자도 사용자도 만족하는,,</p>
<hr>
<p>코테 준비하면서 알고리즘 공부할 때는,,
머리가 아주 지끈지끈 했었다.
막상 실무에 뛰어 들어보니,
우리 서비스처럼 &#39;조건 많은 조합 문제&#39;가 많은 분야에서는
백트래킹이라는 게 꽤 실용적이게 쓰일 수 있을 것 같다.</p>
<p>AI가 후보를 왕창 만들고
백트래킹이 그 후보를 똑똑하게 거르는 느낌?</p>
<p>언젠가는 이론을 실무에 녹일 수 있는 시니어가 되기를.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python | 함수 주석(Args, Returns 등) 사용하기]]></title>
            <link>https://velog.io/@faith_coder_lab/Python-%ED%95%A8%EC%88%98-%EC%A3%BC%EC%84%9DArgs-Returns-%EB%93%B1-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%93%B0%EB%8A%94-%EB%B2%95</link>
            <guid>https://velog.io/@faith_coder_lab/Python-%ED%95%A8%EC%88%98-%EC%A3%BC%EC%84%9DArgs-Returns-%EB%93%B1-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EC%93%B0%EB%8A%94-%EB%B2%95</guid>
            <pubDate>Mon, 30 Jun 2025 15:21:26 GMT</pubDate>
            <description><![CDATA[<h2 id="함수-주석-왜-써야-할까">함수 주석, 왜 써야 할까?</h2>
<p>인수인계를 받아보니,,, 
&quot;이 함수가 뭐 하는 함수지?&quot; 싶은 순간이 꽤 많다.
함수 위에 친절하게 설명이 달려있는 경우, 아주 땡큐베리감사.
이런 설명을 Docstring이라고 하는데, 함수, 클래스, 모듈 어디든 쓸 수 있고, 
커서를 올리면 그게 무슨 역할인지 바로 확인해줘서 꽤 유용하다.</p>
<h2 id="docstring-어떻게-쓰는-게-좋을까">Docstring, 어떻게 쓰는 게 좋을까?</h2>
<p>사실 일반적으로 아는 방식은 그냥 따옴표 세 개 (<code>&quot;&quot;&quot;</code>)로 감싸는 것.
그렇지만 좀 더 보기 좋게 쓰고 싶은 게 사람 마음.
대표적으로 Google 스타일이 많이 쓰인다고 한다.</p>
<pre><code class="language-python">def add(a, b):
    &quot;&quot;&quot;
    두 수를 더해서 반환합니다.

    Args:
        a (int): 첫 번째 숫자
        b (int): 두 번째 숫자

    Returns:
        int: 두 수의 합
    &quot;&quot;&quot;
    return a + b</code></pre>
<p>이렇게 쓰면</p>
<ul>
<li><code>a</code>와 <code>b</code>가 뭔지</li>
<li>반환값이 뭔지
한 눈에 볼 수 있다.</li>
</ul>
<h2 id="주요-기능">주요 기능</h2>
<ul>
<li><strong>Args</strong>: 함수에 들어가는 인자(파라미터) 설명</li>
<li><strong>Returns</strong>: 함수가 뭘 반환하는지</li>
<li><strong>Raises</strong>: 함수에서 어떤 에러가 발생할 수 있는지</li>
</ul>
<pre><code class="language-python">def divide(a, b):
    &quot;&quot;&quot;
    두 수를 나눕니다.

    Args:
        a (float): 분자
        b (float): 분모

    Returns:
        float: 나눈 결과

    Raises:
        ValueError: 분모가 0일 때
    &quot;&quot;&quot;
    if b == 0:
        raise ValueError(&quot;분모는 0이 될 수 없습니다.&quot;)
    return a / b</code></pre>
<hr>
<p>인수인계를 받으면서, 백엔드 코드는 기본적인 주석이 달려 있어서 꽤 도움이 됐었는데,
크롤링 소스코드 쪽을 받고 나서 꼼꼼히 달려 있는 Docstring 덕분에
쉽지 않은 내용을 이해하는 데 큰 도움이 됐었던 것 같은,,,</p>
<p>개발할 때마다 매번 Docstring까지 쓰기는 쉽지 않겠지만,
협업을 하거나 인수인계를 할 일이 있다면
Docstring이 너무 큰 도움이 될 것.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js + MongoDB: 스키마 필드 추가 후 값이 저장되지 않는다?...]]></title>
            <link>https://velog.io/@faith_coder_lab/Next.js-MongoDB-%EC%8A%A4%ED%82%A4%EB%A7%88-%ED%95%84%EB%93%9C-%EC%B6%94%EA%B0%80-%ED%9B%84-%EA%B0%92%EC%9D%B4-%EC%A0%80%EC%9E%A5%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8B%A4</link>
            <guid>https://velog.io/@faith_coder_lab/Next.js-MongoDB-%EC%8A%A4%ED%82%A4%EB%A7%88-%ED%95%84%EB%93%9C-%EC%B6%94%EA%B0%80-%ED%9B%84-%EA%B0%92%EC%9D%B4-%EC%A0%80%EC%9E%A5%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8B%A4</guid>
            <pubDate>Mon, 30 Jun 2025 15:07:25 GMT</pubDate>
            <description><![CDATA[<p>회사 스크래핑 프로젝트를 이해하기가 너무 어려워서 스크래핑 공부 및 실습을 하던 중,,,</p>
<h2 id="문제-상황">문제 상황</h2>
<ul>
<li>아마존 상품의 카테고리(category)를 스크래핑해서 DB에 저장하려고 함</li>
<li>스크래퍼에서 category를 잘 파싱해서 객체에 넣었고,</li>
<li>Mongoose 스키마에도 <code>category: { type: String }</code> 필드를 추가함</li>
<li>그런데 실제 MongoDB에는 category 필드가 저장되지 않았다..</li>
<li>프론트엔드(ProductCard)에서는 category가 계속 undefined/빈 값으로 표시됨</li>
</ul>
<h2 id="해결-과정">해결 과정</h2>
<h3 id="스크래퍼에서-category-파싱-확인">스크래퍼에서 category 파싱 확인</h3>
<pre><code class="language-js">const category = $(&#39;#wayfinding-breadcrumbs_feature_div &gt; ul &gt; li:nth-child(1) &gt; span &gt; a&#39;).text().trim();
console.log(&#39;Scraped category:&#39;, category); // 잘 찍힘</code></pre>
<ul>
<li>콘솔에 원하는 카테고리 값이 잘 찍히고 있음</li>
</ul>
<h3 id="db-저장-로직-점검">DB 저장 로직 점검</h3>
<ul>
<li><code>scrapedProduct</code>에는 category가 잘 들어가고 있었다</li>
<li>DB에 저장하는 코드:<pre><code class="language-js">product = {
...scrapedProduct,
priceHistory: updatePriceHistory,
// ...생략...
category: scrapedProduct.category || existingProduct?.category || &quot;&quot;
}</code></pre>
</li>
<li>findOneAndUpdate:<pre><code class="language-js">const newProduct = await Product.findOneAndUpdate(
{ url: scrapedProduct.url },
{ $set: product },
{ upsert: true, new: true }
);</code></pre>
</li>
</ul>
<h3 id="콘솔-로그로-값-추적">콘솔 로그로 값 추적</h3>
<ul>
<li>파일 처음부터 끝까지 category 들어가는지 질척거리며 확인</li>
<li>scrapedProduct에는 값이 있는데, newProduct에는 undefined라니.</li>
</ul>
<h3 id="db-document-직접-확인">DB document 직접 확인</h3>
<ul>
<li>MongoDB에서 document를 조회해도 category 필드가 없었다,,</li>
</ul>
<h3 id="마이그레이션-스크립트로-기존-상품에-category-필드-추가">마이그레이션 스크립트로 기존 상품에 category 필드 추가</h3>
<ul>
<li>기존 상품에는 category가 없으니, 일괄 추가:<pre><code class="language-js">db.products.updateMany(
{ category: { $exists: false } },
{ $set: { category: &quot;&quot; } }
)</code></pre>
</li>
</ul>
<h3 id="여전히-안됨">여전히 안됨......</h3>
<ul>
<li>코드, DB, 스크래퍼 모두 정상인데도 category가 저장되지도 출력되지도 않음...</li>
</ul>
<h3 id="원인-mongoose-모델-캐싱서버-재시작-필요했다고-한다">원인: Mongoose 모델 캐싱/서버 재시작 필요했다고 한다</h3>
<ul>
<li>Mongoose는 최초 모델 생성 시점의 스키마를 캐싱하기 때문에</li>
<li>개발 중 스키마를 수정(필드 추가)해도, 서버를 재시작하지 않으면 새 필드가 반영되지 않는다고;</li>
<li>서버를 완전히 재시작하니
category 필드가 정상적으로 DB에 저장되고 출력되는 것을 확인할 수 있었다. (나의 소중한 시간..)</li>
</ul>
<h2 id="결론">결론</h2>
<ul>
<li>Mongoose 스키마를 수정(필드 추가/변경)했다면, 반드시 서버를 재시작하자.</li>
<li>로그 살펴보며 질척거리는 게 답인 것 같긴 하다</li>
<li>기존 데이터에는 마이그레이션이 필요한데,, MS AI School 때 마이그레이션에 여러번 당한 적이 있어서 두려워했었던 것 같음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI | Pydantic에서 snake_case ↔︎ camelCase 변환 삽질 기록]]></title>
            <link>https://velog.io/@faith_coder_lab/FastAPI-Pydantic%EC%97%90%EC%84%9C-snakecase-camelCase-%EB%B3%80%ED%99%98-%EC%82%BD%EC%A7%88-%EA%B8%B0%EB%A1%9D</link>
            <guid>https://velog.io/@faith_coder_lab/FastAPI-Pydantic%EC%97%90%EC%84%9C-snakecase-camelCase-%EB%B3%80%ED%99%98-%EC%82%BD%EC%A7%88-%EA%B8%B0%EB%A1%9D</guid>
            <pubDate>Mon, 30 Jun 2025 15:07:05 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-상황">문제 상황</h2>
<p>FastAPI와 Pydantic을 사용해서 API를 만들던 중,,,
프론트엔드와의 협업을 위해 응답(JSON)은 camelCase로,
파이썬 내부에서는 snake_case로 리팩토링을 하던 중이었다.
Pydantic <code>alias_generator</code> 기능을 활용해 BaseModel을 상속한 <code>CamelModel</code>을 만들어 사용.</p>
<pre><code class="language-python">from pydantic import BaseModel

def to_camel(string:str) -&gt; str:
    parts = string.split(&#39;_&#39;)
    return parts[0] + &#39;&#39;.join(word.capitalize() for word in parts[1:])

class CamelModel(BaseModel):
    class Config:
        orm_mode = True
        allow_population_by_field_name = True
        alias_generator = to_camel</code></pre>
<p>이렇게 하면 snake_case로 작성한 필드가 응답에서 자동으로 camelCase로 변환되어 나가야 하는데,,,</p>
<hr>
<h3 id="500-에러가">500 에러가...</h3>
<p>API를 호출했더니 아래와 같은 500 Internal Server Error 발생..</p>
<pre><code class="language-text">pydantic_core._pydantic_core.ValidationError: 7 validation errors for SumingData
sumingField
    Field required [type=missing, input_value={&#39;example_field&#39;: &#39;value&#39;, ...}, input_type=dict]
...</code></pre>
<p>분명 <code>suming_field</code> 등 snake_case로 값을 넘겼는데, pydantic이 camelCase(<code>sumingField</code>) 필드를 못찾겠다고 에러를 낸다.
리팩토링 전에는 동작하던 코드라 신입의 눈물...
고친 게 이것 뿐이라 분명 camelCase랑 snake_case 사이의 문제인 건 확실한데 뭐가 문제냐고 ㅠㅠ</p>
<hr>
<h2 id="원인-분석">원인 분석</h2>
<ul>
<li>pydantic의 <code>alias_generator</code> 는 출력 시에는 camelCase로 변환해주지만,</li>
<li>입력 시에는 기본적으로 snake_case로 값을 받아야 한다.</li>
<li>그런데 pydantic v2에서는 설정 방식이 바뀌어서,
<code>allow_population_by_field_name</code> 대신 <code>populate_by_name</code>을 써야 하고,
<code>Config</code> 대신 <code>model_config</code>를 써야 한단다.</li>
</ul>
<h3 id="pydantic-v1과-v2의-차이">pydantic v1과 v2의 차이</h3>
<table>
<thead>
<tr>
<th>버전</th>
<th>설정 방법</th>
</tr>
</thead>
<tbody><tr>
<td>v1</td>
<td>class Config: ... allow_population_by_field_name = True</td>
</tr>
<tr>
<td>v2</td>
<td>model_config = { &quot;populate_by_name&quot;: True }</td>
</tr>
</tbody></table>
<hr>
<h2 id="해결-방법">해결 방법</h2>
<h3 id="pydantic-v1">pydantic v1</h3>
<pre><code class="language-python">class CamelModel(BaseModel):
    class Config:
         orm_mode = True
        allow_population_by_field_name = True
        alias_generator = to_camel</code></pre>
<h3 id="pydantic-v2">pydantic v2</h3>
<pre><code class="language-python">class CamelModel(BaseModel):
    model_config = {
        &quot;orm_mode&quot;: True,
        &quot;populate_by_name&quot;: True,
        &quot;alias_generator&quot;: to_camel,
    }</code></pre>
<ul>
<li><code>populate_by_name=True</code>가 있어야 snake_case로도 값을 받을 수 있다.</li>
<li><code>alias_generator</code>는 camelCase로 변환해서 응답에 사용한다.</li>
</ul>
<hr>
<h2 id="결론">결론</h2>
<ul>
<li>pydantic에서 snake_case ↔︎ camelCase 변환하려면 <code>alias_generator</code>를 활용하면 된다.</li>
<li>입력도 snake_case로 받고 싶으면<ul>
<li>v1: <code>allow_population_by_field_name = True</code></li>
<li>v2: <code>populate_by_name = True</code></li>
</ul>
</li>
<li>pydantic 버전에 따라 설정법이 다르니 꼭 확인하자!</li>
</ul>
<hr>
<h2 id="삽질에서-얻은-교훈">삽질에서 얻은 교훈</h2>
<ul>
<li>공식 문서와 마이그레이션 가이드를 꼭 읽자.</li>
<li>에러 메시지를 끝까지 읽고, 필드명이 어떻게 매핑되는지 꼼꼼히 확인하자.</li>
<li>기존 코드 리팩토링은 생각보다 훠어어어얼씬 더 까다롭다.
(입사 전에는 리팩토링 무조건 필요하다고 생각했는데, 왜 회사들에서 리팩토링을 잘 안한다고 하는지 알 것 같다.ㅎ)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI | Cursor AI]]></title>
            <link>https://velog.io/@faith_coder_lab/FastAPI-Cursor-AI</link>
            <guid>https://velog.io/@faith_coder_lab/FastAPI-Cursor-AI</guid>
            <pubDate>Mon, 30 Jun 2025 15:06:49 GMT</pubDate>
            <description><![CDATA[<p><strong>Cursor AI</strong> 사용 후기.
첫 출근, 실무 환경에서 Cursor AI를 쓰게 돼서, 첫 적응 중.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI | JWT 인증 시스템 구현하기]]></title>
            <link>https://velog.io/@faith_coder_lab/FastAPI-JWT-%EC%9D%B8%EC%A6%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@faith_coder_lab/FastAPI-JWT-%EC%9D%B8%EC%A6%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 11 Jun 2025 14:18:35 GMT</pubDate>
            <description><![CDATA[<p>오늘은 <strong>JWT 기반 사용자 인증 시스템</strong> 구현하기.
이전에는 Python에 Django 썼어서, JWT 기반은 Java에서만 써봤더랬다.</p>
<h2 id="오늘-구현한-기능들">오늘 구현한 기능들</h2>
<h3 id="jwt-인증-시스템">JWT 인증 시스템</h3>
<ul>
<li><strong>회원가입/로그인</strong>: 사용자 계정 관리</li>
<li><strong>JWT 토큰</strong>: 상태를 저장하지 않는 토큰 기반 인증</li>
<li><strong>비밀번호 해싱</strong>: bcrypt로 비밀번호 저장</li>
<li><strong>라우트</strong>: 인증이 필요한 API 엔드포인트</li>
</ul>
<h2 id="프로젝트-구조-변경">프로젝트 구조 변경</h2>
<h3 id="before">Before</h3>
<pre><code>todo_api/
├── main.py        # 모든 API가 한 파일에
├── database.py
├── models.py
└── schemas.py</code></pre><h3 id="after">After</h3>
<pre><code>todo_api/
├── main.py        # 앱 설정만
├── database.py
├── models.py      # User 모델 추가
├── schemas.py     # User, Token 스키마 추가
├── auth.py        # JWT 관련 로직
├── dependencies.py # 의존성 주입
└── routers/
    ├── auth.py    # 인증 관련 API
    └── todos.py   # 할일 관련 API</code></pre><hr>
<h2 id="학습-내용">학습 내용</h2>
<h3 id="jwt의-동작-원리">JWT의 동작 원리</h3>
<h4 id="전통적인-세션-방식-vs-jwt">전통적인 세션 방식 vs jWT</h4>
<pre><code class="language-python"># 세션 방식 (서버에 상태 저장)
login → 서버가 세션 ID 생성 → 메모리/DB에 저장 → 쿠키로 전달

# JWT 방식 (상태를 저장하지 않음)
login → 서버가 JWT 토큰 생성 → 클라이언트가 저장 → 매 요청마다 헤더에 포함</code></pre>
<h4 id="jwt-토큰-구조">JWT 토큰 구조</h4>
<pre><code>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyIiwiZXhwIjoxNjM5...
헤더.페이로드.서명</code></pre><hr>
<h3 id="fastapi-의존성-주입">FastAPI 의존성 주입</h3>
<h4 id="java-spring과-비교">Java Spring과 비교</h4>
<pre><code class="language-python"># FastAPI
@app.get(&quot;/todos&quot;)
def get_todos(current_user = Depends(get_current_user)):
    return current_user.todos</code></pre>
<pre><code class="language-java">// Java Spring
@GetMapping(&quot;/todos&quot;)
public List&lt;Todo&gt; getTodos(@AuthenticationPrincipal User user) {
    return user.getTodos();
}</code></pre>
<h4 id="의존성-체인">의존성 체인</h4>
<pre><code class="language-python">get_current_user → oauth2_scheme → token 검증 → DB 조회 → User 객체 반환</code></pre>
<hr>
<h3 id="데이터베이스-관계-모델링">데이터베이스 관계 모델링</h3>
<pre><code class="language-python"># User : Todo = 1 : N 관계
class User(Base):
    todos = relationship(&quot;Todo&quot;, back_populates=&quot;owner&quot;)

class Todo(Base):
    owner_id = Column(Integer, ForeignKey(&quot;users.id&quot;))
    owner = relationship(&quot;User&quot;, back_populates=&quot;todos&quot;)</code></pre>
<hr>
<h2 id="마주친-문제들과-해결-과정">마주친 문제들과 해결 과정</h2>
<h3 id="순환-import-문제">순환 Import 문제</h3>
<p><strong>문제</strong>: <code>main.py</code> ↔︎ <code>routers</code> 간 순환 참조</p>
<p>어제 router 설정하기 전에 <code>get_db</code> 함수를 <code>main.py</code> 안에 뒀었는데,
라우터를 오늘 설정하면서 순환 참조 문제가 발생했다.</p>
<pre><code class="language-python"># main.py에서 routers import
from routers import auth, todos

# routers에서 main.py의 get_db import
from main import get_db  # ❌ 순환 import</code></pre>
<p><strong>해결</strong>: 공통 모듈로 분리</p>
<pre><code class="language-python"># database.py로 get_db 이동
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()</code></pre>
<hr>
<h3 id="sqlalchemy-관계-설정-에러">SQLAlchemy 관계 설정 에러</h3>
<h4 id="예러-메시지">예러 메시지</h4>
<pre><code>Mapper &#39;Todo&#39; has no property &#39;user&#39;</code></pre><p><strong>원인</strong>: <code>back_populates</code> 불일치</p>
<pre><code class="language-python"># ❌ 잘못된 설정
class User(Base):
    todos = relationship(&quot;Todo&quot;, back_populates=&quot;user&quot;)  # &quot;user&quot;

class Todo(Base):
    user = relationship(&quot;User&quot;, back_populates=&quot;todos&quot;)  # 실제 속성명</code></pre>
<p><strong>해결</strong>: 의미적으로 명확한 관계명 사용</p>
<p><code>back_populates</code>의 역할을 잘 몰라서 발생한 오류.
다른 클래스에서 해당 관계를 반영하는 속성의 이름을 정확하게 적어줘야 한다.</p>
<pre><code class="language-python"># ✅ 올바른 설정
class User(Base):
    todos = relationship(&quot;Todo&quot;, back_populates=&quot;owner&quot;)

class Todo(Base):
    owner = relationship(&quot;User&quot;, back_populates=&quot;todos&quot;)</code></pre>
<hr>
<h3 id="jwt-토큰-생성-실패">JWT 토큰 생성 실패</h3>
<p><strong>문제</strong>: <code>access_token</code>이 <code>None</code>으로 반환</p>
<p>찾아도 찾아도 안찾아져서 고생을 깨나했는데...
들여쓰기 문제였다..
지옥의 Python 다시 만났다, 들여쓰기 문제.</p>
<pre><code class="language-python"># ❌ 들여쓰기 문제
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=30)
        to_encode.update({&quot;exp&quot;: expire})  # else 블록에만 있음!</code></pre>
<p><strong>해결</strong>: 들여쓰기</p>
<pre><code class="language-python"># ✅ 수정된 버전
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()

    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=30)

    to_encode.update({&quot;exp&quot;: expire})  # 항상 실행
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)</code></pre>
<hr>
<h3 id="swagger-ui-인증-경로-문제">Swagger UI 인증 경로 문제</h3>
<p><strong>문제</strong>: &quot;Auth Error: Not Found&quot;</p>
<pre><code class="language-python"># dependencies.py
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=&quot;login&quot;)  # ❌ 잘못된 경로</code></pre>
<p><strong>실제 엔드포인트</strong>: <code>/auth/login</code>
<strong>Swagger 요청에 사용한 경로</strong>: <code>/login</code></p>
<p><strong>해결</strong>:</p>
<pre><code class="language-python">oauth2_scheme = OAuth2PasswordBearer(tokenUrl=&quot;auth/login&quot;)  # ✅ 올바른 경로</code></pre>
<hr>
<h2 id="인증-시스템-비교-java-jwt-vs-django-vs-fastapi">인증 시스템 비교: Java JWT vs Django vs FastAPI</h2>
<p>이전에 Java JWT와 Django 인증 시스템을 사용해본 작은 경험으로 비교해보기.</p>
<h3 id="설정-복잡도">설정 복잡도</h3>
<h4 id="java-spring-security--jwt">Java Spring Security + JWT</h4>
<pre><code class="language-java">// SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
        return new JwtAuthenticationEntryPoint();
    }

    @Bean
    public JwtRequestFilter jwtRequestFilter() {
        return new JwtRequestFilter();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
            .authorizeRequests()
            .antMatchers(&quot;/auth/**&quot;).permitAll()
            .anyRequest().authenticated()
            .and()
            .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

// JwtUtil.java (별도 유틸리티 클래스 필요)
@Component
public class JwtUtil {
    private String secret = &quot;secret&quot;;

    public String generateToken(UserDetails userDetails) {
        Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();
        return createToken(claims, userDetails.getUsername());
    }
    // ... 더 많은 보일러플레이트 코드
}</code></pre>
<h4 id="django-rest-framework">Django REST Framework</h4>
<pre><code class="language-python"># settings.py
INSTALLED_APPS = [
    &#39;rest_framework&#39;,
    &#39;rest_framework.authtoken&#39;,  # 또는 rest_framework_simplejwt
]

REST_FRAMEWORK = {
    &#39;DEFAULT_AUTHENTICATION_CLASSES&#39;: [
        &#39;rest_framework_simplejwt.authentication.JWTAuthentication&#39;,
    ],
    &#39;DEFAULT_PERMISSION_CLASSES&#39;: [
        &#39;rest_framework.permissions.IsAuthenticated&#39;,
    ],
}

# urls.py
from rest_framework_simplejwt.views import TokenObtainPairView

urlpatterns = [
    path(&#39;api/token/&#39;, TokenObtainPairView.as_view()),
]

# views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view([&#39;GET&#39;])
@permission_classes([IsAuthenticated])
def protected_view(request):
    return Response({&#39;user&#39;: request.user.username})</code></pre>
<h4 id="fastapi">FastAPI</h4>
<pre><code class="language-python"># auth.py (핵심 로직만)
SECRET_KEY = &quot;secret&quot;
ALGORITHM = &quot;HS256&quot;

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=30)
    to_encode.update({&quot;exp&quot;: expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

# dependencies.py
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=&quot;auth/login&quot;)

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # 간단한 의존성 주입
    return verify_and_get_user(token)

# main.py
@app.get(&quot;/protected&quot;)
def protected_route(user = Depends(get_current_user)):
    return {&quot;user&quot;: user.username}</code></pre>
<hr>
<h3 id="코드-가독성-및-유지보수성">코드 가독성 및 유지보수성</h3>
<table>
<thead>
<tr>
<th>측면</th>
<th>Java Spring</th>
<th>Django</th>
<th>FastAPI</th>
</tr>
</thead>
<tbody><tr>
<td>설정 파일</td>
<td>Config 클래스가 복잡함</td>
<td>settings.py 중앙 집중</td>
<td>최소한의 설정</td>
</tr>
<tr>
<td>보일러플레이트</td>
<td>매우 많음</td>
<td>적당</td>
<td>매우 적음</td>
</tr>
<tr>
<td>의존성 주입</td>
<td>어노테이션 기반</td>
<td>전역 설정</td>
<td>함수 기반, 직관적</td>
</tr>
<tr>
<td>타입 안정성</td>
<td>컴파일 타임</td>
<td>런타임</td>
<td>런타임 + 타입 힌트</td>
</tr>
</tbody></table>
<hr>
<h3 id="인증-플로우">인증 플로우</h3>
<h4 id="java-spring-security">Java Spring Security</h4>
<pre><code>클라이언트 → SecurityFilterChain → JwtRequestFilter → UserDetailsService → Controller</code></pre><ul>
<li>장점: 매우 안전하고 검증된 패턴</li>
<li>단점: 설정이 복잡하고 러닝 커브 높음</li>
</ul>
<h4 id="django">Django</h4>
<pre><code>클라이언트 → Middleware → Authentication Class → Permission Class → View</code></pre><ul>
<li>장점: 배터리 포함, ORM과 완벽  통합</li>
<li>단점: 무겁고, API 전용으로는 오버엔지니어링</li>
</ul>
<h4 id="fastapi-플로우">FastAPI 플로우</h4>
<pre><code>클라이언트 → OAuth2Scheme → Dependencies → Route Function</code></pre><ul>
<li>장점: 간단하고 직관적, 성능 우수</li>
<li>단점: 굳이 꼽자면,, 상대적으로 새로운 생태계라는 점이려나</li>
</ul>
<hr>
<h3 id="실제-개발-경험-비교">실제 개발 경험 비교</h3>
<h4 id="개발-속도">개발 속도</h4>
<pre><code>FastAPI &gt; Django &gt; Java Spring</code></pre><h4 id="java-spring-security-1">Java Spring Security</h4>
<ul>
<li>✅ 엔터프라이즈급 보안 기능</li>
<li>✅ 풍부한 생태계와 문서</li>
<li>❌ 설정 지옥, 높은 러닝 커브</li>
<li>❌ 보일러플레이트 코드 과다</li>
</ul>
<h4 id="django--drf">Django + DRF</h4>
<ul>
<li>✅ 관리자 패널, ORM 등 풍부한 기능</li>
<li>✅ 검증된 보안 패턴</li>
<li>✅ 풍부한 써드파티 패키지</li>
<li>❌ 무거운 프레임워크</li>
<li>❌ API 전용 서비스에는 과도한 기능</li>
</ul>
<h4 id="fastapi-1">FastAPI</h4>
<ul>
<li>✅ 빠른 개발 속도</li>
<li>✅ 자동 문서화</li>
<li>✅ 현대적인 Python 기능 활용</li>
<li>✅ 높은 성능</li>
<li>❌ 상대적으로 적은 레퍼런스</li>
<li>❌ 일부 고급 기능은 직접 구현 필요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI | 할일 관리 API 만들어보기]]></title>
            <link>https://velog.io/@faith_coder_lab/FastAPI-%ED%95%A0%EC%9D%BC-%EA%B4%80%EB%A6%AC-API-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@faith_coder_lab/FastAPI-%ED%95%A0%EC%9D%BC-%EA%B4%80%EB%A6%AC-API-%EB%A7%8C%EB%93%A4%EC%96%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jun 2025 13:48:03 GMT</pubDate>
            <description><![CDATA[<p>며칠 뒤 입사를 앞두고 미리 공부를 해보고자 간단한 할일 관리 API를 만들어봤다.
2월 MS AI School 수료 후 오랜만에,, 거의 4개월 만에 Python을 다시 만져보는 거라 기초부터 차근차근 진행했는데, 생각보다 FastAPI가 정말 직관적이고 사용하기 쉬웠다.</p>
<hr>
<h2 id="프로젝트-개요">프로젝트 개요</h2>
<p><strong>목표</strong>: FastAPI 기본 개념 익히기
<strong>기간</strong>: 하루
<strong>기능</strong>: 할일 CRUD(생성, 조회, 수정, 삭제)</p>
<h2 id="사용한-기술-스택">사용한 기술 스택</h2>
<ul>
<li><strong>FastAPI</strong>: 메인 웹 프레임워크</li>
<li><strong>SQLAlchemy</strong>: ORM(데이터베이스 연동)</li>
<li><strong>Pydantic</strong>: 데이터 검증 및 직렬화</li>
<li><strong>SQLite</strong>: 데이터베이스(개발용)</li>
<li><strong>PyCharm Professional</strong>: 개발 환경</li>
</ul>
<h2 id="프로젝트-구조">프로젝트 구조</h2>
<pre><code>todo_api/
├── main.py        # 메인 애플리케이션
├── database.py    # 데이터베이스 설정
├── models.py      # SQLAlchemy 모델
├── schemas.py     # Pydantic 스키마
└── requirements.txt</code></pre><p>간단한 구조지만 실제 실무에서도 많이 사용하는 패턴이라고 한다.</p>
<hr>
<h2 id="학습-내용">학습 내용</h2>
<h3 id="fastapi-기본-구조">FastAPI 기본 구조</h3>
<pre><code class="language-python">from fastapi import FastAPI

app = FastAPI(title=&quot;할일 관리 API&quot;, version=&quot;1.0.0&quot;)

@app.get(&quot;/&quot;)
def read_root():
    return {&quot;message&quot;: &quot;Hello FastAPI!&quot;}</code></pre>
<p>Flask보다도 직관적이게 느껴지는 건,, 그 때보다 내가 조금은 성장했기 때문이려나?
아니면 실제 직관적인가.</p>
<h3 id="자동-api-문서화">자동 API 문서화</h3>
<p>FastAPI에서 가장 인상 깊었던 기능은 <strong>자동 API 문서 생성</strong>이었다. 코드만 작성하면 <code>http://localhost:8000/docs</code>에서 바로 Swagger UI를 만들어줌;;
Java에서 Swagger 설정하던 눈물의 시간들이 떠오른다..</p>
<h3 id="타입-힌팅의-중요성">타입 힌팅의 중요성</h3>
<pre><code class="language-python">@app.get(&quot;/todos/{todo_id}&quot;, response_model=schemas.Todo)
def get_todo(todo_id: int, db: Session = Depends(get_db)):
    # ...</code></pre>
<p>타입 힌팅을 제대로 해주면:</p>
<ul>
<li>자동완성이 훨씬 정확해지고</li>
<li>런타임 에러를 미리 잡을 수 있으며</li>
<li>API 문서에 타입 정보가 자동으로 표시된다고 한다.</li>
</ul>
<h3 id="pydantic-데이터-검증">Pydantic 데이터 검증</h3>
<pre><code class="language-python">class TodoCreate(BaseModel):
    title: str
    description: Optional[str] = None</code></pre>
<p>요청 데이터가 자동으로 검증되고, 잘못된 데이터가 오면 명확한 에러 메시지를 보여준다.</p>
<hr>
<h2 id="마주친-문제와-해결과정">마주친 문제와 해결과정</h2>
<h3 id="java-개발자가-겪는-python-타입-차이">Java 개발자가 겪는 Python 타입 차이</h3>
<p>딱 하나 마주한 에러.</p>
<pre><code>PydanticSchemaGenerationError: Unable to generate pydantic-core schema for &lt;class &#39;sqlalchemy.sql.sqltypes.Boolean&#39;&gt;</code></pre><p><strong>문제</strong>: Java에서는 <code>Boolean</code>이 자연스러워서 그대로 사용
<strong>해결</strong>: Python에서는 소문자 <code>bool</code>을 사용</p>
<pre><code class="language-python"># ❌ Java 스타일로 작성
class Todo(BaseModel):
    completed: Boolean  # Java처럼 대문자

# ✅ Python 스타일로 수정
class Todo(BaseModel):
    completed: bool  # Python은 소문자</code></pre>
<p>Java에서는 <code>Boolean</code>, <code>String</code>, <code>Integer</code> 같은 래퍼 클래스를 사용하지만,
Python에서는 <code>bool</code>, <code>str</code>, <code>int</code> 같은 기본 타입을 사용한다는 것을 다시 한번 상기하며,,,</p>
<hr>
<h2 id="pycharm">PyCharm</h2>
<p>몇 년 전에 처음 Python 쓸 때는 VS Code가 훨씬 편했던 것 같은데, Professional 버전이라 그런가 아니면 IntelliJ에 익숙해져서 그런가 PyCharm이 이제는 꽤나 만족스럽다.</p>
<hr>
<h2 id="구현한-주요-기능들">구현한 주요 기능들</h2>
<h3 id="할일-crud-api">할일 CRUD API</h3>
<ul>
<li><code>GET /todos</code> - 모든 할일 조회</li>
<li><code>GET /todos/{id}</code> - 특정 할일 조회</li>
<li><code>POST /todos</code> - 새 할일 생성</li>
<li><code>PUT /todos/{id}/complete</code> - 할일 완료 처리</li>
<li><code>DELETE /todos/{id}</code> - 할일 삭제</li>
</ul>
<hr>
<h3 id="의존성-주입">의존성 주입</h3>
<h4 id="python-fastapi">Python FastAPI</h4>
<pre><code class="language-python">def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get(&quot;/todos&quot;)
def get_todos(db: Session = Depends(get_db)):
    # db는 자동으로 주입됨
    return db.query(Todo).all()</code></pre>
<p><code>;</code> 없이 들여쓰기로만 구분하는 파이썬 문법에 오랜만에 어색함을 느끼며,,</p>
<h4 id="java-spring">Java Spring</h4>
<pre><code class="language-java">@Service
public class TodoService {
    @Autowired
    private SessionFactory sessionFactory;

    public List&lt;Todo&gt; getTodos() {
        Session session = sessionFactory.getCurrentSession();
        return session.createQuery(&quot;FROM Todo&quot;, Todo.class).list();
    }
}

@RestController
public class TodoController {
    @Autowired
    private TodoService todoService;    // 의존성 주입

    @GetMapping(&quot;/todos&quot;)
    public List&lt;Todo&gt; getTodos() {
        return todoService.getTodos();
    }
}</code></pre>
<p>이렇게 보니까 자바가 진짜 복잡하다는 게 새삼..</p>
<h4 id="주요-차이점">주요 차이점</h4>
<table>
<thead>
<tr>
<th>측면</th>
<th>Java Spring</th>
<th>Python FastAPI</th>
</tr>
</thead>
<tbody><tr>
<td>어노테이션</td>
<td><code>@Autowired</code>, <code>@Service</code></td>
<td><code>Depends()</code> 함수</td>
</tr>
<tr>
<td>설정</td>
<td>XML/Java Config 클래스</td>
<td>함수 정의만으로 충분</td>
</tr>
<tr>
<td>생명주기 관리</td>
<td>Spring Container</td>
<td><code>yield</code>로 명시적 관리</td>
</tr>
<tr>
<td>타입 안정성</td>
<td>컴파일 타임 체크</td>
<td>런타임 + 타입 힌트</td>
</tr>
</tbody></table>
<p>FastAPI의 <code>Depends()</code>는 Spring의 <code>@Autowired</code>와 같은 역할을 한다.
<code>yield</code>를 사용한 리소스 관리가 Python 답게 깔끔하다.</p>
<hr>
<h3 id="에러-처리">에러 처리</h3>
<h4 id="python-fastapi-1">Python FastAPI</h4>
<pre><code class="language-python">from fastapi import HTTPException

@app.get(&quot;/todos/{todo_id}&quot;)
def get_todo(todo_id: int):
    todo = db.query(Todo).filter(Todo.id == todo_id).first()
    if todo is None:
        raise HTTPException(status_code=404, detail=&quot;할일을 찾을 수 없습니다.&quot;)
    return todo</code></pre>
<h4 id="java-spring-1">Java Spring</h4>
<pre><code class="language-java">@RestController
public class TodoController {

    @GetMapping(&quot;/todos/{id}&quot;)
    public ResponseEntity&lt;Todo&gt; getTodo(@PathVariable Long id) {
        Todo todo = todoService.findById(id);
        if (todo == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(todo);
    }

    // 또는 Exception Handler 사용
    @ExceptionHandler(TodoNotFoundException.class)
    public ResponsEntity&lt;ErrorResponse&gt; handleNotFound(TodoNotFoundException ex) {
        return ResponseEntity.status(404)
            .body(new ErrorResponse(&quot;할일을 찾을 수 없습니다.&quot;));
    }
}</code></pre>
<h4 id="주요-차이점-1">주요 차이점</h4>
<table>
<thead>
<tr>
<th>측면</th>
<th>Java Spring</th>
<th>Python FastAPI</th>
</tr>
</thead>
<tbody><tr>
<td>에러발생</td>
<td><code>ResponseEntity</code> 반환 또는 Exception throw</td>
<td><code>HTTPException</code> raise</td>
</tr>
<tr>
<td>상태코드</td>
<td><code>ResponseEntity.notFound()</code></td>
<td><code>status_code=404</code></td>
</tr>
<tr>
<td>에러메시지</td>
<td>별도 ErrorResponse 클래스</td>
<td><code>detail</code> 파라미터</td>
</tr>
<tr>
<td>글로벌처리</td>
<td><code>@ExceptionHandler</code></td>
<td>Exception Handler 함수</td>
</tr>
</tbody></table>
<p>FastAPI에서는 Python 예외 처리 방식을 그대로 활용해서 <code>raise HTTPException</code>으로 간단하게 에러를 던질 수 있어서 직관적이었다.</p>
<hr>
<h2 id="fastapi의-장점">FastAPI의 장점</h2>
<p>일단 내가 오늘 경험한 장점으로는 </p>
<ul>
<li>문법이 직관적이고 (이것은 FastAPI의 장점인지, Python의 장점인지, 둘다인지 모르겠으나),</li>
<li>자동 API 문서화, 이거 너무 좋다.</li>
</ul>
<hr>
<h2 id="다음-단계">다음 단계</h2>
<p>오늘은 다시 Python 감을 찾느라고 기본 CRUD만 구현해봤는데,</p>
<ul>
<li>사용자 인증 (JWT)</li>
<li>권한 관리</li>
<li>페이지네이션</li>
<li>검색 및 필터링</li>
<li>테스트 코드 작성</li>
<li>Docker 컨테이너화</li>
</ul>
<p>까지 차근차근 입사 전까지 공부해보면 좋겠다.
조금 더 여유가 된다면 웹크롤링까지!</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>오랜만에 Python 다시 만져봤는데 너무 재밌다.
잠 안 자고 더 하고 싶은 마음이 들지만,, 컨디션을 관리해야 하므로.</p>
<p>입사하면 실제로 FastAPI를 쓰게 될텐데, 벌써 새로운 공부들이 기대된다 히히 😛</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1주차 | ERD 설계 및 API 명세 작성]]></title>
            <link>https://velog.io/@faith_coder_lab/1%EC%A3%BC%EC%B0%A8-ERD-%EC%84%A4%EA%B3%84-%EB%B0%8F-API-%EB%AA%85%EC%84%B8-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@faith_coder_lab/1%EC%A3%BC%EC%B0%A8-ERD-%EC%84%A4%EA%B3%84-%EB%B0%8F-API-%EB%AA%85%EC%84%B8-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Thu, 22 May 2025 12:09:27 GMT</pubDate>
            <description><![CDATA[<h2 id="erd-설계">ERD 설계</h2>
<p><img src="https://velog.velcdn.com/images/faith_coder_lab/post/b7b40818-cd3b-49a4-82bd-7f5f89a04bb2/image.png" alt=""></p>
<h3 id="핵심-서비스">핵심 서비스</h3>
<ul>
<li>1:1 전문가 상담</li>
<li>금융 카드뉴스</li>
<li>금융 챌린지</li>
<li>개인화된 대시보드</li>
</ul>
<h3 id="erd-구조">ERD 구조</h3>
<pre><code>📈 머니버디 ERD 구조
├── 👤 사용자 관리
│   ├── users (사용자)
│   ├── user_settings (사용자 설정)
│   ├── user_favorites (즐겨찾기)
│   ├── user_points (포인트)
│   └── user_activity_logs (활동 로그)
├── 👨‍💼 전문가 관리
│   ├── experts (전문가)
│   └── expert_specializations (전문분야)
├── 💬 상담 시스템
│   ├── consultations (상담)
│   ├── reviews (리뷰)
│   ├── chat_rooms (채팅방)
│   └── chat_messages (채팅 메시지)
├── 📰 컨텐츠 관리
│   ├── card_news (카드뉴스)
│   ├── card_news_likes (좋아요)
│   ├── daily_contents (오늘의 컨텐츠)
│   └── banners (배너)
├── 🏆 챌린지 시스템
│   ├── challenges (챌린지)
│   ├── challenge_participants (참여자)
│   └── challenge_records (기록)
└── 🔔 지원 시스템
    ├── notifications (알림)
    └── faq (FAQ)</code></pre><h3 id="엔티티-상세">엔티티 상세</h3>
<h4 id="users">Users</h4>
<ul>
<li>회원가입 시 일반 사용자/전문가 선택 가능</li>
<li><code>is_active</code> 플래그로 탈퇴 사용자 관리</li>
</ul>
<h4 id="experts">Experts</h4>
<ul>
<li>관리자가 전문가 자격을 검증 후 승인</li>
<li>리뷰 기반 실시간 평점 계산</li>
<li>전문가별 차별화된 상담료 설정</li>
</ul>
<h4 id="consultations">Consultations</h4>
<pre><code>1. 요청 → 2. 승인 → 3. 진행중 → 4. 완료
                ↓
             취소 (언제든 가능)</code></pre><h4 id="그외">그외</h4>
<ul>
<li>챌린지 시스템</li>
<li>카드뉴스 &amp; 컨텐츠 시스템</li>
</ul>
<hr>
<h2 id="api-설계">API 설계</h2>
<pre><code>🌐 API 엔드포인트 구조
├── /api/auth/* (인증)
├── /api/experts/* (전문가)
├── /api/consultations/* (상담)
├── /api/chat/* (채팅)
├── /api/reviews/* (리뷰)
├── /api/card-news/* (카드뉴스)
├── /api/challenges/* (챌린지)
├── /api/daily-contents/* (오늘의 컨텐츠)
├── /api/banners/* (배너)
├── /api/favorites/* (즐겨찾기)
├── /api/notifications/* (알림)
├── /api/users/* (사용자)
├── /api/faq/* (FAQ)
├── /api/admin/* (관리자)
└── /api/analytics/* (분석)</code></pre><h3 id="api-상세">API 상세</h3>
<h4 id="사용자-인증-api">사용자 인증 API</h4>
<pre><code class="language-js">// 회원가입 - 일반 사용자
POST /api/auth/register
{
  &quot;email&quot;: &quot;suming@example.com&quot;,
  &quot;password&quot;: &quot;password123&quot;,
  &quot;name&quot;: &quot;수밍킴&quot;,
  &quot;user_type&quot;: &quot;USER&quot;
}

// 회원가입 - 전문가 (확장된 정보)
POST /api/auth/register
{
  &quot;email&quot;: &quot;jhpark@example.com&quot;,
  &quot;password&quot;: &quot;password123&quot;, 
  &quot;name&quot;: &quot;박재현&quot;,
  &quot;user_type&quot;: &quot;EXPERT&quot;,
  &quot;expert_info&quot;: {
    &quot;specialization&quot;: &quot;투자 전문가&quot;,
    &quot;experience_years&quot;: 10,
    &quot;certification&quot;: &quot;투자상담사, 재무설계사&quot;,
    &quot;hourly_rate&quot;: 30000,
    &quot;specializations&quot;: [
      {&quot;category&quot;: &quot;주식&quot;, &quot;sub_category&quot;: &quot;ETF&quot;},
      {&quot;category&quot;: &quot;부동산&quot;, &quot;sub_category&quot;: &quot;부동산투자&quot;}
    ]
  }
}</code></pre>
<h4 id="전문가-검색--필터링-api">전문가 검색 &amp; 필터링 API</h4>
<pre><code class="language-js">// 전문가 목록 조회 (고급 필터링)
GET /api/experts?category=주식&amp;rating_min=4.0&amp;sort=rating&amp;page=1&amp;size=10

// 응답 예시
{
  &quot;success&quot;: true,
  &quot;data&quot;: {
    &quot;experts&quot;: [
      {
        &quot;expert_id&quot;: 1,
        &quot;name&quot;: &quot;박재현&quot;,
        &quot;specialization&quot;: &quot;투자 전문가&quot;,
        &quot;rating&quot;: 4.8,
        &quot;total_consultations&quot;: 150,
        &quot;hourly_rate&quot;: 30000,
        &quot;profile_image_url&quot;: &quot;https://...&quot;,
        &quot;specializations&quot;: [&quot;주식&quot;, &quot;부동산&quot;],
        &quot;is_favorited&quot;: false
      }
    ],
    &quot;pagination&quot;: {
      &quot;current_page&quot;: 1,
      &quot;total_pages&quot;: 5,
      &quot;total_count&quot;: 47,
      &quot;has_next&quot;: true
    }
  }
}</code></pre>
<h4 id="챌린지-참여-api">챌린지 참여 API</h4>
<pre><code class="language-js">// 챌린지 참여
POST /api/challenges/1/join
// 응답: 참여 성공 메시지

// 챌린지 기록 등록
POST /api/challenges/1/record
{
  &quot;amount&quot;: 5000,
  &quot;memo&quot;: &quot;매일 5천원 씩 소수점 투자 챌린지&quot;,
  &quot;proof_image_url&quot;: &quot;https://...&quot;,
  &quot;record_date&quot;: &quot;2025-05-22&quot;
}

// 내 챌린지 진행 현황
GET /api/challenges/my-participations
{
  &quot;success&quot;: true,
  &quot;data&quot;: {
    &quot;participations&quot;: [
      {
        &quot;challenge_title&quot;: &quot;주린이 주식 입문 스터디 모임&quot;,
        &quot;current_amount&quot;: 45000,
        &quot;goal_amount&quot;: 100000,
        &quot;progress_percentage&quot;: 45.0,
        &quot;status&quot;: &quot;진행중&quot;,
        &quot;days_left&quot;: 15,
        &quot;ranking&quot;: 23
      }
    ]
  }
}</code></pre>
<h4 id="실시간-채팅-api">실시간 채팅 API</h4>
<pre><code class="language-js">// WebSocket 연결
ws://api.moneybuddy.com/ws/chat/{consultation_id}

// 메시지 전송
{
  &quot;type&quot;: &quot;message&quot;,
  &quot;content&quot;: &quot;안녕하세요&quot;,
  &quot;message_type&quot;: &quot;text&quot;
}

// 메시지 수신
{
  &quot;message_id&quot;: 123,
  &quot;sender_id&quot;: 1,
  &quot;sender_name&quot;: &quot;수밍킴&quot;,
  &quot;content&quot;: &quot;안녕하세요&quot;,
  &quot;message_type&quot;: &quot;text&quot;,
  &quot;created_at&quot;: &quot;2025-05-22T21:06:00Z&quot;,
  &quot;is_read&quot;: false
}

// 읽음 상태 업데이트
{
  &quot;type&quot;: &quot;read&quot;,
  &quot;message_ids&quot;: [123, 124, 125]
}</code></pre>
<hr>
<h2 id="개발-로드맵">개발 로드맵</h2>
<h3 id="핵심-mvp-2주차">핵심 MVP (2주차)</h3>
<ul>
<li>사용자 인증 시스템</li>
<li>전문가 조회 및 필터링</li>
<li>기본 상담 신청/관리</li>
<li>카드뉴스 기본 기능</li>
<li>오늘의 컨텐츠 시스템</li>
</ul>
<h3 id="주요-기능-3주차">주요 기능 (3주차)</h3>
<ul>
<li>실시간 채팅 시스템</li>
<li>전문가 승인 프로세스</li>
<li>챌린지 참여/기록 시스템</li>
<li>즐겨찾기 기능</li>
<li>기본 알림 시스템</li>
</ul>
<h3 id="고도화-4주차">고도화 (4주차)</h3>
<ul>
<li>프로필 관리 고도화</li>
<li>리뷰 시스템 구축</li>
<li>카드뉴스 작성/관리</li>
<li>챌린지 생성/관리</li>
<li>배너 시스템</li>
</ul>
<h3 id="완성도-향상-5주차">완성도 향상 (5주차)</h3>
<ul>
<li>결제 시스템 연동</li>
<li>포인트 시스템 구축</li>
<li>FAQ 시스템</li>
<li>고도화된 알림</li>
<li>관리자 대시보드</li>
<li>사용자 분석 시스템</li>
</ul>
<h3 id="발표-준비-6주차">발표 준비 (6주차)</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | 타입 변환]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%ED%83%80%EC%9E%85-%EB%B3%80%ED%99%98</guid>
            <pubDate>Tue, 20 May 2025 10:24:09 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 <strong>타입 변환(Type Conversion)</strong>은 매우 중요한 개념이다. 자바스크립트는 <strong>동적 타입 언어</strong>이기 때문에, <strong>타입이 자동으로 또는 명시적으로 바뀌는 경우가 자주 발생</strong>한다.</p>
<hr>
<h2 id="두-가지-타입-변환-방식">두 가지 타입 변환 방식</h2>
<ol>
<li><strong>암시적 변환 (Implicit Conversion)</strong><ul>
<li>JS 엔진이 <strong>자동으로</strong> 타입을 변환</li>
<li>일명 *&quot;타입 강제 변환&quot;* 또는 *&quot;형 변환(coercion)&quot;*</li>
</ul>
</li>
<li><strong>명시적 변환 (Explicit Conversion)</strong><ul>
<li>개발자가 <strong>직접 코드로</strong> 타입을 바꿈</li>
<li><code>String()</code>, <code>Number()</code>, <code>Boolean()</code> 같은 함수 사용</li>
</ul>
</li>
</ol>
<hr>
<h3 id="암시적-타입-변환">암시적 타입 변환</h3>
<p>자바스크립트는 표현식의 문맥에 따라 값을 자동으로 변환한다. 가장 흔한 예는 연산자(<code>+</code>, <code>==</code>, 조건문 등)에서 발생한다.</p>
<h4 id="숫자-↔-문자열">숫자 ↔ 문자열</h4>
<pre><code class="language-js">&#39;5&#39; + 1 // &quot;51&quot; → 문자열로 변환됨
&#39;5&#39; - 1 // 4 → 숫자로 변환됨
&#39;5&#39; * &#39;2&#39; // 10 → 숫자로 변환됨</code></pre>
<ul>
<li><code>+</code> 연산자는 <strong>하나라도 문자열이면 전체를 문자열로 변환</strong></li>
<li>나머지 연산자(<code>-</code>, <code>*</code>, <code>/</code>)는 <strong>모두 숫자 변환을 시도</strong></li>
</ul>
<hr>
<h4 id="불리언-↔-다른-타입">불리언 ↔ 다른 타입</h4>
<pre><code class="language-js">!!&quot;hello&quot; // true
!!0 // false
!! undefined // false</code></pre>
<h5 id="falsy-값-boolean으로-변환-시-false가-되는-값">Falsy 값 (Boolean으로 변환 시 <code>false</code>가 되는 값):</h5>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>false</code></td>
<td>거짓</td>
</tr>
<tr>
<td><code>0</code>, <code>-0</code></td>
<td>숫자 0</td>
</tr>
<tr>
<td><code>&quot;&quot;</code></td>
<td>빈 문자열</td>
</tr>
<tr>
<td><code>null</code></td>
<td>없음</td>
</tr>
<tr>
<td><code>undefined</code></td>
<td>정의되지 않음</td>
</tr>
<tr>
<td><code>NaN</code></td>
<td>숫자가 아님</td>
</tr>
<tr>
<td>나머지 모든 값은 <code>true</code>로 간주된다.</td>
<td></td>
</tr>
</tbody></table>
<hr>
<h4 id="느슨한-비교--시의-암시적-변환">느슨한 비교 (<code>==</code>) 시의 암시적 변환</h4>
<pre><code class="language-js">&#39;5&#39; == 5 // true (문자열 → 숫자 변환)
false == 0 // true
null == undefined // true
[] == &#39;&#39; // true
[] == 0 // true
[1] == 1 // true</code></pre>
<blockquote>
<p><strong>혼란스럽기 때문에</strong> 실제 개발에서는 항상 <code>===</code> 사용 권장!</p>
</blockquote>
<hr>
<h3 id="명시적-타입-반환">명시적 타입 반환</h3>
<p>명시적 타입 변환은 <strong>개발자가 의도적으로 타입을 바꾸는 것</strong>이다.</p>
<h4 id="문자열-변환">문자열 변환</h4>
<pre><code class="language-js">String(123) // &quot;123&quot;
(123).toString() // &quot;123&quot;</code></pre>
<h4 id="숫자-변환">숫자 변환</h4>
<pre><code class="language-js">Number(&quot;42&quot;) // 42
parseInt(&quot;42px&quot;) // 42
parseFloat(&quot;3.14&quot;) // 3.14
+true // 1
+&quot;123.45&quot; // 123.45</code></pre>
<h4 id="불리언-변환">불리언 변환</h4>
<pre><code class="language-js">Boolean(0) // false
Boolean(&quot;hello&quot;) // true</code></pre>
<blockquote>
<p><code>!!값</code> 패턴도 많이 사용된다: <code>!!&quot;hello&quot;</code> → <code>true</code></p>
</blockquote>
<hr>
<h3 id="특별한-경우들">특별한 경우들</h3>
<table>
<thead>
<tr>
<th>표현식</th>
<th>결과</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><code>null + 1</code></td>
<td><code>1</code></td>
<td><code>null → 0</code>으로 변환</td>
</tr>
<tr>
<td><code>undefined + 1</code></td>
<td><code>NaN</code></td>
<td><code>undefined → NaN</code> 변환</td>
</tr>
<tr>
<td><code>true + false</code></td>
<td><code>1</code></td>
<td><code>true → 1</code>, <code>false → 0</code></td>
</tr>
<tr>
<td><code>[] + {}</code></td>
<td><code>&quot;[object Object]&quot;</code></td>
<td>배열이 문자열로 변환됨</td>
</tr>
<tr>
<td><code>{} + []</code></td>
<td><code>0</code> 또는 <code>&quot;[object Object]&quot;</code></td>
<td>파싱 방식에 따라 다름</td>
</tr>
<tr>
<td>---</td>
<td></td>
<td></td>
</tr>
<tr>
<td>## 요약 정리</td>
<td></td>
<td></td>
</tr>
<tr>
<td>변환 종류</td>
<td>암시적 예시</td>
<td>명시적 예시</td>
</tr>
<tr>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>문자열 변환</td>
<td><code>&#39;3&#39; + 1 → &#39;31&#39;</code></td>
<td><code>String(123)</code></td>
</tr>
<tr>
<td>숫자 변환</td>
<td><code>&#39;5&#39; * 2 → 10</code></td>
<td><code>Number(&quot;42&quot;)</code></td>
</tr>
<tr>
<td>불리언 변환</td>
<td><code>!!&quot;hello&quot; → true</code></td>
<td><code>Boolean(null)</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="실전-팁">실전 팁</h2>
<ul>
<li>숫자 변환엔 <code>Number()</code>, 문자열 변환엔 <code>String()</code> 또는 <code>.toString()</code>, 불리언은 <code>!!</code> 또는 <code>Boolean()</code></li>
<li>비교에는 항상 <code>===</code>(엄격한 동등) 사용 → 예기치 않은 암시적 변환 방지</li>
<li><code>undefined</code>와 <code>null</code> 비교는 조심 (예: <code>undefined == null</code>은 <code>true</code>, <code>===</code>은 <code>false</code>)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | 래퍼 객체]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EB%9E%98%ED%8D%BC-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EB%9E%98%ED%8D%BC-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Tue, 20 May 2025 10:06:09 GMT</pubDate>
            <description><![CDATA[<h2 id="래퍼-객체란">래퍼 객체란?</h2>
<p>자바스크립트에서 문자열, 숫자, 불리언 같은 <strong>원시 값(primitive value)</strong>도 객체처럼 메서드나 속성을 사용할 수 있는데,
그게 가능한 이유는 <strong>자바스크립트 엔진이 일시적으로 원시 값을 래퍼 객체로 변환</strong>하기 때문이다.
이때 생성되는 객체가 바로 <strong>래퍼 객체</strong>이다.</p>
<hr>
<h3 id="작동-방식-박싱boxing과-언박싱unboxing">작동 방식: &quot;박싱(Boxing)&quot;과 &quot;언박싱(Unboxing)&quot;</h3>
<h4 id="예시">예시:</h4>
<pre><code class="language-js">let str = &quot;hello&quot;;
console.log(str.toUpperCase()); // &quot;HELLO&quot;</code></pre>
<h5 id="이-코드의-실제-내부-흐름">이 코드의 실제 내부 흐름:</h5>
<ol>
<li><code>str.toUpperCase()</code>를 호출하면,</li>
<li>JS 엔진이 <code>&quot;hello&quot;</code>를 <code>new String(&quot;hello&quot;)</code>로 <strong>자동 박싱</strong>함</li>
<li>해당 래퍼 객체의 메서드 <code>.toUpperCase()</code>가 호출됨</li>
<li>결과 반환 후, <strong>래퍼 객체는 즉시 폐기됨 (가비지 컬렉션 대상)</strong></li>
</ol>
<hr>
<h3 id="자바스크립트의-3가지-기본-래퍼-객체">자바스크립트의 3가지 기본 래퍼 객체</h3>
<table>
<thead>
<tr>
<th>원시 타입</th>
<th>래퍼 객체</th>
<th>생성 예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>string</code></td>
<td><code>String</code> 객체</td>
<td><code>new String(&quot;abc&quot;)</code></td>
</tr>
<tr>
<td><code>number</code></td>
<td><code>Number</code> 객체</td>
<td><code>new Number(42)</code></td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>Boolean</code> 객체</td>
<td><code>new Boolean(true)</code></td>
</tr>
<tr>
<td>이들은 전역 객체이며, 직접 인스턴스를 만들 수도 있다.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>하지만, <strong>직접 생성은 권장되지 않는다.</strong></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<hr>
<h4 id="잘못된-예시-권장-x">잘못된 예시: (권장 X)</h4>
<pre><code class="language-js">let x = new String(&quot;hello&quot;);
console.log(typeof x); // &quot;object&quot; ← 이제 더 이상 원시 타입 아님!</code></pre>
<p>이렇게 만들면 비교 연산이나 타입 체크에서 <strong>예상치 못한 결과</strong>가 발생할 수 있다.</p>
<pre><code class="language-js">let a = &quot;hello&quot;;
let b = new String(&quot;hello&quot;);

console.log(a === b); // false ← 타입 다름</code></pre>
<hr>
<h3 id="일반적으로는-자동-변환만-믿고-쓰자">일반적으로는 자동 변환만 믿고 쓰자</h3>
<p>원시 값이 메서드나 속성을 호출하면 <strong>엔진이 자동으로 래퍼 객체를 생성해서</strong> 처리하므로, 개발자가 명시적으로 래퍼 객체를 생성할 일은 거의 없다.</p>
<pre><code class="language-js">console.log(&quot;abc&quot;.length); // 3 ← 자동으로 String 객체로 래핑됨</code></pre>
<hr>
<h3 id="java와-비교">Java와 비교</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>Java</th>
<th>JavaScript</th>
</tr>
</thead>
<tbody><tr>
<td>원시 vs. 래퍼 타입</td>
<td><code>int</code> ↔ <code>Integer</code>, <code>boolean</code> ↔ <code>Boolean</code></td>
<td><code>number</code> ↔ <code>Number</code>, <code>string</code> ↔ <code>String</code> 등</td>
</tr>
<tr>
<td>박싱</td>
<td>명시적 or 자동 (autoboxing)</td>
<td>자동 (메서드 호출 시 래퍼 객체 생성)</td>
</tr>
<tr>
<td>지속성</td>
<td>명시적으로 생성되면 계속 존재</td>
<td>JS에선 래핑 객체는 일시적이고 즉시 제거됨</td>
</tr>
<tr>
<td>비교</td>
<td><code>==</code>는 값 비교, <code>===</code>는 참조 비교</td>
<td>JS에선 <code>===</code>가 타입까지 비교</td>
</tr>
</tbody></table>
<hr>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>원시 타입 값을 일시적으로 객체처럼 다루기 위한 내부 처리</td>
</tr>
<tr>
<td>작동 방식</td>
<td>메서드 호출 시 자동으로 래퍼 객체 생성 후 폐기</td>
</tr>
<tr>
<td>예시 클래스</td>
<td><code>String</code>, <code>Number</code>, <code>Boolean</code></td>
</tr>
<tr>
<td>주의사항</td>
<td><code>new String()</code>, <code>new Number()</code> 직접 생성은 피해야 함</td>
</tr>
<tr>
<td>개발자 행동</td>
<td>대부분 경우, <strong>자동 박싱에 의존</strong>하면 충분</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | undefined & null]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-undefined-null</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-undefined-null</guid>
            <pubDate>Tue, 20 May 2025 09:48:56 GMT</pubDate>
            <description><![CDATA[<h2 id="undefined"><code>undefined</code></h2>
<h3 id="정의">정의</h3>
<blockquote>
<p>&quot;<strong>값이 할당되지 않은 상태</strong>&quot;를 나타낸다.
자바스크립트 엔진이 자동으로 부여하는 값이다.</p>
</blockquote>
<h3 id="주로-발생하는-상황">주로 발생하는 상황</h3>
<h4 id="변수-선언만-했을-때">변수 선언만 했을 때</h4>
<pre><code class="language-js">let x;
console.log(x); // undefined</code></pre>
<h4 id="함수에서-return을-생략했을-때">함수에서 return을 생략했을 때</h4>
<pre><code class="language-js">function doSomething() {}
console.log(doSomething()); // undefined</code></pre>
<h4 id="객체에서-존재하지-않는-속성을-접근할-때">객체에서 존재하지 않는 속성을 접근할 때</h4>
<pre><code class="language-js">let user = { name: &quot;Alice&quot; };
console.log(user.age); // undefined</code></pre>
<h4 id="배열에서-비어-있는-인덱스를-접근할-때">배열에서 비어 있는 인덱스를 접근할 때</h4>
<pre><code class="language-js">let arr = [1, , 3];
console.log(arr[1]); // undefined</code></pre>
<h4 id="매개변수가-전달되지-않았을-때">매개변수가 전달되지 않았을 때</h4>
<pre><code class="language-js">function greet(name) {
  console.log(name);
}
greet(); // undefined</code></pre>
<h3 id="typeof-결과">typeof 결과</h3>
<pre><code class="language-js">typeof undefined; // &#39;undefined&#39;</code></pre>
<hr>
<h2 id="null"><code>null</code></h2>
<h3 id="정의-1">정의</h3>
<blockquote>
<p>&quot;<strong>명시적으로 값이 없음</strong>&quot;을 나타낸다.
즉, 프로그래머가 의도적으로 &quot;비어 있음&quot;을 표현할 때 사용한다.</p>
</blockquote>
<h3 id="주로-사용하는-상황">주로 사용하는 상황</h3>
<h4 id="초기값으로-명시적인-빈-상태-설정">초기값으로 명시적인 빈 상태 설정</h4>
<pre><code class="language-js">let currentUser = null;</code></pre>
<h4 id="의도적으로-참조를-끊을-때">의도적으로 참조를 끊을 때</h4>
<pre><code class="language-js">someElement = null; // GC 대상이 되도록</code></pre>
<h4 id="객체를-나중에-채울-예정임을-표현">객체를 나중에 채울 예정임을 표현</h4>
<pre><code class="language-js">let config = null; // 나중에 설정</code></pre>
<h3 id="typeof-결과-1">typeof 결과</h3>
<pre><code class="language-js">typeof null; // &#39;object&#39; ← JS 초기 설계 실수</code></pre>
<hr>
<h3 id="undefined-vs-null-비교"><code>undefined</code> vs. <code>null</code> 비교</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th><code>undefined</code></th>
<th><code>null</code></th>
</tr>
</thead>
<tbody><tr>
<td>의미</td>
<td>값이 <strong>정의되지 않음</strong></td>
<td><strong>명시적 빈 값</strong></td>
</tr>
<tr>
<td>누가 설정?</td>
<td><strong>자바스크립트 엔진</strong></td>
<td><strong>개발자</strong></td>
</tr>
<tr>
<td>typeof 결과</td>
<td><code>&#39;undefined&#39;</code></td>
<td><code>&#39;object&#39;</code> ← 설계 오류</td>
</tr>
<tr>
<td>사용 의도</td>
<td>초기화되지 않은 상태</td>
<td>의도적인 &quot;값 없음&quot;</td>
</tr>
<tr>
<td>사용 시기</td>
<td>변수 선언만 한 경우 등</td>
<td>비어있음을 명시할 필요가 있을 때</td>
</tr>
<tr>
<td>JSON.stringify</td>
<td>제거되지 않음</td>
<td>유지됨 (<code>null</code> 출력)</td>
</tr>
</tbody></table>
<hr>
<h3 id="사용-시-주의사항">사용 시 주의사항</h3>
<ul>
<li><code>undefined</code>는 <strong>암묵적이며 엔진이 부여하는 값</strong>이므로, <strong>직접 할당하는 건 권장되지 않는다</strong>.<pre><code class="language-js">let x = undefined; // ❌ 권장 X
let x = null; // ✅ 명시적 빈 값</code></pre>
</li>
<li>비교 시 <strong>느슨한 동등 (<code>==</code>)</strong> 비교는 혼란을 유발할 수 있다:<pre><code class="language-js">null == undefined // true
null === undefined // false</code></pre>
→ 실제 개발에서는 <strong>항상 <code>===</code>을 사용하는 것이 좋다</strong> (엄격한 비교).</li>
</ul>
<hr>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
<th>누가 설정함</th>
<th>사용 목적</th>
<th>typeof</th>
</tr>
</thead>
<tbody><tr>
<td><code>undefined</code></td>
<td>값이 없음 (초기 상태)</td>
<td>JS 엔진</td>
<td>아직 할당되지 않음</td>
<td><code>&#39;undefined&#39;</code></td>
</tr>
<tr>
<td><code>null</code></td>
<td>명시적 빈 값</td>
<td>개발자</td>
<td>값이 없음을 표현</td>
<td><code>&#39;object&#39;</code></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | 참조 타입]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85</guid>
            <pubDate>Tue, 20 May 2025 09:33:55 GMT</pubDate>
            <description><![CDATA[<h2 id="참조-타입이란">참조 타입이란?</h2>
<p><strong>참조 타입</strong>은 값 자체가 아닌 <strong>메모리 주소(참조)</strong>를 통해 데이터를 다루는 타입이다.
객체, 배열, 함수 등 복잡한 구조의 데이터가 여기에 속한다.</p>
<hr>
<h3 id="자바스크립트의-주요-참조-타입">자바스크립트의 주요 참조 타입</h3>
<table>
<thead>
<tr>
<th>타입</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>Object</code></td>
<td>키-값 쌍의 데이터 구조</td>
<td><code>{ name: &quot;John&quot;, age: 30 }</code></td>
</tr>
<tr>
<td><code>Array</code></td>
<td>순서가 있는 리스트</td>
<td><code>[1, 2, 3]</code></td>
</tr>
<tr>
<td><code>Function</code></td>
<td>실행 가능한 코드</td>
<td><code>function() { return 1; }</code></td>
</tr>
<tr>
<td><code>Date</code></td>
<td>날짜 및 시간 정보</td>
<td><code>new Date()</code></td>
</tr>
<tr>
<td><code>RegExp</code></td>
<td>정규 표현식</td>
<td><code>/ab+c/</code></td>
</tr>
<tr>
<td>기타</td>
<td><code>Map</code>, <code>Set</code>, <code>WeakMap</code>, <code>WeakSet</code> 등 ES6 이후 추가된 컬렉션 타입들</td>
<td></td>
</tr>
</tbody></table>
<hr>
<h3 id="참조-타입의-특징">참조 타입의 특징</h3>
<h4 id="메모리-참조를-저장">메모리 참조를 저장</h4>
<p>변수에는 실제 값이 아닌 <strong>객체가 저장된 메모리 주소(참조)</strong>가 저장된다.</p>
<pre><code class="language-js">let obj1 = { name: &quot;Alice&quot; };
let obj2 = obj1;

ob2.name = &quot;Bob&quot;;

console.log(obj1.name); // &quot;Bob&quot;</code></pre>
<p>→ <code>obj1</code>과 <code>obj2</code>는 <strong>같은 객체</strong>를 가리키고 있기 때문에, 하나를 수정하면 다른 쪽에도 영향을 미친다.</p>
<hr>
<h4 id="얕은-복사-vs-깊은-복사">얕은 복사 vs. 깊은 복사</h4>
<ul>
<li><strong>얕은 복사 (Shallow Copy)</strong>: 참조만 복사됨 → 원본 변경 시 영향 받음</li>
<li><strong>깊은 복사 (Deep Copy)</strong>: 값 자체를 완전히 복제 → 원본과 독립적<pre><code class="language-js">// 얕은 복사
let original = { a: 1 };
let copy = original;
copy.a = 2;
</code></pre>
</li>
</ul>
<p>console.log(original.a); // 2</p>
<p>// 깊은 복사
let deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.a = 100;</p>
<p>console.log(original.a); // 2
console.log(deepCopy.a); // 100</p>
<pre><code>---
#### typeof 결과는 대부분 &#39;object&#39;
``` js
typeof {}; // &quot;object&quot;
typeof []; // &quot;object&quot;
typeof function(){} // &quot;function&quot; ← 특별 처리됨
typeof null; // &quot;object&quot; ← 버그로 인해 이 결과가 나옴</code></pre><blockquote>
<p><code>null</code>이 <code>object</code>로 나오는 건 오래된 JS 설계 실수지만, 지금도 그대로 유지되고 있다.</p>
</blockquote>
<hr>
<h4 id="속성-및-메서드-사용-가능">속성 및 메서드 사용 가능</h4>
<p>참조 타입은 <strong>속성(property)</strong>과 <strong>메서드(method)</strong>를 가질 수 있다:</p>
<pre><code class="language-js">let user = {
  name: &quot;Jane&quot;,
  greet: function() {
    console.log(&quot;Hello!&quot;);
  }
};

console.log(user.name); // &quot;Jane&quot;
user.greet(); // &quot;Hello!&quot;</code></pre>
<hr>
<h4 id="함수도-참조-타입">함수도 참조 타입</h4>
<p>자바스크립트에서는 함수도 <strong>일급 객체(First-class object)</strong>로 취급되며 참조 타입이다:</p>
<pre><code class="language-js">function greet() {
  return &quot;Hello&quot;;
}

let fn = greet;
console.log(fn()); // &quot;Hello&quot;</code></pre>
<hr>
<h2 id="원시-타입과-참조-타입-비교">원시 타입과 참조 타입 비교</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>원시 타입</th>
<th>참조 타입</th>
</tr>
</thead>
<tbody><tr>
<td>저장 방식</td>
<td>값 자체</td>
<td>메모리 참조 (주소)</td>
</tr>
<tr>
<td>복사 시</td>
<td>값 복사 (독립적)</td>
<td>참조 복사 (공유됨)</td>
</tr>
<tr>
<td>변경 가능성</td>
<td>불변 (immutable)</td>
<td>변경 가능 (mutable)</td>
</tr>
<tr>
<td>크기</td>
<td>작음</td>
<td>상대적으로 큼</td>
</tr>
<tr>
<td>typeof 결과</td>
<td><code>string</code>, <code>number</code>, 등</td>
<td><code>object</code>, <code>function</code> 등</td>
</tr>
</tbody></table>
<hr>
<h2 id="요약">요약</h2>
<ul>
<li>참조 타입은 <strong>값이 아닌 주소(참조)</strong>를 저장</li>
<li>같은 객체를 참조하는 변수는 <strong>서로 영향을 줌</strong></li>
<li>객체, 배열, 함수 등이 이에 해당</li>
<li>복사할 땐 얕은/깊은 복사 구분 필요</li>
<li><code>typeof</code> 결과 대부분 <code>&quot;object&quot;</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | 원시 값]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EC%9B%90%EC%8B%9C-%EA%B0%92</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%EC%9B%90%EC%8B%9C-%EA%B0%92</guid>
            <pubDate>Tue, 20 May 2025 09:12:08 GMT</pubDate>
            <description><![CDATA[<h2 id="원시-값primitive-value이란">원시 값(Primitive Value)이란?</h2>
<p>원시 값은 <strong>더 이상 나눌 수 없는, 기본적인 데이터 단위</strong>이다.
값 자체가 변수에 저장되며, <strong>immutable (불변)</strong>하다. 즉, 한 번 만들어진 원시 값은 변경될 수 없다.</p>
<hr>
<h3 id="자바스크립트의-원시-타입-종류">자바스크립트의 원시 타입 종류</h3>
<p>자바스크립트에는 총 <strong>7가지 원시 타입</strong>이 있다:</p>
<table>
<thead>
<tr>
<th>타입</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>string</code></td>
<td>문자열</td>
<td><code>&#39;hello&#39;</code>, <code>&quot;world&quot;</code></td>
</tr>
<tr>
<td><code>number</code></td>
<td>숫자 (정수, 실수 포함)</td>
<td><code>42</code>, <code>3.14</code></td>
</tr>
<tr>
<td><code>bigint</code></td>
<td>아주 큰 정수 (ES2020 도입)</td>
<td><code>123456789012345678901234567890n</code></td>
</tr>
<tr>
<td><code>boolean</code></td>
<td>참/거짓</td>
<td><code>true</code>, <code>false</code></td>
</tr>
<tr>
<td><code>undefined</code></td>
<td>정의되지 않은 값</td>
<td><code>let x;</code> (초기화 안 된 변수)</td>
</tr>
<tr>
<td><code>null</code></td>
<td>명시적인 &quot;없음&quot; 또는 &quot;비어 있음&quot;</td>
<td><code>let y = null;</code></td>
</tr>
<tr>
<td><code>symbol</code></td>
<td>고유한 식별자 생성용 (ES6 도입)</td>
<td><code>Symbol(&#39;id&#39;)</code></td>
</tr>
</tbody></table>
<hr>
<h3 id="특징-정리">특징 정리</h3>
<h4 id="불변성-immutability">불변성 (Immutability)</h4>
<pre><code class="language-js">let str = &#39;hello&#39;;
str[0] = &#39;H&#39;; // 시도는 가능하지만 실제 값은 변하지 않음
console.log(str); // &#39;hello&#39;</code></pre>
<p>문자열을 바꾸는 것처럼 보여도, 실제로는 <strong>새로운 문자열이 생성</strong>된다.</p>
<hr>
<h4 id="값-복사-값-전달">값 복사 (값 전달)</h4>
<p>원시 값은 <strong>값 자체가 복사</strong>되기 때문에, 다른 변수에 할당해도 원본은 영향받지 않는다.</p>
<pre><code class="language-js">let a = 10;
let b = a;
b = 20;
console.log(a); // 10</code></pre>
<p><code>a</code>와 <code>b</code>는 서로 완전히 독립적인 값이다.</p>
<hr>
<h4 id="타입-확인">타입 확인</h4>
<p><code>typeof</code> 연산자를 사용하여 원시 타입을 확인할 수 있다:</p>
<pre><code class="language-js">typeof &#39;hello&#39;;    // &#39;string&#39;
typeof 42;         // &#39;number&#39;
typeof true;       // &#39;boolean&#39;
typeof undefined;  // &#39;undefined&#39;
typeof null;       // &#39;object&#39; ← 이건 JS 언어 설계상의 오래된 실수
typeof Symbol();   // &#39;symbol&#39;
typeof 123n;       // &#39;bigint&#39;</code></pre>
<hr>
<h3 id="원시-값과-객체의-차이">원시 값과 객체의 차이</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>원시 값</th>
<th>객체 (참조 타입)</th>
</tr>
</thead>
<tbody><tr>
<td>저장 방식</td>
<td>값 자체</td>
<td>메모리 참조 (주소)</td>
</tr>
<tr>
<td>복사 방식</td>
<td>값 복사</td>
<td>참조 복사 (얕은 복사)</td>
</tr>
<tr>
<td>변경 가능성</td>
<td>불변</td>
<td>변경 가능 (mutable)</td>
</tr>
</tbody></table>
<hr>
<h3 id="예시-문자열은-원시-타입인데-메서드를-쓸-수-있는-이유">예시: 문자열은 원시 타입인데 메서드를 쓸 수 있는 이유?</h3>
<pre><code class="language-js">let name = &quot;John&quot;;
console.log(name.toUpperCase()); // &quot;JOHN&quot;</code></pre>
<ul>
<li>문자열은 원시 타입이지만, 메서드를 호출하면 <strong>자바스크립트 엔진이 내부적으로 <code>String</code> 객체로 일시적으로 래핑(wrapping)</strong>한다.</li>
<li>이걸 <strong>&quot;박싱(Boxing)&quot;</strong>이라고 부른다.</li>
<li>이후 메서드 실행이 끝나면 다시 원시 값으로 돌아간다.</li>
</ul>
<hr>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>특징</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>불변</td>
<td>수정 불가. 새 값으로 대체만 가능</td>
</tr>
<tr>
<td>값 복사</td>
<td>변수 간 할당 시 값 자체가 복사됨</td>
</tr>
<tr>
<td>7가지 타입</td>
<td>string, number, bigint, boolean, undefined, null, symbol</td>
</tr>
<tr>
<td>메모리 사용 효율성</td>
<td>객체보다 가볍고 빠름</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 값 | 타입 시스템]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EA%B0%92-%ED%83%80%EC%9E%85-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Tue, 20 May 2025 08:57:37 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트는 <strong>동적 타입(dynamically typed)</strong> 언어이다. 즉, 변수에 어떤 타입의 값이든 할당할 수 있고, 실행 중에 타입이 바뀔 수도 있다. 정적 타입 언어(Java, TypeScript 등)와 달리, 컴파일 타임에 타입 검사가 이뤄지지 않는다.
다음은 자바스크립트의 타입 시스템의 주요 특징이다:</p>
<hr>
<h2 id="원시-타입-primitive-types">원시 타입 (Primitive Types)</h2>
<p>자바스크립트의 기본 데이터 타입은 다음과 같다:</p>
<table>
<thead>
<tr>
<th>타입</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>string</code></td>
<td><code>&quot;hello&quot;</code>, <code>&#39;world&#39;</code></td>
</tr>
<tr>
<td><code>number</code></td>
<td><code>1</code>, <code>3.14</code>, <code>-42</code></td>
</tr>
<tr>
<td><code>boolean</code></td>
<td><code>true</code>, <code>false</code></td>
</tr>
<tr>
<td><code>null</code></td>
<td><code>null</code></td>
</tr>
<tr>
<td><code>undefined</code></td>
<td>변수 선언 후 초기화 안 된 상태</td>
</tr>
<tr>
<td><code>bigint</code></td>
<td><code>123456789012345678901234567890n</code></td>
</tr>
<tr>
<td><code>symbol</code></td>
<td><code>Symbol(&#39;id&#39;)</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="참조-타입-reference-types">참조 타입 (Reference Types)</h2>
<ul>
<li>객체(<code>Object</code>)</li>
<li>배열(<code>Array</code>)</li>
<li>함수(<code>Function</code>)</li>
<li>날짜(<code>Date</code>) 등등<pre><code class="language-js">let obj = { name: &#39;John&#39; };
let arr = [1, 2, 3];
let fn = function() { return &#39;Hello&#39;; };</code></pre>
</li>
</ul>
<hr>
<h2 id="동적-타입-지정">동적 타입 지정</h2>
<p>변수는 어떤 타입이든 가질 수 있으며, 재할당을 통해 타입이 바뀔 수 있다:</p>
<pre><code class="language-js">let x = 10; // number
x = &#39;hello&#39;; // 이제 string
x = true; // 이제 boolean</code></pre>
<hr>
<h2 id="암시적-타입-변환-type-coercion">암시적 타입 변환 (Type Coercion)</h2>
<p>자바스크립트는 상황에 따라 자동으로 타입을 변환한다:</p>
<pre><code class="language-js">&#39;5&#39; + 1 // &#39;51&#39; (문자열로 변환)
&#39;5&#39; - 1 // 4 (숫자로 변환)
true + 1 // 2 (true → 1)
false + &#39;1&#39; // &#39;false1&#39;</code></pre>
<p>이런 특징 때문에 <strong>버그 발생 가능성</strong>이 높고, 유지보수 시 주의가 필요하다.</p>
<hr>
<h2 id="타입-검사-방법">타입 검사 방법</h2>
<p>런타임에 타입을 확인하려면 <code>typeof</code> 연산자를 사용한다:</p>
<pre><code class="language-js">typeof 42 // &#39;number&#39;
typeof &#39;hello&#39; // &#39;string&#39;
typeof null // &#39;object&#39; ← 이건 자바스크립트의 오래된 버그
type of [] // &#39;object&#39;
type of {} // &#39;object&#39;
typeof function(){} // &#39;function&#39;</code></pre>
<hr>
<h2 id="엄격한-타입을-원한다면-→-typescript">엄격한 타입을 원한다면? → TypeScript</h2>
<p>자바스크립트의 유연하지만 위험한 타입 시스템을 보완하기 위해 <strong>TypeScript</strong>가 등장했다.
TypeScript는 정적 타입 검사, 인터페이스, 제네릭 등을 제공해 대규모 애플리케이션 개발에 더 적합하다.</p>
<hr>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>특징</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>동적 타입</td>
<td>변수에 어떤 타입이든 저장 가능</td>
</tr>
<tr>
<td>타입 추론 없음</td>
<td>런타임에 타입 결정</td>
</tr>
<tr>
<td>타입 안전성 낮음</td>
<td>실수로 타입 바꿔도 에러 없음</td>
</tr>
<tr>
<td>타입스크립트 권장</td>
<td>정적 타입 검사를 원한다면</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 문법 | use strict]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-use-strict</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-use-strict</guid>
            <pubDate>Mon, 19 May 2025 12:09:21 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 <code>&quot;use strict&quot;</code>는 <strong>코드 실행 방식에 영향을 주는 특별한 지시문(directive)</strong>이다. 오류를 더 엄격하게 감지하고, 일부 <strong>잠재적인 버그를 방지하기 위한 안전 장치</strong> 역할을 한다.</p>
<hr>
<h2 id="use-strict란"><code>&quot;use strict&quot;</code>란?</h2>
<p><code>&quot;use strict&quot;</code>는 자바스크립트에서 <strong>Strict Mode(엄격 모드)</strong>를 활성화하는 지시문이다. 이 모드를 사용하면 <strong>보다 안전하고 예측 가능한 코드 실행</strong>이 보장된다.</p>
<pre><code class="language-js">&quot;use strict&quot;; // 이 줄 이후부터 엄격 모드 적용

let x = 3.14;</code></pre>
<h3 id="문법">문법</h3>
<ul>
<li>문자열 <code>&quot;use strict&quot;</code> 또는 <code>&#39;use strict&#39;</code>로 명시</li>
<li><strong>스크립트 또는 함수의 첫 줄</strong>에 위치해야 작동함</li>
</ul>
<hr>
<h2 id="왜-사용하는가">왜 사용하는가?</h2>
<p>자바스크립트는 초기 설계 시 유연함과 관용성(forgiveness)을 강조했기 때문에, 실수를 해도 경고 없이 넘어가는 경우가 많다.
<strong>Strict Mode는 이런 관용적인 동작을 제한하고 오류를 강제로 발생시켜 개발자가 문제를 빨리 인지하도록 도와준다.</strong></p>
<hr>
<h2 id="엄격-모드의-주요-특징">엄격 모드의 주요 특징</h2>
<h3 id="암시적-전역-변수-금지">암시적 전역 변수 금지</h3>
<pre><code class="language-js">&quot;use strict&quot;;
x = 10; // ❌ ReferenceError: x is not defined</code></pre>
<p>→ 선언하지 않은 변수는 자동으로 <code>var</code>로 처리되지 않고 <strong>에러 발생</strong>.</p>
<hr>
<h3 id="읽기-전용-속성-변경-금지">읽기 전용 속성 변경 금지</h3>
<pre><code class="language-js">&quot;use strict&quot;;
const obj = {};
Object.defineProperty(obj, &quot;x&quot;, { value: 42, writable: false });

obj.x = 9; // ❌ TypeError: Cannot assign to read only property</code></pre>
<hr>
<h3 id="중복된-매개변수-이름-허용-안-함">중복된 매개변수 이름 허용 안 함</h3>
<pre><code class="language-js">&quot;use strict&quot;;
function sum(a, a, b) { // ❌ SyntaxError
  return a + b;
}</code></pre>
<hr>
<h3 id="this가-undefined로-유지됨-전역-객체-바인딩-금지"><code>this</code>가 undefined로 유지됨 (전역 객체 바인딩 금지)</h3>
<pre><code class="language-js">&quot;use strict&quot;;
function f() {
  console.log(this); // ✅ undefined
}
f();</code></pre>
<p>→ 엄격 모드에서는 <code>this</code>가 자동으로 <code>window</code>(또는 global 객체)로 바인딩되지 않음.</p>
<hr>
<h3 id="삭제-불가능한-값-삭제-시-에러-발생">삭제 불가능한 값 삭제 시 에러 발생</h3>
<pre><code class="language-js">&quot;use strict&quot;;
delete Object.prototype; // ❌ TypeError</code></pre>
<hr>
<h3 id="예약어-사용-제한">예약어 사용 제한</h3>
<p>아직 사용되지 않았지만 미래에 사용할 가능성이 있는 키워드는 사용할 수 없습니다.</p>
<pre><code class="language-js">&quot;use strict&quot;;
let public = 1; // ❌ SyntaxError</code></pre>
<hr>
<h2 id="어디에-쓰나">어디에 쓰나?</h2>
<h3 id="파일-전체에-적용">파일 전체에 적용</h3>
<pre><code class="language-js">&quot;use strict&quot;;

function doSomething() {
  // strict mode 적용됨
}</code></pre>
<h3 id="특정-함수에만-적용">특정 함수에만 적용</h3>
<pre><code class="language-js">function processData() {
  &quot;use strict&quot;;
  // 이 함수 내부만 strict mode 적용
}</code></pre>
<hr>
<h2 id="사용-시-주의사항">사용 시 주의사항</h2>
<ul>
<li><strong>최상단에 선언해야 함</strong> (주석보다 먼저 위치하는 것이 안전)</li>
<li>라이브러리와 혼합 시 부분 적용 권장 (<code>함수 단위</code>로)</li>
</ul>
<hr>
<h2 id="es6-이후의-맥락">ES6 이후의 맥락</h2>
<p>ES6부터는 <strong>모듈(<code>.mjs</code>)이나 클래스 내 코드는 자동으로 strict mode가 적용</strong>된다.
즉, 명시적으로 쓰지 않아도 엄격 모드가 기본이라는 점도 기억해두자!</p>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>엄격 모드 적용 결과</th>
</tr>
</thead>
<tbody><tr>
<td>선언 없는 변수 사용</td>
<td>에러 발생</td>
</tr>
<tr>
<td>중복된 매개변수</td>
<td>에러 발생</td>
</tr>
<tr>
<td><code>this</code>의 암시적 전역 바인딩</td>
<td>undefined 유지 (window에 바인딩 안 됨)</td>
</tr>
<tr>
<td>예약어 사용</td>
<td>금지됨</td>
</tr>
<tr>
<td>상수 변경/삭제</td>
<td>에러 발생</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 문법 | 리터럴]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EB%A6%AC%ED%84%B0%EB%9F%B4</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EB%A6%AC%ED%84%B0%EB%9F%B4</guid>
            <pubDate>Mon, 19 May 2025 11:53:30 GMT</pubDate>
            <description><![CDATA[<h2 id="리터럴이란">리터럴이란?</h2>
<p><strong>리터럴(literal)</strong>은 <strong>고정된 값 자체</strong>를 의미한다.
즉, 변수나 계산이 아닌 <strong>코드에 직접 작성된 값</strong>을 말한다.</p>
<pre><code class="language-js">let num = 10; // 숫자 리터럴 10
let str = &quot;hello&quot;; // 문자열 리터럴 &quot;hello&quot;
let flag = true; // 불리언 리터럴 true</code></pre>
<p>위 예시에서 <code>10</code>, <code>&quot;hello&quot;</code>, <code>true</code>는 모두 리터럴이다.</p>
<hr>
<h2 id="자바스크립트의-주요-리터럴-종류">자바스크립트의 주요 리터럴 종류</h2>
<h3 id="숫자-리터럴-number-literal">숫자 리터럴 (Number Literal)</h3>
<pre><code class="language-js">let a = 42; // 정수
let b = 3.14; // 실수
let c = 0b1010; // 2진수 (0b 또는 0B)
let d = 0o755; // 8진수 (0o 또는 0O)
let e = 0xFF; // 16진수 (0x 또는 0X)</code></pre>
<hr>
<h3 id="문자열-리터럴-string-literal">문자열 리터럴 (String Literal)</h3>
<pre><code class="language-js">let s1 = &quot;hello&quot;;
let s2 = &#39;world&#39;;
let s3 = `template ${s1}`; // 템플릿 리터럴 (백틱 사용)</code></pre>
<ul>
<li>큰 따옴표 <code>&quot;</code>, 작은 따옴표 <code>&#39;</code>, 백틱 <code>̀</code> 모두 문자열 정의 가능</li>
<li>템플릿 리터럴은 문자열 내 변수 삽입 및 줄바꿈 가능</li>
</ul>
<hr>
<h3 id="불리언-리터럴-boolean-literal">불리언 리터럴 (Boolean Literal)</h3>
<pre><code class="language-js">let isActive = true;
let isComplete = false;</code></pre>
<hr>
<h3 id="null-리터럴">null 리터럴</h3>
<pre><code class="language-js">let empty = null;</code></pre>
<ul>
<li>&quot;값이 없음&quot; 또는 &quot;의도적으로 비워둠&quot;을 의미</li>
</ul>
<hr>
<h3 id="undefined-리터럴">undefined 리터럴</h3>
<pre><code class="language-js">let notSet; // 선언만 하고 초기화하지 않으면 undefined</code></pre>
<ul>
<li>직접 쓰는 경우는 드물고, 자바스크립트가 자동으로 부여하는 값</li>
</ul>
<hr>
<h3 id="객체-리터럴-object-literal">객체 리터럴 (Object Literal)</h3>
<pre><code class="language-js">let person = {
  name: &quot;Alice&quot;,
  age: 30
};</code></pre>
<ul>
<li>중괄호 <code>{}</code>를 사용해 키-값 쌍으로 구성</li>
</ul>
<hr>
<h3 id="배열-리터럴-array-literal">배열 리터럴 (Array Literal)</h3>
<pre><code class="language-js">let list = [1, 2, 3, 4];</code></pre>
<ul>
<li>대괄호 <code>[]</code>를 사용해 값의 순서대로 나열</li>
</ul>
<hr>
<h3 id="정규표현식-리터럴-regexp-literal">정규표현식 리터럴 (RegExp Literal)</h3>
<pre><code class="language-js">let regex = /ab+c/i;</code></pre>
<ul>
<li><code>/패턴/플래그</code> 형식</li>
</ul>
<hr>
<h3 id="심볼-리터럴-symbol-literal">심볼 리터럴 (Symbol Literal)</h3>
<pre><code class="language-js">let sym = Symbol(&quot;id&quot;);</code></pre>
<ul>
<li>고유하고 변경 불가능한 식별자 생성</li>
</ul>
<hr>
<h2 id="리터럴-vs-표현식">리터럴 vs. 표현식</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>예시</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>리터럴</td>
<td><code>&quot;hello&quot;</code></td>
<td>고정된 값 자체</td>
</tr>
<tr>
<td>표현식</td>
<td><code>a + b</code>, <code>2 * 3</code></td>
<td>계산 또는 평가되는 코드</td>
</tr>
</tbody></table>
<p>즉, <strong>리터럴은 평가할 필요가 없는 값, 표현식은 평가하면 결과가 나오는 코드</strong>이다.</p>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>종류</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>숫자</td>
<td><code>42</code>, <code>3.14</code>, <code>0xFF</code></td>
</tr>
<tr>
<td>문자열</td>
<td><code>&quot;hello&quot;</code>, <code>&#39;world&#39;</code>, <code>`a`</code></td>
</tr>
<tr>
<td>불리언</td>
<td><code>true</code>, <code>false</code></td>
</tr>
<tr>
<td>null</td>
<td><code>null</code></td>
</tr>
<tr>
<td>undefined</td>
<td><code>undefined</code> (주로 자동 할당)</td>
</tr>
<tr>
<td>객체</td>
<td><code>{ name: &quot;Alice&quot; }</code></td>
</tr>
<tr>
<td>배열</td>
<td><code>[1, 2, 3]</code></td>
</tr>
<tr>
<td>정규식</td>
<td><code>/abc/</code></td>
</tr>
<tr>
<td>심볼</td>
<td><code>Symbol(&quot;id&quot;)</code></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 문법 | 식별자]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%8B%9D%EB%B3%84%EC%9E%90</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%8B%9D%EB%B3%84%EC%9E%90</guid>
            <pubDate>Mon, 19 May 2025 11:03:36 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 <strong>식별자(identifier)</strong>는 매우 중요한 개념으로, 변수, 함수, 클래스 등 모든 <strong>이름</strong>을 정의할 때 사용되며, 코드의 가독성과 유지보수성에도 큰 영향을 준다.</p>
<hr>
<h2 id="식별자란">식별자란?</h2>
<p><strong>식별자(identifier)</strong>는 <strong>변수, 함수, 클래스, 매개변수 등 프로그래밍 요소를 식별하기 위한 이름</strong>이다.</p>
<pre><code class="language-js">let name = &quot;John&quot;;
function sayHello() {
  console.log(&quot;Hello!&quot;);
}</code></pre>
<p>위 코드에서 <code>name</code>과 <code>sayHello</code>는 모두 식별자이다.</p>
<hr>
<h2 id="식별자-작성-규칙-ecmascript-표준-기반">식별자 작성 규칙 (ECMAScript 표준 기반)</h2>
<p>자바스크립트 식별자는 다음과 같은 규칙을 따라야 한다:</p>
<h3 id="시작-문자">시작 문자</h3>
<ul>
<li>문자(a-z, A-Z)</li>
<li>밑줄 <code>_</code></li>
<li>달러 기호 <code>$</code></li>
</ul>
<h4 id="✅-가능한-예">✅ 가능한 예</h4>
<pre><code class="language-js">let userName;
let _tempValue;
let $dollarSign;</code></pre>
<h4 id="❌-잘못된-예">❌ 잘못된 예</h4>
<pre><code class="language-js">let 1stUser; // 숫자로 시작할 수 없음
let @price; // 특수문자 사용 불가</code></pre>
<hr>
<h3 id="이후-문자">이후 문자</h3>
<ul>
<li><strong>문자, 숫자, <code>_</code>, <code>$</code></strong> 사용 가능</li>
<li>숫자 사용은 가능하지만, <strong>첫 글자</strong>로는 올 수 없음</li>
</ul>
<hr>
<h3 id="유니코드-지원">유니코드 지원</h3>
<p>ES6부터 유니코드 문자를 허용하므로 <strong>한글, 이모지</strong> 등도 식별자 이름으로 사용 가능은 하지만 <strong>권장되지 않는다</strong> (유지보수 어려움).</p>
<pre><code class="language-js">let 이름 = &quot;홍길동&quot;; // 가능은 하지만 권장하지 않음
let 💻 = &quot;컴퓨터&quot;; // 가능하지만 실무에서는 피해야 함</code></pre>
<hr>
<h2 id="식별자와-키워드">식별자와 키워드</h2>
<p>자바스크립트에서 예약어(키워드)는 식별자로 <strong>사용할 수 없다</strong>.
예: <code>let</code>, <code>const</code>, <code>var</code>, <code>function</code>, <code>if</code>, <code>class</code>, <code>return</code> 등</p>
<pre><code class="language-js">let if = 5; // ❌ 문법 오류</code></pre>
<hr>
<h2 id="네이밍-컨벤션-naming-conventions">네이밍 컨벤션 (Naming Conventions)</h2>
<p>자바스크립트에서 일반적으로 사용하는 작명 규칙은 다음과 같다:</p>
<table>
<thead>
<tr>
<th>용도</th>
<th>규칙</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td>변수/함수 이름</td>
<td>camelCase</td>
<td><code>userName</code>, <code>getData</code></td>
</tr>
<tr>
<td>클래스 이름</td>
<td>PascalCase</td>
<td><code>UserService</code></td>
</tr>
<tr>
<td>상수</td>
<td>대문자 + 언더스코어</td>
<td><code>MAX_LENGTH</code>, <code>API_KEY</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>변수/함수/클래스 등 이름을 식별</td>
</tr>
<tr>
<td>시작 가능 문자</td>
<td>문자, <code>_</code>, <code>$</code></td>
</tr>
<tr>
<td>이후 문자</td>
<td>문자, 숫자, <code>_</code>, <code>$</code></td>
</tr>
<tr>
<td>숫자 시작 불가</td>
<td><code>let 1a = 10;</code> → 오류 발생</td>
</tr>
<tr>
<td>키워드 사용 불가</td>
<td><code>let if = 5;</code> → 오류 발생</td>
</tr>
<tr>
<td>유니코드 허용</td>
<td>가능하지만 가독성 저하 주의</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript 기본 | 문법 | 제어문과 블럭]]></title>
            <link>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%A0%9C%EC%96%B4%EB%AC%B8%EA%B3%BC-%EB%B8%94%EB%9F%AD</link>
            <guid>https://velog.io/@faith_coder_lab/JavaScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%A0%9C%EC%96%B4%EB%AC%B8%EA%B3%BC-%EB%B8%94%EB%9F%AD</guid>
            <pubDate>Mon, 19 May 2025 10:50:44 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 <strong>제어문(control statement)</strong>과 <strong>블록(block)</strong>은 프로그램의 흐름을 제어하고 구조를 명확하게 만드는 핵심 요소이다.</p>
<hr>
<h2 id="블록block">블록(Block)</h2>
<h4 id="정의">정의</h4>
<p>블록은 <code>{}</code> 중괄호로 묶인 코드 집합이다. 여러 문(statement)을 하나로 묶어서 제어문, 함수, 클래스 등의 내부에서 사용한다.</p>
<pre><code class="language-javascript">{
  let x = 10;
  console.log(x);
}</code></pre>
<ul>
<li>이 블록은 자체적인 <strong>스코프(scope)</strong>를 가진다.</li>
<li><code>let</code>, <code>const</code>는 블록 스코프를 따른다. (예: 블록 밖에서는 변수 <code>x</code>를 접근할 수 없음).</li>
</ul>
<hr>
<h2 id="제어문control-statements">제어문(Control Statements)</h2>
<p>제어문은 코드의 실행 흐름을 조건이나 반복에 따라 다르게 만들기 위해 사용된다. 주요 제어문은 다음과 같다.</p>
<hr>
<h3 id="조건문-conditional-statements">조건문 (Conditional Statements)</h3>
<h4 id="if-else-if-else"><code>if</code>, <code>else if</code>, <code>else</code></h4>
<pre><code class="language-javascript">let score = 85;

if (score &gt;= 90) {
  console.log(&quot;A&quot;);
} else if (score &gt;= 80) {
  console.log(&quot;B&quot;);
} else {
  console.log(&quot;C&quot;);
}</code></pre>
<ul>
<li>조건이 <code>true</code>일 때 블록 내부 코드가 실행된다.</li>
<li>각 블록은 <code>{}</code>로 묶으며, 생략할 수도 있지만 <strong>가독성 유지 및 실수 방지를 위해 블록 사용 권장</strong>.</li>
</ul>
<h4 id="switch"><code>switch</code></h4>
<pre><code class="language-javascript">let fruit = &quot;apple&quot;;

switch (fruit) {
  case &quot;apple&quot;:
    console.log(&quot;사과입니다.&quot;);
    break;
  case &quot;banana&quot;:
    console.log(&quot;바나나입니다.&quot;);
    break;
  default:
    console.log(&quot;알 수 없는 과일입니다.&quot;);
}</code></pre>
<ul>
<li><code>break</code> 없으면 <strong>fall-through(다음 case로 넘어감)</strong> 발생.</li>
<li><code>default</code>는 일치하는 case가 없을 때 실행.</li>
</ul>
<hr>
<h3 id="반복문-loops">반복문 (Loops)</h3>
<h4 id="for"><code>for</code></h4>
<pre><code class="language-javascript">for (let i = 0; i &lt; 5; i++) {
  console.log(i);
}</code></pre>
<ul>
<li>초기식, 조건식, 증감식으로 구성.</li>
<li>블록 내 코드를 반복 실행.</li>
</ul>
<h4 id="while"><code>while</code></h4>
<pre><code class="language-javascript">let i = 0;
while (i &lt; 5) {
  console.log(i);
  i++;
}</code></pre>
<ul>
<li>조건이 참일 동안 반복.</li>
</ul>
<h4 id="dowhile"><code>do...while</code></h4>
<pre><code class="language-javascript">let i = 0;
do {
  console.log(i);
  i++;
} while (i &lt; 5);</code></pre>
<ul>
<li>최소 <strong>한 번은 실행</strong>되고 조건 검사.</li>
</ul>
<hr>
<h3 id="기타-제어-흐름문">기타 제어 흐름문</h3>
<h4 id="break"><code>break</code></h4>
<ul>
<li>반복문이나 <code>switch</code> 문에서 <strong>즉시 빠져나올 때</strong> 사용.<pre><code class="language-javascript">for (let i = 0; i &lt; 10; i++) {
if (i === 5) break;
console.log(i);
}</code></pre>
</li>
</ul>
<h4 id="continue"><code>continue</code></h4>
<ul>
<li>현재 반복을 <strong>건너뛰고 다음 반복으로 넘어감</strong>.<pre><code class="language-javascript">for (let i = 0; i &lt; 5; i++) {
if (i === 2) continue;
console.log(i);
}</code></pre>
</li>
</ul>
<h4 id="return"><code>return</code></h4>
<ul>
<li>함수에서 사용하며 <strong>값을 반환하고 실행을 종료</strong>함.<pre><code class="language-js">function add(a, b) {
return a + b;
}</code></pre>
</li>
</ul>
<hr>
<h2 id="정리-흐름도-개념">정리: 흐름도 개념</h2>
<pre><code class="language-arduino">조건문
 └─&gt; true → 블록 실행
 └─&gt; false → 다음 조건 또는 else

반복문
 └─&gt; 조건 → true → 블록 반복 실행
        → false → 반복 종료</code></pre>
]]></description>
        </item>
    </channel>
</rss>