<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yongyong_21.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 02 Feb 2024 05:57:53 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yongyong_21.log</title>
            <url>https://velog.velcdn.com/images/yongyong_21/profile/6db735e9-5bc8-4b9c-b1f4-5e2b5c2883ff/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yongyong_21.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yongyong_21" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Test] 프론트엔드 Test Code, TDD 방법론에 대한 생각]]></title>
            <link>https://velog.io/@yongyong_21/Test-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-Test-Code-TDD-%EB%B0%A9%EB%B2%95%EB%A1%A0%EC%97%90-%EB%8C%80%ED%95%9C-%EC%83%9D%EA%B0%81</link>
            <guid>https://velog.io/@yongyong_21/Test-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-Test-Code-TDD-%EB%B0%A9%EB%B2%95%EB%A1%A0%EC%97%90-%EB%8C%80%ED%95%9C-%EC%83%9D%EA%B0%81</guid>
            <pubDate>Fri, 02 Feb 2024 05:57:53 GMT</pubDate>
            <description><![CDATA[<h1 id="test-test-code-tdd-방법론에-대한-생각">[Test] Test Code, TDD 방법론에 대한 생각</h1>
<h2 id="test-code란">Test Code란?</h2>
<p>Test Code는 소프트웨어 개발에서 코드의 정확성, 품질, 안정성을 검증하기 위해 사용되는 코드이다.
이는 주로 단위 테스트, 통합 테스트, 시스템 테스트 등과 관련이 있다.</p>
<h2 id="tdd란">TDD란?</h2>
<p>TDD는 소프트웨어를 개발할 때 테스트 코드를 먼저 작성하고, 그 후에 해당 테스트를 통과시키는 싸이클을 반복하는 개발 방법론입니다. </p>
<h2 id="이-두개에-대한-내-생각">이 두개에 대한 내 생각</h2>
<h3 id="test-code는-중요하다-하지만">Test Code는 중요하다. 하지만....</h3>
<p>Test Code를 작성하면 장점이 많다. 위에서 Test Code에 대한 정의처럼 코드의 정확성, 안정성에 대해 1차적으로 검증을 할 수 있다.</p>
<p>하지만, Test Code를 작성할 때 Test Case에 대해 많은 신경을 쓰게 된다면 의미없는 Test Code를 작성할 수 있으며 이것은 Test Code에 대한 본질적인 의미를 잃어버릴 수 있다. 즉, 주객전도가 일어날 수 있다고 생각한다.</p>
<p>이러한 부분은 경력이 쌓이게 된다면, 크게 신경쓸 필요없이 Test Code를 잘 작성하게 되겠지만 초보자의 입장에서는 어떠한 범위까지 테스트를 진행해야 되는 것인지 잘 몰르기 때문에 의미없는 Test Code를 작성할 확률이 매우 높아진다고 생각한다.</p>
<h3 id="tdd의-현실적인-생각-프로젝트-경험">TDD의 현실적인 생각 (프로젝트 경험).</h3>
<p>TDD방식으로 프로젝트의 일부 기능을 구현을 했었다. TDD 방식으로 기능구현을 하니 장점보다 단점이 워낙 많아졌다고 느낀 방식이였던 것 같았다.</p>
<h4 id="prd의-이해">PRD의 이해</h4>
<p>TDD 방식으로 개발을 진행할려면, 모든 케이스에 대해 생각을 해야한다. 그렇다보니 PM이 작성했던 PRD를 100%를 이해한 상태에서 모든 케이스를 생각해야한다. 이것은 쉽지 않은 일이라고 생각한다. 또한 모든 케이스에 대해 생각을 하는 리소스가 많이 들어간다. </p>
<p>실제로, PRD를 보며 Test Case를 작성했지만 실제 로직구현을 했을 때에는 추가적인 Case들이 많아진 경험이 있다.</p>
<h4 id="프로젝트의-기간-및-기획-수정">프로젝트의 기간 및 기획 수정</h4>
<p>TDD 방식은 초기에 많은 시간이 오래 걸리게 된다. 이러한 부분을 보았을 때에는 프로젝트의 기간이 짧으면 TDD의 방식은 적합하지 않다고 생각한다. 또한, 기획 수정은 빈번하게 일어나기 때문에 기획 수정이 된다면 기존에 있던 Test Code들은 의미가 없어지게 된다.</p>
<h4 id="테스트-빌드의-시간소요">테스트 빌드의 시간소요</h4>
<p>로직을 작성하며 이 부분이 크게 와닿았던 것 같았다. 로직 작성의 에러를 고치기 위해 디버깅을 하고 Test를 실행하는 시간이 길어서 즉각적인 반응을 얻을 수 없는 것이 불편했었다.</p>
<h2 id="끝으로">끝으로..</h2>
<p>Test 라는 것은 매우 중요하다고 생각한다. 하지만 초보자일수록 크게 해맬 수 있는 부분이고 기능을 구현하는데에 있어서 리소스가 더 많이 들어갈 수있으며 그 리소스가 의미없는 리소스일 수도 있다. </p>
<p>비록 의미없는 테스트를 작성을 할지라도, 이러한 경험들이 나중에 Test Code를 잘 작성하는 것에 큰 도움이 될 것이라고 생각한다.</p>
<p>TDD의 방식은... 아직까지도 잘 모르겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이널 프로젝트 회고]]></title>
            <link>https://velog.io/@yongyong_21/%ED%8C%8C%EC%9D%B4%EB%84%90-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@yongyong_21/%ED%8C%8C%EC%9D%B4%EB%84%90-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Fri, 02 Feb 2024 04:41:55 GMT</pubDate>
            <description><![CDATA[<h3 id="프로젝트-소개">프로젝트 소개</h3>
<p>작업 기간: 2023.12.26 ~ 2024.01.29</p>
<p>업주야놀자 Final Project : B2B Self-coupon Admin(Backoffice) 서비스</p>
<h3 id="해당-깃-레포지토리">해당 깃 레포지토리</h3>
<p><a href="https://github.com/Upjuyanolja/Upjuyanolja_FE">https://github.com/Upjuyanolja/Upjuyanolja_FE</a></p>
<h3 id="프로젝트-인원">프로젝트 인원</h3>
<p>FE: 6명 / BE: 4명 / PM: 5명 / UXUI: 1명</p>
<h3 id="기술-스택">기술 스택</h3>
<p><strong>Environment</strong></p>
<p>GitHub, Git, Eslint</p>
<p><strong>Front-End</strong></p>
<p>React, TypeScript, ReactQuery, Recoil, Ant design, Styled Component, Jest</p>
<h2 id="담당한-기능">담당한 기능</h2>
<ul>
<li>포인트 충전: 토스페이먼츠를 활용하여 포인트 충전 기능을 구현</li>
<li>포인트 내역조회: React Query와 Recoil, 그리고 Query String을 사용하여 포인트 내역을 조회하는 기능을 구현.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/7879a786-91b6-4f32-aa4e-7c72c46f977d/image.PNG" alt=""></p>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/18c6bdb6-3c2e-4ce1-9859-c76f3a71df35/image.PNG" alt=""></p>
<h3 id="겪었던-문제들">겪었던 문제들</h3>
<h4 id="모달-렌더링-문제">모달 렌더링 문제.</h4>
<pre><code class="language-js">export const PointModal = ({
  isModalOpen,
  setIsModalOpen,
}: PointModalProps) =&gt; {
  const paymentWidgetRef = useRef&lt;PaymentWidgetInstance | null&gt;(null);
  const paymentMethodsWidgetRef = useRef&lt;ReturnType&lt;
    PaymentWidgetInstance[&#39;renderPaymentMethods&#39;]
  &gt; | null&gt;(null);  
  const selector = &#39;#payment-widget&#39;;
  useEffect(() =&gt; {
    (async () =&gt; {
      const paymentWidget = await loadPaymentWidget(clientKey, customerKey);

      const paymentMethodsWidget = paymentWidget.renderPaymentMethods(
        selector,
        { value: price, currency: &#39;KRW&#39;, country: &#39;KR&#39; },
        { variantKey: &#39;DEFAULT&#39; },
      );

      paymentWidgetRef.current = paymentWidget;
      paymentMethodsWidgetRef.current = paymentMethodsWidget;
    })();
  }, [paymentWidgetRef, price]);

  useEffect(() =&gt; {
    const paymentMethodsWidget = paymentMethodsWidgetRef.current;

    if (paymentMethodsWidget == null) {
      return;
    }

    paymentMethodsWidget.updateAmount(price);
  }, [price]);
  // ...

  return (
    ...
    &lt;div id=&quot;payment-widget&quot; /&gt;
  )</code></pre>
<img width="940" alt="20" src="https://github.com/Upjuyanolja/Upjuyanolja_FE/assets/90038848/5376dd9f-1bce-4180-85b6-483365b9d7f7">

<p>selector에 해당하는 HTML 요소를 확인할 수 없어서, 모든 페이지에 해당 에러 발생.</p>
<pre><code class="language-js">// Sidebar UserProfile.tsx
&lt;StyledSpace direction=&quot;vertical&quot; align=&quot;center&quot;&gt;
      &lt;TextBox typography=&quot;h5&quot; color=&quot;primary&quot; fontWeight=&quot;bold&quot;&gt;
        {userInfoData.name} 님
      &lt;/TextBox&gt;
      &lt;TextBox typography=&quot;h3&quot; color=&quot;black900&quot; fontWeight=&quot;bold&quot;&gt;
        {numberFormat(pointSummaryData.currentPoint)} P
      &lt;/TextBox&gt;
      &lt;StyledButton type=&quot;primary&quot; size=&quot;large&quot; onClick={showModal}&gt;
        포인트 추가하기
      &lt;/StyledButton&gt;
      &lt;PointModal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} /&gt;  // 상시 렌더링
&lt;/StyledSpace&gt;</code></pre>
<pre><code class="language-js">export const PointModal = ({
  isModalOpen,
  setIsModalOpen,
}: PointModalProps) =&gt; {
  console.log(&#39;컴포넌트 렌더링&#39;);
}</code></pre>
<img width="844" alt="19" src="https://github.com/Upjuyanolja/Upjuyanolja_FE/assets/90038848/c6aea4cb-4e2f-47a8-b167-bd9bdc33f5f8">

<p>모달 컴포넌트에 들어가져있는 로직이 원래는 모달 컴포넌트가 열린 상태에서 로직실행이 되어야 한다. 하지만,</p>
<pre><code class="language-js">&lt;PointModal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} /&gt;</code></pre>
<p>이런식으로 작성하게 되면 모달 컴포넌트가 보여지지않지만 렌더링이 되는 상황이 된다.</p>
<pre><code class="language-js">{isModalOpen &amp;&amp; (&lt;PointModal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} /&gt;)}</code></pre>
<p>isModalOpen이 true인 경우에만 해당 컴포넌트 렌더링하게 작성.</p>
<h3 id="kpt">KPT</h3>
<h4 id="keep-🎯">KEEP 🎯</h4>
<p>팀원들과의 정기적인 회의(의사소통).
PRD 분석 (요구사항 분석).
컴포넌트의 분리</p>
<h4 id="problem-🥊">PROBLEM 🥊</h4>
<p>Test Code에 대한 이해 및 작성 요령.</p>
<h4 id="try-🚀">TRY 🚀</h4>
<p>React Query와 Recoil로 State 관리.
Util 함수 분리.</p>
<h3 id="협업을-하면서-느낀점">협업을 하면서 느낀점</h3>
<p> 다양한 프로젝트를 진행하면서, 한 프로젝트에서는 각자의 역할과 책임을 명확히 분담했지만 팀원들 간의 의사소통이 효과적으로 이뤄지지 않아 프로젝트의 진행이 지연이 되었다.</p>
<p> 이러한 경험으로 인해 파이널 프로젝트에서 의사소통이라는 부분에 초점을 두어서 진행을 했었다. 의사소통에서는 투명성과 정기적인 업데이트가 중요하다고 느꼈다. 그래서 팀원들과의 정기적인 회의를 통해 진행 상황과 어려움을 공유하고 피드백을 주고받았다.</p>
<p> 이러한 방법을 통해, 프로젝트의 일정에 맞춰서 잘 진행이 되어 큰 문제 없이 프로젝트가 잘 마무리가 되었다. 의사소통이 팀 전체의 성공을 위한 필수적인 요소라는 것을 깨달았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[미니프로젝트 회고]]></title>
            <link>https://velog.io/@yongyong_21/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@yongyong_21/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Thu, 21 Dec 2023 05:33:24 GMT</pubDate>
            <description><![CDATA[<h3 id="프로젝트-소개">프로젝트 소개</h3>
<p>작업 기간: 2023.11.20 ~ 2023.11.30</p>
<p>숙박 예약 서비스</p>
<p>사용자는 다양한 숙박들을 찾아볼 수 있고, 예약할 수 있는 사이트.</p>
<h3 id="해당-깃-레포">해당 깃 레포</h3>
<p><a href="https://github.com/YBEMiniProjectTeam/MINI-Front?tab=readme-ov-file">https://github.com/YBEMiniProjectTeam/MINI-Front?tab=readme-ov-file</a></p>
<p>현재 배포는 끊긴 상태.</p>
<h3 id="맡은-역할">맡은 역할</h3>
<ul>
<li>프로젝트 초기 설정</li>
<li>회원가입</li>
<li>로그인</li>
<li>장바구니</li>
<li>드래그 앤 드랍</li>
</ul>
<h3 id="구현한-기능">구현한 기능</h3>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/6640c913-5eaa-491b-b653-358e769d2ee3/image.gif" alt="">
<img src="https://velog.velcdn.com/images/yongyong_21/post/adf7cc51-0261-4998-9f89-4640365a3989/image.gif" alt="">
<img src="https://velog.velcdn.com/images/yongyong_21/post/6767d1a7-e388-4cb2-b085-2c2f18dade67/image.gif" alt="">
<img src="https://velog.velcdn.com/images/yongyong_21/post/86e882a9-da3a-4485-880f-4537b027a0b9/image.gif" alt=""></p>
<h3 id="겪었던-문제들">겪었던 문제들</h3>
<h4 id="프록시-설정">프록시 설정</h4>
<pre><code>// host
127.0.0.1 domain.com</code></pre><pre><code>//host
127.0.0.1 location.domain.com</code></pre><p>host 파일을 변경할 때, 도메인 주소 앞에 일부 주소를 작성해야 된다는 것을 알았다.
127.0.0.1 <a href="http://domain.com">domain.com</a> 으로 작성할 시, 기존에 있던 api 사이트 domain.com/index/swagger 으로 접속할 경우, 127.0.0.1/index/swagger 로 접속이 되는 것과 같기때문에 네트워크 오류( 존재하지 않는 사이트 )가 뜨게 된다.</p>
<h4 id="css">CSS</h4>
<p>Header 메뉴와 서브메뉴 사이의 간격이 있기때문에 Header Menu → Hover → Submenu 커서를 옮기는 과정에서 계속 닫히게 되었다.
이 부분을 해결하기 위해서 각 메뉴마다 div 태그를 2번 작성을 해서 마우스의 커서 범위를 늘려주는 방식으로 구현하게 되었다.</p>
<p>Z-index
드래그앤 드롭을 사용해서 Drop 컴포넌트의 위치에 대한 에러 css 코드에서 position:fixed z-index:100 을 적용했지만 Drop 컴포넌트가 일부 컴포넌트 보다 아래에 위치해 있는 경우가 있었다.
Stacking contexts 때문에 아무리 Z-index값을 주더라도 해당 컴포넌트는 무조건 아래에 위치하게 된다. 그래서, 해당 컴포넌트를 부모 컴포넌트에 작성을 해서 해결을 했다.</p>
<h3 id="kpt">KPT</h3>
<h4 id="keep-🎯">KEEP 🎯</h4>
<p>다양한 라이브러리 사용 및 시도
맡은 부분에 대한 플로우 이해 후, 코드 작성</p>
<h4 id="problem-🥊">PROBLEM 🥊</h4>
<p>React query의 전체적인 흐름 이해 및 코드 작성.
Typescript Generic 문법</p>
<h4 id="try-🚀">TRY 🚀</h4>
<p>함수 및 컴포넌트 분리
타입을 작성할 시, Generic을 사용해서 확장성 좋게 하기.
htrml, css 태그 속성(option) 이해</p>
<h3 id="협업을-하면서-느낀점">협업을 하면서 느낀점</h3>
<p>이번 프로젝트가 처음으로 백엔드 개발자와 협업을 하다보니 지식의 파편화가 심했던걸 느끼게 되었다.</p>
<p>백엔드 개발자와 대화를 나누면서 백엔드와 관련된 혹은 전반적인 CS지식의 용어들이 익숙하지만 정확하게 의미를 모르다보니 대화 진행이 어려웠던 것 같았다. 물론 백엔드 개발자도 프론트 개발과 관련된 용어와 흐름을 잘 몰랐기 때문에 의사소통이 잘 되지 않았던 것 같았다.</p>
<p>해당 상황에 대한 개발 용어들을 사용하게 된다면 의미를 아는 사람은 정확하게 이해를 하지만, 모르는 사람일 경우에는 비유나 설명을 간단하게 해서 상대방을 이해시켜야한다. 프론트 엔드 개발자는 PM, 디자이너, 백엔드 등 다양한 부서(직군)과 연결이 되어있기 때문에 <strong>커뮤니케이션</strong> 능력이 매우 중요하다고 생각했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux 사용 정리]]></title>
            <link>https://velog.io/@yongyong_21/Redux-%EC%82%AC%EC%9A%A9-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@yongyong_21/Redux-%EC%82%AC%EC%9A%A9-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 31 Oct 2023 05:52:58 GMT</pubDate>
            <description><![CDATA[<h1 id="redux-사용-정리">Redux 사용 정리</h1>
<h3 id="예제-count값을-변경-해주는-버튼">예제) Count값을 변경 해주는 버튼</h3>
<h2 id="1-createslice">1. createSlice</h2>
<pre><code class="language-tsx">// Slice.ts
import { createSlice, PayloadAction } from &quot;@reduxjs/toolkit&quot;;

// 상태의 초기 상태 정의
const initialState: { value: number } = { value: 0 };

// 리듀서 및 액션 생성기 생성
const counterSlice = createSlice({
  name: &quot;counter&quot;,
  initialState,
  reducers: {
    increment: (state) =&gt; {
      state.value += 1;
    },
    decrement: (state) =&gt; {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction&lt;number&gt;) =&gt; {
      state.value += action.payload;
    },
  },
});

// 액션 생성자 내보내기
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// 리듀서 내보내기
export default counterSlice.reducer;
</code></pre>
<p>initialState: 초기 상태값을 정의하고 타입 지정(ts를 사용할 시 )</p>
<p>reducers: 해당 객체내에서 다양한 액션에 대해 함수 정의
만약, 함수에 파라미터값을 넣을려면 action으로 파라미터 값을 받고 action.payload를 사용한다.
타입은 PayloadAction&lt;타입지정&gt;을 사용하고 import를 해서 사용</p>
<p>export를 사용하여 액션 함수와 리듀서를 내보낸다.</p>
<h2 id="2-configurestore">2. configureStore</h2>
<pre><code class="language-tsx">import { configureStore } from &quot;@reduxjs/toolkit&quot;;
import counterReducer from &quot;./counterSlice&quot;;

const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

export type RootState = ReturnType&lt;typeof store.getState&gt;;

export default store;</code></pre>
<p>state 관리하는 것들을 보관하는 파일</p>
<p>store에 configureStore을 사용하여 해당 reduce을 정리한다.</p>
<pre><code class="language-tsx">export type RootState = ReturnType&lt;typeof store.getState&gt;;</code></pre>
<p>을 사용하여 ReturnType을 추론하여 RootState에 타입을 보관한다. </p>
<p>이렇게하면 다른 컴포넌트에서 import를 할 때, useSelector의 state를 쉽게 타입을 지정할 수 있다.</p>
<h2 id="3-해당-컴포넌트-사용">3. 해당 컴포넌트 사용</h2>
<pre><code class="language-tsx">//Counter.tsx
import React from &quot;react&quot;;
import { useDispatch, useSelector } from &quot;react-redux&quot;;
import { increment, decrement, incrementByAmount } from &quot;./counterSlice&quot;;
import { RootState } from &quot;./store&quot;;
import { Dispatch } from &quot;redux&quot;;

const Counter: React.FC = () =&gt; {
  const dispatch: Dispatch = useDispatch();
  const count = useSelector((state: RootState) =&gt; state.counter.value);

  return (
    &lt;div&gt;
      &lt;h2&gt;카운터&lt;/h2&gt;
      &lt;p&gt;값: {count}&lt;/p&gt;
      &lt;button onClick={() =&gt; dispatch(increment())}&gt;증가&lt;/button&gt;
      &lt;button onClick={() =&gt; dispatch(decrement())}&gt;감소&lt;/button&gt;
      &lt;button onClick={() =&gt; dispatch(incrementByAmount(5))}&gt;5 증가&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default Counter;
</code></pre>
<p>컴포넌트에서 사용을 할 때, useDispatch와 useSelector을 import해야한다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux 설치 및 세팅]]></title>
            <link>https://velog.io/@yongyong_21/Redux-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%B8%ED%8C%85</link>
            <guid>https://velog.io/@yongyong_21/Redux-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%B8%ED%8C%85</guid>
            <pubDate>Tue, 31 Oct 2023 01:40:53 GMT</pubDate>
            <description><![CDATA[<h1 id="redux-설치-및-세팅">Redux 설치 및 세팅</h1>
<h2 id="redux-사용하는-이유">Redux 사용하는 이유</h2>
<ul>
<li>컴포넌트가 많을 경우, props drilling 방지</li>
<li>불변성 유지</li>
<li>모든 컴포넌트에서 state관리</li>
</ul>
<h2 id="설치">설치</h2>
<pre><code class="language-cli">npm install @reduxjs/toolkit react-redux 
npm install -D redux-devtools //  크롬브라우저 확장프로그램 연동을 위한 설치</code></pre>
<h2 id="세팅">세팅</h2>
<ol>
<li>store.js / store.tsx 파일 만들기<pre><code class="language-tsx">// store 파일
import { configureStore } from &quot;@reduxjs/toolkit&quot;;
</code></pre>
</li>
</ol>
<p>export default configureStore({
  reducer: {},
});</p>
<pre><code>
2. index.js / main.tsx 파일 수정
```tsx
import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom/client&quot;;
import App from &quot;./App.tsx&quot;;

import { Provider } from &quot;react-redux&quot;; // 추가
import store from &quot;./store.tsx&quot;; // 추가

ReactDOM.createRoot(document.getElementById(&quot;root&quot;)!).render(
  &lt;Provider store={store}&gt; // Provider에 store 사용이 가능하게 추가
    &lt;React.StrictMode&gt;
      &lt;App /&gt;
    &lt;/React.StrictMode&gt;
  &lt;/Provider&gt;
);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 기획 저장용]]></title>
            <link>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%ED%9A%8D-%EC%A0%80%EC%9E%A5%EC%9A%A9</link>
            <guid>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B8%B0%ED%9A%8D-%EC%A0%80%EC%9E%A5%EC%9A%A9</guid>
            <pubDate>Mon, 16 Oct 2023 08:16:59 GMT</pubDate>
            <description><![CDATA[<h1 id="프로젝트-기획">프로젝트 기획</h1>
<h2 id="프로젝트-주제">프로젝트 주제</h2>
<p>자기소개 페이지 (이력서 페이지)</p>
<h2 id="기능">기능</h2>
<p>스크롤 이벤트
메일 보내기 기능</p>
<h2 id="사용-라이브러리">사용 라이브러리</h2>
<ul>
<li>React / TypeScript</li>
<li>Build: vite</li>
<li>Style: emotion</li>
<li>eslint / prettier</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React]  프로젝트 초기세팅 (개인적 저장용)]]></title>
            <link>https://velog.io/@yongyong_21/React-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0%EC%84%B8%ED%8C%85-%EA%B0%9C%EC%9D%B8%EC%A0%81-%EC%A0%80%EC%9E%A5%EC%9A%A9</link>
            <guid>https://velog.io/@yongyong_21/React-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0%EC%84%B8%ED%8C%85-%EA%B0%9C%EC%9D%B8%EC%A0%81-%EC%A0%80%EC%9E%A5%EC%9A%A9</guid>
            <pubDate>Tue, 03 Oct 2023 20:29:34 GMT</pubDate>
            <description><![CDATA[<h1 id="react-초기세팅">[React] 초기세팅</h1>
<p>리액트 프로젝트를 기본적으로 구성하는 것들을 주로 작성</p>
<h2 id="프로젝트-생성">프로젝트 생성</h2>
<h3 id="1-cra">1. CRA</h3>
<pre><code>npx create-reat-app [프로젝트명]
npx create-react-app [프로젝트명] --template typescript</code></pre><h3 id="2-vite">2. Vite</h3>
<pre><code>npm create vite@latest [프로젝트 명] 
npm create vite@latest [프로젝트 명] --template react-ts</code></pre><p>CRA와 Vite 방식으로 프로젝트를 생성할 수 있는데, CRA로 프로젝트를 만들면서 빌드가 매우 느렸던 것을 경험하게 되었다.</p>
<p>그래서 Vite를 사용해보니 빌드가 CRA보다 상대적으로 빠르다는 것을 경험하게 되었다.</p>
<h2 id="eslint-파일">Eslint 파일</h2>
<pre><code class="language-js">module.exports = {
  root: true,
  env: { browser: true, es2020: true }, // 브라우저 환경 및 ES2020 환경 설정

  extends: [
    &quot;eslint:recommended&quot;, // ESLint의 기본 권장 규칙 사용
    &quot;plugin:@typescript-eslint/recommended&quot;, // TypeScript 관련 권장 규칙 사용
    &quot;plugin:react-hooks/recommended&quot;, // React Hooks 규칙 사용
  ],

  ignorePatterns: [&quot;dist&quot;, &quot;.eslintrc.cjs&quot;], // ESLint 무시할 파일 또는 디렉토리 설정

  parser: &quot;@typescript-eslint/parser&quot;, // TypeScript 구문 분석기 사용

  plugins: [&quot;react-refresh&quot;], // React Refresh 플러그인 사용

  rules: {
    &quot;react-refresh/only-export-components&quot;: [
      &quot;warn&quot;,
      { allowConstantExport: true },
    ], // React 컴포넌트는 오직 컴포넌트만 내보내야 합니다.

    indent: [&quot;error&quot;, 2], // 들여쓰기 스타일 설정 (2칸 들여쓰기)

    &quot;no-unused-vars&quot;: &quot;off&quot;, // 사용하지 않는 변수 경고 끄기

    &quot;@typescript-eslint/no-unused-vars&quot;: [
      &quot;error&quot;,
      { vars: &quot;all&quot;, args: &quot;after-used&quot;, ignoreRestSiblings: false },
    ], // TypeScript에서 사용하지 않는 변수를 검출합니다.

    &quot;@typescript-eslint/explicit-function-return-type&quot;: &quot;warn&quot;,
    // 함수의 반환 타입이 추론 가능할 때도 명시적으로 타입을 선언하도록 경고합니다.

    &quot;no-empty&quot;: &quot;warn&quot;, // 빈 블록문에 대한 경고 설정

    semi: [&quot;error&quot;, &quot;always&quot;], // 세미콜론(;) 사용 강제 설정
  },
};</code></pre>
<h2 id="prettier">Prettier</h2>
<pre><code class="language-js">npm install -D prettier</code></pre>
<pre><code class="language-js">// .eslintrc
{
  &quot;extends&quot;: [&quot;plugin:prettier/recommended&quot;]
}</code></pre>
<p>prettier 설치 시, .eslintrc가 있으면 extends에 추가</p>
<pre><code class="language-js">// .prettierrc
{
  &quot;printWidth&quot;: 80,
  &quot;tabWidth&quot;: 2,
  &quot;useTabs&quot;: false,
  &quot;semi&quot;: true,
  &quot;singleQuote&quot;: false,
  &quot;quoteProps&quot;: &quot;as-needed&quot;,
  &quot;jsxSingleQuote&quot;: false,
  &quot;trailingComma&quot;: &quot;none&quot;,
  &quot;bracketSpacing&quot;: true,
  &quot;jsxBracketSameLine&quot;: false,
  &quot;arrowParens&quot;: &quot;always&quot;,
  &quot;endOfLine&quot;: &quot;auto&quot;
}
</code></pre>
<h2 id="라이브러리">라이브러리</h2>
<h3 id="css">CSS</h3>
<h4 id="1-styled-components">1. styled-components</h4>
<pre><code>npm install styled-components</code></pre><h4 id="2-emotion">2. emotion</h4>
<pre><code>npm install @emotion/react</code></pre><pre><code>{  // tsconfig.json
  &quot;compilerOptions&quot;: {
    ...
    &quot;types&quot;: [&quot;@emotion/react/types/css-prop&quot;] // 추가
  }
}</code></pre><p>styled-components를 사용했더니, 컴포넌트 태그가 스타일 컴포넌트인지 혹은 UI가 있는 컴포넌트인지 눈으로 쉽게 확인을 할 수 없었던 경험이 있다.</p>
<p>그러다보니, 개인적인 프로젝트 스타일 라이브러리는 emotion을 사용을 한다.</p>
<hr>
<h3 id="router">Router</h3>
<pre><code>npm install react-router-dom</code></pre><hr>
<h3 id="state-관리">State 관리</h3>
<h4 id="redux">Redux</h4>
<pre><code>npm install redux react-redux
npm install @reduxjs/toolkit react-redux
npm install -D redux-devtools //  크롬브라우저 확장프로그램 연동을 위한 설치</code></pre><h4 id="recoil">Recoil</h4>
<pre><code>npm install recoil
</code></pre><h2 id="폴더-구조">폴더 구조</h2>
<p>Project/
  ├── src/
  │    ├── components/        # React 컴포넌트들
  │    ├── pages/             # 페이지 컴포넌트들 (라우팅)
  │    ├── styles/            # CSS 스타일 및 스타일 유틸리티
  │    ├── assets/            # 이미지, 폰트 등
  │    └── App.js / App.tsx 
  ├── public/
  │    ├── index.html         # HTML 템플릿 파일
  │    └── ...
  ├── package.json            # 프로젝트 설정 및 의존성
  ├── .eslintrc.json          # ESLint 설정 파일
  ├── .prettierrc              # Prettier 설정 파일
  └── ...</p>
<hr>
<h5 id="이-글은-프로젝트를-만들면서-수정이-계속-될-예정">이 글은 프로젝트를 만들면서 수정이 계속 될 예정</h5>
]]></description>
        </item>
        <item>
            <title><![CDATA[[패스트캠퍼스X야놀자] 프론트엔드 개발 부트캠프_JavScript과제 리펙토링]]></title>
            <link>https://velog.io/@yongyong_21/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84JavScript%EA%B3%BC%EC%A0%9C-%EB%A6%AC%ED%8E%99%ED%86%A0%EB%A7%81</link>
            <guid>https://velog.io/@yongyong_21/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84JavScript%EA%B3%BC%EC%A0%9C-%EB%A6%AC%ED%8E%99%ED%86%A0%EB%A7%81</guid>
            <pubDate>Mon, 28 Aug 2023 06:50:14 GMT</pubDate>
            <description><![CDATA[<h1 id="패스트캠퍼스x야놀자-프론트엔드-개발-부트캠프_javscript과제-리펙토링">[패스트캠퍼스X야놀자] 프론트엔드 개발 부트캠프_JavScript과제 리펙토링</h1>
<h2 id="배포링크-httpsthriving-fenglisu-0e5367netlifyapp">배포링크: <a href="https://thriving-fenglisu-0e5367.netlify.app/">https://thriving-fenglisu-0e5367.netlify.app/</a></h2>
<h2 id="레포지토리-httpsgithubcomyongyong21javascript">레포지토리: <a href="https://github.com/YongYong21/javascript">https://github.com/YongYong21/javascript</a></h2>
<h2 id="사용언어">사용언어</h2>
<p>HTML, CSS, JavaScript</p>
<h2 id="리펙토링-한-부분">리펙토링 한 부분</h2>
<h3 id="수정-전">수정 전</h3>
<pre><code class="language-js"> const userList = `
        &lt;tr data-name=&quot;${data.name}&quot;&gt;
        &lt;td class=&#39;check&#39;&gt;&lt;input type=&quot;checkbox&quot; &gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src=&quot;&quot; id=&quot;${data.key}&quot;&gt;&lt;/td&gt;
        &lt;td&gt;&lt;span&gt;${data.name}&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;&lt;span&gt;${data.email}&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;&lt;span&gt;${data.phone}&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;&lt;span&gt;${data.classification}&lt;/span&gt;&lt;/td&gt;
        &lt;td&gt;&lt;button class=&#39;profile-btn&#39;&gt;프로필 보기&lt;/button&gt;&lt;/td&gt;
        &lt;/tr&gt;`;
        $(&quot;tbody&quot;).append(userList);

        // ... </code></pre>
<h3 id="수정-후">수정 후</h3>
<pre><code class="language-js">function createUserRow(data){
  return `
    &lt;tr data-name=&quot;${data.name}&quot;&gt;
      &lt;td class=&#39;check&#39;&gt;&lt;input type=&quot;checkbox&quot;&gt;&lt;/td&gt;
      &lt;td&gt;&lt;img src=&quot;&quot; id=&quot;${data.key}&quot;&gt;&lt;/td&gt;
      &lt;td&gt;&lt;span&gt;${data.name}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;&lt;span&gt;${data.email}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;&lt;span&gt;${data.phone}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;&lt;span&gt;${data.classification}&lt;/span&gt;&lt;/td&gt;
      &lt;td&gt;&lt;button class=&#39;profile-btn&#39;&gt;View Profile&lt;/button&gt;&lt;/td&gt;
    &lt;/tr&gt;`;
};

const userList = createUserRow(data);</code></pre>
<p>가독성을 좋게 하기위해 함수로 빼두었습니다.</p>
<h3 id="수정-전-1">수정 전</h3>
<pre><code class="language-js">function getRandomPhoneNumber() {
  var phoneNumber = &quot;010&quot;;
  for (var i = 0; i &lt; 8; i++) {
      // ...
  }
</code></pre>
<h3 id="수정-후-1">수정 후</h3>
<pre><code class="language-js">function getRandomPhoneNumber() {
  var phoneNumber = &quot;010&quot;;
  for (let i = 0; i &lt; 8; i++) {
      // ...
  }</code></pre>
<p>var을 쓰던 버릇이 있어서 몇몇 변수들이 var로 선언이 되어서 let or const로 수정했습니다.</p>
<h3 id="수정-전-2">수정 전</h3>
<pre><code class="language-js">Promise.all(promises).then(() =&gt; {
    localStorage.setItem(&quot;hasExecuted&quot;, true);
    window.location.href = &quot;index.html&quot;;
  });</code></pre>
<h3 id="수정-후-2">수정 후</h3>
<pre><code class="language-js">await Promise.all(promises);
  localStorage.setItem(&quot;hasExecuted&quot;, true);
  window.location.href = &quot;index.html&quot;;</code></pre>
<p>비동기 처리를 하는 부분을 then보다는 await를 이용하여 작성하는 것으로 수정했습니다,</p>
<h2 id="과제-느낀점">과제 느낀점</h2>
<p>과제를 하면서 느꼈던 점은 아무래도 비동기 작업을 구현하는 부분에서 시간을 걸렸던 것 같습니다.</p>
<p>서버와 데이터를 주고 받는 것이 많은 경험이 없다보니, 구현하는데 어려웠던 것 같습니다. 또한, 서버로부터 정보를 가져오는 것이 비동기적으로 이루어지기 때문에 소스가 생각대로 실행이 되지 않았던 것도 주된 이유였던 것 같습니다.</p>
<p>바닐라 자바스크립트로 구현을 할려고 했으나 많이 복잡하고 비효율적인 것 같아서 J Query를 이용해서 구현하는데 많이 편했던 것 같습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 비동기 패턴: 직렬과 병렬처리 및 안티패턴]]></title>
            <link>https://velog.io/@yongyong_21/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%A8%ED%84%B4-%EC%A7%81%EB%A0%AC%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@yongyong_21/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%8C%A8%ED%84%B4-%EC%A7%81%EB%A0%AC%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Fri, 25 Aug 2023 09:57:02 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-비동기-패턴-직렬과-병렬처리-및-안티패턴">[JavaScript] 비동기 패턴: 직렬과 병렬처리 및 안티패턴</h1>
<h2 id="전체-코드">전체 코드</h2>
<pre><code class="language-js">      async function fetchDataAsync(id) {
        return new Promise((resolve, reject) =&gt; {
          setTimeout(() =&gt; {
            const data = { id, name: &quot;John&quot; + id };
            if (data) {
              resolve(data);
            } else {
              reject(&quot;Data not found&quot;);
            }
          }, Math.random()*1000); 
        });
      }

      async function fetchDataSerially() {
        const dataArray = [];

        for (let i = 1; i &lt;= 5; i++) {
          try {
            const data = await fetchDataAsync(i);
            dataArray.push(data);
            console.log(&quot;Data:&quot;, data);
          } catch (error) {
            console.error(&quot;Error:&quot;, error);
          }
        }
        console.log(&quot;Data Array:&quot;, dataArray);
      }

      fetchDataSerially();


      async function fetchDataParallel() {
        try {
          const promises = [];
          for (let i = 1; i &lt;= 5; i++) {
            promises.push(fetchDataAsync(i));
          }
          const dataArray = await Promise.all(promises);
          console.log(&quot;Data Array:&quot;, dataArray);
        } catch (error) {
          console.error(&quot;Error:&quot;, error);
        }
      }

      fetchDataParallel();

      async function fetchDataForEach() {
        const dataArray = [];

        [1, 2, 3, 4, 5].forEach(async (i) =&gt; {
          try {
            const data = await fetchDataAsync(i);
            dataArray.push(data);
            console.log(&quot;Data:&quot;, data);
          } catch (error) {
            console.error(&quot;Error:&quot;, error);
          }
        });

        console.log(&quot;Data Array:&quot;, dataArray);
      }

      fetchDataForEach();</code></pre>
<h2 id="비동기-함수">비동기 함수</h2>
<pre><code class="language-js"> async function fetchDataAsync(id) {
     return new Promise((resolve, reject) =&gt; {
         setTimeout(() =&gt; {
            const data = { id, name: &quot;John&quot; + id };
            if (data) {
              resolve(data);
            } else {
              reject(&quot;Data not found&quot;);
            }
        }, Math.random()*1000); 
    });
}</code></pre>
<p>무작위 시간이 지나고 data를 반환하도록 하는 비동기 함수입니다.</p>
<h2 id="직렬처리-코드">직렬처리 코드</h2>
<pre><code class="language-js">async function fetchDataSerially() {
    const dataArray = [];

    for (let i = 1; i &lt;= 5; i++) {
        try {
            const data = await fetchDataAsync(i);
            dataArray.push(data);
            console.log(&quot;Data:&quot;, data);
          } catch (error) {
            console.error(&quot;Error:&quot;, error);
          }
     }
     console.log(&quot;Data Array:&quot;, dataArray);
}

fetchDataSerially(); 
// 출력결과
// Data: {id: 1, name: &#39;John1&#39;}
// Data: {id: 2, name: &#39;John2&#39;}
// Data: {id: 3, name: &#39;John3&#39;}
// Data: {id: 4, name: &#39;John4&#39;}
// Data: {id: 5, name: &#39;John5&#39;}
// Data Array: (5) [{…}, {…}, {…}, {…}, {…}]</code></pre>
<p>직렬처리는 비동기 작업을 순차적으로 처리합니다.</p>
<p>이전의 작업이 완료가 되어야 다음 작업을 시작하는 방식입니다.</p>
<h3 id="직렬-처리-장점">직렬 처리 장점</h3>
<ul>
<li>순서 보장</li>
<li>의존성 처리</li>
<li>안정성</li>
</ul>
<h3 id="직렬-처리-단점">직렬 처리 단점</h3>
<ul>
<li>성능 저하</li>
<li>병목 현상</li>
</ul>
<h2 id="병렬처리-코드">병렬처리 코드</h2>
<pre><code class="language-js">async function fetchDataParallel() {
    try {
        const promises = [];
        for (let i = 1; i &lt;= 5; i++) {
            promises.push(fetchDataAsync(i));
        }
        const dataArray = await Promise.all(promises);
        console.log(&quot;Data Array:&quot;, dataArray);
        } catch (error) {
          console.error(&quot;Error:&quot;, error);
        }
}

fetchDataParallel();
// 출력결과: Data Array: (5) [{…}, {…}, {…}, {…}, {…}]</code></pre>
<p>Promise.all은 내부적으로 비동기 작업을 병렬로 처리하고 결과를 모아서 반환합니다. </p>
<p>이 비동기 작업은 싱글 스레드에서 병렬적으로 처리되는 것은 아니지만, 비동기 특성을 활용하여 효과적인 병렬 작업 처리를 구현한 것입니다.</p>
<h3 id="병렬처리-장점">병렬처리 장점</h3>
<ul>
<li>성능 향상</li>
<li>자원활용</li>
<li>응답성 향상</li>
<li>대기시간 감소</li>
</ul>
<h3 id="병렬처리-단점">병렬처리 단점</h3>
<ul>
<li>동기화와 동시성 관리</li>
<li>코드 복잡성</li>
<li>데이터 일관성</li>
<li>병렬화 비용</li>
</ul>
<h2 id="foreach-안티패턴">forEach 안티패턴</h2>
<pre><code class="language-js">async function fetchDataForEach() {
    const dataArray = [];

    [1, 2, 3, 4, 5].forEach(async (i) =&gt; {
        try {
            const data = await fetchDataAsync(i);
            dataArray.push(data);
            console.log(&quot;Data:&quot;, data);
          } catch (error) {
            console.error(&quot;Error:&quot;, error);
          }
    });

    console.log(&quot;Data Array:&quot;, dataArray);
}

fetchDataForEach();
// 출력결과
// Data Array: []
// Data: {id: 2, name: &#39;John2&#39;}
// Data: {id: 5, name: &#39;John5&#39;}
// Data: {id: 1, name: &#39;John1&#39;}
// Data: {id: 4, name: &#39;John4&#39;}
// Data: {id: 3, name: &#39;John3&#39;}</code></pre>
<p>위의 코드는 비동기 콜백 함수가 async로 선언되어 있어도, forEach 안에서는 각 비동기 작업이 병렬로 실행되지 않습니다.</p>
<p>그렇기 때문에 console.log부터 먼저 실행을 하게 되고, data를 가져오는 과정은 비동기 처리하게 됩니다.</p>
<p>forEach 안에 있는 내부의 함수가 완료되지 않는 상태에서 console.log를 하게 되면, 데이터를 가지고 오는 각 시간에 따라서 순서가 보장이 되지 않는 문제점이 있을 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 비동기 디자인 패턴(Callback, Promise, async/await)]]></title>
            <link>https://velog.io/@yongyong_21/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4Callback-Promise-asyncawait</link>
            <guid>https://velog.io/@yongyong_21/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4Callback-Promise-asyncawait</guid>
            <pubDate>Tue, 22 Aug 2023 07:20:54 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-비동기-디자인-패턴callback-promise-asyncawait">[JavaScript] 비동기 디자인 패턴(Callback, Promise, async/await)</h1>
<h2 id="callback-디자인-패턴">Callback 디자인 패턴</h2>
<pre><code class="language-js">function delay(message, callback) {
    setTimeout(() =&gt; {
        console.log(message);
        callback(); 
    }, 1000); 
}

console.log(&quot;1&quot;);
delay(&quot;2&quot;, () =&gt; {
    console.log(&quot;3&quot;); 
});
console.log(&quot;4&quot;); // 출력결과 1 4 2 3</code></pre>
<p>콜백 패턴은 비동기 작업을 다루는 가장 기본적인 패턴이지만, 중첩된 콜백 함수들이 발생할 수 있어 가독성이나 유지 보수성 측면에서 한계가 있을 수 있습니다.</p>
<p>이를 해결하기 위해 Promise, async/await 등의 패턴이 도입되었습니다.</p>
<h2 id="promise-패턴">Promise 패턴</h2>
<pre><code class="language-js">function fetchData() {
    return new Promise((resolve, reject) =&gt; {
        setTimeout(() =&gt; {
            const data = { id: 1, name: &quot;John&quot; };
            if (data) {
                resolve(data); // 성공 시 데이터 전달
            } 
            else {
                reject(&quot;Data not found&quot;); // 실패 시 오류 메시지 전달
            }
        }, 1000);
    });
}

fetchData()
    .then((data) =&gt; {
        console.log(data); // 출력 {id: 1, name: &#39;John&#39;}
    })
    .catch((error) =&gt; {
        console.error(error);
    }); </code></pre>
<p>Promise는 JavaScript에서 비동기 작업을 더 효율적으로 다룰 수 있도록 도와주는 객체입니다.</p>
<p>비동기 작업을 수행하고 해당 작업의 <strong>성공</strong> 또는 <strong>실패</strong> 결과를 처리하기 위한 추상화된 방식을 제공합니다.</p>
<p>Promise는 세 가지 상태를 가집니다</p>
<p><strong>Pending (대기):</strong> 비동기 작업이 아직 완료되지 않은 상태입니다.
<strong>resolved (성공):</strong> 비동기 작업이 성공적으로 완료된 상태입니다. 결과 값이 있습니다.
<strong>Rejected (실패)</strong>: 비동기 작업이 실패한 상태입니다. 오류 정보가 있습니다.</p>
<h2 id="async--await-패턴">async / await 패턴</h2>
<pre><code class="language-js">async function fetchDataAsync() {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      const data = { id: 1, name: &quot;John&quot; };
      if (data) {
        resolve(data);
      } else {
        reject(&quot;Data not found&quot;);
      }
    }, 1000);
  });
}

async function main() {
  try {
    const data = await fetchDataAsync();
    console.log(&quot;Data:&quot;, data);
  } catch (error) {
    console.error(&quot;Error:&quot;, error);
  }
}

main();
</code></pre>
<p>async는 JavaScript에서 비동기 작업을 보다 쉽게 다룰 수 있도록 도와주는 키워드입니다.</p>
<p>async 함수를 사용하면 코드를 동기적으로 작성하듯이 비동기 작업을 다룰 수 있게 됩니다.</p>
<p>await 키워드 다음에는 Promise가 위치하며, 해당 Promise가 완료될 때까지 함수의 실행을 일시 중지하고 기다립니다.</p>
<p>Promise는 resolve, reject를 사용했지만 async는 Promise와 다르게 성공과 실패를 try catch 문법을 사용하여 에러를 구분합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java Script] 자바스크립트 동작원리( 동기, 비동기)]]></title>
            <link>https://velog.io/@yongyong_21/Java-Script-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0</link>
            <guid>https://velog.io/@yongyong_21/Java-Script-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0</guid>
            <pubDate>Tue, 22 Aug 2023 06:47:12 GMT</pubDate>
            <description><![CDATA[<h1 id="java-script-자바스크립트--동작원리-동기-비동기">[Java Script] 자바스크립트  동작원리( 동기, 비동기)</h1>
<h2 id="자바스크립트의-런타임-이미지">자바스크립트의 런타임 이미지</h2>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/06d1be13-3792-4de1-9667-ba2de9297c8d/image.png" alt=""></p>
<h3 id="이미지-설명">이미지 설명</h3>
<p>*<em>Heap: *</em></p>
<p>힙은 동적으로 할당된 메모리 공간으로, 객체와 변수들이 저장되는 곳입니다.</p>
<p>JavaScript에서 객체와 배열은 힙에 저장되며, 할당된 메모리 공간은 더 이상 사용하지 않을 때 가비지 컬렉터에 의해 해제됩니다.</p>
<p><strong>스택(Stack):</strong></p>
<p>스택은 함수 호출과 관련된 메모리 공간으로, 함수 호출 시 지역 변수와 매개변수 등이 저장됩니다.</p>
<p>함수가 호출되면 해당 함수의 스택 프레임이 생성되고, 함수의 실행이 끝나면 스택 프레임이 제거됩니다. 이를 통해 함수의 호출과 복귀를 관리합니다.
**
Web API:**</p>
<p>Web API는 브라우저가 제공하는 인터페이스로, 브라우저 환경에서 비동기 작업을 처리하고 외부 리소스에 접근할 수 있도록 도와줍니다.</p>
<p>setTimeout, XMLHttpRequest, fetch 등의 비동기 함수들은 Web API를 사용하여 작동합니다.</p>
<p><strong>콜백 큐(Callback Queue):</strong></p>
<p>콜백 큐는 비동기 작업의 콜백 함수들이 대기하는 공간입니다.</p>
<p>비동기 작업의 결과나 완료 시 콜백 함수가 호출되어야 할 때, 해당 함수들은 콜백 큐에 저장되어 기다리게 됩니다.</p>
<h3 id="자바스크립트의-동작-특징">자바스크립트의 동작 특징</h3>
<p>자바스크립트의 동작 특징중에 하나인 싱글 스레드는 한 번에 하나의 작업만을 처리할 수 있습니다.</p>
<p>스레드: 프로세스 내에서 실행되는 작은 실행 단위로, 프로그램의 코드 실행 흐름을 나타냅니다.</p>
<p>JavaScript 코드가 메인 스레드에서 실행되며, 다른 작업은 메인 스레드가 이벤트 루프를 통해 비동기적으로 처리하는 방식을 가지고 있습니다.</p>
<p>싱글 스레드 환경에서 비동기 작업을 처리하려면 이벤트 루프와 콜백 함수, Promise, async/await과 같은 메커니즘을 사용하여 비동기 작업을 대기하고 처리합니다.</p>
<h3 id="예시-코드">예시 코드</h3>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/06d1be13-3792-4de1-9667-ba2de9297c8d/image.png" alt=""></p>
<pre><code class="language-js">console.log(1)
setTimeout(()=&gt;{
  console.log(2)
}
console.log(3) // 출력결과 1 3 2</code></pre>
<h3 id="실행-설명">실행 설명</h3>
<ol>
<li><p>console.log(1) 실행: 이 부분은 동기적으로 실행됩니다. 콘솔에 &quot;1&quot;이 출력됩니다.</p>
</li>
<li><p>setTimeout 함수 호출: 내부의 콜백 함수가 Web API로 이동하여 지정된 시간 후에 실행되도록 예약됩니다</p>
</li>
<li><p>console.log(3) 실행: 이 부분은 동기적으로 실행됩니다. 콘솔에 &quot;3&quot;이 출력됩니다.</p>
</li>
<li><p>이벤트 루프와 콜백 큐: setTimeout 함수가 예약한 콜백 함수가 실행될 차례입니다.</p>
<p>메인 스레드의 실행이 모두 끝나고 콜백 큐에 있는 작업이 실행 대기 상태가 됩니다.</p>
</li>
<li><p>콜백 함수 실행: 콜백 큐에 있는 콜백 함수가 메인 스레드의 실행이 완료된 후에 실행됩니다. 따라서 &quot;2&quot;가 콘솔에 출력됩니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 데이터 타입의 종류 및 참조 타입에 대해]]></title>
            <link>https://velog.io/@yongyong_21/JavaScript-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%9D%98-%EC%A2%85%EB%A5%98-%EB%B0%8F-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%B4</link>
            <guid>https://velog.io/@yongyong_21/JavaScript-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%9D%98-%EC%A2%85%EB%A5%98-%EB%B0%8F-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%B4</guid>
            <pubDate>Mon, 21 Aug 2023 05:22:49 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-데이터-타입의-종류-및-참조-타입에-대해">[JavaScript] 데이터 타입의 종류 및 참조 타입에 대해</h1>
<h2 id="원시-데이터-타입-primitive-data-types">원시 데이터 타입 (Primitive Data Types):</h2>
<p> 원시 데이터 타입은 값 자체가 변수에 저장되며, 변수 사이에 값이 복사될 때 실제 데이터가 복사됩니다.</p>
<p> 이러한 데이터 타입은 불변(immutable)하다는 특징을 가지며, 값을 변경하려면 새로운 값을 할당해야 합니다.</p>
<h2 id="원시-데이터-타입의-종류">원시 데이터 타입의 종류</h2>
<p><strong>숫자(Number)</strong>: 정수와 부동소수점 숫자를 포함합니다. 예: 42, 3.14.</p>
<p><strong>문자열(String):</strong> 문자들의 시퀀스입니다. 작은따옴표나 큰따옴표로 둘러싸인 텍스트입니다. 예: &#39;Hello, world!&#39;.</p>
<p><strong>불리언(Boolean):</strong> true나 false 값을 가집니다. 조건식 평가 등에 사용됩니다.</p>
<p><strong>null:</strong> 값이 없음을 나타냅니다. 변수에 명시적으로 값을 주지 않을 때 자동으로 할당됩니다.</p>
<p><strong>undefined:</strong> 값을 할당하지 않은 변수의 초기값입니다. 또는 함수 내에서 반환값이 없는 경우의 기본 반환값입니다.</p>
<p><strong>심볼(Symbol):</strong> 유일한 식별자를 생성하는 데 사용되는 원시 값입니다. 주로 객체 속성의 키로 사용됩니다.</p>
<h2 id="복합-데이터-타입-참조-타입-reference-data-types">복합 데이터 타입 (참조 타입, Reference Data Types)</h2>
<p>avaScript의 복합 데이터 타입은 객체와 배열을 포함합니다. 
이러한 데이터 타입은 값 대신 메모리 주소(참조)를 가리키며, 변수에 할당할 때 메모리 주소가 할당됩니다.</p>
<p>복합 데이터 타입은 변수에 메모리 주소(참조)가 할당되며, 변수 간에 복사될 때 메모리 주소가 복사됩니다. 
따라서 여러 변수가 동일한 객체나 배열을 참조할 수 있습니다. 이로 인해 한 변수에서 객체나 배열의 내용을 변경하면, 모든 해당 변수에서 변경 내용을 볼 수 있습니다.</p>
<h3 id="복합-데이터-타입의-종류">복합 데이터 타입의 종류</h3>
<p><strong>객체(Object):</strong> 여러 속성(key-value 쌍)을 포함하는 데이터 구조입니다. 객체의 속성은 다양한 데이터 타입을 포함할 수 있습니다.</p>
<p><strong>배열(Array):</strong> 값의 목록으로, 순서에 따라 접근할 수 있는 인덱스를 가지고 있습니다. 모든 원소가 동일한 데이터 타입일 필요는 없습니다.</p>
<p><strong>함수(Function):</strong> 코드 블록을 나타내며, 재사용 가능한 작업 단위입니다.</p>
<p><strong>날짜(Date):</strong> 특정 날짜와 시간 정보를 나타내는 객체입니다.</p>
<h2 id="데이터-복사copy에-대해">데이터 복사(Copy)에 대해</h2>
<h3 id="원시-데이터-타입-primitive-data-types-1">원시 데이터 타입 (Primitive Data Types)</h3>
<pre><code class="language-js">let name1 = &quot;kim&quot;;
let name2 = name1;
name1 = &quot;park&quot;;
console.log(name1); // park
console.log(name2); // kim</code></pre>
<p>원시 데이터 타입은 값 자체가 변수에 저장되며, 변수 사이에 값이 복사될 때 실제 데이터가 복사됩니다.
따라서 name1과 name2는 각각 서로 다른 데이터값을 가지게 됩니다.</p>
<h3 id="복합-데이터-타입-참조-타입-reference-data-types-1">복합 데이터 타입 (참조 타입, Reference Data Types)</h3>
<pre><code class="language-js">const person1 = { name: &quot;kim&quot; };
const person2 = person1;
person1.name = &quot;park&quot;;
console.log(person1.name) // park
console.log(person2.name) // park</code></pre>
<p>복합 데이터 타입은 변수에 메모리 주소(참조)가 할당되며, 변수 간에 복사될 때 메모리 주소가 복사됩니다. </p>
<p>참조 타입에서 변수에 할당되는 메모리 주소는 힙(heap)이라는 메모리 영역에 할당됩니다.</p>
<p>따라서 여러 변수가 동일한 객체나 배열을 참조할 수 있습니다.</p>
<h2 id="복합-데이터-타입-비교-연산">복합 데이터 타입 비교 연산</h2>
<pre><code class="language-js">const person1 = { name: &quot;kim&quot; };
const person2 = { name: &quot;kim&quot; };

console.log(person1 == person2); // false
console.log(person1 === person2); // false</code></pre>
<p>객체의 내용이 동일하더라도, 이들은 서로 다른 메모리 주소를 가지기 때문에 엄연히 다른 객체입니다. </p>
<p>따라서 두 객체 간의 일치 비교(===)나 동등 비교(==)는 모두 false를 반환합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[패스트캠퍼스X야놀자] 프론트엔드 개발 부트캠프_HTML/CSS 과제 카카오페이지 수정 및 기능추가]]></title>
            <link>https://velog.io/@yongyong_21/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84HTMLCSS-%EA%B3%BC%EC%A0%9C-%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%88%98%EC%A0%95-%EB%B0%8F-%EA%B8%B0%EB%8A%A5%EC%B6%94%EA%B0%80</link>
            <guid>https://velog.io/@yongyong_21/%ED%8C%A8%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%8D%BC%EC%8A%A4X%EC%95%BC%EB%86%80%EC%9E%90-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84HTMLCSS-%EA%B3%BC%EC%A0%9C-%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%88%98%EC%A0%95-%EB%B0%8F-%EA%B8%B0%EB%8A%A5%EC%B6%94%EA%B0%80</guid>
            <pubDate>Mon, 07 Aug 2023 06:26:57 GMT</pubDate>
            <description><![CDATA[<h1 id="패스트캠퍼스x야놀자-프론트엔드-개발-부트캠프_htmlcss-과제-카카오페이지-리팩토링">[패스트캠퍼스X야놀자] 프론트엔드 개발 부트캠프_HTML/CSS 과제 카카오페이지 리팩토링</h1>
<h2 id="레포지토리-주소">레포지토리 주소</h2>
<p><a href="https://github.com/YongYong21/clone-coding-kakao">https://github.com/YongYong21/clone-coding-kakao</a></p>
<h2 id="원본-주소-및-클론코딩-주소">원본 주소 및 클론코딩 주소</h2>
<p>원본주소(카카오 페이지) : <a href="https://www.kakaocorp.com/page/">https://www.kakaocorp.com/page/</a>
클론코딩 주소 : <a href="https://fantastic-cat-71b104.netlify.app/">https://fantastic-cat-71b104.netlify.app/</a></p>
<h2 id="수정-부분">수정 부분</h2>
<h3 id="hover-스타일링">hover 스타일링</h3>
<pre><code class="language-css">.header-menu:hover li{
    color: #888;
}
.header-menu &gt; li:hover  {
    color: #333;
}</code></pre>
<p>처음 생각했을 때에는, 메인 메뉴(Header nav)를 hover했을 경우 그 태그를 제외한 나머지의 색상이 바뀌게 만들어야 해서, 자바스크립트를 사용해야 되는줄 알았지만, 스타일을 덮어쓰는 방식으로 수정을 했습니다.</p>
<h2 id="추가-기능">추가 기능</h2>
<h3 id="스크롤-이벤트-리스너nav와-calender">스크롤 이벤트 리스너(Nav와 Calender)</h3>
<pre><code class="language-js">const header = document.querySelector(&quot;header&quot;)
const calenderHeader = document.querySelector(&#39;.calender-header&#39;)
let preScrollY = window.scrollY;

window.addEventListener(&#39;scroll&#39;, function(){
  if(window.scrollY &gt; 1){
    header.classList.add(&#39;brd-bt&#39;)
  }
  else {
    header.classList.remove(&#39;brd-bt&#39;)
    header.style.display = &#39;block&#39;
  }

  if(window.scrollY &gt; 100) {
    header.style.top = &#39;-70px&#39;
    calenderHeader.style.display = &#39;block&#39;
    calenderHeader.style.top = &#39;0&#39;
    if(preScrollY &gt; window.scrollY){
      header.style.top = &#39;0&#39;
      calenderHeader.style.top = &#39;73px&#39;
    }
  }
  else {
    calenderHeader.style.display = &#39;none&#39;
  }

  preScrollY = window.scrollY
})
</code></pre>
<p>스크롤을 할 때, 특정한 scrollY값에 이벤트 발생 및 스크롤 업 이벤트 발생 부분을 추가했습니다.</p>
<h3 id="max-width-1024px이하일-때-footer-메뉴-클릭-시-메뉴-버튼-보이기-첫-렌더링-페이지-기준">max-width 1024px이하일 때, Footer 메뉴 클릭 시 메뉴 버튼 보이기 (첫 렌더링 페이지 기준)</h3>
<pre><code class="language-js">const serviceContainer = document.querySelector(&quot;.service-container&quot;);
const serviceItem = document.querySelectorAll(&quot;.service-item&quot;);

if (window.innerWidth &lt;= 1024) {
  serviceContainer.addEventListener(&quot;click&quot;, (e) =&gt; {
    e.target.querySelectorAll(&quot;.service-item&quot;).forEach((item) =&gt; {
      item.classList.toggle(&quot;show&quot;);
    });
  });
}</code></pre>
<p>이용자의 해상도에 따라서 반응형 디자인이 다르다보니, 추가하게 되었습니다.</p>
<h2 id="느낀점">느낀점</h2>
<p>이번 과제는 주된 목표가 html과 css를 이용하여 클론코딩을 진행하게 되었습니다.</p>
<p>하지만 대부분의 사이트들은 자바스크립트를 이용하여 좀 더 동적으로 사이트가 구성이 되어있었습니다,</p>
<p>그렇다보니 일부 기능들을 JS로 구현을 했었지만, 구현하는 과정에서 아직 익숙하지가 않아 구현하는 시간이 오래 걸리게 되었습니다.</p>
<p>구체적으로는 JS에서 html에 작성된 DOM 객체에 대해 원하는 부분에 해당하는 속성값들을 가지고 올 때 필요한 문법과 메소드들을 활용하는 과정에서 에러가 가장 많이 나왔던 것 같습니다.</p>
<p>메소드를 활용하는 부분에서는 JS로 알고리즘 문제를 풀었던 것들이 크게 도움이 되었다고 느껴졌었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 코딩테스트 [1차] 비밀지도]]></title>
            <link>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-1%EC%B0%A8-%EB%B9%84%EB%B0%80%EC%A7%80%EB%8F%84</link>
            <guid>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-1%EC%B0%A8-%EB%B9%84%EB%B0%80%EC%A7%80%EB%8F%84</guid>
            <pubDate>Sun, 06 Aug 2023 11:10:15 GMT</pubDate>
            <description><![CDATA[<h1 id="프로그래머스-코딩테스트-1차-비밀지도">[프로그래머스] 코딩테스트 [1차] 비밀지도</h1>
<h2 id="문제">문제</h2>
<p>비밀지도
네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다행히 지도 암호를 해독할 방법을 적어놓은 메모도 함께 발견했다.</p>
<p>지도는 한 변의 길이가 n인 정사각형 배열 형태로, 각 칸은 &quot;공백&quot;(&quot; &quot;) 또는 &quot;벽&quot;(&quot;#&quot;) 두 종류로 이루어져 있다.
전체 지도는 두 장의 지도를 겹쳐서 얻을 수 있다. 각각 &quot;지도 1&quot;과 &quot;지도 2&quot;라고 하자. 지도 1 또는 지도 2 중 어느 하나라도 벽인 부분은 전체 지도에서도 벽이다. 지도 1과 지도 2에서 모두 공백인 부분은 전체 지도에서도 공백이다.
&quot;지도 1&quot;과 &quot;지도 2&quot;는 각각 정수 배열로 암호화되어 있다.
암호화된 배열은 지도의 각 가로줄에서 벽 부분을 1, 공백 부분을 0으로 부호화했을 때 얻어지는 이진수에 해당하는 값의 배열이다.
<img src="http://t1.kakaocdn.net/welcome2018/secret8.png" alt=""></p>
<p>네오가 프로도의 비상금을 손에 넣을 수 있도록, 비밀지도의 암호를 해독하는 작업을 도와줄 프로그램을 작성하라.</p>
<p>입력 형식
입력으로 지도의 한 변 크기 n 과 2개의 정수 배열 arr1, arr2가 들어온다.</p>
<p>1 ≦ n ≦ 16
arr1, arr2는 길이 n인 정수 배열로 주어진다.
정수 배열의 각 원소 x를 이진수로 변환했을 때의 길이는 n 이하이다. 즉, 0 ≦ x ≦ 2n - 1을 만족한다.
출력 형식
원래의 비밀지도를 해독하여 &#39;#&#39;, 공백으로 구성된 문자열 배열로 출력하라.</p>
<h2 id="소스">소스</h2>
<pre><code class="language-js">function solution(n, arr1, arr2) {
  const map = [];
  for (let i = 0; i &lt; n; i++) {
    const binaryMap = (arr1[i] | arr2[i]).toString(2).padStart(n, &#39;0&#39;);
    const row = binaryMap.replace(/0/g, &#39; &#39;).replace(/1/g, &#39;#&#39;);
    map.push(row);
  }
  return map;
}</code></pre>
<h2 id="문제-풀이">문제 풀이</h2>
<ul>
<li>각 주어진 배열의 인덱스 값인 정수를 이진수로 비교해야함</li>
<li><blockquote>
<p>비트 연산(|)을 활용</p>
</blockquote>
</li>
<li>이진수값이 n(한 변의 크기)보다 작으면 맨 앞에 0을 채워줘야함</li>
<li><blockquote>
<p>padstart() 메소드 사용</p>
</blockquote>
</li>
<li>이진수값을 1은 #, 0은 &#39; &#39;으로 바꿔줘야함</li>
<li><blockquote>
<p>정규식을 이용하여 replace()</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] for문에 var을 쓰면 안되는 이유]]></title>
            <link>https://velog.io/@yongyong_21/JavaScript-for%EB%AC%B8%EC%97%90-var%EC%9D%84-%EC%93%B0%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@yongyong_21/JavaScript-for%EB%AC%B8%EC%97%90-var%EC%9D%84-%EC%93%B0%EB%A9%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Thu, 03 Aug 2023 06:00:43 GMT</pubDate>
            <description><![CDATA[<h1 id="javascript-for문에-var을-쓰면-안되는-이유">[JavaScript] for문에 var을 쓰면 안되는 이유</h1>
<h3 id="예시코드">예시코드</h3>
<pre><code class="language-js">let button = $(&#39;.tab-button&#39;)
let content = $(&#39;.tab-content&#39;)

for(var i = 0; i &lt; button.length; i++){
    button.eq(i).on(&#39;click&#39;, function () {
        button.removeClass(&#39;on&#39;);
        button.eq(i).addClass(&#39;on&#39;);
        content.removeClass(&#39;show&#39;);
        content.eq(i).addClass(&#39;show&#39;)
    })
}</code></pre>
<h3 id="해설">해설</h3>
<p>tab-button은 3개이고, tab-content또한 3개이다.</p>
<p>이 코드에서는 각 버튼에 클릭 이벤트리스너가 발생되지 않는다.</p>
<p><strong>그 이유는 var의 특징 중에 하나인 함수 스코프와 클로저 문제이다.</strong></p>
<p>&#39;var&#39; 키워드로 선언한 &#39;i&#39;는 함수 스코프를 가지고 반복문 내에서 생성된 모든 이벤트 핸들러에서 같은 &#39;i&#39;변수를 공유한다.</p>
<p>함수가 끝나고도 i의 값(3)은 남아있게 되고 클릭 이벤트가 추가 되어도 마지막 i값에 해당하는 인덱스 값으로 동작하게 된다.</p>
<h3 id="해결-방법">해결 방법</h3>
<h4 id="let-사용">let 사용</h4>
<pre><code class="language-js">let button = $(&#39;.tab-button&#39;);
let content = $(&#39;.tab-content&#39;);

for (let i = 0; i &lt; button.length; i++) {
  button.eq(i).on(&#39;click&#39;, function () {
    button.removeClass(&#39;on&#39;);
    button.eq(i).addClass(&#39;on&#39;);
    content.removeClass(&#39;show&#39;);
    content.eq(i).addClass(&#39;show&#39;);
  });
}</code></pre>
<h4 id="foreach-사용">forEach 사용</h4>
<pre><code class="language-js">let button = $(&#39;.tab-button&#39;);
let content = $(&#39;.tab-content&#39;);

button.each(function (index) {
  $(this).on(&#39;click&#39;, function () {
    button.removeClass(&#39;on&#39;);
    button.eq(index).addClass(&#39;on&#39;);
    content.removeClass(&#39;show&#39;);
    content.eq(index).addClass(&#39;show&#39;);
  });
});
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[정규식]정규식에 대해 알아보자]]></title>
            <link>https://velog.io/@yongyong_21/%EC%A0%95%EA%B7%9C%EC%8B%9D%EC%A0%95%EA%B7%9C%EC%8B%9D%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@yongyong_21/%EC%A0%95%EA%B7%9C%EC%8B%9D%EC%A0%95%EA%B7%9C%EC%8B%9D%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Tue, 01 Aug 2023 11:02:00 GMT</pubDate>
            <description><![CDATA[<h1 id="정규식에-대해-알아보자">정규식에 대해 알아보자</h1>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/3eb1e1a0-5d11-403d-8033-3122556114c2/image.png" alt=""></p>
<h2 id="정규식regular-expression이란">정규식(Regular Expression)이란?</h2>
<p>정규식(Regular Expression)은 <strong>문자열</strong>에서 특정 패턴을 찾거나 매칭하는 데 사용되는 문자열의 표현 방법입니다. 정규식은 매우 강력하고 유연하며, 문자열 검색, 치환, 추출 등 다양한 문자열 조작 작업에 사용됩니다.</p>
<h2 id="정규식-구성-요소">정규식 구성 요소</h2>
<pre><code class="language-js">const regexr = /pattern/flag</code></pre>
<p>양 끝에 있는 /는 시작과 종료를 알려준다.</p>
<h2 id="pattern">pattern</h2>
<h3 id="a">/a/</h3>
<pre><code class="language-js">const str = &#39;abcdefg&#39;
console.log(/a/.test(str)); //ture
console.log(/z/.test(str)); //false</code></pre>
<p>해당하는 문자가 들어가 있는지 확인한다</p>
<h3 id="a-z">[a-z]</h3>
<pre><code class="language-js">const str2 = &#39;axyz&#39;;
console.log(/[a-z]/.test(str2)) // true
console.log(/[b-g]/.test(str2)) // false</code></pre>
<pre><code class="language-js">const str3 = &#39;안녕&#39;;
console.log(/[a-zA-z]/.test(str3)) // false
console.log(/[ㄱ-ㅎ가-힣ㅏ-ㅣ]/.test(str3)) // true</code></pre>
<p>문자 범위를 지정해서 들어가 있는지 확인한다.</p>
<h3 id="a-a">^a, a$</h3>
<pre><code class="language-js">const str4 = &#39;abc&#39;;
console.log(/^a/.test(str4)) // true
console.log(/c$/.test(str4)) // true</code></pre>
<p>^는 시작하는 문자, $는 끝나는 문자를 체크해준다.</p>
<h3 id="a-1">/a+/</h3>
<pre><code class="language-js">const str5 = &#39;aaaa&#39;;
console.log(/a+/.test(str5)) // true aaaa</code></pre>
<p>+를 붙이게 되면 a뒤에 똑같은 문자가 있는지 확인해준다.</p>
<h2 id="플래그">플래그</h2>
<p>정규식에서는 플래그(Flags)를 사용하여 검색의 방법과 동작을 세부적으로 제어할 수 있습니다. </p>
<pre><code class="language-js">const str = &#39;Hello, hello, HELLO&#39;;
console.log(/hello/gi/.test(str) // true Hello, hello, HELLO</code></pre>
<p>i : 대소문자 무시하여 검색
g : 전역 검색, 일치하는 모든 부분을 찾는다.</p>
<h2 id="활용-예시">활용 예시</h2>
<p>이메일 검사</p>
<pre><code class="language-js">const email = &#39;abc23@gmail.com&#39;
console.log(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) //true</code></pre>
<hr>
<p>핸드폰번호 검사</p>
<pre><code class="language-js">const number = &#39;010-1234-5678&#39;
console.log(/^\d{3}-\d{3,4}-\d{4}$/.test(number)) // true</code></pre>
<h2 id="정규식의-장단점">정규식의 장단점</h2>
<h3 id="장점">장점</h3>
<ul>
<li>다양한 패턴에 대해 검색을 할 수 있다.</li>
<li>이메일 주소, 전화번호, 비밀번호등의 유효성 검사하는데 유용하다.<h3 id="단점">단점</h3>
</li>
<li>가독성이 매우 떨어진다.</li>
<li>정규식의 패턴이 복잡할수록 실행속도가 느려진다.</li>
<li>패턴이 복잡할 수록 실수가 많아진다.</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스]코딩테스트 옹알이1 JavaScript]]></title>
            <link>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%98%B9%EC%95%8C%EC%9D%B41-JavaScript-yxqrarbt</link>
            <guid>https://velog.io/@yongyong_21/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%98%B9%EC%95%8C%EC%9D%B41-JavaScript-yxqrarbt</guid>
            <pubDate>Sat, 29 Jul 2023 15:08:05 GMT</pubDate>
            <description><![CDATA[<h1 id="문제">문제</h1>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/fd7a8126-de86-4ef9-9528-274975820082/image.PNG" alt=""></p>
<h1 id="소스">소스</h1>
<pre><code class="language-js">function solution(babbling) {
    let word = [&#39;aya&#39;, &#39;ye&#39;, &#39;woo&#39;, &#39;ma&#39;];

    let count = 0;
    babbling.forEach(item =&gt; {
        word.forEach(w =&gt; {
            item = item.replace(w,&#39;1&#39;);
        })
        if(item.replace(/1/g, &#39;&#39;) === &#39;&#39;)
            count += 1;
    })
    return count;
}</code></pre>
<h1 id="포인트">포인트</h1>
<ul>
<li>각 단어가 최대 한번씩 등장</li>
<li>포함에 집중해서 includes를 사용하지말고 replace를 사용</li>
<li>replace 활용방식에 대해 알 것</li>
</ul>
<h1 id="후기">후기</h1>
<p>처음에는 includes를 사용해서 풀려고 시도했으나, &#39;yee&#39;에 &#39;ye&#39;가 Ture값이 나오다보니 힌트로 replace 활용을 해서 풀었습니다.</p>
<p>replace로 풀던 도중, &#39;&#39;로 치환할 경우 &#39;wyeoo&#39;가 &#39;ye&#39; &#39;woo&#39;를 처리할 때 &#39;wyeoo&#39; -&gt; &#39;woo&#39; -&gt; &#39;&#39; 이렇게 처리가 되다보니 true값이 나오게 됩니다.</p>
<p>그래서 저는 빈문자열로 치환하지않고 data input값이 숫자가 나오지 않기때문에 숫자 1을 넣고 마지막에 .replace(/1/g, &#39;&#39;)를 사용하여 item에 있는 &#39;1&#39;을 전부 &#39;&#39;로 바꾸어서 풀었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WEB] 브라우저가 웹페이지를 읽어내는 과정]]></title>
            <link>https://velog.io/@yongyong_21/WEB-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EA%B0%80-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80%EB%A5%BC-%EC%9D%BD%EC%96%B4%EB%82%B4%EB%8A%94-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@yongyong_21/WEB-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EA%B0%80-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80%EB%A5%BC-%EC%9D%BD%EC%96%B4%EB%82%B4%EB%8A%94-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Sat, 29 Jul 2023 13:45:46 GMT</pubDate>
            <description><![CDATA[<h1 id="web-브라우저가-웹페이지를-읽어내는-과정">[WEB] 브라우저가 웹페이지를 읽어내는 과정</h1>
<h2 id="browser-processing-pipeline">Browser processing pipeline</h2>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/55db012a-49bb-4a40-b61e-2e0c35da2f0e/image.svg" alt=""></p>
<ul>
<li>이미지 출처: <a href="https://hpbn.co/primer-on-web-performance/">https://hpbn.co/primer-on-web-performance/</a></li>
</ul>
<p>위 사진은 웹 브라우저가 웹 페이지를 처리하는 과정을 간단하게 표현한 파이프라인입니다.</p>
<h3 id="파싱parsing이란">파싱(parsing)이란?</h3>
<p>파싱(parsing) 입력 데이터를 읽어들이고 그 구문을 분석하고 해석하는 과정</p>
<h3 id="파싱하는-과정">파싱하는 과정</h3>
<h4 id="html-파싱">HTML 파싱</h4>
<p>웹 브라우저는 HTML 문서를 요청하고 그 문서를 토큰화 하여 문자열로 읽어들입니다.
토큰화된 토큰들을 이용하여 DOM을 구성하고 그 과정에서 각 요소들은 노트로 변환되며 이 노드들은 트리 구조로 연결됩니다.
DOM 구성이 된다면 웹 페이지의 구조가 브라우저 내부에 객체로 저장이 됩니다.</p>
<ul>
<li>만약 HTML을 파싱하는 도중 스크립트 파일을 만나게 되면, 파싱하는 것을 멈추고 스크립트를 실행시킵니다.</li>
<li>만약 DOMContentLoaded가 있으면, HTML파싱이 완료되었을 때 즉시 발생합니다</li>
<li>onload는 웹페이지의 모든 리소스가 로드가 되었을 때, 즉 DOM이 CSSOM과 구성이 된 이후에 발생합니다</li>
</ul>
<h4 id="css-파싱">CSS 파싱</h4>
<p>HTML 파싱을 하는 것 처럼 CSS파일을 토큰을 만들고, 이러한 토큰들을 이용하여 CSSOM을 구성하게 됩니다.</p>
<h4 id="render-tree-구성">Render Tree 구성</h4>
<p>DOM과 CSSOM이 구성된 후에는 이 두 객체를 결합하여 Render Tree를 생성합니다.</p>
<ul>
<li>Render Tree에는 화면에 보이지 않는 요소들도 렌더트리에 포함이 되지만 몇몇 태그들은 렌더트리에 포함이 되지 않는다.</li>
<li>예시) meta태그, link태그, display:none 등</li>
</ul>
<h4 id="layout">Layout</h4>
<p>Render Tree의 각 노드들의 크기와 위치를 계산하여 화면에 배치화는 과정
브라우저는 Render Tree를 순회하면서 각 노드들을 화면 위치에 배치합니다.</p>
<h4 id="paint">Paint</h4>
<p>Layout 단계에서 계산된 각 노드의 스타일을 적용하여 실제로 화면에 그리는 과정
브라우저는 Render Tree를 순회하면서 각 노드들의 스타일을 적용하여 화면을 그리게 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트] 백준 2480번 문제 (JavaScript)]]></title>
            <link>https://velog.io/@yongyong_21/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%B1%EC%A4%80-2480%EB%B2%88-%EB%AC%B8%EC%A0%9C-JavaScript</link>
            <guid>https://velog.io/@yongyong_21/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%B1%EC%A4%80-2480%EB%B2%88-%EB%AC%B8%EC%A0%9C-JavaScript</guid>
            <pubDate>Sun, 23 Jul 2023 13:08:29 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/7cb0a370-fa33-42fb-bfda-8fede54ac56e/image.PNG" alt=""></p>
<h3 id="소스">소스</h3>
<pre><code class="language-js">const fs=require(&#39;fs&#39;);
const input=fs.readFileSync(&#39;/dev/stdin&#39;).toString().trim().split(&#39;\n&#39;);
let [a, b, c] = input[0].split(&#39; &#39;).map(Number);

let price = 0;

if ( a === b &amp;&amp; b === c) {
    price = 10000 + a * 1000
}
else if ( a !== b &amp;&amp; b !== c &amp;&amp; a !== c ) {
    price = Math.max(a,b,c) * 100
}
else {
    if ( a === b ){
        price = 1000 + a * 100
    }
    else if ( a === c){
        price = 1000 + a * 100
    }
    else {
        price = 1000 + b * 100
    }
}

console.log(price)</code></pre>
<h3 id="주요-포인트와-유의사항">주요 포인트와 유의사항</h3>
<ul>
<li>구조 분해 할당을 이용해서 변수로 바로 받을 수 있다.</li>
<li>Math 메소드를 이용해 Max값을 쉽게 구할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩테스트] 백준 2525번 문제 (JavaScript)]]></title>
            <link>https://velog.io/@yongyong_21/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%B1%EC%A4%80-2525%EB%B2%88-%EB%AC%B8%EC%A0%9C-JavaScript</link>
            <guid>https://velog.io/@yongyong_21/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%B0%B1%EC%A4%80-2525%EB%B2%88-%EB%AC%B8%EC%A0%9C-JavaScript</guid>
            <pubDate>Sun, 23 Jul 2023 13:01:57 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p><img src="https://velog.velcdn.com/images/yongyong_21/post/fb988e1a-db92-4eaf-80f4-adb6ded2a264/image.PNG" alt=""></p>
<h3 id="소스">소스</h3>
<pre><code class="language-js">const fs=require(&#39;fs&#39;);
const input=fs.readFileSync(&#39;/dev/stdin&#39;).toString().trim().split(&#39;\n&#39;);
let [hour, minute] = input[0].split(&#39; &#39;).map(Number);
let delay = Number(input[1]);

minute += delay;

if(minute &gt;= 60){
    hour += parseInt(minute/60);
    minute %= 60;
    if(hour &gt;= 24){
        hour %= 24;
    }    
}

console.log(hour+ &#39; &#39; + minute)</code></pre>
<h3 id="주요-포인트와-유의사항">주요 포인트와 유의사항</h3>
<pre><code>14 30
20</code></pre><ul>
<li>입력값이 이렇게 주어지기 때문에, split(&#39;\n&#39;)을 이용해서 받아야한다.</li>
<li>구조 분해 할당을 이용해서 변수로 바로 받을 수 있다.</li>
<li>/ 와 % 를 잘 활용하고 /를 할 시 소수점이 나오는 것을 주의하자.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>