<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jhyun_k.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 02 Jul 2025 15:09:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jhyun_k.log</title>
            <url>https://velog.velcdn.com/images/jhyun_k/profile/0d51d923-86ac-421d-a1ac-4a9e90df9d34/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jhyun_k.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jhyun_k" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[프레임워크 및 상태관리, 빌드 도구 등]]></title>
            <link>https://velog.io/@jhyun_k/%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%B0%8F-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%B9%8C%EB%93%9C-%EB%8F%84%EA%B5%AC-%EB%93%B1</link>
            <guid>https://velog.io/@jhyun_k/%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%B0%8F-%EC%83%81%ED%83%9C%EA%B4%80%EB%A6%AC-%EB%B9%8C%EB%93%9C-%EB%8F%84%EA%B5%AC-%EB%93%B1</guid>
            <pubDate>Wed, 02 Jul 2025 15:09:31 GMT</pubDate>
            <description><![CDATA[<p>기회가 닿아 공부하면서 정리도 할 겸 쓰는 글</p>
<h2 id="1-프레임워크-삼대장-비교-angular-vs-vue-vs-react">1. 프레임워크 삼대장 비교 (Angular vs Vue vs React)</h2>
<p>사실 리액트는 프레임워크로 분류하지 않지만 같이 껴넣어봤다.  </p>
<h3 id="공통점">공통점</h3>
<p>우선 세가지 모두 공통적으로 자바스크립트로 작성 되었고 웹 애플리케이션 개발을 위한 라이브러리/프레임워크이다. 세가지의 차이점과 특징을 비교해보려한다.</p>
<h3 id="angular-앵귤러">Angular (앵귤러)</h3>
<ul>
<li>구글에서 만든 프론트엔드 프레임워크이다.</li>
<li>Angular의 가장 큰 특징은 모든 것이 공식 지원 범위 안에서 통합되어 있다는 점이다. 라우팅, 폼 처리, HTTP 통신, 테스트, 국제화, 빌드 설정까지 모두 Angular 생태계 안에서 제공하고 있어 유지보수, 테스트가 용이하다고 한다.</li>
<li>양방향 데이터 바인딩 지원 <blockquote>
<p>  <strong>양방향 바인딩</strong>:  React는 기본적으로 단방향 데이터 흐름(부모 → 자식)을 따르지만, Angular는 양방향 바인딩을 지원하여 데이터가 변경되면 UI가 자동으로 업데이트되고, 반대로 UI 변경도 데이터에 즉시 반영된다.</p>
<ul>
<li>데이터가 변경되면 UI가 자동으로 업데이트되고, UI 요소에서 변경이 발생하면 데이터도 자동으로 업데이트 </li>
</ul>
</blockquote>
</li>
<li>의존성 주입(Dependency Injection) 시스템이 제공되어 애플리케이션을 쉽게 설정할 수 있다.<blockquote>
<p><strong>의존성 주입(Dependency Injection)</strong> : 외부에서 의존 객체를 생성하여 넘겨주는 것 일반적인 객체 생성의 경우에는 클래스 안에서 사용할 객체를 생성하지만, 의존성 주입의 경우 외부에서 생성된 객체를 주입 받는 방식이다. 의존성 주입을 사용한다면 클래스 간의 결합도를 낮춤으로 재사용성과 테스트하기 용이하게 된다.</p>
</blockquote>
</li>
<li>러닝커브가 높은 편이라 금융권, 공공기관, 대기업 SI 프로젝트에서 많이 사용되고, 규모가 크고 역할이 분리된 팀에서 빛을 발하는 프레임워크라고함</li>
</ul>
<h3 id="vue-뷰">Vue (뷰)</h3>
<ul>
<li><strong>점진적 프레임워크</strong> 가 캐치프라이즈다. 이는 쉽게 말해서 필요할 때 필요한 것만 사용 가능하다는 것으로 기존 웹 페이지에 점진적으로 통합하거나, 전체 애플리케이션을 Vue.js로 구축할 수 있다. </li>
<li>앵귤러의 특징인 양방향 데이터 바인딩을 채택하여 데이터 공유의 유동성을 높이고, 리엑트의 가상돔을 채택하여 렌더링 성능을 높였다고 한다.</li>
<li>러닝커브가 낮고 문법이 단순함</li>
<li>컴포넌트 기반 아키텍처로 웹 페이지를 독립적인 재사용 가능한 컴포넌트 단위로 개발하여 유지보수 및 개발 속도를 향상시킨다.</li>
</ul>
<h3 id="react-리액트">React (리액트)</h3>
<p>리액트는 사용자 인터페이스 구축에 용이한 자바스크립트 라이브러리이다. 재사용 가능한 코드 개발과 반응형 웹 구축에 많이 사용</p>
<blockquote>
<p><strong>라이브러리와 프레임워크 차이</strong>
가장 큰 차이점은 제어흐름의 권한이 어디있는지 라이브러리는 개발하는 우리가 직접 애플리케이션 코드의 흐름을 제어해야하는 반면, 프레임워크는 우리가 프레임워크가 정해둔 틀에 맞춰서 애플리케이션 코드를 짜고 그 틀 안에서 이 코드들이 실행된다. </p>
<ul>
<li>라이브러리는 개발자가 필요할 때 직접 가져다 쓰는 도구, 프레임워크는 전체 흐름과 구조를 프레임워크가 정해줌</li>
</ul>
</blockquote>
<ul>
<li><p>React는 왜 라이브러리라고 할까?
React는 UI를 그리는 <strong>&quot;View만 담당하는 라이브러리&quot;</strong>.
라우팅, 상태관리, 빌드 등은 직접 선택하고 조립해야 하기 때문에 그래서 프레임워크가 아니라 라이브러리라고 불린다.</p>
</li>
<li><p>JSX 문법 사용 (JavaScript 안에 HTML처럼 보이는 코드를 작성하는 방식)</p>
</li>
<li><p>Hook 사용</p>
</li>
<li><p>Virual DOM(가상 돔)을 이용하여 렌더링 성능을 최적화</p>
</li>
<li><p>Real DOM(실제 돔)에 비해 변경사항을 빠르게 적용해 주어서 사용자에게 더 나은 인터렉션 경험 제공</p>
</li>
</ul>
<h2 id="2-상태관리-패턴-비교">2. 상태관리 패턴 비교</h2>
<p><strong>상태관리(state management)</strong>는 컴포넌트 간에 공유되는 데이터(상태)를 어떻게 저장하고, 전달하고, 갱신할지를 관리하는 방식이다. 다양한 패턴이 있는데 대표적인 몇가지만 비교해보려 한다.</p>
<h3 id="flux-패턴">Flux 패턴</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/674569b7-1008-46cd-9ee4-d20b43469d64/image.png" alt=""></p>
<ul>
<li><p>Facebook이 제안한 단방향 데이터 흐름 구조</p>
</li>
<li><p><code>Action</code> → <code>Dispatcher</code> → <code>Store</code> → <code>View</code> 구조로, 상태 변경이 예측 가능하게 만들어짐</p>
</li>
<li><p>사용자 입력을 기반으로 Action을 생성 하고 그것을 Dispatch에 전달하여 데이터가 모여있는 Store의 데이터를 변경하게 된다. 그 후 실제 렌더링 = View 에 반영됨</p>
</li>
<li><p>데이터 흐름 추적 용이</p>
<blockquote>
<p>대표 라이브러리</p>
<ul>
<li>Redux: 가장 널리 쓰이는 Flux 패턴 상태관리 도구 (Flux에서 파생된 구조)</li>
</ul>
</blockquote>
</li>
</ul>
<h4 id="atom-패턴">Atom 패턴</h4>
<p>상태를 아주 작고 독립적인 단위로 나눠서 관리하는 구조. 각각의 atom은 독립적으로 존재하고, 컴포넌트는 필요한 atom만 구독함.</p>
<ul>
<li>상태 갱신을 부작용 없이 관리하기 위한 패턴</li>
<li>데이터 흐름이 없으며, 상태는 불변하고 필요 시 새로 생성됨<blockquote>
<p>대표 라이브러리</p>
<ul>
<li>Recoil    Facebook에서 만든 React 전용 atom 기반 상태관리. atom/selector 단위로 상태 조절.</li>
</ul>
</blockquote>
</li>
<li>Jotai    Recoil보다 더 간단한 구조. Hook만으로 상태를 제어함.</li>
</ul>
<h3 id="proxy-패턴">Proxy 패턴</h3>
<p>JavaScript의 Proxy 객체를 활용하여 객체의 속성에 대한 접근, 할당, 삭제 등을 가로채고 추가적인 로직을 수행하는 방식
프록시(Proxy)의 사전적인 의미는 &#39;대리인&#39;이라는 뜻이다. 즉, 누군가에게 어떤 일을 대신 시키는 것을 의미하는데, 이를 객체 지향 프로그래밍에 접목해보면 클라이언트가 대상 객체를 직접 쓰는게 아니라 중간에 프록시(대리인)을 거쳐서 쓰는 코드 패턴이라고 보면 된다</p>
<ul>
<li>양방향 데이터흐름 </li>
<li>상태 변경 시 자동 감지 및 반응<blockquote>
</blockquote>
대표 라이브러리<blockquote>
<ul>
<li>Valtio : 상태 사용 추적 기법 기반으로 렌더링 최적화를 하는 라이브러리</li>
</ul>
</blockquote>
</li>
</ul>
<h2 id="3-빌드-도구와-프레임워크">3. 빌드 도구와 프레임워크</h2>
<h3 id="31-빌드도구">3.1 빌드도구</h3>
<p>개발 코드를 브라우저에서 동작 가능한 상태로 변환해주는 도구
프론트엔드 코드를 빌드하고 번들링하며, 최적화하고, 테스트하고, 배포하는 데 사용된다.</p>
<blockquote>
<p>번들링 : 여러 JS 파일을 하나로 합침 번들러는 프로젝트에 포함된 파일(모듈)들을 연결하고 묶어서 브라우저가 실행할 수 있는 파일로 만들어준다. 이를 번들링한다고 한다.</p>
</blockquote>
<h4 id="webpack">Webpack</h4>
<ul>
<li>가장 널리 쓰이는 전통적인 번들러</li>
<li>여러 JavaScript 파일을 하나로 번들링함으로써 HTTP 요청 수를 줄이고, 로딩 성능 개선</li>
<li>JavaScript 외에도 CSS, 이미지, 폰트 등 다양한 파일 형식을 사용하는데 로더를 통해 이러한 다양한 파일들을 모두 하나의 번들 파일로 묶어준다</li>
<li>생태계 크고 커스터마이징 강력</li>
<li>개발 중 변경 사항이 있을 때마다 전체 번들을 재생성해야 하므로, 변경 반영 속도가 느려질 수 있다. HMR(Hot Module Replacement) 어려움</li>
</ul>
<blockquote>
<p>HMR(Hot Module Replacement) : 개발 중인 애플리케이션의 특정 모듈을 새로 고침하지 않고도(브라우저를 새로 고침 하지 않고도) 교체할 수 있게 하는 기능 </p>
</blockquote>
<h4 id="vite">Vite</h4>
<p>이전엔 주로 Webpack을 썼는데, 느리고 설정이 복잡하다보니 그걸 더 빠르고 가볍게 만든 대체 도구가 Vite 라고한다.</p>
<ul>
<li>Vite는 ES 모듈을 기본으로 사용</li>
<li>자바스크립트 파일을 각각의 모듈로 취급하여 필요한 모듈만 개별적으로 로드함 코드 전체를 다시 번들링하지 않고, 수정된 파일만 빠르게 다시 로드하므로 HMR 성능이 매우 뛰어나고, 브라우저에서 즉시 결과를 확인할 수 있다</li>
<li>번들링 최적화: 개발 환경에서는 번들링 없이 ES 모듈을 사용하고, 배포 시에는 최적화된 번들로 빌드를 진행 (Rollup 사용)</li>
<li>로컬 개발 시에는 번들링을 하지 않고 프로덕션 빌드 시에만 번들링을 하는데, 각 모듈을 브라우저가 직접 요청하도록 하여 HMR 성능을 극대화</li>
</ul>
<h3 id="32-프레임워크-비교">3.2. 프레임워크 비교</h3>
<p>SPA, SSR, SSG 등 웹 애플리케이션 구조를 설계하고 제어하는 큰 틀
<a href="https://velog.io/@jhyun_k/%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-vs-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-SSR%EA%B3%BC-CSR">참고 : 서버사이드렌더링과 클라이언트사이드렌더링</a></p>
<h4 id="nextjs">Next.js</h4>
<ul>
<li>React 기반의 풀스택 프레임워크</li>
<li>React로 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG), API 라우팅, 이미지 최적화까지 가능</li>
<li>SEO에 강함 (SSR)</li>
<li>백엔드 없이 풀스택 개발 가능 (API routes)</li>
<li>Vercel이 만들어서 호환 좋음</li>
</ul>
<h4 id="nuxtjs">Nuxt.js</h4>
<ul>
<li>Vue 기반 SSR 프레임워크</li>
<li>파일 기반 라우팅</li>
<li>SSR, SSG, CSR 모두 지원</li>
<li>API 서버 내장 (Nuxt 3부터)</li>
<li>Vite 지원 (Nuxt 3 이상)</li>
</ul>
<h4 id="sveltekit">SvelteKit</h4>
<ul>
<li>svelte 기반의 프레임워크</li>
<li>가볍고 빠름</li>
<li>SSR/SSG/CSR 모두 지원</li>
<li>Svelte 자체 학습 필요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[쿠키 이용하여 오늘 하루 안 보기 팝업 만들기]]></title>
            <link>https://velog.io/@jhyun_k/%EC%BF%A0%ED%82%A4-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%EC%98%A4%EB%8A%98-%ED%95%98%EB%A3%A8-%EC%95%88-%EB%B3%B4%EA%B8%B0-%ED%8C%9D%EC%97%85-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/%EC%BF%A0%ED%82%A4-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%EC%98%A4%EB%8A%98-%ED%95%98%EB%A3%A8-%EC%95%88-%EB%B3%B4%EA%B8%B0-%ED%8C%9D%EC%97%85-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 13 Oct 2023 07:57:42 GMT</pubDate>
            <description><![CDATA[<p>개발을 할 때에는 다양한 저장소에 데이터를 저장한다. 그동안 거의 로컬스토리지 기능만 이용하였는데 팝업을 띄울 일이 있어서 쿠키를 이용해보았다. 팝업을 띄우는 것은 어렵지 않지만 체크박스를 체크하면 하루동안 팝업이 나오지 않고 다시 하루가 지나면 팝업이 뜨게 해야 했다. 이러한 기능은 인터넷을 이용하고 있으면 자주 볼 수 있는데 대부분이 <strong>쿠키</strong> 를 이용해서 구현 한다고 한다. </p>
<blockquote>
<p>목차</p>
</blockquote>
<ol>
<li>쿠키란?</li>
<li>쿠키 저장하고 사용하기</li>
</ol>
<h2 id="쿠키란">쿠키란?</h2>
<p>쿠키는 공개 가능한 정보를 사용자의 브라우저에 저장시킨다. 쉽게 말하자면 브라우저에서 저장되는 키와 같이 들어있는 작은 파일이다. 인터넷 사용자가 어떠한 웹사이트를 방문할 경우 그 사이트가 사용하고 있는 서버를 통해 인터넷 사용자의 컴퓨터에 작은 기록 정보 파일이 설치된다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/9cc3a32a-2693-415d-b2da-f7a9e94686ed/image.png" alt=""></p>
<p>쿠키는 Web Storage(local storage, session storage)에 비하면 작은 데이터를 저장할 수 있지만 서버에 전송할 수 있기 때문에 서버 데이터를 공유하는 용도로 사용된다. 쿠키는 브라우저 상태 정보를 로컬에 저장했다가 참조한다. 쿠키는 사용자 상태 정보를 클라이언트 측에 저장한다는 특징이 있다.</p>
<h3 id="쿠키-제약">쿠키 제약</h3>
<ul>
<li>브라우저에 300개까지 쿠키 저장 가능하고 </li>
<li>하나의 도메인당 20개 값만 가질 수 있으며 </li>
<li>쿠키값도 4kb 까지만 저장 가능하다. </li>
</ul>
<h3 id="쿠키는-어디서-보나요">쿠키는 어디서 보나요</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/ebe2887b-1d8e-403a-9041-d6ec31e67d53/image.png" alt="">
개발자 도구의 Application 탭을 눌러보면 다른 스토리지와 더불어 귀여운 쿠키모양으로 이렇게 쿠키를 확인할 수 있다. 혹은 window.document.cookie 로도 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/bdbfa72f-2c79-4b5d-aa34-9c6f60ef8729/image.png" alt="">
쿠키가 가진 속성은 이렇게 다양한데 보면 크게 어려운 영어는 없기에 어떤 역할을 하는지는 쉽게 알 수 있다.</p>
<p>쿠카는 key - value 쌍으로 이루어진 문자열 정보이다. HTTP 쿠키는 서버가 클라이언트에게 준 정보를 브라우저에 저장하고, 클라이언트가 요청을 보낼 때 HTTP 헤더에 정보를 담아서 서버에 전달한다. 도메인은 보다시피 벨로그이다. HTTP 요청을 보낼 주소의 도메인이 Domain 속성값과 같은 경우에만 쿠키를 보낸다. path는 HTTP 요청을 보낼 주소의 URL 경로가 Path 속성값과 같은 경우에만 쿠키를 보낸다. 팝업을 띄울 때는 expires 속성이 중요하다. Secure, HttpOnly 는 보안 관련 정보이다.</p>
<h3 id="쿠키-종류">쿠키 종류</h3>
<h4 id="세션쿠키-session-cookie">세션쿠키 (Session Cookie)</h4>
<p>쿠키를 설정할 때 Expires나 Max-Age로 만료일을 설정하지 않으면 세션쿠키가 된다. 세션 쿠키라는 말처럼 브라우저를 종료하면 파기된다. 이는 사용자가 사이트를 탐색할 때 선호 사항, 임시 설정 등을 저장하는 쿠키로 주로 최근 검색어나 최근 본 상품 등의 기능을 구현할 때 사용한다.</p>
<h4 id="지속쿠키-permanent-cookie">지속쿠키 (Permanent Cookie)</h4>
<p>디스크에 저장되어서 만료일까지는 브라우저를 끄거나 재부팅하여도 남아있는다. 다음 방문에도 영향을 주는 설정 정보나 로그인 정보 등을 유지할 때 사용하는 쿠키이다. 내가 구현하려는 n일간 팝업 보지 않기나 로그인 유지 기능을 구현할 때 사용한다.</p>
<h2 id="쿠키-설정하고-사용하기">쿠키 설정하고 사용하기</h2>
<h3 id="어떤-걸-구현해야-할까">어떤 걸 구현해야 할까?</h3>
<ul>
<li>사용자가 그냥 닫기를 눌렀는지, 오늘 하루 보지 않기 버튼을 눌렀는지 확인</li>
<li>팝업이 다시 보이는 시각 계산하여 저장</li>
</ul>
<h3 id="쿠키-설정하기">쿠키 설정하기</h3>
<pre><code class="language-tsx">
/* 쿠키 설정 */
  const [showPopup, setShowPopup] = useState&lt;boolean&gt;(false);
  const [checked, setChecked] = useState&lt;boolean&gt;(false);

  const today = new Date();
  let todayDate = today.getDate();
  let tomorrow = new Date(today.setDate(todayDate + 1));

  const closeOptionCheck = () =&gt; {
    document.cookie = `name=${todayDate}; path=/; expires=${tomorrow.toUTCString()}; secure`;
  };

  const closeBtn = () =&gt; {
    if (checked) closeOptionCheck();
    setShowPopup(false);
  };

  const Cookie = () =&gt; {
    const cookies = document.cookie.match(&quot;(^|;) ?&quot; + &quot;name&quot; + &quot;=([^;]*)(;|$)&quot;);
    const cookieDate = cookies ? Number(cookies[2]) : 0;
    let dateCheck = cookieDate !== todayDate;
    return dateCheck;
  };

    useLayoutEffect(() =&gt; {
        setShowPopup(Cookie());
  }, []);

  return (&lt;Popup display={showPopup}&gt;
          &lt;Checkbox checked={checked} onChange={()=&gt;setChecked(prev=&gt;!prev)}오늘 하루 안 보기 &lt;/Checkbox&gt;
        &lt;Button onClick={()=&gt; closeBtn()}닫기&lt;/Button&gt;
    &lt;/Popup&gt;)
</code></pre>
<p> 위 코드는 쿠키의 value 값과 오늘 날짜가 같을 경우 팝업을 띄우지 않도록 하는 코드이다.</p>
<pre><code class="language-tsx">  const today = new Date();
  let todayDate = today.getDate();
  let tomorrow = new Date(today.setDate(todayDate + 1));

  const closeOptionCheck = () =&gt; {
    document.cookie = `name=${todayDate}; path=/; expires=${tomorrow.toUTCString()}; secure`;
  };</code></pre>
<p><code>document.cookie</code> 에 저런 형식으로 원하는 속성들을 입력하면 쿠키를 저장할 수 있다. 각 속성은 <code>;</code> 으로 구분되며 ; 이후 한 칸 띄고 적어야한다. </p>
<ul>
<li>key값은 원하는 이름으로 value 값은 오늘 날짜를 입력한다.</li>
<li>만료일은 내일로 설정한다. 하지만 Date객체는 GMT시간을 기준으로 하므로 날짜값에 <code>toUTCString()</code>을 해주어야 위치 상관없이 같게 동작한다. </li>
<li>secure은 보안관련이다. https 에서만 쿠키를 불러오게 한다고 알고있다. (확실치않음)</li>
</ul>
<pre><code class="language-tsx">  const closeBtn = () =&gt; {
    if (checked) closeOptionCheck();
    setShowPopup(false);
  };</code></pre>
<p>closeBtn 닫기 버튼을 눌렀을 때 체크박스에 체크가 되어있다면 closeOptionCheck함수가 실행되어 쿠키가 저장된다. </p>
<h3 id="쿠키-불러오기">쿠키 불러오기</h3>
<pre><code class="language-tsx">const Cookie = () =&gt; {
    const cookies = document.cookie.match(&quot;(^|;) ?&quot; + &quot;name&quot; + &quot;=([^;]*)(;|$)&quot;);
    const cookieDate = cookies ? parseInt(cookies[2]) : 0;
    let dateCheck = cookieDate !== todayDate;
    return dateCheck;
  };</code></pre>
<p>쿠키값을 불러오기 위해 document.cookie 객체에서 key값이 name(정한 대로)인 값을 찾아준다. <code>cookies[2]</code>가 value값이다.  key값이 name인 데이터가 있다면 value값을 가져오고 아니면 0을 반환한다.</p>
<p>그리고 오늘 날짜와 비교한다. 화면단에서 <code>&lt;Popup&gt;</code> 컴포넌트는 display속성이 true이면 팝업을 띄우고 false이면 안띄운다. 값이 같지 않아야 팝업이 출력되는 구조이므로 <code>Cookie</code> 함수는 <code>cookieDate!==todayDate</code> 값의 boolean을 반환한다. </p>
<blockquote>
<p>이로써 체크박스를 체크하고 닫기를 누르면 쿠키에 오늘 날짜가 저장되어 다시 그 화면을 방문해도 팝업이 뜨지 않고 하루가 지난 후에 다시 방문하면 expires 날짜가 지나 다시 쿠키가 삭제되었으므로 팝업이 뜨게 되었다. 체크박스를 체크하지 않고 그냥 닫기를 누를 경우 쿠키가 저장되지 않으므로 사이트를 다시 방문하면 팝업이 뜨게 된다.</p>
</blockquote>
<h2 id="결론">결론</h2>
<p>뭔가 단순한 기능을 너무 복잡하게 설계한 것 같다. 인터넷에 찾아보면 다 똑같은 방법으로 하고있는데 그 방법이 내가 화면을 내보내는 방식이랑 상이하여 적용이 되지 않았다. 고민하다가 결국 이런 무식한 방법으로 팝업을 띄우게 되었는데 더 좋은 방법이 있지않을까 더 고민해봐야겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TS | 리터럴, 유니온/교차타입, 클래스, 제네릭, 유틸리티 타입]]></title>
            <link>https://velog.io/@jhyun_k/TypeScript-%EA%B3%B5%EB%B6%80-ntvxyb70</link>
            <guid>https://velog.io/@jhyun_k/TypeScript-%EA%B3%B5%EB%B6%80-ntvxyb70</guid>
            <pubDate>Sat, 23 Sep 2023 13:57:07 GMT</pubDate>
            <description><![CDATA[<h2 id="리터럴-유니온교차-타입">리터럴, 유니온/교차 타입</h2>
<h3 id="리터럴타입">리터럴타입</h3>
<p>리터럴 타입은 정해진 값을 가진 타입이다.</p>
<pre><code class="language-ts">const userName1 = &#39;Bob&#39;; // 얘는 재할당 불가능하므로 무조건 &#39;Bob&#39;임
let userName2 : string | number = &#39;Tom&#39;;
userName2 = 3 // ㄴ&gt; 이렇게 string이랑 number 둘 다로 설정 안해놓으면 초기 타입이 string이었기 때문에 string만 넣을 수 있음

type Job = &#39;police&#39; | &#39;developer&#39; | &#39;teacher&#39;

interface User {
  name : string;
  job : Job;
}

const user : User = {
  name : &#39;Bob&#39;,
  // job : &#39;student&#39;,  &lt; Job 타입에 지정된 값이 아니므로 에러뜸
  job : &#39;developer&#39;,
}

interface HighSchoolStudent {
  name : string,
  grade : 1 | 2 | 3
}</code></pre>
<h3 id="유니온-타입">유니온 타입</h3>
<p>| (or 조건 타입) , 동일한 속성의 타입을 다르게 해서 구분할 수 있는 것을 식별 가능한 유니온 타입이라고 한다.</p>
<pre><code class="language-ts">interface Car {
  name : &#39;car&#39;;
  color : string;
  start():void;
}

interface Mobile{
  name : &quot;mobile&quot;
  color : string;
  call():void;
}

function getGift(gift : Car | Mobile){
  console.log(gift.color);
  //gift.start(); error : Property &#39;start&#39; does not exist on type &#39;Mobile&#39;  start() 는 Car에만 있어서
  if(gift.name===&#39;car&#39;){
    gift.start();
  }else{
    gift.call();
  }
}</code></pre>
<h3 id="교차-타입-intersection-types">교차 타입 (Intersection Types)</h3>
<p>&amp; (and 조건 타입) , 모든 속성을 다 기입하기 전까지는 에러 안사라진다. 교차타입은 여러개의 타입을 하나로 합쳐준다. 필요한 모든 기능을 가진 하나의 타입을 만들어주는 것이다.</p>
<pre><code class="language-ts">interface Car {
  name : string;
  start() : void;
}

interface Toy {
  name : string;
  color : string;
  price : number;
}

const toyCar : Toy &amp; Car = {
  name : &#39;타요&#39;,
  start(){}.
  color : &#39;red&#39;,
  price : 1000,
}
</code></pre>
<h2 id="클래스-class">클래스 (Class)</h2>
<p>타입스크립트에서는 자바스크립트 es6의 클래스와 달리 멤버 변수를 constructor 전에 먼저 선언해줘야한다.</p>
<pre><code class="language-ts">class Car {
 color: string
 constructor(color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
  }
}

const bmw = new Car(&#39;red&#39;)</code></pre>
<p>먼저 선언하지 않는 방법은 readonly 사용하면됨</p>
<h3 id="접근제한자access-modifier">접근제한자(Access modifier)</h3>
<p>es6 의 클래스는 접근제한자 제공하지 않음, 하지만 타입스크립트는 접근 제한자 제공한다. 타입스크립트의 접근제한자는 public, private,protected가 있다.</p>
<h4 id="public">public</h4>
<p>아무것도 안쓰면 public 이다</p>
<pre><code class="language-ts">class Car {
  name : string = &#39;car&#39;;
  color : string;
 constructor(readonly color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
  }
}

class Bmw extends Car {
  constructor(color:string){
    super(color);
  }
  showName(){
    console.log(super.name);
  }
}

const z4 = new Bmw(&#39;black&#39;)</code></pre>
<h4 id="private">private</h4>
<p>속성 이름 앞에 <code>private</code>를 쓰거나 <code>#</code>을 입력하면 private 속성으로 해당 클래스에서밖에 사용하지 못한다.</p>
<pre><code class="language-ts">class Car {
 private name : string = &#39;car&#39;;
 //#name : string = &#39;car&#39;;
 color : string;
 constructor(readonly color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
  }
}

//위 코드처럼 Bmw 에서는 못쓴다
</code></pre>
<h4 id="protected">protected</h4>
<p>protected도 public과 마찬가지로 자식클래스에서 접근이 가능하다. public과 다른 점은 자식클래스 내부에서는 참조할수있으나 클래스 인스턴스로는 참조할 수 없다.</p>
<pre><code class="language-ts">class Car {
  protected name : string = &#39;car&#39;;
  color : string;
 constructor(readonly color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
  }
}

class Bmw extends Car {
  constructor(color:string){
    super(color);
  }
  showName(){
    console.log(super.name);
  }
}
const z4 = new Bmw(&#39;black&#39;)
console.log(z4.name) // error : property &#39;name&#39; is protected and only accessible within class &#39;Car&#39; and its subclassess</code></pre>
<blockquote>
<ul>
<li>public : 자식클래스, 클래스 인스턴스에서 모두 접근 가능</li>
</ul>
</blockquote>
<ul>
<li>protected : 자식클래스에서 접근 가능</li>
<li>private : 해당 클래스 내부에서만 접근 가능</li>
</ul>
<h3 id="static-프로퍼티">static 프로퍼티</h3>
<p>static 이용하면 정적 멤버 변수 만들 수 있다. 접근하려면 클래스이름.속성 으로 접근해야한다.</p>
<pre><code class="language-ts">class Car {
  protected name : string = &#39;car&#39;;
  color : string;
  static wheels = 4;
 constructor(readonly color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
    console.log(Car.wheels); //이렇게 클래스명을 써줘야한다!
  }
}</code></pre>
<h3 id="추상클래스">추상클래스</h3>
<p>추상클래스는 <code>new</code> 를 이용하여 객체 만들 수 없고 상속을 이용해서만 사용가능함. class 앞에 <code>abstract</code> 기입</p>
<pre><code class="language-ts">abstract class Car {
  protected name : string = &#39;car&#39;;
  color : string;
  static wheels = 4;
 constructor(readonly color:string){
   this.color = color;
 }
  start(){
    console.log(&#39;start&#39;)
  }
  abstract doSomething(): void // 추상메서드는 반드시 상속 받은 곳에서 구체적인 구현을 해줘야함, 여기서는 이름 정도만 정한다고 생각하면 된다.
}

const car = new Car(&#39;red&#39;) // error

class Bmw extends Car{
  . . . 
  doSomething(){
    alert(3)
  }//이렇게 상속받은 곳에서 어떤 기능을 할건지 구현을 해줘야한다.

} // 이렇게만 가능</code></pre>
<h2 id="제네릭-generics">제네릭 (Generics)</h2>
<p>제네릭을 이용하면 클래스나 함수, 인터페이스를 다양한 타입으로 재사용 할 수 있다. 선언할 때는 그냥 파라미터만 적어주고 사용할 때 파라미터의 구체적인 타입을 정해준다.</p>
<p>이렇게 일일이 타입을 다 적어주면 번거롭기도 하고 정해진 타입이 아닌 경우 재사용성이 떨어진다.</p>
<pre><code class="language-ts">function getSize(arr : number[] | string[] | boolean[] | object[] ):number{
  return arr.length
}

const arr1 = [1,2,3]
getSize(arr1) // 3

const arr2 = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;]
getSize(arr2) // 3

const arr3 = [true,false,true]
getSize(arr3) // 3

const arr4 = [{},{},{name:&#39;Tims&#39;}]
getSize(arr4) // 3</code></pre>
<p>이 때 제네릭을 이용하면 편하게 재사용성을 높일 수 있다.</p>
<pre><code class="language-ts">function getSize&lt;T&gt;(arr:T[]):number{
  return arr.length
}

//&lt;T&gt; (꼭 T가 아니어도 됨, 그냥 타입이라는 뜻인듯) 를 써주고 파라미터의 타입을 배열이라는 것만 설정한다. 그 후 아래처럼 사용할 때 원하는 타입 쓰면 된다.

const arr1 = [1,2,3]
getSize&lt;number&gt;(arr1) // 3

const arr2 = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;]
getSize&lt;string&gt;(arr2) // 3
//사실 꼭 &lt;string&gt; 이렇게 안써줘도 받는 값의 타입을 알아서 인식해서 타입 지정해준다.

const arr3 = [true,false,true]
getSize&lt;boolean&gt;(arr3) // 3

const arr4 = [{},{},{name:&#39;Tims&#39;}]
getSize&lt;object&gt;(arr4) // 3
</code></pre>
<h3 id="인터페이스에서-제네릭-사용">인터페이스에서 제네릭 사용</h3>
<p>제네릭을 이용하면 하나의 인터페이스를 선언하고 각기 다른 모습의 객체들을 만들어줄 수 있다.</p>
<pre><code class="language-ts">interface Moblie&lt;T&gt;{
  name : string;
  price : number;
  option:T // 뭐가 들어올지 몰라서 제네릭으로 타입 지정 안하고 넘어감
}

const m1 : Mobile&lt;object&gt; = {
  name : &#39;s21&#39;,
  price : 1000,
  option : {
    color : &#39;red&#39;,
    coupon: false,
  },
}

const m2 : Mobile&lt;string&gt; = {
  name : &#39;s20&#39;,
  price : 1300,
  option : &#39;good&#39;
}

//만약 option 의 형태가 정해져있다면 이렇게 미리 쓰는 것도 된다
const m1 : Mobile&lt;{color:string;coupon:boolean}&gt; = {
  name : &#39;s21&#39;,
  price : 1000,
  option : {
    color : &#39;red&#39;,
    coupon: false,
  },
}</code></pre>
<h3 id="제네릭-다른-예제">제네릭 다른 예제</h3>
<pre><code class="language-ts">interface User{
  name:string;
  age : number;
}

interface Car {
  name : boolean;
  color:string;
}

interface Book {
  price: number;
}

const user:User = {name : &#39;a&#39;,age:10}
const car:Car = {name : &#39;bmw&#39;,color:&#39;red&#39;}
const book : Book = {price:3000}

//어떤 T타입이 올건데 그 타입은 name이 string인 객체를 확장한 것이다
function showName&lt;T extends {name : string}&gt;(data:T):string{
  return data.name
}

showName(user)
showName(car) // error : name이 string이 아님
showName(book) // error : book 에는 name 없음</code></pre>
<h2 id="유틸리티-타입-utility-types">유틸리티 타입 (Utility Types)</h2>
<h3 id="keyof">keyof</h3>
<p>keyof 키워드를 이용하면 key값들을 유니온 형태로 받을 수 있다.</p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age : number;
  gender : &#39;m&#39;|&#39;f&#39;
}

type UserKey = keyof User; //&#39;id&#39; | &#39;name&#39; | &#39;age&#39; | &#39;gender&#39;

const uk : UserKey = &#39;id&#39; </code></pre>
<h3 id="partial">Partial</h3>
<p><code>Partial&lt;T&gt;</code>프로퍼티를 모두 optional로 바꿔준다. </p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age : number;
  gender : &#39;m&#39;|&#39;f&#39;
}

//이렇게 인터페이스를 Partial로 묶어주면 User의 프로퍼티가 모두 optional이 된다
let admin : Partial&lt;User&gt; = {
  id:1,
  name:&#39;Bob&#39;
}

interface User{
  id? : number;
  name? : string;
  age? : number;
  gender? : &#39;m&#39;|&#39;f&#39;
}
이렇게 되는 것과 마찬가지인것!</code></pre>
<h3 id="required">Required</h3>
<p><code>Required&lt;T&gt;</code>모든 프로퍼티를 필수로 바꿔준다</p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age? : number;
  gender : &#39;m&#39;|&#39;f&#39;
}

//이렇게 인터페이스를 Required로 묶어주면 User에서 optional 프로퍼티로 정해놨던 age까지 필수로 입력해야함
let admin : Required&lt;User&gt; = {
  id:1,
  name:&#39;Bob&#39;,
  age : 30,
}</code></pre>
<h3 id="readonly">Readonly</h3>
<p><code>Readonly&lt;T&gt;</code> 프로퍼티를 읽기전용으로 바꾼다</p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age? : number;
  gender : &#39;m&#39;|&#39;f&#39;
}

//이렇게 인터페이스를 Readonly로 묶어주면 할당만 가능하고 값 수정은 불가능해진다
let admin : Readonly&lt;User&gt; = {
  id:1,
  name:&#39;Bob&#39;,
  age : 30,
}</code></pre>
<h3 id="record">Record</h3>
<p><code>Record&lt;K,T&gt;</code> 
K는 key , T는 type</p>
<pre><code class="language-ts">const score : Record&lt;&#39;1&#39;|&#39;2&#39;|&#39;3&#39;|&#39;4&#39;,&#39;A&#39;|&#39;B&#39;|&#39;C&#39;|&#39;F&#39;&gt; = {
  1:&#39;A&#39;,
  2:&#39;C&#39;,
  3:&#39;F&#39;,
  4:&#39;B&#39;,
}

type Grade = &#39;1&#39;|&#39;2&#39;|&#39;3&#39;|&#39;4&#39;;
type Score = &#39;A&#39;|&#39;B&#39;|&#39;C&#39;|&#39;F&#39;;

const score : Record&lt;Grade,Score&gt; = {
  1:&#39;A&#39;,
  2:&#39;C&#39;,
  3:&#39;F&#39;,
  4:&#39;B&#39;,
}
이렇게도 사용 가능</code></pre>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age : number;
}

// 유저 정보가 유효한지를 boolean으로 반환하는 함수
function isValid(user:User){
  const result : Record&lt;keyof User,boolean&gt; = {
    id : user.id &gt;0,
    name : user.name !== &quot;&quot;,
    age: user.age &gt;0,
  }
  return result;
}</code></pre>
<h3 id="pick">Pick</h3>
<p><code>Pick&lt;T,K&gt;</code> T타입에서 K프로퍼티만 골라서 사용한다</p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age : number;
}

// User에서 id와 name만 사용
const admin : Pick&lt;User,&#39;id&#39;|&#39;name&#39;&gt; = {
  id : 0;
  name : &#39;Bob&#39;;
}
</code></pre>
<h3 id="omit">Omit</h3>
<p><code>Omit&lt;T,K&gt;</code> T타입에서 K프로퍼티만 제외하고 사용한다</p>
<pre><code class="language-ts">interface User{
  id : number;
  name : string;
  age : number;
  gender : &#39;M&#39; | &#39;F&#39;
}

// User에서 age와 gender만 빼고 사용  
const admin : Omit&lt;User,&#39;age&#39;|&#39;gender&#39;&gt; = {
  id : 0;
  name : &#39;Bob&#39;;
}</code></pre>
<h3 id="exclude">Exclude</h3>
<p><code>Exclude&lt;T1,T2&gt;</code> T1에서T2를 제외하고 사용하는 방식, Omit과 다른점은 Omit은 프로퍼티로 제외하는 것이고, Exclude는 타입으로 제외하는 방식</p>
<pre><code class="language-ts">type T1 = string | number | boolean;
type T2 = Exclude&lt;T1,number|string&gt; // 이러면 boolean만 사용</code></pre>
<h3 id="nonnullable">NonNullable</h3>
<p><code>NonNullable&lt;Type&gt;</code> null을 제외한 타입 생성 null뿐만 아니라 undefined도 함께 제외시킨다.</p>
<pre><code class="language-ts">type T1 = string | null | undefined | void;
type T2 = NonNullable&lt;T1&gt; // string과 void만 남는다.
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 배열 메소드 : every , some]]></title>
            <link>https://velog.io/@jhyun_k/every</link>
            <guid>https://velog.io/@jhyun_k/every</guid>
            <pubDate>Wed, 30 Aug 2023 09:08:44 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스 배열 문제를 풀다가 every 와 some 메소드 사용이 헷갈려서 공부하기 위해 적어본다.</p>
<p>이 메소드들은 둘 다 배열의 요소들이 주어진 조건을 만족하는지 여부에 대한 검증을 수행한다.</p>
<h2 id="arrayprototypeevery">Array.prototype.every()</h2>
<ul>
<li><code>every()</code>는 배열의 각 엘리먼트에 대해서 테스트 함수의 반환 값이 <strong>모두 true인지 확인</strong>한다.</li>
<li>모든 반환값이 true일때만 true를 반환한다.</li>
<li>하나라도 false이면 false를 반환한다.</li>
<li>기존 배열 값은 변경되지 않는다.</li>
</ul>
<h3 id="문법">문법</h3>
<p><code>arr.every(function(currentValue, index, array), thisValue))</code></p>
<ul>
<li>currentValue 인자는 필수, 나머지는 옵션</li>
</ul>
<h2 id="arrayprototypesome">Array.prototype.some()</h2>
<ul>
<li><code>some()</code>은배열의 각 엘리먼트에 대해서 테스트 함수의 반환 값이 <strong>하나라도 true가 있는지 확인</strong>한다.</li>
<li>하나라도 true가 발생하면 true를 반환한다.</li>
<li>모든 반환값이 false일 경우에만 false를 반환한다.</li>
<li>기존 배열 값은 변경되지 않는다.</li>
</ul>
<h3 id="문법-1">문법</h3>
<p><code>arr.some(function(currentValue, index, array), thisValue))</code></p>
<ul>
<li>currentValue 인자는 필수, 나머지는 옵션</li>
</ul>
<h2 id="두-메소드-사용-예제">두 메소드 사용 예제</h2>
<pre><code class="language-js">cosnt array = [1, 2, 3, 4];
let result = array.some(num =&gt; num &gt; 2);
console.log(result); // true
result = array.every(num =&gt; num &gt; 2);
console.log(result); // false</code></pre>
<h2 id="정리">정리</h2>
<p>두 메소드는 배열의 값을 확인하고 true/false를 반환한다는 점에서 비슷하지만 <code>every()</code> 메소드는 모든 값이 true 일때만 true를 반환하고 하나라도 false인 경우 false 를 반환한다. 반면 <code>some()</code> 메소드는 값 중 하나라도 true이면 true를 반환하고 모든 값이 false일때만 false를 반환한다.</p>
<blockquote>
<p>쉽게 말하자면 <code>every()</code>는 And 조건, <code>some()</code>은 Or 조건이라고 할 수 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TS | 타입스크립트 사용 이유, 기본 타입, 인터페이스, 함수]]></title>
            <link>https://velog.io/@jhyun_k/TypeScript-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@jhyun_k/TypeScript-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Fri, 21 Jul 2023 08:27:41 GMT</pubDate>
            <description><![CDATA[<p>요즘 대세를 따르기 위해 타입스크립트 기초 강좌를 보며 정리해보려한다. 그동안 JavaScript만 써왔어서 걱정되지만 변화하는 흐름을 따라가기 위해.... 영상은 코딩앙마 유튜브 영상을 시청했다.</p>
<h2 id="타입스크립트를-사용하는-이유">타입스크립트를 사용하는 이유</h2>
<ul>
<li>우리가 사용하는 브라우저는 타입스크립트를 이해하지 못한다. 즉, 브라우저가 타입스크립트를 이해하기 위해서는 자바스크립트 언어로 변환한 뒤 읽을 수 있다. 그럼에도 불구하고 타입스크립트를 사용하는 이유는 무엇일까 알아보자.</li>
</ul>
<h3 id="예시">예시</h3>
<p>자바스크립트에서 실행</p>
<pre><code class="language-js">function add(num1,num2){
  console.log(num1+num2);
}
add(); // NaN
add(1) // NaN
add(1,2) // 3
add(3,4,5) // 7 
add(&#39;hello&#39;,&#39;world&#39;);//&#39;helloworld&#39;</code></pre>
<p>숫자 두개를 받아서 둘을 더하는 함수를 만든다고 가정해보자. 인간은 글자만 봐도 인수가 number 여야 한다는 것을 알지만 컴퓨터는 그것을 모른다. 그러나 add함수에 인자 없이 함수를 실행할 때 자바스크립트에서 실행할 경우 아무런 오류 없이 NaN 이 반환된다. (undefined+undefined = NaN), 그 외 인수의 개수를 맞추지 않거나 의도한 바가 아닌 문자열을 입력해도 자바스크립트는 아무런 경고 없이 문자열도 더해준다ㅠ</p>
<h3 id="예시2">예시2</h3>
<p>자바스크립트에서 실행</p>
<pre><code class="language-js">function showItems(arr){
  arr.forEach((item)=&gt;{
    console.log(item);
  });
}

showItems([1,2,3]) ; // 1 2 3
showItems(1,2,3) // TypeError (배열이 아니라 에러 뜸)</code></pre>
<p>배열의 요소를 반환하는 showItems 함수에 배열이 아닌 값을 넣게 되면 타입 에러가 뜬다. </p>
<blockquote>
<p>JavaScript는 동적언어, 런타입에 타입이 결정되고 오류를 발견한다. 개발자가 실수할 때 사용자는 고스란히 오류를 발견하게 된다. 
반면 Java 나 TypeScript의 경우는 정적언어, 컴파일할 때 타입이 결정되고 오류를 발견한다.</p>
</blockquote>
<h3 id="예제를-타입스크립트로-실행해보자">예제를 타입스크립트로 실행해보자</h3>
<pre><code class="language-ts">function add(num1:number,num2:number){
  console.log(num1+num2);
}
add(); // error : Expected 2 arguments, but got 0
add(1) // error : Expected 2 arguments, but got 1
add(1,2) // 3  (^^)
add(3,4,5) // error : Expected 2 arguments, but got 3
add(&#39;hello&#39;,&#39;world&#39;);// error : Argument of type &#39;string&#39; is not assignable to parameter of type &#39;number&#39;</code></pre>
<pre><code class="language-ts">function showItems(arr:number[]){
  arr.forEach((item)=&gt;{
    console.log(item);
  });
}

showItems([1,2,3]) ; // 1 2 3
showItems(1,2,3) // error : Expected 1 arguments, but got 3</code></pre>
<blockquote>
<p>이처럼 타입스크립트는 개발하면서 발생할 수 있는 타입 에러들을 미리 감지하여 알려준다!</p>
</blockquote>
<h2 id="기본-타입">기본 타입</h2>
<pre><code class="language-ts">//string
let car: string = &#39;bmw&#39;;
// car = 3 ; // type error

//number
let age: number = 30;

//boolean
let isAdult: boolean = true;

//array (number)
let a: number[] = [1, 2, 3];
let a2: Array&lt;number&gt; = [1, 2, 3];

//array(string)
let week1: string[] = [&#39;mon&#39;, &#39;tue&#39;, &#39;wed&#39;];
let week2: Array&lt;string&gt; = [&#39;mon&#39;, &#39;tue&#39;, &#39;wed&#39;];

// 튜플(Tuple) - 인덱스별로 타입 다를 때 사용 가능
let b: [string, number] = [&#39;hello&#39;, 123];
b[0].toLowerCase(); // 가능
// b[1].toLowerCase() // error : &#39;toLowerCase&#39; does no exist on ype &#39;number&#39;

//void - 아무것도 반환하지 않을 때
function sayHello(): void {
  console.log(&#39;hello&#39;);
}

//never - 항상 에러 반환하거나 영원히 끝나지 않는 타입
function isfLoop() {
  while (true) {
    //do something..
  }
}

//enum - 비슷한 값들끼리 묶어줌 , 알아서 1씩 증가시켜서 값 배정
enum Os {
  Window, //1
  Ios, //2
  Android, //3
}
let myOs: Os; // Os에 있는 것만 입력할 수 있음

// null , undefined
let nulla: null = null;
let nullb: undefined = undefined;
</code></pre>
<h2 id="인터페이스-interface">인터페이스 (Interface)</h2>
<p>인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미한다. (속성과 속성의 타입, 파라미터, 접근 방식, 클래스 등)</p>
<h3 id="인터페이스-예제">인터페이스 예제</h3>
<p>user라는 object 를 만든다고 가정해보자.</p>
<pre><code class="language-ts">let user:object;

user = {
  name : &#39;xx&#39;,
  age : 30
}

console.log(user.name) // error : Property &#39;name&#39; does not exist on type &#39;object&#39;</code></pre>
<p>프로퍼티 정의해서 객체로 표현하고자 할 때는 인터페이스를 사용한다.</p>
<pre><code class="language-ts">type Score = &#39;A&#39; | &#39;B&#39; | &#39;C&#39; | &#39;F&#39;;

interface User {
  name: string;
  age: number;
  gender?: string; // optional 한 항목 만드려면 항목 이름 뒤에 ? 붙이고 타입 설정해준다.
  readonly birthYear: number; // 값 수정 못하게 하려면 항목 이름 앞에 readonly 라고 써준다.
  [grade: number]: Score; // 문자열 인덱스 서명 추가하기 [key : type] : type (이 경우는 직접 Scroe 타입 만들어서 Score타입 넣어줌)
}

let user: User = {
  name: &#39;xx&#39;,
  age: 30,
  birthYear: 2000,
  1: &#39;A&#39;,
  2: &#39;B&#39;,
};

user.gender = &#39;male&#39;;
// user.birthYear = 1900;//error:Cannot assign to &#39;birtyYear&#39; because it is a read-only property

console.log(user.age); // 30
</code></pre>
<pre><code class="language-ts">interface Add {
  (num1:number,num2:number) : number;
}

const add : Add = function (x,y){
  return x + y;
}

add(10,20) // 30
</code></pre>
<h3 id="boolean-값-반환하는-interface">boolean 값 반환하는 interface</h3>
<pre><code class="language-ts">interface IsAult {
  (age:number):boolean;
}

const a:IsAdult = (age) =&gt;{
  return age &gt; 19;
}

a(33) // true
</code></pre>
<h3 id="interface로-class-만들기-implements">interface로 class 만들기 (implements)</h3>
<pre><code class="language-ts">//implements

interface Car {
  color : string;
  wheels : number;
  start() :void;
}

class Bmw implements Car{
  color;
  wheels = 4;

  constructor(c:string){
    this.color = c&#39;
  }
  start(){
    console.log(&#39;go..&#39;);
  }
  const b =  new Bmw(&#39;green&#39;)
    consoe.log(b) // &#39;wheels&#39; : 4, &#39;color&#39; : &#39;green&#39;
    b.start(); // &#39;go...&#39;</code></pre>
<h3 id="interface는-확장-extends">interface는 확장 (extends)</h3>
<pre><code class="language-ts">interface Benz extends Car{
  door : number;
  stop() : void;
}

const benz : Benz = {
  door : 5,
  stop(){
    console.log(&#39;stop&#39;)
  }
  color : &#39;black&#39;,
  wheels : 4,
  start
}</code></pre>
<h4 id="interface는-여러개-이용해서-확장-가능">interface는 여러개 이용해서 확장 가능</h4>
<pre><code class="language-ts">interface Car {
  color : string;
  wheels : number;
  start():void;
}
interface Toy {
  name : string;
}

interface ToyCar extends Car, Toy {
  price : number;
}
</code></pre>
<h2 id="함수">함수</h2>
<pre><code class="language-ts">function add(num1:number,num2:number):number{
  return num1+num2;
}

//반환값 없는 경우에는 함수의 반환값 타입을 void로 지정
function add(num1:number,num2:number):void{
  console.log(num1+num2)
}</code></pre>
<h3 id="함수-매개변수-선택적으로-지정">함수 매개변수 선택적으로 지정</h3>
<pre><code class="language-ts">function hello(name?:string){ // name 뒤에 ? 붙여서 optional로 지정 (입력 해도 되고 안해도 됨)
  return `Hello, ${name||&quot;world&quot;}`;
}

function hello2(name = &#39;world&#39;){
    return `Hello, ${name}`;
}
const result = hello()
const result2 = hello(&#39;sam&#39;)
const result3 - hello(123) // error
</code></pre>
<pre><code class="language-ts">function hello(name:string, age?:number):string{ // 선택적 매개변수는 무조건 필수 매개변수 뒤에!
  if(age !== undefined){
    return `Hello, ${name}. You are ${age}.`&#39;
  }else {
    return `Hello, ${name}`;
  }
}
console.log(hello(&#39;Sam&#39;)); // Hello, Sam
console.log(hello(&#39;Sam&#39;,30));//Hello, Sam. You are 30</code></pre>
<h3 id="rest-parameterpar-전달받은-매개변수-배열로">rest parameter(...par :전달받은 매개변수 배열로)</h3>
<pre><code class="language-ts">function add(...nums: number[]){
  return nums.reduce((result,num)=&gt; result + num,0);
}

add(1,2,3) // 6
add(1,2,3,4,5,6,7,8,9,10) //55
</code></pre>
<h3 id="this의-타입지정">this의 타입지정</h3>
<p>this의 타입은 맨 앞에 써준다.</p>
<pre><code class="language-ts">interface User{
  name:string;
}

const Sam : User = {name : &#39;Sam&#39;}

function showName(this:User , age:number,gender:&#39;m&#39;|&#39;f&#39;){
  console.log(this.name,age,gender)
}

const a = showName.bind(sam);
a(30,&#39;m&#39;); // &quot;Sam , 30, &#39;m&#39;&quot;</code></pre>
<h3 id="함수-오버로드">함수 오버로드</h3>
<p>함수 오버로드는 전달받은 매개변수의 개수나 타입에 따라 다른 동작을 하게하는 것을 말한다.</p>
<pre><code class="language-ts">interface User3 {
  name: string;
  age: number;
}

//함수 오버로드
function join(name: string, age: string): string; // age가 string이면 string 반환
function join(name: string, age: number): User3; // age가 number면 User반환

function join(name: string, age: number | string): User3 | string {
  if (typeof age === &#39;number&#39;) {
    return {
      name,
      age,
    };
  } else {
    return &#39;나이는 숫자로 입력하셈&#39;;
  }
}

const sam: User3 = join(&#39;Sam&#39;, 30); // &#39;Sam&#39;,30&#39;
const jane: string = join(&#39;Jane&#39;, &#39;30&#39;); // &#39;나이는 숫자로 입력하셈&#39;

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux-Toolkit 연습하기 ]]></title>
            <link>https://velog.io/@jhyun_k/Redux-Tookit%EC%97%B0%EC%8A%B5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/Redux-Tookit%EC%97%B0%EC%8A%B5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 11 Jul 2023 09:12:12 GMT</pubDate>
            <description><![CDATA[<h2 id="리덕스-툴킷-간단-설명">리덕스 툴킷 간단 설명</h2>
<p>리덕스 툴킷은 상태관리 라이브러리인 리덕스의 문제점을 보완하기 위해 만들어졌다. </p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/b3908377-0544-4b20-9523-57eb62868801/image.png" alt=""></p>
<blockquote>
</blockquote>
<ul>
<li>store에서 state를 구독하여 어떻게 변경시킬지에 대한 정보를 담아서 action이라는 객체를 만든다. </li>
<li>그리고 그 action을 dispatch(처리될 작업을 실행시키고 보내는 것)해서 reducer에 넘겨준다</li>
<li>reducer는 action의 정보를 보고 state를 정해진 규칙에 따라 변경한다.<blockquote>
</blockquote>
</li>
<li>최종적으로는 전역state가 변경되고 해당하는 state를 구독하던 component들은 리렌더링된다.</li>
</ul>
<p>하지만 이러한 리덕스에는 여러 불편한 점이 있었다.</p>
<blockquote>
<ol>
<li>기존 redux는 리덕스 스토어를 구성하는 것은 너무 복잡했다.</li>
<li>너무 많은 패키지를 설치해야했다. (redux devtool, immer, thunk 등) redux-toolkit 내부에 이미 설치가 되어 있기에 굳이 설치 할 필요가 없다.</li>
<li>보일러 플레이트 코드가 너무 많다.<blockquote>
<p>보일러 플레이트 (Boiler Plate) : 최소한의 변경으로 여러곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드를 말한다. 간단히 말해서 &#39;묻지도 따지지도 않고 써야하는 코드&#39; </p>
</blockquote>
</li>
</ol>
</blockquote>
<h2 id="연습">연습</h2>
<p>리덕스 툴킷은 복잡한 리덕스를 보완하기 위해 고안되었지만 아직 나에게는 리덕스 툴킷도 연습이 필요하다. 때문에 간단히 반복되는 패턴의 방식으로 리덕스 툴킷 상태관리에 익숙해져보고자 한다.</p>
<p>구현하고자 하는 기능은 Counter, Todo, Auth, Cart이다.</p>
<h2 id="반복되는-코드-설명">반복되는 코드 설명</h2>
<ul>
<li><code>useDispatch()</code> : 생성한 action을 useDispatch를 통해 발생시킬 수 있다, 만들어둔 액션 생성 함수를 import한다.</li>
<li><code>useSelector()</code> : 리덕스의 state를 조회할 수 있다.</li>
<li><code>createSlice</code> : 리듀서 함수의 객체, 슬라이스 이름, 초기 상태 값을 받아들이고 해당 액션 생성자와 액션 유형으로 슬라이스 리듀서를 자동으로 생성</li>
</ul>
<h3 id="storejs">store.js</h3>
<pre><code class="language-javascript">import { configureStore } from &#39;@reduxjs/toolkit&#39;;
import counterSlice from &#39;./counterSlice&#39;;
import todoSlice from &#39;./todoSlice&#39;;
import authSlice from &#39;./authSlice&#39;;
import cartSlice from &#39;./cartSlice&#39;;

const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
    todo: todoSlice.reducer,
    auth: authSlice.reducer,
    cart: cartSlice.reducer,
  },
});

export default store;</code></pre>
<p>이렇게 store.js에서 구독하고자 하는 state를 설정한다.</p>
<h2 id="counter">Counter</h2>
<p>plus, minus, reset 기능</p>
<h3 id="counterslicejs">counterSlice.js</h3>
<pre><code class="language-js">import { createSlice } from &#39;@reduxjs/toolkit&#39;;

const initialState = {
  id: 1,
  value: 0,
};

const counterSlice = createSlice({
  name: &#39;counter&#39;,
  initialState,
  reducers: {
    plus: (state, action) =&gt; {
      state.value = state.value + action.payload;
    },
    minus: (state, action) =&gt; {
      state.value = state.value - action.payload;
    },
    init: (state, action) =&gt; {
      state.value = 0;
    },
  },
});

export default counterSlice;
export const { plus, minus, init } = counterSlice.actions;</code></pre>
<h3 id="counterreduxjsx">CounterRedux.jsx</h3>
<pre><code class="language-javascript">import React from &#39;react&#39;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { plus, minus, init } from &#39;../store/counterSlice&#39;;

const CounterRedux = () =&gt; {
  const dispatch = useDispatch();
  const count = useSelector((state) =&gt; {
    return state.counter.value;
  });
  const plusNum = () =&gt; {
    dispatch(plus(1));
  };
  const minusNum = () =&gt; {
    dispatch(minus(1));
  };
  const resetNum = () =&gt; {
    dispatch(init());
  };

  return (
    &lt;div&gt;
      &lt;hr /&gt;
      &lt;div&gt;{count}&lt;/div&gt;
      &lt;button onClick={minusNum}&gt;-&lt;/button&gt;
      &lt;button onClick={plusNum}&gt;+&lt;/button&gt;
      &lt;button onClick={resetNum}&gt;reset&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default CounterRedux;</code></pre>
<h2 id="todo">Todo</h2>
<p>add, delete, check 기능</p>
<h3 id="todoslicejs">todoSlice.js</h3>
<pre><code class="language-js">import { createSlice } from &#39;@reduxjs/toolkit&#39;;

const initialState = [];

export const todoSlice = createSlice({
  name: &#39;todolist&#39;,
  initialState,
  reducers: {
    addTodo: (state, action) =&gt; {
      return [...state, action.payload];
    },
    deleteTodo: (state, action) =&gt; {
      return state.filter((todo) =&gt; todo.id !== action.payload);
    },
    checkTodo: (state, action) =&gt; {
      const todo = state.find((todo) =&gt; todo.id === action.payload);
      if (todo) {
        todo.checked = !todo.checked;
      }
    },
  },
});

export default todoSlice;
export const { addTodo, deleteTodo, checkTodo } = todoSlice.actions;</code></pre>
<h3 id="todoreduxjsx">TodoRedux.jsx</h3>
<pre><code class="language-js">import React, { useState } from &#39;react&#39;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { addTodo, deleteTodo, checkTodo } from &#39;../store/todoSlice&#39;;

const TodoRedux = () =&gt; {
  const [input, setInput] = useState(&#39;&#39;);

  const dispatch = useDispatch();
  const todos = useSelector((state) =&gt; {
    return state.todo;
  });
  const onCreate = () =&gt; {
    if (input.trim() !== &#39;&#39;) {
      const newTodo = {
        id: Date.now(),
        text: input,
        checked: false,
      };
      dispatch(addTodo(newTodo));
    }
    setInput(&#39;&#39;);
  };
  const onDelete = (id) =&gt; {
    dispatch(deleteTodo(id));
  };
  const handleInput = (e) =&gt; {
    setInput(e.target.value);
  };
  const onChecked = (id) =&gt; {
    dispatch(checkTodo(id));
  };

  return (
    &lt;div&gt;
      &lt;h2&gt;Redux로 할 일 목록&lt;/h2&gt;
      &lt;input
        type=&quot;text&quot;
        placeholder=&quot;오늘할일&quot;
        onChange={handleInput}
        value={input}
      /&gt;
      &lt;button onClick={onCreate}&gt;추가하기&lt;/button&gt;
      &lt;ul&gt;
        {todos.map((item) =&gt; (
          &lt;div key={item.id}&gt;
            &lt;li
              onClick={() =&gt; onChecked(item.id)}
              style={
                item.checked
                  ? { textDecoration: &#39;line-through&#39; }
                  : { textDecoration: &#39;none&#39; }
              }
            &gt;
              {item.text}
            &lt;/li&gt;
            &lt;button onClick={() =&gt; onDelete(item.id)}&gt;삭제하기&lt;/button&gt;
          &lt;/div&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
};

export default TodoRedux;</code></pre>
<h2 id="auth">Auth</h2>
<p>auth라기에는 그저 상태에 따라 토글하는 정도인...</p>
<h3 id="authslicejs">authSlice.js</h3>
<pre><code class="language-js">import { createSlice } from &#39;@reduxjs/toolkit&#39;;

const initialState = {
  value: false,
};

const authSlice = createSlice({
  name: &#39;auth&#39;,
  initialState,
  reducers: {
    changeAuth: (state, action) =&gt; {
      state.value = !action.payload;
    },
  },
});

export default authSlice;
export const { changeAuth } = authSlice.actions;</code></pre>
<h3 id="authreduxjsx">AuthRedux.jsx</h3>
<pre><code class="language-js">import React from &#39;react&#39;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { login, logout, changeAuth } from &#39;../store/authSlice&#39;;

const AuthRedux = () =&gt; {
  const dispatch = useDispatch();
  const auth = useSelector((state) =&gt; {
    return state.auth.value;
  });
  const loginUser = () =&gt; {
    dispatch(login(true));
  };
  const logoutUser = () =&gt; {
    dispatch(logout(false));
  };
  const authChange = () =&gt; {
    dispatch(changeAuth(auth));
  };
  return (
    &lt;div&gt;
      &lt;h2&gt;Redux로 auth상태에 따른 토글 만들기&lt;/h2&gt;
      &lt;p&gt;{auth ? &#39;로그인상태&#39; : &#39;로그아웃상태&#39;}&lt;/p&gt;
      &lt;button onClick={authChange}&gt;
        {auth ? &#39;로그아웃하기&#39; : &#39;로그인하기&#39;}
      &lt;/button&gt;
    &lt;/div&gt;
  );
};

export default AuthRedux;</code></pre>
<h2 id="cart">Cart</h2>
<p>상품1 과 상품2를 넣는 action 감지</p>
<h3 id="cartslicejs">cartSlice.js</h3>
<pre><code class="language-js">import { createSlice } from &#39;@reduxjs/toolkit&#39;;

const initialState = [];

const cartSlice = createSlice({
  name: &#39;cart&#39;,
  initialState,
  reducers: {
    addItem_1: (state, action) =&gt; {
      return [...state, action.payload];
    },
    addItem_2: (state, action) =&gt; {
      return [...state, action.payload];
    },
    deleteItem: (state, action) =&gt; {
      return state.filter((item) =&gt; item.id !== action.payload);
    },
  },
});

export default cartSlice;
export const { addItem_1, addItem_2, deleteItem } = cartSlice.actions;</code></pre>
<h3 id="cartreduxjsx">CartRedux.jsx</h3>
<pre><code class="language-js">import React from &#39;react&#39;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { addItem_1, addItem_2, deleteItem } from &#39;../store/cartSlice&#39;;

const CartRedux = () =&gt; {
  const dispatch = useDispatch();
  const cart = useSelector((state) =&gt; {
    return state.cart;
  });
  const addItem01 = () =&gt; {
    const newItem = {
      id: Date.now(),
      value: &#39;상품1&#39;,
      price: 10000,
    };
    dispatch(addItem_1(newItem));
  };
  const addItem02 = () =&gt; {
    const newItem = {
      id: Date.now(),
      value: &#39;상품2&#39;,
      price: 20000,
    };
    dispatch(addItem_2(newItem));
  };

  const onDelete = (id) =&gt; {
    dispatch(deleteItem(id));
  };
  return (
    &lt;div&gt;
      &lt;h2&gt;Redux로 쇼핑카트 만들기&lt;/h2&gt;

      &lt;ul&gt;
        {cart.map((item) =&gt; (
          &lt;li key={item.id}&gt;
            {item.value} - {item.price}원
            &lt;button onClick={() =&gt; onDelete(item.id)}&gt;제거&lt;/button&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
      &lt;button onClick={addItem01}&gt;상품1 추가&lt;/button&gt;
      &lt;button onClick={addItem02}&gt;상품2 추가&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default CartRedux;</code></pre>
<h2 id="정리">정리</h2>
<p>처음에는 사실 잘 이해가 되지 않았는데 다양한 예시로 상태를 변화시켜보니 어떤 로직으로 움직이는지 어느정도 이해가 되었다. 하지만 실제로 거대한 프로젝트에서 쓰기 위해서는 더욱 연습이 필요할듯싶다. </p>
<p>상태관리 라이브러리에는 리덕스(툴킷) 이외에도 다양하다. 각 라이브러리의 장단점을 비교하여 익히는 과정이 필요할 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS Momentum Todolist 만들기]]></title>
            <link>https://velog.io/@jhyun_k/JS-Momentum-Todolist-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/JS-Momentum-Todolist-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 04 Jul 2023 10:08:01 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/jhyun-k/Momentum">깃허브 레포</a>
<a href="https://jhyun-k.github.io/Momentum/">배포링크</a></p>
<p>JS 연습 삼아 이번에는 많은 사람들이 만들어본다는 Momentum 어플리케이션을 만들어보았다. 모 강사의 인터넷강의 챌린지로 많이 만드는 것 같던데 챌린지를 듣지는 않았지만 이런거 만들면 이쁠 것 같아서 독자적으로 만들어보았다..^^ 간지</p>
<h2 id="html-코드">html 코드</h2>
<pre><code class="language-html">&lt;body&gt;
    &lt;div class=&#39;wrap&#39;&gt;
        &lt;div id=&#39;weather&#39;&gt;
            &lt;img src=&quot;&quot; alt=&quot;&quot; class=&#39;icon&#39;&gt;
            &lt;p class=&#39;temp&#39;&gt;&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class=&#39;date&#39;&gt;&lt;/div&gt;
        &lt;div class=&#39;container&#39;&gt;
            &lt;div class=&#39;clock&#39;&gt;&lt;/div&gt;
            &lt;div class=&#39;greet&#39;&gt;
                &lt;p&gt;안녕하세요!&lt;/p&gt;&lt;input type=&quot;text&quot; class=&quot;name&quot; placeholder=&#39;이름을 입력해주세요&#39;&gt;
            &lt;/div&gt;
            &lt;div class=&#39;todoContainer&#39;&gt;
                &lt;form action=&quot;&quot; class=&#39;inputContainer&#39;&gt;
                    &lt;input type=&quot;text&quot; name=&#39;task&#39; autocomplete=&#39;off&#39; placeholder=&#39;Write your plan!&#39;&gt;
                    &lt;button class=&#39;addBtn&#39;&gt;추가하기&lt;/button&gt;
                &lt;/form&gt;
                &lt;div&gt;
                    &lt;ul class=&#39;todoList&#39;&gt;
                    &lt;/ul&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;</code></pre>
<h2 id="기능설명">기능설명</h2>
<h3 id="날짜-가져오기">날짜 가져오기</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/18cdae37-711f-4dc9-8a18-575d6b1ea026/image.png" alt=""></p>
</blockquote>
<ul>
<li>Date 객체 이용하여 년, 월, 일, 요일 가져오기</li>
<li>dayArr 배열 만들어서 index와 getDat() 가 같은 값을 filter 함수로 가져오기</li>
</ul>
<h3 id="사용자-이름-입력">사용자 이름 입력</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/6345f0b9-ccba-4b4b-b012-7b419ab8d50a/image.gif" alt=""></p>
</blockquote>
<p>input 에 사용자 이름을 입력하고 엔터를 누르면 환영인사를 해준다. 사용자 이름은 로컬스토리지에 저장되어 새로고침 해도 사라지지 않고 로그아웃 버튼을 눌러야 사라진다.</p>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/16c06859-af8b-47f5-9dc5-85dde76f8c0f/image.png" alt=""></p>
<h3 id="투두리스트-추가완료삭제">투두리스트 추가/완료/삭제</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/b975cdea-c963-4cd4-846c-de8ef3c16eae/image.gif" alt="">
간단한 투두리스트이다. 투두리스트 또한 로컬스토리지에 저장되고 로그아웃하면 정보가 사라진다. item 을 누르면 완료했다는 뜻으로 취소선이 그어지고 한 번 더 누르면 취소선이 사라진다 (toggle), 삭제 버튼을 누르면 항목이 삭제된다.</p>
</blockquote>
<ul>
<li>할일 추가
<img src="https://velog.velcdn.com/images/jhyun_k/post/7650783c-a931-4b54-96d9-1d9f8ccf295a/image.png" alt=""><blockquote>
</blockquote>
</li>
<li>할일 삭제 및 체크
<img src="https://velog.velcdn.com/images/jhyun_k/post/757072c4-a3b3-47c0-be0a-a4b8f62068df/image.png" alt=""></li>
</ul>
<h3 id="새로고침하여도-정보유지">새로고침하여도 정보유지</h3>
<blockquote>
<p><img src="https://github.com/jhyun-k/Momentum/assets/105181266/a46f2a51-4ebf-4607-a2c4-2f9460ef9fbc" alt="chrome_RBHFpHSo4l">
앞서 말했듯 로컬스토리지에 저장하여 새로고침해도 정보는 사라지지 않고 배경이미지만 바뀐다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/2a628067-827f-4ae0-ad40-a204af76532b/image.png" alt=""></p>
</blockquote>
<ul>
<li>saveToDos 함수를 통해 todo 아이템을 로컬스토리지에 저장하고, 새로고침을 해도 todoKey 라는 key값을 기준으로 할 일 목록 불러옴</li>
<li>처음 환영인사 만드는 <code>init</code> 함수에도 사용자 이름을 저장하기 위해 <code>localStorage.setItem(userKey, JSON.stringify(user));</code> 나 <pre><code class="language-javascript">const loadedUser = localStorage.getItem(userKey);
if (loadedUser !== null) {
  const parsedItem = JSON.parse(loadedUser);</code></pre>
같은 코드를 통해 로컬스토리지의 정보를 불러왔다.</li>
</ul>
<h3 id="로그아웃기능">로그아웃기능</h3>
<blockquote>
<p><img src="https://github.com/jhyun-k/Momentum/assets/105181266/d403bd12-98ee-4f4e-9bad-4cdcde2f6771" alt="chrome_DvpfXKQXEz">
보이는 것과 같이 로그아웃 버튼을 누르면 로컬스토리이제 있는 사용자 정보가 삭제되고 초기화면으로 돌아간다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/5edec5dd-b4df-4ddf-ae49-b8b80f7b3efe/image.png" alt=""></p>
</blockquote>
<ul>
<li>간단하게 그냥 <code>localStorage.removeItem</code> 해주면 userKey와 todoKey 라는 키를 갖고있는 모든 정보들이 삭제된다.</li>
</ul>
<h3 id="날씨-api-이용하여-현재-위치의-날씨-가져오기">날씨 api 이용하여 현재 위치의 날씨 가져오기</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/e4593c96-5176-45f4-90c1-91eb3277f2d1/image.png" alt=""></p>
</blockquote>
<ul>
<li>위 이미지들의 우측 상단을 보면 작게 날씨정보와 기온이 써있는 것을 확인할 수 있다. openweather api를 이용하여 현재 위치정보와 기온을 불러오고 그에 맞는 아이콘을 띄워준다.</li>
</ul>
<h2 id="트러블슈팅">트러블슈팅</h2>
<blockquote>
<ol>
<li><code>setInterval</code> 로 시계를 만들었는데 delay를 1초인 1000으로 설정해놓으니 시계가 뜨는 것도 1초 후에 떠서 문제가 생겼다. 이를 해결하려 찾아보니 먼저 <code>getTime</code>이라는 시계생성함수를 <strong>즉시실행함수</strong>로 먼저실행한 후 setInterval 함수를 이용해야 화면이 켜지는 즉시 시계가 뜨고 1초마다 초가 바뀐다.</li>
</ol>
</blockquote>
<ol start="2">
<li>투두리스트를 추가할 때 flex 로 정렬해놓다보니 추가할때마다 크기가 점점 늘어나서 인사와 시계를 밀어버리는 상황이 일어났다. 이를 막고자 투두리스트를 감싸는 컨테이너를 만들어 height 를 지정하니 해결되었다.<blockquote>
</blockquote>
</li>
<li>투두리스트 flex 의 <code>justify-content</code> 를 space-between으로 해놓으니 투두리스트가 아래부터 추가되고, center로 하니 또 자꾸 크기가 늘어났다. 속성을 flex-start로 바꾸자 정상적으로 처음부터 생성되었다.<blockquote>
</blockquote>
</li>
<li>로그아웃 기능을 구현할 때 사용자이름을 입력하고 새로고침을 하지 않으면 기능이 동작하지 않았다. enter키 입력 이벤트를 할 때에는 logoutBtn 변수가 할당되어있지 않아서 발생하는 문제였다. enter키 입력 이벤트 함수 안에도 logout함수를 넣으니 해결되었다.</li>
</ol>
<h2 id="결론">결론</h2>
<p>모든 코드들이 js를 처음 배울 때 자주 하는 실습들이라 쉽게 할 줄 알았지만 이 모든 것들이 얽혀있다보니 가끔 예기치못한 오류들이 나타나 당혹스러웠다. 하지만 원하는 기능을 모두 갖춘 완결된 어플리케이션을 만드니 재미있고 뿌듯했다. 다음엔 뭘 만들까?</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이벤트 루프(Event Loop)]]></title>
            <link>https://velog.io/@jhyun_k/%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84</link>
            <guid>https://velog.io/@jhyun_k/%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84</guid>
            <pubDate>Thu, 29 Jun 2023 09:56:37 GMT</pubDate>
            <description><![CDATA[<p>이번에는 이벤트루프에 대해 써보려고한다.</p>
<blockquote>
<p>목차</p>
</blockquote>
<ol>
<li>개요</li>
<li>자바스크립트 엔진 </li>
<li>런타임환경
3-1. Web APIs
3-2. 콜백 큐</li>
<li>이벤트루프</li>
<li>태스크큐와 마이크로태스크큐</li>
<li>정리</li>
</ol>
<h2 id="개요">개요</h2>
<blockquote>
<p>” 자바스크립트는 싱글 쓰레드 기반이며 논 블로킹 방식의 비동기적인 동시성 언어이며 콜 스택, 이벤트 루프와 콜백 큐 그리고 여러가지 다른 API들을 가지고 있다. ”</p>
</blockquote>
<h3 id="자바스크립트는-싱글스레드-기반의-프로그래밍-언어이다">자바스크립트는 싱글스레드 기반의 프로그래밍 언어이다.</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/f848097b-1226-49f5-ad07-dd4eeaa8258e/image.png" alt=""></p>
<p>자바스크립트의 특징 중 하나는 싱글 스레드 언어라는 것이다. 이는 콜스택이 하나이고 따라서 한 번에 하나의 태스크만 처리할 수 있다는 뜻이다. 하지만 막상 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 보인다. </p>
<p>이는 비동기로 동작하기 때문에 단일 스레드임에도 불구하고 동시에 많은 작업을 수행할 수 있는 것은 이벤트루프 덕분이다. 자바스크립트는 이벤트 루프를 이용해서 비동기 방식으로 동시성을 지원한다. </p>
<h2 id="자바스크립트-엔진">자바스크립트 엔진</h2>
<p>자바스크립트 엔진은 JS코드를 이해하고 실행하는 것을 도와준다. 가장 유명한 엔진으로는 구글의 V8이 있다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/d6a11bf2-46dd-4fec-ad25-5b785d8238e1/image.png" alt=""></p>
<p>자바스크립트 엔진은 크게 <strong>메모리힙</strong>과 <strong>콜스택</strong>으로 이루어져 있다. </p>
<ul>
<li>메모리 힙 : <code>메모리 할당이 일어나는 장소</code> 
(우리가 프로그램에 선언한 변수, 함수 등) </li>
<li>콜 스택:  <code>코드가 실행될 경우 하나씩 stack의 형태로 쌓이는 장소</code> 
한 번에 여러 개를 실행시키는게 아닌 하나씩 실행<ul>
<li>Stack 구조란 자료구조 중 하나로 선입후출(LIFO, Last In First Out)의 룰을 따른다. (마지막에 들어간게 먼저 나감)</li>
</ul>
</li>
</ul>
<h2 id="런타임-환경">런타임 환경</h2>
<p>여기서 중요한 사실은 자바스크립트에는 이벤트 루프가 없다는 것이다. V8과 같은 자바스크립트 엔진은 단일 호출 스택을 사용하고, 요청이 들어오면 그 순서에 따라 순차적으로 처리할 뿐입니다.</p>
<p>비동기 요청은 자바스크립트 엔진을 구동하는 런타임 환경, 즉 브라우저나 Node.js가 담당한다. 런타임 환경에서는 Web API와 Event Loop를 제공한다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/06bfe11d-b368-4c01-9b38-444ec2909cdc/image.png" alt=""></p>
<p>이렇게 자바스크립트 엔진과 런타임환경이 만나 앞서 나왔던 익숙한 그림이 완성된다. </p>
<h3 id="web-apis">Web APIs</h3>
<p>그림을 보면 Web APIs는 자바스크립트 엔진 밖에 그려져있는 것을 볼 수 있다. 즉, Web APIs는 자바스크립트 엔진이 아니고 브라우저에서 제공하는 API이다.  DOM, Ajax, TimeOut 등이 있다. 콜스택에서 실행된 비동기 함수들은 모두 Web API를 호출한다. 그리고 Web API는 비동기 함수의 콜백 함수를 <code>콜백 큐</code>(Callback Queue)에 넣는다.</p>
<h3 id="콜백-큐-callback-queue">콜백 큐 (Callback Queue)</h3>
<p><code>비동기적으로 실행된 콜백 함수가 보관되는 곳</code>이다. 쉽게 말하면 콜 스택에 가기 위한 대기열이라고 할 수 있다.</p>
<ul>
<li>큐 : 자료 구조 중 하나, 선입선출(FIFO, Frist In Frist OUT)의 룰을 따른다. (빨리 들어온 게 빨리 나감) </li>
</ul>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/5aa1fe4a-2e39-4715-8d12-5b3ffebe8f0c/image.png" alt="">
콜백큐에는 세가지 종류가 있다. 태스크 큐,마이크로태스크 큐,애니메이션 프레임이 그것이다.</p>
<blockquote>
</blockquote>
<ul>
<li>태스크 큐 : setTimeout, setInterval 등</li>
<li>마이크로태스크 큐 : Promise callback, async callback 등</li>
<li>애니메이션 프레임 : requestAnimationFrame</li>
</ul>
<h2 id="이벤트-루프-evnet-loop">이벤트 루프 (Evnet Loop)</h2>
<p>이제 남은 것은 이벤트루프 뿐이다. 자바스크립트 엔진과 그 런타임 환경을 상호 연동 시켜주는 장치가 바로 이벤트 루프이다. 이벤트루프의 원리는 간단하다. </p>
<blockquote>
<p>콜 스택과 콜백 큐를 감시하다가 콜 스택에 쌓여있는 함수가 없는 경우, 콜백 큐에 있는 콜백함수를 콜 스택으로 넘긴다. </p>
</blockquote>
<p>여기서 큐마다 우선순위가 다르고 우선순위에 따라 순차적으로 스택으로 옮겨진다. 우선순위는 <strong><code>마이크로태스크 큐 &gt; 애니메이션 프레임 &gt; 태스크 큐</code></strong> 순으로 우선순위가 높은 큐가 비워져야만 다음 큐가 실행된다.</p>
<h2 id="태스크-큐와-마이크로태스크-큐">태스크 큐와 마이크로태스크 큐</h2>
<p>여기서 태스크 큐와 마이크로태스크 큐를 자세히 알아보면 앞서 말했듯이 마이크로 태스크 큐의 콜백함수가 우선순위를 가지고 때문에 마이크로태스크 큐의 콜백 함수를 전부 실행하고나서 태스크 큐의 콜백 함수들을 실행한다.</p>
<ul>
<li>태스크 큐<ul>
<li><code>setTimeout()</code>, <code>setInterval()</code>, UI 렌더링, <code>script</code>, <code>mousemove</code></li>
<li>일반적인 이벤트 핸들러, 콜백함수라고 보면 된다.</li>
</ul>
</li>
</ul>
<ul>
<li><p>마이크로태스크 큐</p>
<ul>
<li><code>Promise</code> (.then/catch/finally), <code>MutationObserver</code>, <code>async/await</code></li>
</ul>
</li>
</ul>
<blockquote>
<p>여기서 면접 단골 질문인 <code>setTimeOut()</code>과 <code>Promise</code> 객체의 함수 중 어떤 것이 먼저 실행될까요? 하는 질문들이 나오는 것이다. </p>
<blockquote>
<p>이벤트 루프는 콜 스택을 감시하고 있다가 콜 스택이 비면 콜백 큐에 있는 콜백 함수를 스택으로 넘긴다. 이 때 마이크로 태스크큐가 태스크큐 보다 먼저 실행되기 때문에 Promise 객체의 함수가 먼저 실행되고 setTimeOut() 함수가 실행된다.</p>
</blockquote>
</blockquote>
<pre><code class="language-javascript">console.log(&#39;안녕&#39;);
setTimeout(() =&gt; console.log(&#39;큐!&#39;),0);
Promise.resolve().then(() =&gt; console.log(&#39;마이크로 큐!&#39;));</code></pre>
<p>의 코드에서 결과는</p>
<pre><code>안녕
마이크로 큐!
큐!</code></pre><p>가 되는 것이다.</p>
<h2 id="정리">정리</h2>
<p>이벤트 루프의 원리는 간단한데 이를 설명하기 위해서는 자바스크립트 엔진과 실행환경에 대한 이해가 필요하다. 때문에 면접 단골 질문이 된 듯하다.</p>
<blockquote>
<ul>
<li>코드가 실행되면 콜 스택(Call Stack)에 쌓이고 선입후출 방식대로 실행된다. </li>
</ul>
</blockquote>
<ul>
<li>이 때 비동기 함수가 실행되면  Web API가 호출된다. Web API는 비동기함수의 콜백함수를 콜백 큐(Callback Queue)에 밀어넣는다<ul>
<li>각각 함수에 따라 맞는 큐로 (setTimeOut 은 태스크 큐, Promise 는 마이크로태스크 큐)</li>
<li>이벤트루프(Event Loop)는 콜 스택과 콜백 큐를 계속 감시하고 있다가 콜 스택이 빈 상태가 되면 큐에 있는 콜백을 콜 스택으로 이동시킨다 <ul>
<li>큐의 우선 순위는 <code>마이크로태스크 큐 &gt; 애니메이션 프레임 &gt; 태스크 큐</code> 이다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="출처">출처</h4>
<p> <a href="https://medium.com/sessionstack-blog/how-does-javascript-actually-work-part-1-b0bacc073cf">How JavaScript works: an overview of the engine, the runtime, and the call stack</a></p>
<p> <a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ">YouTube | 어쨌든 이벤트 루프는 무엇입니까? </a></p>
<p> <a href="https://joshua1988.github.io/web-development/translation/javascript/how-js-works-inside-engine/">자바스크립트의 동작원리: 엔진, 런타임, 호출 스택</a></p>
<p> <a href="https://velog.io/@leemember/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EB%8B%A8%EA%B3%A8-%EA%B0%9C%EB%85%90%EB%93%A4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8E%B8#%F0%9F%A7%91-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84-%EF%B8%8F-%EB%8B%A8%EA%B3%A8-%EC%A7%88%EB%AC%B8-top5">Velog  | 프론트엔드 기술 면접 단골 개념들 정리</a></p>
<p> <a href="https://baeharam.netlify.app/posts/javascript/event-loop">Tistory | [JS] 도대체 이벤트 루프가 뭔가요?</a></p>
<p> <a href="https://medium.com/sjk5766/javascript-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%95%B5%EC%8B%AC-event-loop-%EC%A0%95%EB%A6%AC-422eb29231a8">Tistory | JavaScript 비동기 핵심 Event Loop 정리</a></p>
<p> <a href="https://talkwithcode.tistory.com/89">Tistory | Javascript Event Loop 이벤트 루프 정리</a></p>
<p> <a href="https://velog.io/@thms200/Event-Loop-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84">Velog  | Event Loop (이벤트 루프)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 로 계산기 만들기]]></title>
            <link>https://velog.io/@jhyun_k/js-calculator</link>
            <guid>https://velog.io/@jhyun_k/js-calculator</guid>
            <pubDate>Mon, 19 Jun 2023 13:20:40 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트 연습 겸 하여 사칙연산 계산기를 만들어보았다. 처음에는 간단할 거라 생각했지만 생각보다 고려해야할 점이 많았다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/70642bb3-771d-49e5-b828-7960c3c3ce4a/image.gif" alt=""></p>
<p>복잡한 계산은 아니지만 사칙연산 기능은 문제없이 작동된다.</p>
<h2 id="🧱-html">🧱 HTML</h2>
<blockquote>
<p>버튼을 이렇게 일일이 만드는 방법 뿐인가 고민을 했지만 당장 생각나는 방안이 없어 그냥 16개의 버튼을 다 만들었다. 연산자는 <code>operator</code> , 숫자는 <code>numBtn</code>, 초기화는 <code>ac</code>, 결과는 <code>result</code> 라는 클래스를 각각 달아주어 조작했다.</p>
</blockquote>
<pre><code>&lt;body&gt;
    &lt;div class=&#39;wrap&#39;&gt;
        &lt;div class=&#39;display&#39;&gt;
            &lt;div class=&#39;input&#39;&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;div class=&#39;buttons&#39;&gt;
            &lt;button data-type=&quot;ac&quot; class=&#39;ac&#39;&gt;C&lt;/button&gt;
            &lt;button data-type=&#39;operator&#39; class=&#39;operator&#39;&gt;+&lt;/button&gt;
            &lt;button data-type=&#39;operator&#39; class=&#39;operator&#39;&gt;-&lt;/button&gt;
            &lt;button data-type=&#39;operator&#39; class=&#39;operator&#39;&gt;x&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;7&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;8&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;9&lt;/button&gt;
            &lt;button data-type=&#39;operator&#39; class=&#39;operator&#39;&gt;/&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;4&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;5&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;6&lt;/button&gt;
            &lt;button data-type=&#39;result&#39; class=&#39;result&#39;&gt;=&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;1&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;2&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;3&lt;/button&gt;
            &lt;button class=&#39;numBtn&#39;&gt;0&lt;/button&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;</code></pre><h2 id="🎨style">🎨Style</h2>
<blockquote>
<p>이유는 모르겠는데 다른 계산기를 만든 분들이 아이폰 기본 계산기의 색감을 따르고 있길래 나도 그렇게 만들어보았다. 사실 디자인적으로 큰 고민은 하지 않은 것 같😅</p>
</blockquote>
<pre><code class="language-css">.wrap {
  margin: 100px auto;
  width: 300px;
  height: 400px;
  border: 1px solid transparent;
  background-color: rgb(151, 151, 151);
  border-radius: 5px;
}
.input {
  height: 20px;
  text-align: right;
}
.display {
  display: flex;
  flex-direction: column;
  height: 50px;
  font-size: 36px;
  font-weight: 700;
  border: 1px solid #777676;
  margin: 5px 5px 0 5px;
  padding: 10px;
  border-radius: 5px;
  background-color: #777676;
  color: #fff;
}
.buttons {
  padding: 5px;
  display: grid;
  height: calc(100% - 85px);
  gap: 5px;
  grid-template-columns: repeat(4, 1fr);
}
button {
  color: #fff;
  font-size: 36px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.numBtn {
  background-color: #828284;
}
.operator,
.result,
.ac {
  background-color: orange;
}</code></pre>
<h2 id="💪-js">💪 JS</h2>
<blockquote>
</blockquote>
<ul>
<li>기본적인 계산 기능은 <code>calculate</code> 함수를 만들었다. <code>switch</code>문을 이용하여 각 연산자 버튼을 눌렀을 때 인자로 받은 첫번째 수와 두번째 수를 계산해준다.</li>
<li><code>operatorOn</code> , <code>previoustNum</code> , <code>resentNum</code> 은 각각 연산자를 입력했는지, 이전값인지 직전값인지 판별해주는 변수이다. (연속해서 계속 계산할 수 있도록 연산자를 누른 순간 방금까지 display에 있던 숫자가 previousNum이 된다)<pre><code class="language-javascript">const buttons = document.querySelectorAll(&#39;button&#39;);
const operators = document.querySelectorAll(&#39;.operator&#39;);
const displayElement = document.querySelector(&#39;.input&#39;);
const numBtn = document.querySelectorAll(&#39;.numBtn&#39;);
&gt;
let operatorOn = &#39;&#39;; // 연산자 입력
let previousNum = &#39;&#39;; //이전 값
let resentNum = &#39;&#39;; // 최근값
&gt;
//calculate 함수 (previousNum, operatorOn, resentNum 인자로 받음)
let calculate = (n1, operator, n2) =&gt; {
let result = 0;
switch (operator) {
  case &#39;+&#39;:
    result = Number(n1) + Number(n2);
    break;
  case &#39;-&#39;:
    result = Number(n1) - Number(n2);
    break;
  case &#39;x&#39;:
    result = Number(n1) * Number(n2);
    break;
  case &#39;/&#39;:
    result = Number(n1) / Number(n2);
    break;
  default:
    break;
}
return String(result);
};
&gt;</code></pre>
</li>
<li>첫번째 자리에 0이 오면 안되기 때문에 <code>isFirstDigit</code> 변수를 만들어 판별한다. 023 이런거 안되게...</li>
<li>클릭한 버튼의 클래스를 <code>action</code> 이라는 변수로 두어 어떤 버튼을 클릭했는지 판별한다.</li>
<li>그 이후에는 각각의 상황에 따라 조건을 부여하여 계산한다. 자세한 조건은 코드 내 주석 참고<pre><code class="language-javascript">let calculator = () =&gt; {
let isFirstDigit = true; // 첫 번째 숫자 여부를 판별하는 변수
&gt;
buttons.forEach((item) =&gt; {
  item.addEventListener(&#39;click&#39;, (e) =&gt; {
    let action = e.target.classList[0];
    let click = e.target.innerHTML;
&gt;
    if (action === &#39;operator&#39;) {
      //연산자 눌렀을 때
      operatorOn = click;
      previousNum = displayElement.textContent;
      displayElement.textContent = &#39;&#39;;
      isFirstDigit = true; 
      // 연산자를 누르면 다음 숫자는 첫 번째 숫자가 됨
    }
    if (action === &#39;numBtn&#39;) {
      if (isFirstDigit &amp;&amp; click === &#39;0&#39;) {
        // 첫 번째 숫자이고 입력된 값이 0인 경우 아무 작업도 수행하지 않음
        return;
      }
&gt;
      if (displayElement.textContent === &#39;&#39; &amp;&amp; operatorOn === &#39;&#39;) {
        //창이비어있고 연산자 누르지 않았을때(한자리)
        displayElement.textContent = click;
        previousNum = displayElement.textContent;
      } else if (
        //창이비어지 않고 연산자 누르지 않았을때(한자리이상)
        displayElement.textContent !== &#39;&#39; &amp;&amp;
        operatorOn === &#39;&#39;
      ) {
        displayElement.textContent = 
        displayElement.textContent + click;
        previousNum = displayElement.textContent;
      } else if (
        //창이비어있고 연산자 눌렀을때(한자리)
        displayElement.textContent === &#39;&#39; &amp;&amp;
        operatorOn !== &#39;&#39;
      ) {
        displayElement.textContent = click;
        resentNum = displayElement.textContent;
      } else if (
        //창이비어있지않고 연산자 누르지 않았을때 (한자리이상)
        displayElement.textContent !== &#39;&#39; &amp;&amp;
        operatorOn !== &#39;&#39;
      ) {
        displayElement.textContent = 
        displayElement.textContent + click;
        resentNum = displayElement.textContent;
      }
      isFirstDigit = false; 
      // 첫 번째 숫자 입력 후에는 첫 번째 숫자가 아님을 표시
    }
&gt;
    if (action === &#39;result&#39;) {
      // = 눌렀을 때 calculate함수 실행
      displayElement.textContent = calculate(
        previousNum,
        operatorOn,
        resentNum
      );
      isFirstDigit = true; 
      // 결과를 표시한 후에는 다음 숫자는 첫 번째 숫자가 됨
    }
    if (action === &#39;ac&#39;) {
      //C 버튼 눌렀을 때 모든 할당 초기화
      displayElement.textContent = &#39;&#39;;
      previousNum = &#39;&#39;;
      operatorOn = &#39;&#39;;
      resentNum = &#39;&#39;;
      isFirstDigit = true; 
      // 모든 할당 초기화 후에는 다음 숫자는 첫 번째 숫자가 됨
    }
  });
});
};
calculator();</code></pre>
</li>
</ul>
<h2 id="마무리--고민">마무리 &amp; 고민</h2>
<ul>
<li>모든 코드에 <code>displayElement.textContent</code> 를 일일이 입력하는게 너무 지저분해보여서 변수로 할당하고 싶었는데 변수에 넣으면 값이 바뀌지 않는다.. 이를 해결하기 위해 찾아보니 따로 <code>displayElement.textContent</code>를 해주는 함수를 만들라고 하는데 그럼 쓸 때 마다 그 함수를 호출하나 저걸 쓰나 거기서거기 아닌가..? 하는 생각이 들어 보류중이다.<pre><code class="language-javascript">function a(value) {
  let content = displayElement.textContent
  content = value
  return content
}</code></pre>
이런식이나 <pre><code class="language-javascript">const getDisplayValue = () =&gt; displayElement.textContent;</code></pre>
이런식으로 해보라는 조언을 받았는데 이렇게 해서 함수로 쓰면 정말 코드가 덜 지저분해지는게 맞나요..? 아직 잘 모르겠다ㅠ</li>
</ul>
<p>뭔가 다른 분들은 더 기깔나게 만든 사람이 많은 것 같아 아직도 갈 길이 멀다는 생각이 든다. 하지만 하나의 어플리케이션 결과물을 만든 것도 오랜만이기에 블로그에 글을 써보았다. 다음엔 또 어떤 걸 만들까? 무언가 만들면서 공부하는게 제일 재밌는 것 같다..~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT란?]]></title>
            <link>https://velog.io/@jhyun_k/JWT%EB%9E%80</link>
            <guid>https://velog.io/@jhyun_k/JWT%EB%9E%80</guid>
            <pubDate>Sat, 17 Jun 2023 12:34:29 GMT</pubDate>
            <description><![CDATA[<p>이번에는 JWT 에 대해 써보려고 한다. 익히 들어왔지만 뭔지 설명하라고 하면 쉽지않은.. </p>
<p>JWT 공식 문서인
<a href="https://jwt.io/introduction">https://jwt.io/introduction</a>
이 글을 번역하는 식으로 포스팅 해보려고 한다. 더듬더듬...</p>
<h2 id="목차">목차</h2>
<blockquote>
<ol>
<li>JWT 정의</li>
<li>언제 JWT를 사용할까?</li>
<li>JWT 구조</li>
<li>JWT 작동 방식</li>
<li>우리가 JWT를 사용해야하는 이유</li>
</ol>
</blockquote>
<h2 id="1-jwt의-정의">1. JWT의 정의</h2>
<p>JWT는 <strong>JSON Web Token</strong> 의 준말로 정보를 JSON 객체로 안전하게 전송하기 위한 표준 방식이다. JWT 정보는 디지털로 서명되어 신뢰할 수 있다. <strong>인증 및 권한 부여 목적으로 사용되는 일종의 토큰</strong>이다.</p>
<h2 id="2-언제-jwt-를-사용할까">2. 언제 JWT 를 사용할까?</h2>
<h3 id="21-authorization-권한-부여">2.1. Authorization (권한 부여)</h3>
<p>가장 많이 사용하는 경우이다. *<em>사용자가 로그인하면 이후 각 요청에 JWT가 포함되어 해당 토큰으로 허용된 경로, 서비스 및 리소스에 엑세스 할 수 있다. *</em>
최근에는 오버헤드가 적고 다양한 도메인에서 쉽게 사용할 수 있는 단일로그인(Single Sign On) 기능이 자주 사용된다.</p>
<blockquote>
<p><strong><code>오버헤드란?</code></strong> : (프로그램 실행 흐름 도중 동떨어진 위치의 코드를 실행시켜야 할 때 추가적으로 시간,메모리,자원이 사용되는 현상 즉, 특정 기능을 수행하는데 드는 간접적인 자원)</p>
</blockquote>
<p>JWT를 이용하여 회원 정보를 주고받게 되면 유저의 정보를 세션에 유지할 필요가 없게된다. 즉 stateless 한 서버를 만들 수 있도록 도와준다. 이전 방식은 브라우저와 서버의 세션 영역에 로그인 정보가 저장되어있는 statefull한 서버였다.</p>
<h3 id="22-information-exchange-정보교환">2.2. Information Exchange (정보교환)</h3>
<p>JWT 는 당사자간에 정보를 안전하게 전송하는 좋은 방법이다. 예를들면 JWT는 공개/개인 키쌍 을 사용하여 서명할 수 있기 때문에 보낸사람이 실제 당사자가 맞는지 확신할 수 있다. 또한 서명은 header 와 payload를 사용하여 계산되기 때무에 내용 변경 유무도 확인할 수 있다.</p>
<h2 id="3-jwt-구조">3. JWT 구조</h2>
<p>JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성된다.</p>
<ul>
<li>Header</li>
<li>Payload</li>
<li>Signature</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/0f9b5382-7372-46c2-9736-f395234ada33/image.png" alt=""></p>
<p>따라서 JWT는 일반적으로 <code>xxxxx.yyyyy.zzzzz</code> 와 같은 형식을 갖고있다.</p>
<h3 id="31header">3.1.Header</h3>
<p>Header 에는 일반적으로 <strong>토큰 유형</strong>과 <strong>사용중인 서명 해싱 알고리즘</strong> 이렇게 두 부분으로 구성된다. </p>
<pre><code>{
  &quot;alg&quot;: &quot;HS256&quot;,
  &quot;typ&quot;: &quot;JWT&quot;
}</code></pre><p>이후 이 JSON 은 <code>BASE64Url</code> 로 인코딩되어서 Header 부분을 형성한다.&#39;</p>
<blockquote>
<p><strong><code>Base 64인코딩이란?</code></strong> : Binary 데이터를 텍스트(String)로 바꾸는 인코딩방식으로 char-set 에 영향받지 않는 ASCII 문자열로만 되어있는 텍스트로 바꾸는 일을 한다. (64진법)</p>
</blockquote>
<p>그리고 여기서 나온게 <strong><code>Base64Url</code></strong> =&gt; Url에는 path를 구분짓는 / 와 space를 의미하는 +문자가 있다. 이를 _ 기호와 - 기호로 수정하여 url에서 Base64 를 사용해도 문제가 발생하지 않게 된다.</p>
<h3 id="32-payload">3.2. Payload</h3>
<p>두번째 파트는 Payload이다. 이 부분은 클레임, 데이터를 포함한다. 이 클레임은 Entity(일반적으로 사용자) 및 추가 데이터에 대한 설명이다. 이 클레임은 또 <em>registered, public, private</em> 세가지로 나뉜다. 전달하고자 하는 데이터라고 생각하면 편함.</p>
<h4 id="321-registered-claims">3.2.1. Registered claims</h4>
<p>필수사항은 아니지만 유용하고 상호간에 사용 가능한 클레임을 제공하기 위해 권장되는 사전에 정의된 클레임 집합이다. ex)iss(issuer), exp(expiration time), sub(subject), aud(audience) 등등..</p>
<h4 id="322-public-claims">3.2.2. Public claims</h4>
<p>사용하는 사람에 의해 맘대로 정의될 수 있다. 하지만 충돌을 방지하기 위해서는  IANA JSON Web Token Registry에 정의하거나 충돌을 방지하는 네임스페이스를 포함하는 url로 정의되어야한다. </p>
<h4 id="323-private-claims">3.2.3. Private claims</h4>
<p>사용에 동의하는 당사자간 정보를 교환하기 위해 공유되는 커스텀 클레임이다. (Registered도 아니고 Public 도 아님)</p>
<p>Payload 는 이런식으로 정의된다는 예시</p>
<pre><code>{
  &quot;sub&quot;: &quot;1234567890&quot;,
  &quot;name&quot;: &quot;John Doe&quot;,
  &quot;admin&quot;: true
}</code></pre><h3 id="33-signature-서명">3.3. Signature (서명)</h3>
<p>signature 부분을 생성하려면 인코딩된 Header와 Payload, Header에 지정된 알고리즘이 필요하다. 
예를들어 HMAC SHA256 알고리즘을 사용하기 위해서는 아래와 같은 방식으로 생성할 수 있다.</p>
<pre><code>HMACSHA256(
  base64UrlEncode(header) + &quot;.&quot; +
  base64UrlEncode(payload),
  secret)</code></pre><p>이러한 signature 은 <strong>전송 중에 토큰이 변조되지 않았는지 확인하는 데 사용된다.</strong> private key 로 서명된 토큰의 경우 JWT를 보낸 사람이 누구인지도 알 수 있다.</p>
<h3 id="이-부분들을-다-합치면">이 부분들을 다 합치면?</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/d0ec2abe-1b52-4a1d-8494-c8fdb355e3d0/image.png" alt=""></p>
<p>이런식의 암호화된 토큰 정보가 생성된다. 이를 풀면 
<img src="https://velog.velcdn.com/images/jhyun_k/post/83d59dbd-42bb-4788-9c1a-fca9af2c9739/image.png" alt="">
요런식으로 정보를 알 수 있다. </p>
<h2 id="4-jwt-작동방식">4. JWT 작동방식</h2>
<p>보통 인증과정에서 사용자가 성공적으로 로그인하면 JSON 웹 토큰이 반환된다. 이렇게 반환된 토큰은 보안을 위해 필요한 것보다 오래 보관하면 안된다. 그리고 중요한 세션데이터를 로컬스토리지와 같은 브라우저 저장소에 저장하면 안된다. </p>
<p>사용자가 보호된 경로나 리소스에 접근할 때 일반적으로 <code>Bearer</code> 를 이용하여 Authorization header로 JWT를 전송한다.</p>
<p><code>Authorization: Bearer &lt;token&gt;</code></p>
<p>Path는 이러한 헤더에서 유효한 JWT인지 확인하고 유효한 경우 사용자는 무사히 접근할 수 있다. HTTP 헤더를 통해 JWT 토큰을 보내는 경우에는 크기가 너무 커지지 않게 주의해야한다. (일부 서버는 8KB를 초과할 수 없음)</p>
<blockquote>
<p>JWT를 가져와 API 또는 정보에 접근하는 방식
<img src="https://velog.velcdn.com/images/jhyun_k/post/ec3cb1b4-e003-4467-9a78-bd640b9568e0/image.png" alt=""></p>
</blockquote>
<ol>
<li>어플리케이션이나 사용자가 Auth 서버에 권한을 요청한다.</li>
<li>권한요청이 승인되면 authorization 서버는 접근 토큰을 반환한다.</li>
<li>사용자는 이 토큰을 갖고 보호된 리소스에 접근할 수 있다.(ex. API)<blockquote>
</blockquote>
<br/> 다른 예시<blockquote>
</blockquote>
<img src="https://velog.velcdn.com/images/jhyun_k/post/1575b72e-0a5f-4c0f-ac00-49130ad43a50/image.png" alt=""></li>
<li>브라우저의 로그인 과정에서 회원 정보를 입력한다(id,pw ...)</li>
<li>서버는 JWT를 생성한다.</li>
<li>서버가 브라우저에게 JWT를 보낸다.</li>
<li>브라우저는 JWT를 갖고 서버에게 데이터를 요청한다.</li>
<li>서버는 서명을 확인하고 유저 정보를 클라이언트에게 제공한다.</li>
</ol>
<h2 id="5-우리가-jwt를-사용해야하는-이유">5. 우리가 JWT를 사용해야하는 이유</h2>
<p>결론적으로 JWT가 다른 방식(SWT, SAML 등)보다 편한 이유 </p>
<blockquote>
<ul>
<li><ol>
<li>JSON은 XML보다 복잡하지 않기 때문에 인코딩할 크기도 작아지기 때문에 훨씬 컴팩트하다는 것에 있다. </li>
</ol>
</li>
</ul>
</blockquote>
<ul>
<li>2.보안적측면에서도 다른 방식보다 우수하고 간편하다. </li>
<li><ol start="3">
<li>JSON 파서(parsers)는 객체에 직접 매핑되는 만큼 가장 많은 프로그래밍 언어에서 사용된다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/7aa745e5-bfbf-4893-9159-0a9a99a895bc/image.png" alt="">
SAML방식과 비교해서 훨씬 보기편하고 간편함..</li>
</ol>
</li>
</ul>
<h2 id="정리">정리</h2>
<p>JWT 공식문서를 번역한 것이기 때문에 JWT가 왜 짱짱인지 나열한 것 같지만 결론적으로는 JWT는 독립형으로 설계되었으며 세션 데이터의 서버 측 스토리지가 필요하지 않으므로 분산 시스템에서 보다 확장 가능하고 사용하기 쉽다는 장점이 있다.</p>
<p>JWT는 일반적으로 <strong>웹 애플리케이션 및 API에서 클라이언트와 서버 간에 사용자 데이터를 안전하게 전송하는 수단으로 사용된다.</strong> 토큰은 서버에서 생성되어 저장되는 클라이언트로 전송되고 그런 다음 클라이언트는 각 후속 요청과 함께 토큰을 전송하여 서버가 사용자 이름과 암호를 계속 확인하지 않고도 <strong>사용자를 인증하고 권한을 부여할 수 있도록 도와준다.</strong></p>
<blockquote>
<p>JWT는 클라이언트와 서버가 통신할 때 권한부여를 위해서 사용하는 토큰이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[클래스형 컴포넌트와 함수형 컴포넌트 차이]]></title>
            <link>https://velog.io/@jhyun_k/%ED%81%B4%EB%9E%98%EC%8A%A4%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@jhyun_k/%ED%81%B4%EB%9E%98%EC%8A%A4%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Thu, 15 Jun 2023 12:01:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jhyun_k/post/e332e857-3463-495e-bf92-8f9ac9ca8f90/image.png" alt=""></p>
<h2 id="목차">목차</h2>
<blockquote>
<ol>
<li>⭐컴포넌트란?</li>
<li>🆑클래스형 컴포넌트 설명</li>
<li>😎함수형 컴포넌트 설명</li>
<li>🌱두 방식의 차이</li>
</ol>
</blockquote>
<h2 id="⭐-컴포넌트란component">⭐ 컴포넌트란?(Component)</h2>
<p>React에서는 컴포넌트 기반 개발 방식을 사용한다. 컴포넌트란 리액트로 만들어진 애플리케이션을 이루는 최소한의 단위이다. 컴포넌트는 props라고 하는 데이터를 받아 출력할 수 있다. 이렇게 작은 단위로 쪼개서 개발하면 필요한 부분에 해당 컴포넌트를 <strong>재사용</strong> 할 수 있어 편리하다. 
리액트에서는 이러한 컴포넌트를 <strong>클래스형 컴포넌트</strong> 와 <strong>함수형 컴포넌트</strong> 로 나눌 수 있다.</p>
<h2 id="🆑-클래스형-컴포넌트class-component">🆑 클래스형 컴포넌트(Class Component)</h2>
<pre><code class="language-js">class Welcome extends React.Component {
  render() {
    const text = &#39;hello world&#39;
    return &lt;h1&gt;{text} {this.props.name}&lt;/h1&gt;;
  }
}</code></pre>
<blockquote>
<ul>
<li>ES6 의 클래스 문법을 이용하여 정의한다.</li>
</ul>
</blockquote>
<ul>
<li><code>React.Components</code>를 상속받아 사용한다. </li>
<li>리액트의 <code>state</code>와 <code>Life Cycle(생명주기)메서드</code>를 사용할 수 있다 <blockquote>
<blockquote>
<p>리액트의 <strong>생명주기</strong>란? : 리액트의 모든 컴포넌트들은 생명주기(라이프사이클)를 가지고 동작한다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/68cd3e69-6b9f-4810-b542-f4cfb7bf29fc/image.png" alt=""></p>
</blockquote>
</blockquote>
<ul>
<li>컴포넌트가 브라우저를 기준으로 <code>Mount(생성)</code> ,<code>Update(변경)</code>,  <code>Unmonut(제거)</code> 됨에 따라 크게 세가지 주기를 가진다. </li>
<li>이 주기 사이 모든 순간을 메서드를 이용하여 관리할 수 있다. </li>
<li>컴포넌트 라이프사이클 메서드는 클래스형 컴포넌트에서만 직접 사용이 가능하고 함수형 컴포넌트에서는 <code>useEffect</code>와 같은 <code>hooks</code>을 이용해 사용할 수 있다.</li>
<li><code>render()</code>나 <code>constructor</code> 도 생명주기 메서드이고 그 외에 <code>componentDidMount()</code> , <code>componentDidUpdate()</code>등이 있다.<blockquote>
</blockquote>
</li>
</ul>
</li>
<li><code>render()</code> 메서드를 이용하여 UI를 출력한다. </li>
<li>장점 : 생명주기 메서드를 사용할 수 있기에 초기화나 해제 등의 작업을 처리할 수 있다.</li>
<li>단점 : 함수형 컴포넌트에 비해 코드가 길고 복잡한 경우가 많다. this 바인딩 등 주의해야할 사항이 많다.</li>
</ul>
<h2 id="😎-함수형-컴포넌트function-component">😎 함수형 컴포넌트(function component)</h2>
<pre><code class="language-js">function Welcome(props) {
  const text = &#39;hello world&#39;
  return
  &lt;h1&gt;{text}!!! {props.name}&lt;/h1&gt;;
}</code></pre>
<blockquote>
<ul>
<li>클래스형 컴포넌트에 비해 선언이 간편하다. </li>
</ul>
</blockquote>
<ul>
<li><code>render()</code> 메서드도 필요없고 <code>React.Components</code>상속도 필요없다.</li>
<li>일반 자바스크립트 함수로 정의된다.</li>
<li><code>Hook</code> 과 함께 사용하기 편하다, <code>Hooks</code>이 도입된 이후로 상태관리와 생명주기 메서드 사용 문제가 상당 부분 해소되었다.</li>
<li>함수 스코프를 사용하기 때문에 this 바인딩 문제가 없다</li>
</ul>
<h2 id="🌱두-방식의-차이">🌱두 방식의 차이</h2>
<h3 id="state-사용-차이">state 사용 차이</h3>
<h4 id="🆑클래스형">🆑클래스형</h4>
<blockquote>
<ul>
<li>초기값을 설정할 때</li>
</ul>
</blockquote>
<pre><code class="language-js">constructor(props){
    super(props);
    this.state = {
        name: &#39;jihyun&#39;,
        money : 0,
        };
      };</code></pre>
<p>처럼 <code>constructor</code> 안에서 <code>this.state</code> 를 이용하여 초기값을 설정하거나</p>
<pre><code class="language-js">class App extends Components {
    state = {
        name: &#39;jihyun&#39;,
        money : 0,
       }
    }</code></pre>
<p>처럼 <code>constructor</code> 없이 초기값을 설정할 수 있다. </p>
<ul>
<li>클래스형 컴포넌트에서 <code>state</code>는 객체형식으로 이루어져있다.<blockquote>
<ul>
<li>state의 값을 변경하려면 <code>this.setState</code> 를 이용한다</li>
</ul>
</blockquote>
<pre><code class="language-js">this.setState({money: money + 10000});</code></pre>
</li>
</ul>
<h4 id="😎-함수형">😎 함수형</h4>
<blockquote>
<p>함수형 컴포넌트에서 state는 <code>useState</code> 와 같은 훅을 이용하여 다룰 수 있다. </p>
</blockquote>
<pre><code class="language-js">const App = () =&gt;{
    const [money,setMoney] = useState(0)    
    const clickBtn = () =&gt;{
        setMoney(10000);
        }
      }</code></pre>
<h3 id="props-사용-차이">props 사용 차이</h3>
<h4 id="🆑-클래스형">🆑 클래스형</h4>
<blockquote>
<p><code>this.props</code>로 불러온다.</p>
</blockquote>
<pre><code class="language-js">class App extends Component {
    render() {
    const {name,money} = this.props;
    return &lt;h1&gt;안녕하세요 저는 {name}이고 {money}원 있습니다&lt;/h1&gt;
    }
   }</code></pre>
<h4 id="😎-함수형-1">😎 함수형</h4>
<blockquote>
<p>함수의 매개변수로 props를 받아서 사용할 수 있다.</p>
</blockquote>
<pre><code class="language-js">const App = ({name,money}) =&gt; {
    return &lt;h1&gt;안녕하세요 저는 {name}이고 {money}원 있습니다&lt;/h1&gt;
    }
  }</code></pre>
<h3 id="이벤트">이벤트</h3>
<h4 id="🆑-클래스형-1">🆑 클래스형</h4>
<blockquote>
<p>함수 선언 할 때 화살표 함수로 바로 선언이 가능하다. 이 또한 this 를 붙여야한다. </p>
</blockquote>
<pre><code class="language-js">clickFunc = e =&gt; { 함수내용 }
render () {
    return (
        &lt;div&gt;
              &lt;button onClick={this.clickFunc}&gt;클릭&lt;/button&gt;
          &lt;/div&gt;
       )
     }</code></pre>
<h4 id="😎-함수형-2">😎 함수형</h4>
<blockquote>
<p>const 어쩌구 함수 이렇게 선언을 해야하고 사용할 때 this 필요없다.</p>
</blockquote>
<pre><code class="language-js">const clickFunc = () =&gt; { 함수내용 }
return (
        &lt;div&gt;
              &lt;button onClick={clickFunc}&gt;클릭&lt;/button&gt;
          &lt;/div&gt;
       )</code></pre>
<h2 id="마치며">마치며</h2>
<p>클래스형 컴포넌트와 함수형 컴포넌트를 간단하게 비교해보았다. 원래 함수형 컴포넌트에서는 라이프사이클 메서드를 사용하지 못한다는 단점이 있었지만 React v16.8 부터는 Hook을 사용할 수 있게 되면서 일면 해소되었다. 과거에는 클래스형 컴포넌트도 많이 사용했지만 공식문서에서도 함수형 컴포넌트와 Hook을 함께 사용하라고 권하고 있다. 하지만 클래스형 컴포넌트에 대해서도 공부해놓으면 후에 도움이 될 것이라 생각하며 정리해본다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[서버사이드렌더링 vs 클라이언트 사이드렌더링 (SSR과 CSR)]]></title>
            <link>https://velog.io/@jhyun_k/%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-vs-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-SSR%EA%B3%BC-CSR</link>
            <guid>https://velog.io/@jhyun_k/%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-vs-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%82%AC%EC%9D%B4%EB%93%9C%EB%A0%8C%EB%8D%94%EB%A7%81-SSR%EA%B3%BC-CSR</guid>
            <pubDate>Tue, 13 Jun 2023 12:07:48 GMT</pubDate>
            <description><![CDATA[<p>기술면접을 몇 차례 보다보니 어렴풋이 알고 있던 지식을 말로 설명하는 건 어렵다는 것을 깨달았다. 그래서 자주 나오는 질문들을 모아 블로그에 정리하는 시간을 갖기로 했다. 첫 주제는 면접때 질문을 받았으나 완벽하게 대답을 하지 못해 계속 마음에 걸렸던 서버사이드렌더링(SSR)과 클라이언트사이드렌더링(CSR)에 대해 쓰려한다</p>
<h2 id="목차">목차</h2>
<blockquote>
<ol>
<li>SSR 설명과 장단점</li>
<li>CSR 설명과 장단점</li>
<li>두 방식의 차이</li>
<li>SSR과 CSR을 사용해야할때</li>
</ol>
</blockquote>
<h2 id="ssrserver-side-rendering">SSR(Server Side Rendering)</h2>
<h3 id="ssr-설명">SSR 설명</h3>
<p>서버사이드렌더링의 약자이다. 말 그대로 서버쪽에서 렌더링을 하여 화면을 보여주는 방식을 말한다. 서버로부터 완전하게 만들어진 HTML 파일을 받아와 화면을 그리기 때문에 첫 화면 로딩 속도가 빠르다. </p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/295f958d-e2cd-4afe-9a8b-e4c422bcd9ec/image.png" alt="">
이 사진은 SSR 방식의 단계를 설명해주는 그림이다.</p>
<blockquote>
<p>1.사용자가 웹사이트에 요청을 보낸다
2. 서버는 렌더링 가능한 HTML 파일을 만든다
3. 브라우저는 빠르게 HTML파일을 읽을 수 있어 화면은 렌더링 된 상태이지만 아직 JS 파일을 읽지 않았기 때문에 조작은 불가능하다.
4. 브라우저가 JS를 읽는다
5. 이제 유저는 콘텐츠를 보고 사용자의 조작도 기록된다.
6. 브라우저가 JS 프레임워크를 실행한다 
7. 기록된 사용자 조작도 실행되고 페이지 상호작용도 가능해진다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/a39b837b-8447-4d21-a917-cfb8c4e240aa/image.png" alt="">
좀 더 간단히 보자면 이렇다.</p>
<blockquote>
<p>서버가 렌더링된 HTML 파일을 보내고 브라우저가 받음 =&gt; 브라우저가 페이지를 화면에 띄워주고 JS 파일을 다운받는다 =&gt; 브라우저가 React(프레임워크)를 실행한다 =&gt; 이제 페이지가 모두 작동된다!</p>
</blockquote>
<p>정리하자면 서버사이드렌더링은 클라이언트(브라우저)가 서버에 매번 데이터를 요청하고 서버에서 처리하는 방식이다. 요청이 들어올 때마다 서버에서 새로운 화면을 만들어서 제공한다. <strong>화면을 그리는(렌더링) 주체가 서버</strong></p>
<p>전통적인 웹은 대부분 서버사이드렌더링 방식이었다. 하지만 요즘은 웹에 제공되는 정보가 너무 많고 이를 매번 서버에서 요청하는 방식은 성능적 문제를 낳았다. SSR 방식은 서버에 정보를 요청할 때마다 새로고침이 일어나고 페이지를 로딩할때마다 서버로부터 리소스를 전달받아 이를 읽고 화면에 렌더링하는 방식이기 때문이다. </p>
<h3 id="장단점">장단점</h3>
<h4 id="ssr-장점">SSR 장점</h4>
<blockquote>
<ol>
<li>첫페이지 로딩속도가 빠르다. </li>
<li>검색엔진 최적화가 가능하다. </li>
</ol>
</blockquote>
<h4 id="ssr-단점">SSR 단점</h4>
<blockquote>
<ol>
<li>초기 로딩 이후 페이지 이동 시 속도가 CSR에 비해 느리다.</li>
<li>깜빡임 이슈 (매번 새로고침 해야하기 때문에)</li>
<li>서버 과부하</li>
<li>TTV(Time To View) 와 TTI(Time To Interact) 의 공백시간</li>
</ol>
</blockquote>
<h2 id="csr-client-side-rendering">CSR (Client Side Rendering)</h2>
<h3 id="csr-설명">CSR 설명</h3>
<p>말 그래도 클라이언트가 렌더링을 맡아서 하는 방식. 여기서 말하는 클라이언트는 브라우저를 말한다. 서버에서 받은 데이터를 클라이언트인 브라우저가 화면에 그린다. 바로 렌더링 가능한 HTML을 서버에서 보여줘 바로 화면에 띄우는게 가능한 SSR 과 달리 HTML 파싱부터 JS 읽기까지 브라우저에서 하기때문에 처음에 화면을 띄우는 데 시간이 좀 걸린다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/c35748ca-b24b-41a3-80bb-2b2e51085b19/image.png" alt=""></p>
<blockquote>
<ol>
<li>사용자가 웹사이트에 요청을 보낸다.</li>
<li>CDN이 빠르게 HTML파일과 JS파일에 접근할 수 있는 링크를 보낸다.<blockquote>
<p>CDN(Content Delivery Network)콘텐츠 전송네트워크 : 엔드 유저의 요청에 &#39;물리적&#39;으로 가까운 서버에서 요청에 응답하는 방식</p>
</blockquote>
</li>
<li>브라우저는 HTML,JS 파일을 다운받고 그동안 화면에는 아무것도 보이지 않는다.</li>
<li>브라우저가 JS파일을 읽는다. (이때도 화면 안보임)</li>
<li>다운이 완료된 JS가 실행된다. 데이터를 위한 API가 호출된다.
(이때 유저들은 placeholder를 보게된다. )</li>
<li>서버가 API 요청에 응답한다</li>
<li>API로부터 받아온 data를 placeholder 자리에 넣어준다. 이제 페이지는 상호작용이 가능해진다.</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/d6555ac2-c109-40c7-8df4-310c32f8663c/image.png" alt=""></p>
<blockquote>
<p>확실히 SSR 과 달리 화면이 띄워지는 타이밍이 늦다. 브라우저가 HTML파일 JS파일 다 읽고 프레임워크 실행까지 다 하고나서야 페이지가 보여지고 상호작용이 가능해진다. </p>
</blockquote>
<p>정리하자면 클라이언트 사이드 렌더링은 클라이언트인 브라우저가 렌더링을 도맡아 처리하는 방식이다. 서버에서 필요한 데이터를 한 번에 받아오고 받은 데이터를 브라우저가 주체가 되어 그린다.</p>
<p>이는 요즘 화면을 그리는 방식인 SPA(Single Page Aplication)과도 밀접한 연관이 있다.  SPA는 처음 한번 페이지 전체를 로딩한 후 필요시 데이터만 바꿔 화면을 그려주는 것을 말한다. SPA는 <strong>클라이언트사이드렌더링</strong>방식이다. 최근 개발할때 많이 사용하는 React도 SPA이다. CSR은 SPA 트랜드와 CPU 성능 상승 +JS 표준화(리액트, 뷰, 앵귤러 등 프레임워크의 발전)와 함께 본격적으로 시작되었다. </p>
<p>클라이언트사이드렌더링은 서버에서 데이터를 받아 모두 읽고 다시 화면에 전체 페이지를 바꿔서 보여주는 것보다 훨씬 빠르게 화면을 그릴 수 있는 것이다. 이는 성능적으로도 페이지를 새로 렌더링하지 않아 서버자원을 덜 사용하고, 새로고침이 발생하지 않기 때문에 화면이 바뀔때 화면 깜빡임도 없어 우수한 사용자 경험을 제공한다.</p>
<h3 id="장단점-1">장단점</h3>
<h4 id="csr-장점">CSR 장점</h4>
<blockquote>
<ol>
<li>새로고침이 발생하지 않아 사용자 경험에 도움을 준다.</li>
<li>초기 로딩 이후 빠른 웹사이트 렌더링이 가능(웹사이트가 로딩되는 즉시 상호작용 가능</li>
<li>필요한, 변경된 데이터만 받아오므로 트래픽 감소</li>
</ol>
</blockquote>
<h4 id="csr-단점">CSR 단점</h4>
<blockquote>
<ol>
<li>검색엔진 최적화에 보완필요</li>
<li>초기 로딩 느림</li>
</ol>
</blockquote>
<h2 id="두-방식의-차이">두 방식의 차이</h2>
<h3 id="차이점">차이점</h3>
<p><strong>1. 웹페이지 로딩 시간</strong>
SSR방식은 데이터를 서버에서 그려진 화면을 먼저 띄워주고 차근차근 화면에 그려준다. 때문에 첫 페이지 로딩속도가 빠르다. 하지만 CSR방식은 화면을 그리는데 필요한 데이터를 한번에 다 받아오고 화면을 띄우기 때문에 첫 화면이 뜨는 속도가 느리다.</p>
<p> 하지만 첫 페이지를 로딩한 이후에 다른 화면을 그려야 할 때에는 이야기가 다르다. SSR방식은 첫페이지를 로딩한 과정을 다른 페이지로 갈때마다 반복해야하기 때문에 페이지 이동 속도가 느리다. 서버는 첫페이지에 해당하는 문서만 브라우저에 전달하여 화면을 렌더링했기 때문에 화면이 바뀔때마다 다시 문서들을 받기 위해 서버에 데이터를 요청하고 응답받는 과정을 거쳐 그려야하기 때문이다. 하지만 CSR방식은 이미 첫 페이지를 로딩할 때 정보를 다 받아왔기 때문에 페이지 전환 속도가 SSR방식보다 빠르다.</p>
<p><strong>2. SEO (Serach Engine Optimization : 검색엔진 최적화)</strong>
SSR 방식은 검색엔진 최적화가 가능하지만 CSR 방식은 검색엔진 최적화가 어렵다는 차이가 있다. 포털사이트 검색엔진 크롤러가 데이터를 수집하지 못하는 경우가 많기 때문이다. 하지만 사실 최근에는 구글 검색엔진에 자바스크립트 엔진이 내장되어 있어 크롤링이 된다고 한다. 네이버나 다음 같은 경우 CSR방식으로 만든 페이지의 데이터를 검색하지 못하는 이슈가 있어 별도의 보완작업이 필요하다.</p>
<p><strong>3. 서버자원 사용 정도의 차이</strong>
단순하게 생각해도 SSR방식은 화면이 바뀔 때마다 매번 서버에 요청을 보내고 다시 그려야하기 때문에 많은 자원을 사용한다. CSR방식은 처음에만 서버에서 데이터를 받아오고 그 이후에는 브라우저 쪽에서 화면을 그리기 때문에 서버 자원을 덜 사용한다.</p>
<h2 id="언제-뭘-사용해야할까">언제 뭘 사용해야할까?</h2>
<table>
<thead>
<tr>
<th>SSR</th>
<th>CSR</th>
</tr>
</thead>
<tbody><tr>
<td>- 네트워크가 느릴 때</td>
<td>- 네트워크 빠를 때</td>
</tr>
<tr>
<td>- 검색엔진 최적화가 필요할 때</td>
<td>- 검색엔진 최적화가 필요 없을 때</td>
</tr>
<tr>
<td>- 페이지 상호작용이 별로 없을 때</td>
<td>- 페이지 상호작용이 많이 필요할 때</td>
</tr>
</tbody></table>
<h2 id="결론">결론</h2>
<p>정리를 해보니 막연하게 느껴졌던 두 방식의 차이를 알 것 같다. 리액트는 CSR 방식이라 SEO에 어려움이 있기 때문에 최근에는 NEXT.js 와 같은 프레임워크를 통해 서버사이드렌더링을 가능하게 하는 방식을 많이 도입하고 있다. next.js는 pre-reloading을 통해 미리 데이터가 렌더링된 페이지를 가져올수 있게 해주므로 사용자에게 더 좋은 경험을 주고, 검색 엔진에 잘 노출 될 수 있도록 해주는 SEO에서도 장점을 얻을 수 있다. </p>
<p>예전에 리액트를 이용하여 개발하면 검색엔진에 걸리지 않고 어쩌구.. 이런 단점을 많이 들었었는데 최근에는 이를 거의 보완 가능한 모양이다. 사용자 경험이나 성능 측면에서도 SSR방식과 CSR방식의 차이가 매우 뚜렷하다보니 기술면접에서 이러한 차이를 알고있냐는 의도로 많이 질문하는 것 같다. 두 방식의 차이를 알고나니 더욱 다양한 면을 고려하여 개발을 해야하는구나 하는 생각이 들었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[바닐라 JS로 캘린더 만들기]]></title>
            <link>https://velog.io/@jhyun_k/%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%EC%BA%98%EB%A6%B0%EB%8D%94-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%EC%BA%98%EB%A6%B0%EB%8D%94-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Fri, 27 Jan 2023 11:13:20 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-시작하며--디자인">🌱 시작하며 &amp; 디자인</h2>
<p>부트캠프 수료 후 게으른 일상을 보내고 있는 어느날 이렇게 살면 안 된다는 생각이 들어 할 일을 적어내려가는 투두리스트를 작성하려고 했다. 그런데 문득 내가 쓰는 투두리스트 엡을 내 손으로 만들면 재밌을 것 같다는 생각이 들어 당장 만들기 시작했다. </p>
<p>리액트를 이용해서 만들어볼까? 하는 생각도 했지만 굳이 한 페이지 짜리 웹에서 리액트를 쓸 필요성을 느끼지 못했다. 그리고 플젝을 하면서 리액트 위주로 쓰다보니 또 바닐라JS가 어색해지는 무한의 굴레에서 벗어나기 위해 이번 캘린더-투두리스트는 바닐라JS로만 만들어보기로했다. (그리고 사실 내 노트북에서 리액트 파일 켜는데만 한 세월이라 조금 부담스럽다 ㅠ..)
<img src="https://velog.velcdn.com/images/jhyun_k/post/3317e633-e05b-4f0e-a816-67ae50f17ca8/image.jpg" alt="">
얼추 이런 느낌의 단순히 캘린더와 투두리스트를 합친 할 일 관리 웹을 만들고 싶었다.</p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/c02cb874-b470-4925-860b-9b3a79910147/image.png" alt=""></p>
<p>후에 구체적인 색상이나 레이아웃을 정하기 위해 피그마를 켜서 적당히 네모네모하게 만들었다. 딱히 다른 기능은 당장 생각이 안나서 우선 이 정도로만 정해놓고 vscode를 켰다.</p>
<h2 id="🗓️-캘린더-만들기-시작">🗓️ 캘린더 만들기 시작</h2>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/c1539f8d-0627-40dd-8caa-6f4488f8dff8/image.png" alt="">
위 피그마와 큰 차이 없어 보이지만 완성한 것이다.</p>
<p>아직 캘린더만 만들었는데 모든 기능을 다 만들고 블로그를 쓰려하니 까먹을 것 같아 캘린더 코드만 써보려고 한다.</p>
<p>해당 코드는 <a href="https://www.youtube.com/watch?v=jFmcH5GVRs4">17분 안에 자바스크립트로 달력 만들기</a> &lt;&lt; 이 영상을 참고하여 만들었다. 처음부터 혼자 만들어야 더욱 의미있겠으나 그러다가 막히면 영영 놔버릴 것 같아 완성에 의의를 두고 시작하기로 했다. 코드를 이해하면서 진행하고 싶었기 때문에 주석이 가득하다.</p>
<h3 id="🏗️-indexhtml-中-캘린더-부분">🏗️ index.html 中 캘린더 부분</h3>
<pre><code class="language-html">&lt;section class=&#39;cal&#39;&gt;
  &lt;div class=&#39;header&#39;&gt;
    &lt;button class=&quot;nav-btn go-prev&quot; onclick=&#39;prevMonth()&#39;&gt;&amp;lt;&lt;/button&gt;
    &lt;div class=&quot;year-month&quot;&gt;&lt;/div&gt;
    &lt;button class=&quot;nav-btn go-next&quot; onclick=&#39;nextMonth()&#39;&gt;&amp;gt;&lt;/button&gt;
    &lt;button class=&quot;nav-btn go-today&quot; onclick=&#39;goToday()&#39;&gt;Today&lt;/button&gt;
   &lt;/div&gt;
   &lt;div class=&#39;main&#39;&gt;
     &lt;div class=&quot;days&quot;&gt;
       &lt;div class=&quot;day&quot;&gt;SUN&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;MON&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;TUE&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;WED&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;THU&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;FRI&lt;/div&gt;
       &lt;div class=&quot;day&quot;&gt;SAT&lt;/div&gt;
     &lt;/div&gt;
     &lt;div class=&quot;dates&quot;&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/section&gt;</code></pre>
<p>캘린더 부분의 마크업이다. 원래는 nav를 이용하여 월 이동과 오늘날짜로 이동하는 방식이었으나 nav를 없애버렸다. </p>
<h3 id="📜-calindexjs-캘린더-script파일">📜 calIndex.js (캘린더 script파일)</h3>
<h4 id="✨-날짜-가져오기">✨ 날짜 가져오기</h4>
<p>달력을 보여주는 <code>renderCalendar</code> 함수를 만들고 그 안에서 달력을 보여주는 코드를 짠다</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/2466fe8e-45ec-46ca-b1c6-05922b0d1b8c/image.png" alt=""></p>
</blockquote>
<ul>
<li><code>new Date()</code> 를 이용해 오늘 날짜를 가져온다</li>
<li>현재 연월을 표시하는 <code>viewYear</code> 와 <code>viewMonth</code> 를 만들고 연과 월만 각각 할당한다. (getMonth는 0부터 시작이므로 이번달을 구하려면 +1 해줘야한다)</li>
<li>화면에 <code>textContent</code>를 이용하여 &#39;2022년 1&#39;월 과 같은 형태로 출력한다</li>
<li>달력에는 이번달만 있는게 아니라 이전달과 다음달이 흐리게 표시될 예정이므로 지난달 마지막날과 이번달 마지막날을 구해준다.</li>
</ul>
<h4 id="✨-지난달-이번달-다음달-달력-배열-만들고-합치기">✨ 지난달, 이번달, 다음달 달력 배열 만들고 합치기</h4>
<p>각각의 배열을 만들어준 후 합쳐준다</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/642a1ca2-0c8a-4e2b-8874-6dc4a00e62a3/image.png" alt=""></p>
</blockquote>
<ul>
<li><code>const thisDates = [...Array(TLDate + 1).keys()].slice(1)</code> 에서 인덱스는 0부터 시작하므로 TLDate에 +1 해주어 요소 하나가 추가된 배열을 만들고, <code>slice(1)</code> 을 이용해 1일부터 마지막날까지의 배열로 만든다.</li>
<li>지난달 마지막 요일이 토요일이 아니면 (요일 시작이 일요일부터니까) 지난달 날짜들을 넣어준다</li>
<li><code>concat</code>으로 지난달 이번달 다음달 배열을 합쳐준다.</li>
</ul>
<h4 id="✨-화면에-날짜-뿌려주기">✨ 화면에 날짜 뿌려주기</h4>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/f27b2fb1-ec11-4133-bd55-8529c2b87d1d/image.png" alt=""></p>
</blockquote>
<ul>
<li>date의 인덱스가 이번달 1일 인덱스보다 크거나 같고 막날 인덱스보다 작으면 this, 아니면 other 클래스를 부여한다. 다른달은 opacity 흐리게 해주기 위함</li>
<li><code>forEach</code> 이용하여 dates 배열의 item을 각각의 div 태그에 뿌려준다. </li>
<li><code>&lt;div class=&#39;dates&#39;&gt;&lt;/div&gt;</code> 안에 <code>innerHTML</code> 이용하여 dates 배열을 string으로 출력한다.</li>
</ul>
<h4 id="✨-오늘-날짜-표시하기">✨ 오늘 날짜 표시하기</h4>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/067d03b8-3300-4847-9ff7-53ca63aec530/image.png" alt=""></p>
</blockquote>
<ul>
<li>지금 보고있는 달력이 이번년 이번달 달력이면 <code>this</code>라는 클래스를 갖고있는 값을 돌려서, date의 text가 오늘 날짜와 같으면 (string에 + 붙여줘서 type을 number로 바꿔줌) <code>today</code>라는 클래스를 붙여준다</li>
<li><code>break</code> 이용해서 조건 충족되면 반복문 빠져나오기
<img src="https://velog.velcdn.com/images/jhyun_k/post/1b43d184-7441-47e7-b53f-6d1db56dc96f/image.png" alt=""></li>
<li>그럼 오늘 날짜에만 today 클래스가 붙으므로 이렇게 스타일을 따로 지정해줄 수 있다.</li>
</ul>
<h4 id="✨-캘린더출력-함수-실행하고-이전달-다음달로-이동하기">✨ 캘린더출력 함수 실행하고 이전달 다음달로 이동하기</h4>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/65ff9056-f1e4-4246-a432-d1d142ce4490/image.png" alt=""></p>
</blockquote>
<ul>
<li><code>renderCalendar()</code> 로 캘린더 출력 함수 실행하기</li>
<li><code>Date.prototype.setMonth()</code> : setMonth () 메서드는 현재 설정된 연도에 따라 지정된 날짜의 월을 설정할 수 있다</li>
</ul>
<h2 id="🎉-마치며">🎉 마치며</h2>
<p>코드를 보면 그렇게 이해가 안 될 만한 코드는 아닌데 스스로 생각하기에는 아직 너무 어려운 것 같다.. 예전에 라이브러리로 달력을 불러온 적이 있는데 이렇게 라이브러리 없이 바닐라js로만 만들어보니 생각해야할게 많아서 놀랐다. 
나중에 원하는 연월일로 가는 기능(갤럭시 기본 캘린더앱처럼)이나 여러날에 걸친 일정 기능도 추가해보고싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useId 알아보기]]></title>
            <link>https://velog.io/@jhyun_k/useId-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/useId-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Thu, 12 Jan 2023 05:33:21 GMT</pubDate>
            <description><![CDATA[<h2 id="usdid-사용하는방법">usdId 사용하는방법</h2>
<p>useId를 이용하면 간단하게 고유의 ID를 생성할 수 있습니다. useId를 사용하는 방법을 간단한 예제를 통해 알아보겠습니다.</p>
<pre><code class="language-jsx">import React, { useId } from &#39;react&#39;;
import Child from &#39;./Child&#39;;

export default function App() {
  const id = useId();
  return (
    &lt;&gt;
      &lt;label htmlFor={id}&gt;App check&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id={id} /&gt;
      &lt;Child /&gt;
      &lt;Child /&gt;
      &lt;Child /&gt;
    &lt;/&gt;
  );
}</code></pre>
<p>App.jsx는 useId로 체크박스에 ID를 부여하고, Child 라는 컴포넌트를 보여주는 코드입니다.</p>
<pre><code class="language-jsx">import React, { useId } from &#39;react&#39;;

export default function Child() {
  const id = useId();

  return (
    &lt;&gt;
      &lt;br /&gt; //줄바꿈 위한 태그
      &lt;label htmlFor={id}&gt;Child Check&lt;/label&gt;
      &lt;input type=&quot;checkbox&quot; id={id} /&gt;
    &lt;/&gt;
  );
}</code></pre>
<p>Child 컴포넌트 또한 위와 같이 체크박스에 useId를 이용하여 아이디를 부여하는 코드입니다.</p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/6cb7b2ce-9382-46db-a94a-a1f1633d23f5/image.png" alt="">
App.jsx 를 보면 같은 Child라는 컴포넌트를 3번 보여주고 있습니다.
해당 코드들의 ID값을 확인하기 위해 개발자도구를 확인하면, 같은 Child 컴포넌트의 코드이지만 이렇게 각각 다른 ID값이 생성되는 것을 확인할 수 있습니다.</p>
<p>이처럼 useId를 이용하면 일일이 다른 ID를 직접 넣지 않고 편리하게 고유한 ID값을 부여할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useDeferredValue이란?]]></title>
            <link>https://velog.io/@jhyun_k/useDeferredValue%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jhyun_k/useDeferredValue%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Wed, 11 Jan 2023 09:48:11 GMT</pubDate>
            <description><![CDATA[<h1 id="121-usedefferedvalue-개요">12.1. useDefferedValue 개요</h1>
<h2 id="1211-usedeferredvalue이란">12.1.1. useDeferredValue이란?</h2>
<p><code>useDeferredValue</code>는 React18에 새로 나온 Hook으로, 리렌더링의 우선순위에 따라 의도적으로 렌더링을 지연할 수 있는 Hook입니다. useDeferredValue는 값의 업데이트 우선순위를 지정하여 우선순위가 높은 작업을 실행하는 동안 useMemo와 같이 기존의 값을 가지고 있으며 업데이트를 지연시키는 것입니다.</p>
<p>이러한 기능은 이후 챕터에서 다룰 debounce, throttle 과 비슷해 보이지만  <code>useDeferredValue</code> Hook을 이용하면 딜레이 시간을 고정하지 않고 더 긴급한 요청이 끝난 후 바로 지연된 렌더링을 실행한다는 이점이 있습니다.</p>
<pre><code class="language-jsx">const deferredValue = useDeferredValue(value);</code></pre>
<p><code>useDeferredValue</code>는 첫번째 인자로 지연하길 원하는 값을 받고 해당 값의 복사본을 리턴합니다.</p>
<h2 id="1212-usedeferredvalue를-사용하는-이유">12.1.2 useDeferredValue를 사용하는 이유</h2>
<p>브라우저에서 더 우선적으로 출력 되어야 할 값을 계산하는 동안 <code>useDeferredValue</code>를 이용하여 DOM 트리에서 긴급하지 않은 부분의 리렌더링을 의도적으로 지연 시킬 수 있습니다.</p>
<p>예를 들어 현재 실행되는 렌더링이 input창과 같이 타이핑 즉시 화면에 반영 되어야 하는 렌더링이라면 React에서는 이러한 긴급한 렌더링을 완료하기 전까지는 지연된 값을 기존의 값으로 출력하다가, 긴급한 렌더링이 끝나면 새로운 값을 출력하는 것입니다.</p>
<p>간단한 예제를 통해 useDeferredValue 사용법을 알아보겠습니다.</p>
<pre><code class="language-jsx">import React, { useState } from &#39;react&#39;;

export default function App() {
  let heavyArray = new Array(10000).fill(0);

  const [type, setType] = useState(0);

  const typeChange = (e) =&gt; {
    setType(e.target.value);
  };

  return (
    &lt;div&gt;
      &lt;input type=&quot;text&quot; onChange={typeChange} /&gt;
      {heavyArray.map(() =&gt; {
        return &lt;div&gt;{type}&lt;/div&gt;;
      })}
    &lt;/div&gt;
  );
}</code></pre>
<p>위 코드는 input에 텍스트를 입력하면 같은 내용이 10000번 출력 되는 코드입니다. 간단한 코드지만 타이핑을 해보면 10000번의 계산을 하느라 값이 출력 되는 속도 뿐만 아니라 input창 내부의 렌더링 속도 또한 느린 것을 알 수 있습니다.</p>
<p>이 때 <code>useDeferredValue</code> 를 이용한다면 <code>heavyArray</code>의 출력을 지연 시킬 수 있습니다.</p>
<pre><code class="language-jsx">import React, { useState, useDeferredValue } from &#39;react&#39;;

export default function App() {
  let heavyArray = new Array(10000).fill(0);

  const [type, setType] = useState(0);

  let deferredType = useDeferredValue(type);

  const typeChange = (e) =&gt; {
    setType(e.target.value);
  };

  return (
    &lt;div&gt;
      &lt;input type=&quot;text&quot; onChange={typeChange} /&gt;
      {heavyArray.map(() =&gt; {
        return &lt;div&gt;{deferredType}&lt;/div&gt;;
      })}
    &lt;/div&gt;
  );
}</code></pre>
<p>같은 코드에서 <code>useDeferredValue</code>를 사용한 <code>deferredType</code>값을 넣어주면 <code>type</code>값이 변경되는 시점이 지연되어 input창의 출력 속도가 현저히 빨리진 것을 확인할 수 있습니다. 즉, input창의 내부는 빠르게 변경되지만, 해당 값을 사용하여 출력 되는 요소들의 렌더링은 후에 처리될 수 있어 사용자 입력에 빠르게 대응할 수 있는 것입니다.</p>
<p>이처럼 <code>useDeferredValue</code>를 이용하면 긴급한 렌더링을 우선적으로 실행하도록 원하는 값의 렌더링을 지연 시킬 수 있습니다. 하지만 useDeferredValue는 값의 우선순위만을 지정하기 때문에 자식 컴포넌트의 값이나 상태의 업데이트를 지연시키기 위해서는 useMemo 혹은 React.memo를 사용해야합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useMemo 예제로 알아보기]]></title>
            <link>https://velog.io/@jhyun_k/useMemo-%EC%98%88%EC%A0%9C%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/useMemo-%EC%98%88%EC%A0%9C%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Thu, 29 Dec 2022 02:27:20 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>useMemo 라는 훅이 있는 것은 알았지만 그동안 메모이제이션까지 할 일이 없어서 사용해본적은 없다. 하지만 이번에 useMemo에 대해 배운김에 어떻게 사용하는 것인지 예제를 통해 정리해보려한다.</p>
</blockquote>
<p>해당 예제는 일부러 무거운 연산을 실행함과 동시에 부하를 일으키면서 숫자와 텍스트를 변경하는 코드이다.</p>
<h2 id="appjsx">App.jsx</h2>
<p>App.jsx에서는 화면이 렌더링 될 때마다 <code>heavyCalc</code> 함수를 실행하며 number와 text를 바꿔주는 함수핸들러, 그리고 바뀐 number와 text값을 보여주는 <code>ShowState</code> 컴포넌트가 있다. </p>
<blockquote>
</blockquote>
<pre><code class="language-jsx">import React, { useState,useMemo } from &#39;react&#39;;
import ShowState from &#39;./ShowState&#39;;
&gt;
export default function App() {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState(&#39;&#39;);
&gt;
  // 일부러 과도한 연산을 하는 함수
  function heavyCalc() {
    let s = 0;
    for (let i = 0; i &lt; 1000000000; i++) {
      s += i;
    }
    return s;
  }
  let calc = heavyCalc();
&gt;
  //number 값 바꿔주는 함수
  const increaseNum = () =&gt; {
    setNumber((prev) =&gt; prev + 1);
  };
&gt;
  const decreaseNum = () =&gt; {
    setNumber((prev) =&gt; prev - 1);
  };
&gt;
  //text값 바꿔주는 함수
  const handleText = (e) =&gt; {
    setText(e.target.value);
  };
&gt;
  return (
    &lt;&gt;
      &lt;h1&gt;엄청난 연산값&lt;/h1&gt;
      &lt;p&gt;{calc}&lt;/p&gt;
      &lt;h2&gt;숫자바꾸기&lt;/h2&gt;
      &lt;button onClick={increaseNum}&gt;+&lt;/button&gt;
      &lt;button onClick={decreaseNum}&gt;-&lt;/button&gt;
      &lt;h2&gt;글자바꾸기&lt;/h2&gt;
      &lt;input type=&quot;text&quot; onChange={handleText} /&gt;
      &lt;ShowState number={number} text={text} /&gt;
    &lt;/&gt;
  );
}</code></pre>
<h2 id="showstatejsx">ShowState.jsx</h2>
<p>ShowState 컴포넌트에서는 App.jsx에서 바꾼 값들을 출력해주고 값이 바뀔 때 마다 &#39;숫자가 변경되었습니다.&#39; 와 &#39;글자가 변경되었습니다.&#39; 라는 문구를 console에 출력한다.</p>
<blockquote>
<pre><code class="language-jsx">import React, { useMemo } from &#39;react&#39;;
</code></pre>
</blockquote>
<p>export default function ShowState({ number, text }) {
  const consoleNumber = (number) =&gt; {
    console.log(&#39;숫자가 변경되었습니다.&#39;);
    return number;
  };</p>
<blockquote>
</blockquote>
<p>  const consoleText = (text) =&gt; {
    console.log(&#39;글자가 변경되었습니다.&#39;);
    return text;
  };</p>
<blockquote>
</blockquote>
<p>  const showNum = consoleNumber(number);
  const showText = consoleText(text);</p>
<blockquote>
</blockquote>
<p>  return (
    <div>
      <p> 숫자 : {showNum}</p>
      <p> 글자 : {showText}</p>
    </div>
  );
}</p>
<pre><code>
![](https://velog.velcdn.com/images/jhyun_k/post/85e2cea2-cb92-4a56-bcc4-1b0049156322/image.png)

위 예제를 실행한 모습

`+` 와 `-` 버튼을 누르면 숫자 값이 바뀌고, input창에 글자를 입력하면 입력하는대로 글자가 출력되는 것을 알 수 있다.

하지만 이를 실행해보면 매우 느리게 실행된다. 이는 숫자나 글자를 바꿈으로써 화면이 리렌더링될 때마다 heavyCalc 함수가 실행되기 때문..


## useMemo 를 사용해보자! 

 `heavyCalc` 함수의 결과값인 calc는 계속 같은 값을 가지기 때문에 매번 새로 연산을 진행할 필요가 없다. 이 때 쓸 수 있는 것이 이전에 이미 계산한 값을 재사용할 수 있도록 도와주는 `useMemo` 인 것이다.


App.jsx의 `heavyCalc` 함수 실행문을 이렇게 `useMemo`를 이용하여 감싼다면?
&gt;
```jsx
  const calc = useMemo(() =&gt; {
    return heavyCalc();
  }, []);</code></pre><p>useMemo를 통해 이전에 계산했던 499999999067109000 라는 값을 계속 재사용하여 화면에 출력해주기 때문에 같은 계산을 위해 부하를 일으키지 않는 것을 확인할 수 있다. </p>
<p><strong>이처럼 useMemo는 렌더링이 발생했을 때, 이전 렌더링과 현재 렌더링 사이에 값이 동일하다면 다시 함수를 호출을 하여 결과를 구하는 대신, 기존에 메모리에 저장해두었던 값을 그대로 사용하도록 도와주는 것이다.</strong></p>
<p>useMemo로 감싼 후 다시 값을 변경해보면?</p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/776a80f2-68c1-4ade-8d01-a4e0781da98b/image.png" alt="">
increaseNum 함수를 두번 실행하여 숫자가 2가 되었다!</p>
<hr>
<h3 id="근데-문제가-있는데">근데 문제가 있는데?</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/cf1dce19-9e5e-401e-a0cb-09818695d223/image.png" alt=""></p>
<p>하지만 콘솔창을 확인하니 increaseNum 함수가 실행될 때마다 Text값을 바꾸지 않았음에도 &#39;글자가 변경되었습니다.&#39; 라는 문구가 같이 출력된다.</p>
<p>변경하고자 하는 state에 해당되지 않는 함수가 실행될 필요는 없기 때문에 useMemo를 사용하여 숫자가 변경될 경우와 글자가 변경될 경우에만 console 출력을 하도록 바꿔보자.</p>
<blockquote>
</blockquote>
<pre><code class="language-jsx">  const showNum = useMemo(() =&gt; consoleNumber(number), [number]);
  const showText = useMemo(() =&gt; consoleText(text), [text]);</code></pre>
<p>  showNum과 showText 값을 이렇게 변경하여 number 값이 변했을때만 consoleNumber 함수가, text값이 변했을때만 consoleText함수가 실행되도록 했다.</p>
<p>  <img src="https://velog.velcdn.com/images/jhyun_k/post/52c6316e-2c18-4a55-8d1c-ee06a66d53d8/image.png" alt=""></p>
<p>아까처럼 increasNum 을 두번 실행했을때 text의 값을 변경하지 않았으므로 consoleNumber 함수만 두 번 실행되는 것을 볼 수 있다.</p>
<p>  <img src="https://velog.velcdn.com/images/jhyun_k/post/f0cb818f-545d-4c1a-9186-e205d3db815f/image.png" alt=""></p>
<p>그 상태에서 text의 값을 4번 변경하니 consoleText함수도 4번 실행된다. </p>
<p>즉, 숫자가 변경될 때는 &#39;숫자가 변동되었습니다.&#39; 라는 console만 뜨고
글자가 변경될 때는 &#39;글자가 변동되었습니다.&#39; 라는 console만 뜨게 되는 것이다.</p>
<h3 id="결론">결론</h3>
<blockquote>
<p><code>useMemo</code> 를 사용하면 메모이제이션 기법을 이용하여 이전에 저장되었던 결과를 다시 가져와 재사용할 수 있기 때문에 코드최적화에 도움을 줄 수 있다. 언젠간 사용해볼 날이 오길.. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[useState 에서 setter 함수에 파라미터를 넣어서 사용하기]]></title>
            <link>https://velog.io/@jhyun_k/React-useState-%EC%97%90%EC%84%9C-setter-%ED%95%A8%EC%88%98%EC%97%90-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A5%BC-%EB%84%A3%EC%96%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jhyun_k/React-useState-%EC%97%90%EC%84%9C-setter-%ED%95%A8%EC%88%98%EC%97%90-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A5%BC-%EB%84%A3%EC%96%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 05 Dec 2022 08:41:21 GMT</pubDate>
            <description><![CDATA[<p>제목이 너무 장황하군요
누군가에게는 당연하다고 느껴질 수 있지만 
나는 처음 깨달은 사실이기에 블로그에 글을 남겨 까먹지 않으려 한다.</p>
<h2 id="usestate-기본-사용법">useState 기본 사용법</h2>
<blockquote>
<p>useState 는 리액트 훅의 일종으로 state값 관리를 도와주는 훅이다.<br>
useState의 기본 형태는 다음과 같다</p>
</blockquote>
<pre><code class="language-js">const [state(값을 담을 변수),setState(변수값을 바꿔주는 함수)] = useState(초기값)</code></pre>
<p>여기서 state와 setState는 정해진 이름이 아니라 그냥 암묵적인 룰처럼 <code>[변수,set변수]</code> 로 사용한다. <code>[banana,setBanana]</code>라고 해도 상관없고 <code>[banana,orange]</code>라고 해도 상관없다. 하지만 이왕이면 그러지 말도록 하자.</p>
<pre><code class="language-js">import React, { useState } from &#39;react&#39;;
function Example() {
  // 새로운 state 변수를 선언하고, 이것을 count라 부르겠습니다.
  const [count, setCount] = useState(0);</code></pre>
<p>이것은 count라는 state변수와 count를 바꿔주는 setCount함수를 선언하고 count의 초기값을 0이라고 정해주는 코드이다!</p>
<pre><code> &lt;p&gt;You clicked {count} times&lt;/p&gt;</code></pre><p> 여기서 선언한 count라는 변수는 이렇게 직접 사용할 수 있다.
 <br>
 만약 count의 값을 바꾸고 싶으면?</p>
<pre><code class="language-js">   &lt;button onClick={() =&gt; setCount(count + 1)}&gt;
    Click me
  &lt;/button&gt;</code></pre>
<p>  이렇게 아주 간단하게 <code>setCount</code>를 사용하면 된다. 위 코드는 Click me 버튼을 클릭하면 count의 값을 1씩 늘려주는 함수이다.</p>
<p>여기까지는 기본적으로 알고있던 useState의 사용법이다.</p>
<h2 id="setcount에-인자-넣으면">setCount()에 인자 넣으면?</h2>
<blockquote>
</blockquote>
<p>위처럼 setCount 함수에서 보통 count의 값을 바꾸고싶으면 그냥 count라는 변수명을 그대로 사용하곤 한다. 하지만 만약 setCount에서 인자를 사용하면 어떻게 될까?</p>
<pre><code class="language-js">setCount((prev) =&gt; prev +1)</code></pre>
<p>요렇게!
<br>끌지않고 바로 말하자면 
<strong>useState 훅에서 set함수 파라미터의 첫번째값은 직전 state의 값이다.</strong> 상태를 변경하는 set함수를 실행하면 컴포넌트 외부의 값을 변경하는 것이기 때문에, 상태가 변경된 직후 리렌더링 되기 전까지는 이전의 값을 그대로 참조하기 때문이다.
<br>Setter 함수를 사용 할 때, 업데이트 하고 싶은 새로운 값을 파라미터로 넣어주는 대신에 <strong>기존 값</strong>을 어떻게 업데이트 할 지에 대한 함수를 등록하는 방식으로도 값을 업데이트 할 수 있는 것이다.</p>
<p>이를 활용하면</p>
<pre><code class="language-js">const [multi, setMulti] = useState(1);
const 곱해줭 = () =&gt; {
    setMulti((oldData) =&gt; oldData * 2);
  };
//
return
&lt;button onClick={() =&gt; {곱해줭()}}&gt;곱해줭&lt;/button&gt;</code></pre>
<p>이렇게 multi라는 변수를 사용하지 않고도 직전값을 불러와서 곱하기 함수를 만들 수 있고</p>
<pre><code class="language-js">const [state, setState] = useState(true);
  const 바꿔줭 = () =&gt; {
    setState((old) =&gt; !old);

&lt;button onClick={() =&gt; {바꿔줭()}}&gt;바꿔줭&lt;/button&gt;;</code></pre>
<p>이렇게 true/false를 반복하는 toggle 버튼도 쉽게 만들 수 있다.
(클릭하면 직전 state 값의 반대를 출력하는 이벤트)</p>
<p>이렇게 되는 이유는....
<img src="https://velog.velcdn.com/images/jhyun_k/post/d029f71d-8ec8-48ea-aba7-f6af764d5127/image.png" alt=""> (출처 : <a href="https://react.vlpt.us/basic/07-useState.html">벨로퍼트님 블로그 의 댓글</a>)</p>
<p>그냥 원래 그런거다 개발자가 정한거임
그렇기때문에 그냥 편하게 쓰면 된다.</p>
<h2 id="마치며">마치며</h2>
<p>useState 훅은 정말 자주 사용하는 훅임에도 제대로 활용하지 못했던 것 같다.. 이번 기회에 다양한 사용법을 많이 알 수 있었고... 이렇게 글을 쓰니 다시는 잊지 않을 것 같다는 생각이 들었다. 알려주고 숙제도 내줘서 익힐 수 있게 해준 로**님에게 감사를 드립니다^0^/</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[멋쟁이 사자처럼 FE스쿨 12주차 회고]]></title>
            <link>https://velog.io/@jhyun_k/%EB%A9%8B%EC%9F%81%EC%9D%B4-%EC%82%AC%EC%9E%90%EC%B2%98%EB%9F%BC-FE%EC%8A%A4%EC%BF%A8-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@jhyun_k/%EB%A9%8B%EC%9F%81%EC%9D%B4-%EC%82%AC%EC%9E%90%EC%B2%98%EB%9F%BC-FE%EC%8A%A4%EC%BF%A8-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 22 Nov 2022 06:38:11 GMT</pubDate>
            <description><![CDATA[<h2 id="6주마다-회고-쓰는-이런-동기-어때">6주마다 회고 쓰는 이런 동기 어때?</h2>
<blockquote>
<p>결국 또 엄청난 텀을 두고 회고를 쓰게 되었다 😂 하지만 나름 6을 공차로 하는 등차수열의 규칙으로 회고를 쓰는 것도 나쁘지 않지 않을까? 하며 합리화해본다. 사실 저번에는 너무 고민이 커서 쓴 회고였지만 이번에는 뭔가 12주차에 일이 많았어서 기억하기 위해 쓰는 것에 가깝다...!</p>
</blockquote>
<h2 id="리액트-시작">리액트 시작</h2>
<p>드디어 자바스크립트 수업이 끝나고 리액트 수업이 시작되었다. 예전에 다른 수업을 들을 때 리액트를 사용해 본 적이 있긴 하지만 그때도 맛보기 수준으로 배운지라 자신이 없었다. 때문에 이번 멋사에서 수업을 들으며 리액트 공부를 철저하게 하려고 했으나.. 후술할 동료특강 준비와 겹치는 바람에 산산히 깨어졌다. 물론 수업시간에는 열심히 들었다. 하지만 끝나고 복습할 시간이 절대적으로 부족하여 매일 매일 새로운 우물을 파는 기분이었다. </p>
<p>그래도 확실히 자바스크립트를 처음 배울 때 보다는 느낌이 나은 것 같다. 이미 강사님들의 스타일에 익숙해져서일까 막 엄청 멘붕이 오고 그러지는 않았다. 그냥 어려울 뿐.. 자바스크립트 근간이 있어야 리액트도 잘 한다는데 이 시점에서 자바스크립트 공부를 해야하는 건지 새로 리액트 공부를 해야하는 건지 헷갈렸다. 둘 다 결국 같은 공부라고는 하던데 .. 방향성을 잡지 못해서 혼란스러운 기분이다.</p>
<p>다른 동료분들은 슬슬 토이프로젝트도 하고 배운 것을 활용해서 만들고 싶은 것들도 만들어내던데 나는 이번에도 뒤쳐진 기분을 씻어낼 수가 없다. 하지만 이번에는 저번만큼 우울하지는 않다. 결국 뭐라도 하는 것이 중요하는 것을 깨달았기 때문이다. <strong>한 걸음을 걸어도 맞는 길로 가자.</strong></p>
<h2 id="회고조-랜선-만남">회고조 랜선 만남</h2>
<p>수요일에는 멋쟁이사자처럼 회고조와의 랜선 만남을 진행했다. 각 지방에 흩어져 있는 우리 회고조는 오프라인 만남이 쉽지 않기 때문에 온라인으로 만나기로 했다. 2시간 정도 떠들면서 각자 고민도 이야기 하고 위로도 해주며 돈독해지는 타임을 가졌다. 초반에 어색했던 시간이 지나니 이제는 정말 회고조원들이 편해진 것 같다.</p>
<p>한창 힘들 시기인지라 모두 고민이 많았다. 물론 나도.. ㅎ 대체로 취업, 공부와 같은 비슷비슷한 고민들이었기에 공감하며 들을 수 있었다. 사실 주어진 것들을 해내기도 힘든데 그보다 나아가기는 더 힘들기에 다들 아무렇지도 않은 척 잘 해내는 것 같지만 막막한 건 비슷한가보다. 나도 하루 하루 잘 살고 있는지 모르겠는데 잘할거야~ 잘 하고 있어~ 라고 섣불리 말하기도 어려웠다. 그래도 무거운 분위기는 아니었기에 모두 즐거운 기분으로 마무리 할 수 있었다. 다음번에 또 하면 좋겠다. 실제로 만나면 더 더 좋구.
<img src="https://velog.velcdn.com/images/jhyun_k/post/476afa11-3210-47fc-9ae1-fdfba0b9d008/image.png" alt=""></p>
<p>감동 받은 장문의 디코를 마무리로.. 사실 별 내용 아닌데 우리 이름이 너무 많이 나와서 그냥 다 가려버렸다. 모두 포기하지 말고 파이팅~~ 따수운 우리조..</p>
<h2 id="동료특강---러버덕스-첫번째-꽥-🐤">동료특강 - 러버덕스 첫번째 꽥 🐤</h2>
<p>좋은 기회로 스터디에서 발표를 하게 되었다. 내가 정한 주제는 최근에 블로그에도 작성한 <strong>브라우저 렌더링 과정</strong> 이었다. <a href="https://velog.io/@jhyun_k/%EB%82%B4-%ED%99%94%EB%A9%B4%EC%97%90-%EB%84%A4%EC%9D%B4%EB%B2%84%EA%B0%80-%EC%BC%9C%EC%A7%80%EB%8A%94-%EA%B3%BC%EC%A0%95">해당 글을 보려면 여기로!</a></p>
<p>나름 이 글이 벨로그 트렌딩 3위 (11/22 기준) 에도 올라서 상당히 기분이 좋다. 정성 들여 쓴 글이기도 하고 다른 사람들이 내 글로 인해 도움을 받았으면 좋겠다는 마음으로 쓴 글이기 때문이다.</p>
<h3 id="준비를-하며">준비를 하며..</h3>
<p>처음에는 면접대비 겸으로 준비하게 된 주제였고 나도 잘 모르는 부분이었어서 나부터 공부를 해야 했다. 응당 발표를 위해서라면 조금 더 시간을 들여서 준비를 해야 했으나 무슨 객기인지 금요일 발표인데 월요일 부터 준비를 시작해버렸다. 왜 그랬을까..? 하지만 외롭지 않았다. 나를 비롯한 다른 4인의 스터디원들도 나랑 비슷하게 준비를 시작했기 때문이다. 우리는 발표를 준비하며 발등에 떨어진 불에 정신을 잃어가고 있었다..</p>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/ef231471-d85b-45c0-a4e8-d37d0789765c/image.png" alt=""></p>
<p>그래도 나름 타이트한 일정 속에서 정신 놓으면 끝이다 라는 생각으로 준비를 진행했다. 사실 나는 리미트 타임이 다가오면 효율이 좋아지는 인간이라 나쁘지 않았을지도..?</p>
<h3 id="준비-시작">준비 시작</h3>
<p>우선 브라우저 렌더링 이라고 검색해서 나온 글들을 냅다 읽었다. 다행인 것은 자료가 많은 주제였기 때문에 내가 원하는 정보를 찾기가 쉬웠던 것이다. 그리고 그 글을 쓴 사람들이 남긴 출처도 따라가서 또 읽고 읽고.. 읽다보니 그동안 흐린눈으로 봤던 개념들이 드디어 이해가 되었다! 이게 공부구나.. </p>
<p>내용을 이해하고 나서는 블로그에 글을 쓰기 시작했다. 어렴풋한 개념으로 발표 자료를 만들기에는 무리가 있다고 생각했기 때문이다. 글을 토대로 대본과 피피티를 만들 생각이었기에 나름 체계를 두고 글을 작성했다. 정보 과부화 상태의 뇌 속에서 나름 남들이 이해할 수 있게 글을 정돈하느라 글 작성 시간만 <strong>6시간</strong>이 걸려버렸다. . . <img src="https://velog.velcdn.com/images/jhyun_k/post/614fe36e-ae48-480d-ab8b-cc9adb34d0a1/image.png" alt=""> (사진이 왜이렇게 크지?)
나는 아날로그 인간이라 공책에다 적어놓고 글을 썼다.. -이상 코딩 배우는 인간이</p>
<p>블로그 글 작성이 끝난 후에는 피피티를 만들었다. 대학 졸업 후 피피티를 만드는 것은 처음이었기 때문에 정말 애먹었다. 하지만 요즘 애들은 &#39;미리캔버스&#39; 라는 것으로 피피티를 만든다는 소리를 듣고 나도 한 번 만들어 보았습니다. 
<img src="https://velog.velcdn.com/images/jhyun_k/post/a4b6bdcc-0afe-41de-9914-ecacbc3821fe/image.png" alt=""></p>
<p>나름 귀엽죠? 피피티 30장을 만드는데에도 <strong>6시간</strong>이 걸렸답니다.</p>
<p>이 다음부터는 그냥 피피티 내용과 블로그 글을 섞어 대본을 만들고 연습하고.. 이게 다 하루 전날에 일어난 일.. 발표 하루 전날에는 동네에 사는 스터디원들과 모여 발표연습도 진행했다. 혼자 준비할 때는 비교군이 없어서 막막했는데 다른 스터디원들의 발표도 들으니 내가 개선해야할 부분이 보여서 좋았다. 그래서 스터디원들과 헤어지고 집에와서 대본도 다시 수정하고 긴장 100의 상태로 잠들었다.</p>
<h3 id="드디어-발표-당일">드디어 발표 당일</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/7c6adc2e-c5f2-4cf6-a06a-641416f84298/image.png" alt=""></p>
<p>심장이 너무 뛰었다.. 약 30명 앞에서 발표를 해야한다니.. 너무 긴장됐다. 내 순서는 세번째였다. <code>브라우저 렌더링 배워보자링 =3</code> 긴장을 너무 하느라 발표 전까지 손에 아무 것도 잡히지 않았다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/0174609b-6209-4fe8-ba97-e6e6784c7e41/image.png" alt=""></p>
<p>하지만 결론부터 말하면 발표는 썩 만족스럽지 못했다. 발표 경험이 많이 없어서인지 너무 긴장해서인지 결국 경계하던 대본읽기st의 발표가 되었다고 생각하기 때문이다ㅠ.. 능청스럽고 말하듯이, 대본도 보지 않고 발표 잘 하는 사람들이 너무 부럽다. 나중에 또 이런 기회가 있으면 그때는 나도 발표스킬을 조금 더 키워서 자연스럽게 발표하고 싶다. </p>
<p>그렇지만 이번에 발표자로 참여한 것은 정말 좋은 경험이 되었다고 생각한다. 이렇게 강제로나마 브라우저 렌더링 과정에 대해 공부할 수 있었고 남들에게 어떻게 하면 잘 설명할 수 있을까를 고민하면서 내 머릿속에서도 정리가 더 잘 되었던 것 같다.</p>
<p>발표를 마친 후 다른 사람들의 발표를 들으면서도 많이 배웠다. 실력 차이가 천차만별이기 때문에 누구는 1시간동안 알고리즘 문제를 풀어주기도 하고 고차함수 만들기를 통해 원리를 알려주기도 하고.. 넘사라는 생각과 함께 언젠가는 나도 실력이 늘면 좋겠다 하는 생각이 동시에 들었다. </p>
<p>**님이 발표가 끝날 때 쯤 해주신 말씀이 기억에 남는다. </p>
<blockquote>
<p>지금은 모두 힘들겠지만, 원래 의미있는 일을 하면 힘들대요
우리가 하는 이 모든것들이 큰 의미를 가지고 있기에 그만큼 힘든겁니다.</p>
</blockquote>
<p>지금 내가 하고 있는 일이 어쩔 때는 의미 없고 시간 낭비라고 느껴지는 때도 많지만, 그리고 어쩌면 내가 추후에 개발을 하지 않을 수도 있지만 지금 이 순간에 뭔가를 위해 노력하고 공부하며 전력을 다한 경험은 어떤 방식으로든 나에게 디딤돌이 되어주리라고 믿는다. 믿어야겠다.</p>
<p>모든 사람들의 발표를 마치고 뒤풀이를 했다. 항상 온라인에서만 보던 사람들과 대면하여 이야기하니 신기했다. 같이 발표를 준비했던 스터디원들과도 돈독해지고 다양한 모습을 알게되어 좋은 시간이었다. </p>
<h2 id="12주차-회고-끝">12주차 회고 끝~</h2>
<p>언제가 될지 모르겠지만 처음 규칙 대로라면 18주차에 써야하는 거 아니냐구요.. 그렇지 않기를 바라며 회고 글을 마무리 하겠습니다~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🌏 내 화면에 네이버가 켜질 때까지 - 브라우저 렌더링 과정 ]]></title>
            <link>https://velog.io/@jhyun_k/%EB%82%B4-%ED%99%94%EB%A9%B4%EC%97%90-%EB%84%A4%EC%9D%B4%EB%B2%84%EA%B0%80-%EC%BC%9C%EC%A7%80%EB%8A%94-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@jhyun_k/%EB%82%B4-%ED%99%94%EB%A9%B4%EC%97%90-%EB%84%A4%EC%9D%B4%EB%B2%84%EA%B0%80-%EC%BC%9C%EC%A7%80%EB%8A%94-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Tue, 15 Nov 2022 11:42:48 GMT</pubDate>
            <description><![CDATA[<h1 id="브라우저-렌더링-과정을-알아보자">브라우저 렌더링 과정을 알아보자!</h1>
<blockquote>
<p>스터디에서 동료 특강으로 브라우저렌더링 과정에 대해 발표하게 되었다. 나도 공부를 하기 위해서 맡은 주제이긴 하지만 생각보다 DEEP하게 가려면 엄청나게 방대한 내용이 되어버리는지라 머리가 너무 아팠다..  내가 다른 글들을 수없이 보며 공부한 것을 나중에 잊지 않기 위해, 그리고 다른 사람들에게도 전달하기 위해 블로그에 정리해보려고 한다..! </p>
</blockquote>
<h2 id="📒-이번-글에서는">📒 이번 글에서는!</h2>
<blockquote>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/d1a9dafd-3494-4ffc-86e4-19035f99b500/image.png" alt="">공부하는 과정에서 다른 글들을 보며 <strong>주소창에 <a href="http://www.google.com">www.google.com</a> 을 입력했을 때</strong> , <strong>&#39;주소창에 <a href="http://www.naver.com">www.naver.com</a> 을 입력했을 때&#39;</strong>  일어나는 일을 차근차근 되짚어보니 이해가 훨씬 잘되었다! 그냥 이론적인 부분만 보는 것이 아니라, 평소에 일상적으로 하는 행위의 원리를 알아보니 진입장벽이 낮아지는 것 같아서 나도 그런 방식으로 설명해보려고 한다! </p>
<h3 id="🤔-브라우저-렌더링-과정을-알아야하는-이유">🤔 브라우저 렌더링 과정을 알아야하는 이유?</h3>
<blockquote>
<ol>
<li>프론트엔드 개발 공부를 하면서 내가 쓰는 코드가 어떻게 화면에 뜨는지 정도는 알아야 하지 않을까! 결국 내가 짠 코드는 브라우저에서 동작한다!</li>
<li>성능 최적화에 용이하다!</li>
<li><strong>면접 단골 질문이다^^! 알아두면 나쁠 것 전혀 없다</strong></li>
</ol>
</blockquote>
<h2 id="🌏-브라우저란">🌏 브라우저란?</h2>
<p>MDN 에서는 브라우저를 <strong>웹 브라우저 또는 브라우저는 웹에서 페이지를 찾아서 보여주고, 사용자가 하이퍼링크 (en-US)를 통해 다른 페이지로 이동할 수 있도록 하는 프로그램</strong>  이라고 설명한다.</p>
<p>말하자면 <strong>웹 서버와 통신하여 인터넷 사이트 및 다양한 컨텐츠를 볼 수 있도록 지원해주는 소프트웨어 프로그램이다.</strong> 브라우저의 주요 기능은 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것이다. </p>
<p>브라우저의 종류는 매우 다양하지만 최근에는 구글 크롬, 인터넷 익스플로러, 파이어폭스, 사파리, 오페라 이렇게 다섯 개의 브라우저를 많이 사용한다. (그 중에서 크롬 점유율이 가장 높다..!)</p>
<h3 id="브라우저의-기본-구조">브라우저의 기본 구조</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/6ecff3a2-f4c8-4d5b-a01d-f16ac25dd76d/image.png" alt="">
구조는 브라우저마다 조금씩 다를 수 있다</p>
<blockquote>
<ol>
<li><strong>사용자 인터페이스</strong> - 주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등. 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분에 해당한다.</li>
<li><strong>브라우저 엔진</strong> - 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어한다. Data storage 컴포넌트와 통신할 수 있다.</li>
<li><strong>렌더링 엔진</strong> - 요청한 콘텐츠를 표시. 예를 들어 HTML을 요청하면 HTML과 CSS를 파싱하여 요청받은 내용을 화면에 그려주는 일을 한다.  일반적으로 HTML+CSS를 보여주지만 플러그인의 도움으로 PDF, XML등의 문서도 나타낼 수 있다. </li>
<li><strong>통신</strong> - HTTP 요청과 같은 네트워크 호출에 사용된다. </li>
<li><strong>UI 백엔드</strong> - 콤보 박스와 창 같은 기본적인 장치를 그린다. 플랫폼에서 명시하지 않은 일반적인 인터페이스로서, OS의 유저 인터페이스 메서드를 사용해 창이나 콤보박스, 체크박스 등의 기본적인 위젯을 그려준다. </li>
<li><strong>자바스크립트 해석기(인터프리터)</strong> - 자바스크립트 코드를 해석하고 실행한다.</li>
<li><strong>자료 저장소</strong> - 이 부분은 자료를 저장하는 계층</li>
</ol>
</blockquote>
<h2 id="💻-브라우저-주소창에-wwwnavercom-을-검색하면">💻 브라우저 주소창에 <a href="http://www.naver.com">www.naver.com</a> 을 검색하면?</h2>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/622f4f2f-9f89-48ad-9e40-626a5558b089/image.png" alt="">
브라우저 검색창에 <code>www.naver.com</code> 을 치고 엔터! 를 누르면 이러한 일련의 과정을 거치게 된다. 렌더링 작업 전에 일어나는 과정을 간략히 살펴보자!</p>
<h3 id="✔-1-입력한-text-정보를-확인">✔ 1. 입력한 text 정보를 확인</h3>
<ul>
<li>내가 입력한 텍스트가 <strong>검색어</strong>인지, <strong>url 주소</strong>인지 확인한다.</li>
<li>크롬을 포함한 대부분의 브라우저는 주소창을 검색엔진과 같이 사용한다. (크롬의 경우 주소창에 검색어를 입력하면 자동으로 구글 검색처럼 작동한다) </li>
<li>텍스트가 url 주소일 경우 브라우저 엔진에서 네트워크 호출을 수행한다
즉, 주소창에 <a href="http://www.naver.com">www.naver.com</a> 을 입력하면 네트워크 호출 단계로 넘어가는 것이다!<h3 id="✔-2-네트워크-호출">✔ 2. 네트워크 호출</h3>
네트워크 호출을 간단하게 설명하자면 컴퓨터 세상의 집 주소라고 할 수 있는 <strong>IP주소</strong>를 찾는 과정이다. 내 브라우저에 네이버 화면을 띄워야하는데 네이버에 대한 정보가 없으니 정보가 있는 주소에 가서 요청을 해야하는 것이다. 그 정보는? 당연히 &#39;네이버&#39; 라는 회사 서버에 있다. 때문에 브라우저는 네이버 서버와 통신하여 데이터를 가져와야한다.<h4 id="21-ip-주소-찾기">2.1. IP 주소 찾기</h4>
<img src="https://velog.velcdn.com/images/jhyun_k/post/14021e16-e00e-4183-901a-ab7948b4427d/image.png" alt="">
IP 주소란 앞서 설명했듯이 사이트의 주소를 말한다. 네이버 서버의 주소를 확인하기 위해 사용자(클라이언트)는 DNS 서버에 검색하기 전에 캐싱된 DNS 기록들을 먼저 확인한다. 만약 해당 도메인 <code>(naver.com)</code> 이름에 맞는 IP 주소 <code>(125.209.222.142)</code>가 존재하면, DNS 서버에 해당 도메인 이름에 해당하는 IP주소를 요청하지 않고 캐싱된 IP주소를 바로 반환한다.</li>
</ul>
<p>인터넷 세상에서는 IP 주소를 기반으로 동작하지만 인간인 우리는 그것을 식별하기 어렵기 때문에 IP주소 대신 문자로 이루어진 도메인주소를 사용한다. </p>
<p>때문에 <strong>도메인 주소를 IP주소로 변환해주는 DNS(Domain Name Server)</strong>가 필요한 것이다. 이를 수행하는 것이 DNS 서버이다. </p>
<blockquote>
<p>DNS서버는 도메인 주소에 대응하는 IP 주소를 찾아주는 역할을 수행한다.</p>
</blockquote>
<p>만약 DNS 기록에 가려고 하는 URL과 일치하는 IP주소가 존재하지 않는다면 DNS 서버에 해당 사이트 IP주소를 요청한다.</p>
<h4 id="22-http-통신">2.2. HTTP 통신</h4>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/2134f5e0-ff01-4238-9eba-2422f06aa496/image.png" alt="">
이제 브라우저가 네이버의 IP주소를 알게 되었으므로 네이버 서버와 통신할 수 있게 되었다! 클라이언트의 브라우저는 네이버 서버에 데이터를 요청하는 <strong><code>HTTP Request</code></strong>를 보낸다. request를 받은 네이버서버는 이를 바이트 형태 (1과 0으로 이루어짐) 로 변환하여, 클라이언트로 <strong><code>HTTP Response</code></strong>를 보낸다.</p>
<hr>
<p>여기까지가 데이터가 불러와지는 과정이다!
이제 이 받아온 데이터를 화면에 <strong>그려야</strong> 한다!</p>
<h1 id="💻-렌더링">💻 렌더링</h1>
<h3 id="렌더링이란">렌더링이란?</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/baeb1617-8344-45a1-9a36-7f76978ffed2/image.png" alt="">
웹 브라우저에 출력되는 단계를 <code>Critical Rendering Path</code> 라고 한다.</p>
<blockquote>
<p>받아온 데이터의 내용대로 화면에 그리는 것을 <strong>렌더링</strong>이라고 한다.
렌더링에 필요한 것은 HTML과 CSS 문서이다. ( 물론 플러그인이나 브라우저 확장 기능을 이용해 PDF와 같은 다른 유형도 표시할 수 있지만.... =333 )</p>
</blockquote>
<h3 id="렌더링-엔진">렌더링 엔진</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/0441f5d9-0804-4aaa-9fb8-289a23dc5d89/image.png" alt="">(웹킷)
<img src="https://velog.velcdn.com/images/jhyun_k/post/b828f2d7-d404-4087-8af5-e7cdcce05ce3/image.png" alt="">(게코)</p>
<p>렌더링 엔진은 위에서 설명한 것처럼 요청받은 내용을 브라우저 화면에 표시해주는 역할을 한다. 브라우저마다 사용하는 렌더링 엔진이 각각 다르며 사파리는 <code>webkit</code>, 파이어폭스는 <code>gecko</code> 엔진을 사용한다. 크롬은 원래는 webkit 엔진을 사용하다가 그것을 fork하여 <code>blink</code> 엔진을 사용하고 있다.</p>
<p>웹킷과 게코가 용어를 약간 다르게 사용하고 있지만 동작 과정은 기본적으로 동일하다는 것을 위 두 그림에서 알 수 있다.</p>
<h2 id="💻-브라우저-렌더링-과정browser-rendering">💻 브라우저 렌더링 과정(Browser Rendering)</h2>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/ded4326c-17a6-4d24-9291-780df981b016/image.png" alt=""><img src="https://velog.velcdn.com/images/jhyun_k/post/d4c1e04a-4ee5-4360-a4c8-5ed26ae2efc1/image.png" alt="">네트워크 통신 이후 렌더링 과정은 총 4단계로 이루어져 있다.</p>
<blockquote>
<ol>
<li><strong>파싱</strong></li>
<li><ol>
<li>HTML문서파싱 =&gt; DOM 트리 생성             </li>
</ol>
</li>
<li><ol start="2">
<li>CSS 문서 파싱 =&gt; CSSOM 트리 생성</li>
</ol>
</li>
<li><strong>Render Tree 구축</strong></li>
<li><strong>Layout</strong></li>
<li><strong>Paint</strong></li>
</ol>
</blockquote>
<p>여기서 이러한 일련의 과정들이 점진적으로 진행된다는 것을 아는 것이 중요하다. 렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 <strong>모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다.</strong> 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시하는 것이다. </p>
<p>이제부터 각각의 단계에 대해 자세히 알아보자!</p>
<h3 id="1-🌱-파싱">1. 🌱 파싱</h3>
<p>렌더링 과정 중 가장 중요한 것이 이 파싱(Parsing) 이다. 브라우저는 HTML CSS 등의 단순한 텍스트 문서를 이해할 수 없기 때문에 브라우저가 읽을 수 있도록 변환하는 과정이 필요하다. 즉, 파싱은 서버로부터 전송받은 문서의 문자열을 <strong>브라우저가 이해할 수 있는 구조로 변환하는 과정</strong>이라고 할 수 있다.</p>
<h4 id="11-html-파싱">1.1. HTML 파싱</h4>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/87bde6ec-0526-4b19-979f-8b59161333ee/image.png" alt="">
렌더링 엔진이 HTML 문서를 수신받으면, HTML 파서는 이를 _위에서부터 읽어 내려가며 파싱을 진행_하고, 그 결과물로 <strong>DOM 트리</strong>를 생성한다.</p>
<blockquote>
<p><strong>DOM트리 생성 과정</strong></p>
</blockquote>
<ol>
<li>HTML 문서를 바이트(1011011...)형태로 받는다.</li>
<li><code>meta</code> 태그의 <code>charset</code> 에 지정된 인코딩 방식(UTF-8)에 따라 문자열로 변환한다.</li>
<li>문자열로 변환된 HTML문서를 문법적 의미를 갖는 최소 단위인 토큰(token)으로 분해한다.<ul>
<li>가령 <code>&lt;div&gt;&lt;/div&gt;</code> 라는 코드를 토큰화하면 <code>[&#39;&lt;&#39;,&#39;div&#39;,&#39;&gt;&#39;,&#39;&lt;/&#39;,&#39;div&#39;,&#39;&gt;&#39;]</code> 처럼 나타낼 수 있다.</li>
</ul>
<ol start="4">
<li>토큰들을 내용에 따라 객체로 변환하여 노드를 생성한다. (문서 노드, 요소 노드 등)</li>
<li>이 노드들을 계층 형태의 트리구조로 구성하여 DOM 트리 생성!</li>
</ol>
</li>
</ol>
<h4 id="12-css-파싱">1.2. CSS 파싱</h4>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/d3bc0481-28ff-47a4-8901-b9c29e35aed0/image.png" alt="">
CSS 문서를 파싱하여 <strong>CSSOM 트리</strong>를 생성한다. 앞서 렌더링 엔진은 HTML문서를 한 줄 씩 파싱하면서 DOM을 생성한다고 했다. 이 과정에서 CSS 문서를 연결한 <code>&lt;link&gt;</code> or <code>&lt;style&gt;</code> 태그를 만나면 CSS문서를 파싱하여 스타일 규칙을 담고있는 CSSOM 트리를 만들기 시작하는 것이다. </p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
 &lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt; // 여기까지 해석 후, 
  &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt; //link를 만나면 DOM생성을 일시정지하고 
  //CSS파일을 서버에 요청한 후 응답받아 CSS파싱을 시작한다. 
  ...</code></pre><p>CSS는 렌더링을 할 때 반드시 필요한 리소스이기 때문에 브라우저는 빠르게 CSS를 다운로드하는 것이 좋다. 그래서 <code>&lt;head&gt;</code> 태그 안에서 정의하여 빠르게 리소스를 받을 수 있도록 하는 것이다..!</p>
<p>CSSOM을 생성하는 과정은 DOM을 생성하는 과정과 같다.</p>
<h4 id="13-js-파싱">1.3. JS 파싱</h4>
<p>파싱 과정에서 <code>&lt;script&gt;</code> 태그 만나면 렌더링 엔진은 파싱을 잠시 중단하고 script를 읽는다. 그리고 JS파싱이 끝나면 렌더링 엔진은 다시 HTML 문서를 파싱한다.</p>
<p><code>&lt;script&gt;</code> 태그가 <code>&lt;body&gt;</code> 태그 중간에 위치할 경우 HTML 파싱을 하는 도중에 갑자기 JS 파일을 읽게 되므로 오류 발생 위험이 있다. 그래서 우리가 <code>&lt;script&gt;</code> 태그를 <code>&lt;body&gt;</code> 태그 최하단에 쓰는거다~! </p>
<p>(만약 <code>&lt;script&gt;</code> 태그에 <code>defer(지연)</code> 속성을 부여하면 HTML 문서 파싱을 중단하지 않고 파싱이 완료된 이후에 스크립트가 실행되도록 할 수 있다. HTML5에서 스크립트를 비동기(async)로 처리하는 속성이 추가되어서 자바스크립트가 별도의 맥락에 의해 파싱 되고 실행할 수 있다. <a href="https://beomy.github.io/tech/browser/async-defer/">async와 defer</a> &lt;= 여기서 더 자세한 내용을 볼 수 있다.)</p>
<h3 id="2-🌳-render-tree">2. 🌳 Render Tree</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/a3c345dd-e2ae-4a68-9416-014a5dbb1b9d/image.png" alt="">
파싱하여 만든 DOM 트리와 CSSOM 트리를 결합하는 것을 <code>Attachment</code> 라고 한다. <code>Attachment</code>를 통해 <strong>Render Tree</strong>를 구축한다.
<img src="https://velog.velcdn.com/images/jhyun_k/post/ddad3eee-2a7b-4200-99c3-c8b4ba725452/image.png" alt="">
렌더트리란 실제 화면에 표현되는 노드들로만 구성된 트리를 뜻한다. (여기서 화면에 표현되는 것은 눈에 보이는 것이 아닌 <strong>화면상에서 공간을 차지하느냐</strong>이다.</p>
<blockquote>
<h4 id="렌더-트리-생성-과정">렌더 트리 생성 과정</h4>
</blockquote>
<ol>
<li><code>html</code> 태그와 <code>body</code> 태그를 처리하며 렌더트리 루트를 구성<br></li>
<li>DOM의 최상위 노드부터 순회하면서 <strong>화면에 보여지지 않는 노드</strong>를 렌더 트리의 구성에서 제외한다. (렌더러는 DOM 요소에 부합하지만 1:1로 대응하는 관계는 아니다)
ex ) </li>
</ol>
<ul>
<li><code>&lt;head&gt;</code> 요소와 같은 비시각적 DOM 요소는 렌더 트리에 추가되지 않는다. </li>
<li><code>display : none</code> 속성은 아예 사라지는 것이므로 렌더트리에서 제외된다. </li>
<li>하지만 <code>visibility : hidden</code> 속성은 자리는 화면상에서 공간을 차지하는 속성이기 때문에 렌더트리에 반영된다.<br></li>
</ul>
<ol start="3">
<li>화면에 보여지는 나머지 노드에 CSSOM 규칙을 찾아 일치하는 스타일을 적용한다.
이 과정에서 <code>position</code>이나 <code>float</code> 속성을 만나면 실제 그려지는 위치로 랜더 객체가 이동한다.)</li>
</ol>
<h3 id="3-⚒-레이아웃reflow">3. ⚒ 레이아웃(reflow)</h3>
<blockquote>
<p>렌더트리의 노드를 화면에 배치하는 과정을 레이아웃이라고 한다.
렌더트리 생성이 끝나면 웹페이지 화면 안에서 렌더트리에 있는 각 노드의 위치와 크기, 너비, 높이 등을 <strong>계산</strong>하고 화면에 <strong>배치</strong>하는 레이아웃 과정이 실행된다. </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/61247413-c4cf-4725-ac44-b3cc8771b826/image.png" alt=""></p>
<p>이 과정에서 뷰포트 내에서 생성된 render tree의 각 노드들이 스크린 상의 어느 공간에 위치해야할지가 결정된다. </p>
<p>이때 모든 상대적인 값(rem, vw 등)이 절대단위인 <code>px</code>로 변환된다.</p>
<p>레이아웃은 전체의 배치과정이 필요한 경우인 <strong>글로벌 레이아웃</strong>, 일부의 배치과정만 변경하면 되는 경우인 <strong>로컬 레이아웃</strong>으로 구분할 수 있다.</p>
<p>처음 배치되거나 font와 같은 전역 스타일이 변경될 경우, 창이 resize되는 경우 전체적으로 layout 과정이 일어난다.(<strong>글로벌 레이아웃</strong>) 초기 배치 이후 요소의 크기나 위치가 변할 때 Layout이 다시 일어나는 것을 리플로우(reflow) 라고 한다. </p>
<p><strong>로컬 레이아웃</strong>은 초기 배치 이후 일부 DOM 노드에 변경이 생기는 것처럼, 특정 부분만 재배치가 필요할 때 발생한다. 화면의 일부만 바뀌어도 전체 배치를 새로 하는 것은 너무나 비효율적이기 때문에 화면의 구조가 바뀌었을 때 일어나는 것!! </p>
<h3 id="4-🎨-페인트">4. 🎨 페인트</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/d48ba1a7-dbff-4646-ac0b-1ddbad5bbf57/image.png" alt=""></p>
<blockquote>
<p>레이아웃 과정에서 계산된 정보들을 바탕으로 각 노드들을 화면에 그려주는 과정</p>
</blockquote>
<p>렌더 트리의 각 노드를 화면의 <strong>실제 픽셀</strong>로 나타낼 때 Painting메서드가 호출된다. Painting 과정 후 브라우저 화면에 UI가 나타나게 된다. 브라우저 성능 개선을 위해 각 노드를 레이어별로 나눠서 준비한다. 그리고 변경되는 요소가 있을 경우 그 레이어만 업데이트한다. </p>
<p>이러한 과정이 모두 끝나면
<img src="https://velog.velcdn.com/images/jhyun_k/post/9b2626cd-a5c5-4a13-ad10-50839b8d505a/image.png" alt="">
드디어 네이버 화면이 보이게 되는 것이다.. 휴
검색이 아니고서도 내가 코딩한 화면도 이런 과정을 거쳐서 보이는 것이다...!
이러한 과정이 몇 초 만에 일어나다니 정말 신기할 따름...</p>
<h3 id="끝❓-노노-reflow와-repaint">끝❓ 노노 Reflow와 Repaint</h3>
<p>위 4단계의 과정을 모두 마치면 브라우저에 화면이 그려진다. 하지만 특정 액션이나 이벤트에 따라 HTML요소의 크기나 위치 등의 레이아웃 수치가 변하면 해당 요소의 영향을 받는 자식 노드나 부모 노드들을 포함하여 _Layout(Reflow)과정을 다시 수행_하게 된다.
이럴경우 각 요소들의 크기와 위치를 다시 계산하게 되는데 이 과정을 <code>Reflow</code>, 그리고 Reflow 된 렌더 트리를 다시 화면에 그려주는 과정을 <code>Repaint</code>라고 한다.</p>
<blockquote>
<p><strong>Reflow가 일어나는 경우</strong></p>
<ul>
<li>페이지 초기 렌더링 시 (최초 Layout 과정)</li>
</ul>
</blockquote>
<ul>
<li>브라우저 리사이징 시 (Viewport 크기 변경)</li>
<li>노드 추가 또는 제거</li>
<li>DOM 노드의 위치 변경</li>
<li>DOM 노드의 크기 변경(margin, padding, border, width, height 등..)</li>
<li>요소의 위치, 크기 변경</li>
<li>폰트 변경과 이미지 크기 변경</li>
</ul>
<blockquote>
<p><strong>Repaint</strong></p>
</blockquote>
<ul>
<li>Reflow만 수행되면 실제 화면에는 반영되지 않기 때문에 다시 Painting이 일어나야 한다. 이 과정을 Repaint라고 한다.</li>
<li>Reflow가 발생하지 않아도 <code>background-color</code> 나 <code>opacity</code> 같이 레이아웃에 영향을 주지 않는 스타일 속성이 변했을 때는 reflow 없이 repaint만 일어난다.</li>
</ul>
<blockquote>
<p>** Reflow와 Repaint 차이**</p>
</blockquote>
<ul>
<li>Repaint(Redraw)는 화면에 변화가 있을 때 화면을 다시 그리는 과정.<ul>
<li>Repaint가 발생하는 경우는 <strong>화면이 변경되는 모든 경우</strong>.</li>
</ul>
</li>
<li>Reflow(Layout)는 뷰포트 내에서 렌더 트리의 노드의 정확한 위치와 크기를 계산하는 과정.<ul>
<li>Reflow가 발생하는 경우는 <strong>화면의 구조가 바뀌었을 경우</strong>.</li>
</ul>
</li>
</ul>
<p>하지만 우리는 한국인.. 몇 초만 로딩이 딜레이 되어도 인터넷에 문제 있는지 확인해 보는 민족 아닙니까 렌더링을 최적화하여 화면을 빨리 뜨게 하려면 어떻게 해야할까요..!</p>
<h2 id="💫-렌더링-최적화">💫 렌더링 최적화</h2>
<h3 id="렌더링-최적화하기-위해서는">렌더링 최적화하기 위해서는</h3>
<blockquote>
<p><strong>1. Reflow 최소화하기</strong></p>
</blockquote>
<ul>
<li>브라우저가 더 빠르게 렌더링하기 위해서는 Reflow 과정을 최소화 시켜야 한다. Reflow가 발생하면 필연적으로 Repaint가 일어나기 때문에 렌더링 최적화에 좋지 않다. 따라서 Reflow가 발생하는 속성보다 Repaint만 발생하는 속성을 사용하는 것이 좋다.<img src="https://velog.velcdn.com/images/jhyun_k/post/64090b6f-e4d9-4e77-a68e-32321b24b505/image.png" alt=""></li>
<li><em>2. CSS문서와 JS문서로 인한 비효율 줄이기 *</em></li>
</ul>
<p>2.1. CSS</p>
<ul>
<li><code>&lt;link&gt;</code>,<code>&lt;style&gt;</code>과 같은 css문서 <code>&lt;head&gt;</code> 태그 안에 배치</li>
<li>미디어 유형과 미디어 쿼리 이용 (해당 조건에 부합될 때만 로드되므로)</li>
</ul>
<p>2.2. JS
HTML 파싱 도중 <code>&lt;script&gt;</code>태그를 만나면 DOM생성을 중단하고 javascript가 실행되게 한 후 DOM생성을 재개한다.</p>
<ul>
<li><code>&lt;script&gt;</code> 태그를 <code>&lt;body&gt;</code> 최하단에 위치한다.</li>
<li><code>async</code> 속성을 <code>&lt;script&gt;</code> 태그에 부여</li>
<li><code>defer</code> 속성을 <code>&lt;script&gt;</code> 태그에 부여</li>
<li><em>3. 영향을 주는 노드 최소화하기*</em>
JavaScript와 CSS를 조합해 애니메이션이나 레이아웃 변화가 많은 요소의 경우 <code>position</code>을 <code>absolute</code> 또는 <code>fixed</code>를 사용하면 영향을 받는 주변 노드들을 줄일 수 있다.
<code>fixed</code>와 같이 영향을 받는 노드가 전혀 없는 경우 Reflow과정이 전혀 필요없어지기 때문에 Repaint연산비용만 들게 되어 효율적이다.</li>
</ul>
<h2 id="🤓-후기">🤓 후기</h2>
<p>이렇게 하나의 주제로 글을 오래, 깊이 써본 것은 처음이다. 스터디와 발표가 아니었으면 브라우저 렌더링 과정에 대해 이만큼이나 톺아볼 기회는 없었을 것 같다. 프론트엔드 개발 공부를 하면서도 내가 짜는 코드가 어떻게 화면에 구현되는지 모른채 얼레벌레 코드를 짜고있었다는 것을 알게된 시간이었다. 공부를 하면서 정말 이런 동작 원리 하나하나가 코드를 짜는 데 중요하다는 것을 알았다. <BR>
짧은 시간 동안 여러 레퍼런스를 머리에 욱여넣으며 공부한 것이라 부족한 점이 많겠지만 나중에 이번에 공부한 내용을 실제 코드를 짤 때 활용해보고싶다. 
그리고 혹시라도 틀린 내용이 있다면 꼭 알려주세요 틀린 지식을 전파하고 싶지 않아요 흑흑..</p>
<blockquote>
<p><strong>참고자료 및 사진 출처</strong></p>
</blockquote>
<p><a href="https://d2.naver.com/helloworld/59361">브라우저는 어떻게 동작하는가?</a> (네이버 D2)
<a href="https://developer.mozilla.org/ko/docs/Glossary/Browser">https://developer.mozilla.org/ko/docs/Glossary/Browser</a> (MDN 문서)
<a href="https://web.dev/critical-rendering-path-render-tree-construction/#tl;dr">Render-tree Construction, Layout, and Paint</a> (Web.dev)
<a href="https://velog.io/@tnehd1998/%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-www.google.com%EC%9D%84-%EC%9E%85%EB%A0%A5%ED%96%88%EC%9D%84-%EB%95%8C-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EA%B3%BC%EC%A0%95#9-render-tree-%EC%83%9D%EC%84%B1">주소창에 www.google.com을 입력했을 때 일어나는 과정</a> (벨로그)
<a href="https://velog.io/@ye-ji/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95%EA%B3%BC-%EC%B5%9C%EC%A0%81%ED%99%94Browser-Rendering-and-Optimization">브라우저 렌더링 과정과 최적화(Browser Rendering and Optimization)</a> (벨로그)
<a href="https://velog.io/@bbumjun/how-browser-works">브라우저는 어떻게 동작할까?</a>  (벨로그)
<a href="https://velog.io/@sylagape1231/%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-naver.com%EC%9D%84-%EC%B9%98%EB%A9%B4-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EC%9D%BC%EC%9D%84-%EC%89%BD%EA%B2%8C-%EC%9D%B4%ED%95%B4%ED%95%B4%EB%B3%B4%EC%9E%90#-step-2-render-tree-%EC%83%9D%EC%84%B1">주소창에 naver.com을 치면 일어나는 일을 쉽게 이해해보자</a>  (벨로그)
<a href="https://velog.io/@thyoondev/%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90#%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%99%80-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%9D%98-%ED%86%B5%EC%8B%A0%EA%B3%BC%EC%A0%95">웹 브라우저의 동작원리를 알아보자</a>  (벨로그)
<a href="https://wormwlrm.github.io/2021/03/27/How-browsers-work.html">프론트엔드 개발자라면 알고 있어야 할 브라우저의 동작 과정</a>  (개인 블로그)
<a href="https://velog.io/@moonshadow/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%88%9C%EC%84%9C">브라우저의 렌더링 순서</a>  (벨로그)
<a href="https://chanyeong.com/blog/post/43">브라우저 렌더링과 최적화</a> (개인 블로그)
<a href="https://beomy.github.io/tech/browser/browser-rendering/">[Browser] 브라우저 렌더링</a>  (개인 블로그)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[숫자가 줄어드는 타이머 ⏱]]></title>
            <link>https://velog.io/@jhyun_k/%EC%88%AB%EC%9E%90%EA%B0%80-%EC%A4%84%EC%96%B4%EB%93%9C%EB%8A%94-%ED%83%80%EC%9D%B4%EB%A8%B8</link>
            <guid>https://velog.io/@jhyun_k/%EC%88%AB%EC%9E%90%EA%B0%80-%EC%A4%84%EC%96%B4%EB%93%9C%EB%8A%94-%ED%83%80%EC%9D%B4%EB%A8%B8</guid>
            <pubDate>Fri, 11 Nov 2022 07:28:13 GMT</pubDate>
            <description><![CDATA[<h2 id="숫자가-줄어드는-타이머⏱">숫자가 줄어드는 타이머⏱</h2>
<blockquote>
<p>디자인 저작권 문제로 디자인은 올릴 수 없지만 내가 보기 위해 기능 구현 방식만 간단하게 정리해놓기로 한다. 디자인 요소는 다 제거하고 js만 ...이 블로그 포스팅도 문제가 된다면 비공개 하겠습니다ㅠ.ㅠ </p>
</blockquote>
<h3 id="기능-명세">기능 명세</h3>
<blockquote>
<ol>
<li>hrs, min, sec에 각각 시, 분, 초를 입력하고 start버튼을 누르면 숫자가 줄어든다</li>
<li>pause 버튼을 누르면 타이머가 멈춘다</li>
<li>reset 버튼을 누르면 초기화된다</li>
<li>지정한 시간이 다 되면 alert 창이 뜬다</li>
</ol>
</blockquote>
<ul>
<li>상세기능<ul>
<li>input 창에 값이 입력되면 start버튼 활성화됨</li>
<li>아무것도 입력하지 않은 상태라면 start 버튼 비활성화</li>
<li>타이머가 시작되면 input 값 변경 불가</li>
</ul>
</li>
</ul>
<h3 id="구현영상">구현영상</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/87677f5f-4692-4707-961a-0b8cbb85c5ff/image.gif" alt=""></p>
</blockquote>
<p>음 정말 디자인의 힘이 중요하군 아무튼 아시겠죠? 어떤 느낌인지???</p>
<h3 id="기능">기능</h3>
<blockquote>
</blockquote>
<h3 id="1-showbtn-hidebtn-로-버튼-조절하기">1. <code>showBtn()</code>, <code>hideBtn()</code> 로 버튼 조절하기</h3>
<p><img src="https://velog.velcdn.com/images/jhyun_k/post/3a541788-8eed-4ee5-a37a-bc974439bcbb/image.png" alt=""></p>
<ul>
<li>start 버튼을 누르면 start 버튼이 사라지고 pause 버튼이 나오고,
pause 버튼을 누르면 start버튼이 나오게 하기</li>
<li>버튼 3개를 만들고 <code>display</code> 속성을 조절하였다<h3 id="2-input-초기화">2. input 초기화</h3>
<img src="https://velog.velcdn.com/images/jhyun_k/post/394883e6-826d-49b0-af1d-eb32b53d4c57/image.png" alt=""></li>
<li><strong>input 창에 input 이벤트 발생시 <code>able</code> (활성화 클래스) 붙여주고 startBtn에 <code>disabled</code> 속성 제거</strong><ul>
<li><code>change</code> 이벤트를 넣을 경우 값을 입력하고 다른 곳을 눌러야 이벤트가 실행된다. 하지만 내 경우에는 값이 입력되자마자 버튼을 활성화 시키고 싶었기 때문에 <code>input</code> 이벤트를 사용하였다</li>
<li><code>input</code> 변수는 <code>hrs</code>,<code>min</code>,<code>sec</code> 값을 <code>querySelectorAll</code>로 받아온 값이라서 <code>for of</code> 를 이용하여 반복문 안에서 진행되도록 함</li>
</ul>
</li>
<li><strong>input 창 클릭 이벤트 발생시 이벤트가 발생한 value를 &#39;&#39; 으로 할당</strong><ul>
<li><code>e.currentTarget</code> 를 쓰면 이벤트 핸들러가 붙어있는 input의 값을 바꿀 수 있다. <code>e.target</code> 을 쓸 경우 클릭한 그 요소의 값이 나옴 </li>
<li>target은 이벤트가 발생한 바로 그 요소를 직접 가리키고 currentTarget은 이벤트 리스너(EventListener)를 가진 요소를 가리킨다. 이 경우는 input 태그에 자식이 없기에 문제가 없는데 event 를 달 때 유의해서 사용해야한다..!<h3 id="3-타이머-기능">3. 타이머 기능</h3>
<h4 id="startbtn-클릭-이벤트">startBtn 클릭 이벤트</h4>
<img src="https://velog.velcdn.com/images/jhyun_k/post/cbc5cae7-2647-4198-8495-eda01ffcd6dc/image.png" alt=""></li>
</ul>
</li>
<li><strong>start 버튼 클릭하면 모든 input창에 <code>disabled</code> 속성 추가</strong><ul>
<li><code>setAttribute()</code> 이용</li>
<li><strong>input 클릭시 내용 입력 위해 값을 비우는데 그러고 값을 입력하지 않으면 오류가 났다. 그래서 <code>if(el.value===&#39;&#39;)</code> 일 경우 다시 <code>el.value=&#39;00&#39;</code> 으로 값을 할당</strong>해주었다. &#39;00&#39; 은 string이므로 <code>parseInt</code> 이용하여 숫자로 바꿔주기</li>
<li><strong>totalSeconds 는 <code>const totalSeconds = hours * 60 * 60 + minutes * 60 + seconds</code> 로 계산</strong></li>
<li>startTimer 실행</li>
<li>start버튼은 숨기고 pause 버튼 보이기<h4 id="starttimer">startTimer</h4>
<img src="https://velog.velcdn.com/images/jhyun_k/post/feb86714-293c-47cb-8183-65d77d414ea1/image.png" alt=""></li>
</ul>
</li>
<li><strong><code>startTimer()</code> 함수를 만들고 <code>setInterval()</code> 을 이용하기</strong><ul>
<li>interval 변수에 <code>setInterval()</code> 전체를 받아줘야 clear 할 때 편하다</li>
</ul>
</li>
<li><strong>총 초수(totalSeconds) 를 받아와서 1초씩(1000) 감소</strong>시킨다</li>
<li>totalSeconds가 0이 되면 <code>clearInterval</code>속성으로 타이머 종료</li>
<li>*<em>타이머가 종료되면 시분초는 다시 &#39;00&#39;으로 만들어주기 *</em>(hrs,min,sec 은 각각 <code>input</code>태그를 받아온 것이므로 <code>변수.value</code>로 해야 <code>input</code>의 <code>value</code> 속성을 제어할 수 있다!</li>
<li>타이머가 끝났으니 당연히 start버튼을 show 하고 pause버튼 숨기기</li>
<li><code>able</code>이라는 활성화 클래스도 <code>classList.remove</code> 로 지워준다<h4 id="input값-업데이트">input값 업데이트</h4>
<blockquote>
</blockquote>
<img src="https://velog.velcdn.com/images/jhyun_k/post/13eb0830-2637-48e9-928a-24b30edb9357/image.png" alt=""></li>
<li>분, 초는 최대 60까지만 입력되어야하기 때문에 계산을 해주어야한다..!<pre><code class="language-js">const hours = Math.floor(totalSeconds / 60 / 60);
const minutes = Math.floor((totalSeconds/60)%60)
const seconds = totalSeconds % 60</code></pre>
</li>
<li><strong>각 input 이 10보다 작아지면 앞에 0이 있어야하므로 붙여주기</strong><ul>
<li><code>padStart</code> 라는 간편한 속성이 있었다...! 나중에 사용해보기 <h3 id="4-pause-기능">4. pause 기능</h3>
<img src="https://velog.velcdn.com/images/jhyun_k/post/1786763d-9649-40b3-a38e-3975d9639a47/image.png" alt=""></li>
</ul>
</li>
<li><code>clearInterval</code> 로 타이머 멈추기</li>
<li>pause 버튼은 숨기고 start 버튼 보이기<h3 id="5-reset-기능">5. reset 기능</h3>
<img src="https://velog.velcdn.com/images/jhyun_k/post/19ae0b54-09dc-4984-964f-afb7c95dc201/image.png" alt=""></li>
<li><code>resetBtn</code> 클릭 이벤트 발생시 각 인풋의 value는 00으로 초기화</li>
<li><code>clearInterval</code> 로 타이머 종료</li>
<li><code>able</code> 활성화 클래스도 <code>classList.remove</code> 로 지워준다</li>
<li>start버튼을 show 하고 pause버튼 숨기기</li>
<li>타이머가 진행되는 동안 input 창에 동작하던 disabled 속성도 지워주기</li>
</ul>
<h2 id="후기">후기</h2>
<blockquote>
<p>어플리케이션을 처음부터 끝까지 스스로 만든 것은 처음이라 상당히 뿌듯했다. 어떻게 해야 기능이 동작할지 고민해보고 html 코드도 갈아엎어가며 만들어본 시간이었다. 
처음에 대략적으로 기능이 돌아가고 멋사 동료분에게 자랑했는데 바로 버그가 미친듯이 발견되어 좌절했었다... 그런데 버그가 명시적으로 드러나니 그 버그를 수정하기 위해 어떤 것을 해야 할지 생각해보고 그것이 고쳐지니까 정말 신기했다..!
<img src="https://velog.velcdn.com/images/jhyun_k/post/1995d776-6e67-478e-a594-601eb2558f6f/image.png" alt="">
처음에는 해결 못한 것 목록이 가득했는데 지금은 적어도 발견한 버그는 모두 해결했다...! 왜 내가 혼자 테스트 해볼 때는 원하는 방향으로만 테스트 해본 것일까? 사용자를 믿으면 안된다는 강사님들의 말씀을 여실히 깨달은 날이다. 버그 테스트 해주던 동료분이 정말 내가 상상도 못한 방식으로 이것저것 동작시켜보는 걸 보고 피드백의 중요성을 다시 한 번 상기했다. 
다음번에는 저렇게 뭉뚱그려서 <code>해결완</code> 이렇게 적지 말고 어떻게 해결했는지도 대략적으로 적어놔서 기록 해보면 좋을 것 같다. </p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>