<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>may.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 27 Nov 2024 06:10:05 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>may.log</title>
            <url>https://velog.velcdn.com/images/may_05/profile/4d84f244-81ec-410c-ae6e-6d8e090a689b/image.webp</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. may.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/may_05" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Eslint와 Prettier]]></title>
            <link>https://velog.io/@may_05/Eslint%EC%99%80-Prettier</link>
            <guid>https://velog.io/@may_05/Eslint%EC%99%80-Prettier</guid>
            <pubDate>Wed, 27 Nov 2024 06:10:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>포매터와 린터</strong></p>
</blockquote>
<ul>
<li><strong><code>포매터</code></strong> | 코드 스타일 검사/수정(포매팅) → 규칙과 다른 코드가 있는지</li>
<li><strong><code>린터</code></strong>    | 코드의 구조를 검사해서 잘못 작성된 코드가 없는지 확인<blockquote>
</blockquote>
</li>
</ul>
<h2 id="0️⃣-자동화-도구들">0️⃣ 자동화 도구들</h2>
<p>포매터와 린터의 실행을 대신해 주는 자동화 도구를 사용한다.</p>
<h3 id="husky">Husky</h3>
<p>husky를 사용하면 커밋을 하기 전이나 푸시를 하기 전에 포매터와 린터를 실행해서 자동으로 코드를 검사하도록 할 수 있다.</p>
<p>참고로 Husky는 Git에서 제공하는 깃 훅(Git Hooks)이라는 기능을 쉽게 사용할 수 있도록 해주는 패키지이기 때문에, 꼭 husky를 사용하지 않더라도 Git의 기능으로 이런 자동화를 할 수 있다.</p>
<h3 id="github-action">Github Action</h3>
<p>자동화 스크립트를 내 컴퓨터에서만 실행하는 게 아니라, 깃허브 같은 원격 저장소에서도 실행할 수 있다. 최근에는 깃허브에서 기본적으로 제공하는 Github Action이라는 걸 많이들 사용한다.</p>
<h2 id="1️⃣-prettier">1️⃣ Prettier</h2>
<h3 id="01-패키지로-설치하기">01. 패키지로 설치하기</h3>
<p>프로젝트에 <code>devDependencies</code> 로 <code>prettier</code> 라는 패키지를 설치한다.</p>
<pre><code>npm install --save-dev prettier</code></pre><p>Prettier에서 사용할 규칙을 적은 파일인 <code>.prettierrc.json</code> 파일을 만든다.</p>
<pre><code>{
  &quot;trailingComma&quot;: &quot;es5&quot;,
  &quot;tabWidth&quot;: 2,
  &quot;semi&quot;: false,
  &quot;singleQuote&quot;: true
}</code></pre><h3 id="02-vs-code-확장-프로그램으로-사용하기">02. VS Code 확장 프로그램으로 사용하기</h3>
<p>VS Code의 Extension 메뉴에서 prettier를 검색해서 설치할 수 있다.</p>
<p>마찬가지로 <code>.prettierrc.json</code>를 만든다.</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/7893a8e4-38e7-42a4-b5bf-12a70397e1d3/image.png" alt=""></p>
<h2 id="2️⃣-eslint">2️⃣ ESLint</h2>
<p>: 코딩 컨벤션에 위배되는 코드나 안티 패턴을 자동 검출하는 도구</p>
<h3 id="01-react-create-react-app에서-사용하기">01. React (Create React App)에서 사용하기</h3>
<p>프로젝트 폴더에서 터미널을 열고, ESLint에서 제공하는 도구를 사용해서 초기화 한다.</p>
<pre><code class="language-bash">npm init @eslint/config</code></pre>
<p>설치 목적을 선택한다. 일단 문법을 검사하고, 문제를 찾아내는 것을 선택한다.</p>
<pre><code class="language-bash">? How would you like to use ESLint? …
❯ To check syntax and find problems
  To check syntax, find problems, and enforce code style
  To check syntax only</code></pre>
<p>모듈 문법은 import/export 를 위주로 쓴다면 그렇게 설정한다.</p>
<pre><code class="language-bash">? What type of modules does your project use? …
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these</code></pre>
<p>그 외에도 필요한 설정을 선택한다.</p>
<p>성공적으로 세팅했다면 <code>package.json</code> 의 <code>devDependencies</code>에 아래 두 패키지가 추가되어 있을 것이다.
(버전은 달라도 상관 없음)</p>
<pre><code class="language-bash">&quot;eslint&quot;: &quot;^8.39.0&quot;
&quot;eslint-plugin-react&quot;: &quot;^7.32.2&quot;</code></pre>
<p>이제 NPM 스크립트를 추가한다.</p>
<pre><code class="language-bash">{
  ...
  &quot;script&quot;: {
    &quot;lint&quot;: &quot;eslint src/**/*.js&quot;,
    ...
  }
}</code></pre>
<p>src 폴더 아래에 있는 모든 자바스크립트 파일에 eslint를 실행하도록 하는 코드이다.</p>
<p><code>npm run lint</code> 를 실행하면 eslint가 실행된다.</p>
<p><code>.eslintrc.js</code>라는 파일이 만들어져 있는데, 이 파일은 eslint에 적용할 규칙을 코드로 작성한 파일이다. 이걸 수정하면 적용할 규칙을 바꿀 수 있다.</p>
<pre><code class="language-bash">module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [&#39;eslint:recommended&#39;, &#39;plugin:react/recommended&#39;],
  overrides: [],
  parserOptions: {
    ecmaVersion: &#39;latest&#39;,
    sourceType: &#39;module&#39;,
  },
  plugins: [&#39;react&#39;],
  rules: {},</code></pre>
<h3 id="02-vs-code에서-확장-프로그램으로-사용하기">02. VS Code에서 확장 프로그램으로 사용하기</h3>
<p>확장 프로그램을 설치하고 <code>.eslintrc.js</code>와 같은 설정 파일을 만들어 두면 VS Code에서 바로바로 린트 결과를 확인할 수 있다.</p>
<p>확장 프로그램 탭에서 eslint를 검색해 설치하고 소스 코드에 생긴 빨간 줄에 마우스 커서를 올려보면 ESLint 오류를 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/572b016d-4bfc-480c-8459-568bccebe5f0/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Github 템플릿]]></title>
            <link>https://velog.io/@may_05/Github-%ED%85%9C%ED%94%8C%EB%A6%BF</link>
            <guid>https://velog.io/@may_05/Github-%ED%85%9C%ED%94%8C%EB%A6%BF</guid>
            <pubDate>Sun, 29 Sep 2024 15:54:22 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>Github 템플릿</strong>
: Github 컨벤션을 정했다면 템플릿을 활용해서 효율적으로 프로젝트를 진행해보자!
: <strong>협업에 있어서 템플릿을 활용한다면 서로 작업 중인 상황에 대해 더 잘 파악할 수 있다</strong></p>
</blockquote>
<h3 id="1️⃣-issue-템플릿">1️⃣ Issue 템플릿</h3>
<ol>
<li>Github Repository &gt; Settings &gt; Features &gt; Issues → <strong><code>Set up templates</code></strong> 클릭</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/39ff20b4-2168-4f01-93d2-8e1f9c5add3f/image.png" alt=""></p>
<ol start="2">
<li>목적에 맞는 <strong>template</strong> 선택하여 생성 (ex. <code>Feature request</code>)</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/0629b2e0-f0c8-4161-8fec-38f483c1f21d/image.png" alt=""></p>
<ol start="3">
<li>생성된 <strong>template</strong>은 <code>Preview and edit</code>을 통해 수정 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/4e4ac960-8f41-41cf-ac03-64e9fee161a1/image.png" alt=""></p>
<ol start="4">
<li>커스텀을 진행했다면 <strong><code>Propose Changes</code></strong>를 클릭하여 레포에 <strong>Issue Template</strong> 반영</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/7393bd91-faaf-4db2-9e62-8b30e79cd9c3/image.png" alt=""> <img src="https://velog.velcdn.com/images/may_05/post/a634201c-f3ee-49ae-b576-34b968084312/image.png" alt=""> <img src="https://velog.velcdn.com/images/may_05/post/250095fa-c9d0-47c1-8ee3-89697d9abc13/image.png" alt=""></p>
<ol start="5">
<li><code>.github</code> 하위 폴더 내부에 <strong><code>ISSUE_TEMPLATE</code></strong> 폴더 생성 확인 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/2976cc4c-af2f-4c9b-b09c-9f2e985041b1/image.png" alt=""></p>
<ol start="6">
<li>템플릿을 활용하여 이슈 생성 가능 🎉</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/e3c5a831-fc1a-476b-a2f5-ae3e9002f982/image.png" alt=""> <img src="https://velog.velcdn.com/images/may_05/post/2fabc182-792f-4e82-924a-21b01c793185/image.png" alt=""></p>
<ol start="7">
<li>➕ Github에서가 아닌 직접 <code>.github</code> 폴더를 추가하여 업로드해도 사용 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/a150df41-cd4e-4743-a7b8-0b65753dba24/image.png" alt=""></p>
<h3 id="2️⃣-pr-템플릿">2️⃣ PR 템플릿</h3>
<p>(위치는 상관없지만 일반적으로 숨겨진 디렉토리에 저장하기 위해 <code>.github</code> 폴더 내부에 생성한다)</p>
<ol>
<li>Github에서 <code>.github</code> 의 <code>Create new file</code> 클릭</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/f5202c91-0c54-4c39-b332-51e07869c365/image.png" alt=""></p>
<ol start="2">
<li><strong><code>pull_request_template.md</code></strong>로 파일명을 작성 후 템플릿 작성 및 <strong><code>Commit changes</code></strong>로 반영</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/cc6236bd-e80b-423f-b0de-9849a6d64df0/image.png" alt=""></p>
<ol start="3">
<li><code>.github</code> 하위 폴더 내부에 <strong><code>pull_request_template.md</code></strong> 파일 생성 확인 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/a1447d43-8131-461e-9678-cbffb4bf0afd/image.png" alt=""></p>
<ol start="4">
<li>템플릿을 활용하여 PR 생성 가능 🎉</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/f089c911-2499-437b-8899-04f73726341d/image.png" alt=""></p>
<ol start="5">
<li>➕ Github에서가 아닌 직접 <code>pull_request_template.md</code> 파일 추가하여 업로드해도 사용 가능</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/78b85f86-c04a-42ee-851f-337cbdec2b27/image.png" alt=""></p>
<h3 id="3️⃣-template-repository">3️⃣ Template Repository</h3>
<p>: 여러개의 프로젝트를 같은 세팅으로 진행한다면? 템플릿 레포를 설정해둔다면 쉽게 세팅을 가져올 수 있다!</p>
<ol>
<li>Github Repository &gt; Settings &gt; General → <strong><code>Template repository</code></strong> 체크박스 클릭</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/1de3f889-f6c6-41db-ad5a-9f63db14f1bd/image.png" alt=""></p>
<ol start="2">
<li>새로운 repository를 생성할 때 템플릿을 활용하여 세팅 그대로 repository 생성 가능 🎉</li>
</ol>
<p><img src="https://velog.velcdn.com/images/may_05/post/a33f6b93-6a91-4e06-a08e-574bcc0fd9ea/image.png" alt=""> <img src="https://velog.velcdn.com/images/may_05/post/d194d67f-849f-472e-80f7-df2808b072de/image.png" alt=""></p>
<h3 id="참고-링크">참고 링크</h3>
<ul>
<li><a href="https://green1229.tistory.com/479">https://green1229.tistory.com/479</a></li>
<li><a href="https://2jinishappy.tistory.com/337">https://2jinishappy.tistory.com/337</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[어플리케이션 개발]]></title>
            <link>https://velog.io/@may_05/%EC%96%B4%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EA%B0%9C%EB%B0%9C</link>
            <guid>https://velog.io/@may_05/%EC%96%B4%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EA%B0%9C%EB%B0%9C</guid>
            <pubDate>Tue, 27 Aug 2024 21:06:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>어플리케이션 개발 종류</strong>
: 웹앱, 하이브리드 앱, 크로스 플랫폼, 네이티브 앱</p>
</blockquote>
<h3 id="1️⃣-웹앱">1️⃣ 웹앱</h3>
<p>→ 모바일 앱의 모습을 한 웹 사이트</p>
<p>→ HTML, CSS, JS 와 같은 웹 기술로 개발</p>
<blockquote>
<p><strong>💻 PWA (Progressive Web Apps)</strong></p>
<ul>
<li><strong>기존 웹 개발에 추가적인 세팅만 필요</strong></li>
<li>모바일 기기에서 네이티브 앱과 같은 사용자 경험을 제공</li>
<li>앱 다운로드나 업데이트 없이 웹 브라우저 통해 앱을 바로 사용 가능</li>
<li>웹페이지와 달리 오프라인에서도 사용 가능</li>
<li>푸시알림, 카메라, 마이크 처럼 모바일 기기 자체의 기능도 사용 가능</li>
</ul>
<p><strong>→ 아래와 같이 다운로드 버튼이 생성되며, 설치 가능 (ex. Pinterest)</strong></p>
<p><img src="https://velog.velcdn.com/images/may_05/post/2c7b92f9-f219-406f-b506-413a62ca22df/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/may_05/post/4f58bd24-dd7f-42bc-b52e-41ba85008801/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/may_05/post/866173e0-4f6b-4fa8-83c5-5caeee7f152b/image.png" alt=""></p>
</blockquote>
<h3 id="2️⃣-하이브리드-앱">2️⃣ 하이브리드 앱</h3>
<p>→ 네이티브 앱 + 웹앱</p>
<p>→ 앱의 화면이나 기능 등 콘텐츠 영역은 웹 뷰를 통해 웹앱으로 제작하며, 최종 앱 배포에 필요한 앱 마켓 등록과 설치를 위한 패키징(안드로이드/iOS) 처리는 네이티브 앱으로 구현한 방식</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/3b398a86-8d00-4425-ae50-3c3db6a48bca/image.png" alt=""></p>
<h3 id="3️⃣-크로스-플랫폼">3️⃣ 크로스 플랫폼</h3>
<p>→  한 가지의 개발 언어와 프레임워크로 안드로이드, iOS 네이티브 앱을 만드는 개발 방식</p>
<p>→ 다른 개발 언어로 코드를 작성 후 각각의 OS가 이해할 수 있는 코드로 컴파일 한 후, 각각의 OS의 엔진으로 실행하는 방식</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/791067e3-7304-4f04-9614-d16e1b4d14ec/image.png" alt=""></p>
<table>
<thead>
<tr>
<th></th>
<th><strong>Flutter</strong></th>
<th><strong>React Native</strong></th>
</tr>
</thead>
<tbody><tr>
<td>개발 언어</td>
<td>Dart</td>
<td>JavaScript (React)</td>
</tr>
<tr>
<td>만든 곳</td>
<td>Google</td>
<td>페이스북</td>
</tr>
<tr>
<td>대표적인 서비스</td>
<td>알리바바, 텐센트, eBay, Google Pay, Google Classroom, BMW</td>
<td>페이스북, 인스타그램, 테슬라, 우버이츠, 디스코드, 토스, 카카오페이, 숨고, 미소 등</td>
</tr>
</tbody></table>
<h3 id="4️⃣-네이티브-앱">4️⃣ 네이티브 앱</h3>
<p>→ 가장 보편적인 앱 개발 방식으로 안드로이드와 iOS 각각의 플랫폼에서 요구하는 언어로 앱을 제작</p>
<table>
<thead>
<tr>
<th></th>
<th><strong>Android</strong></th>
<th><strong>iOS</strong></th>
</tr>
</thead>
<tbody><tr>
<td>개발 언어</td>
<td>Java, Kotlin</td>
<td>Swift, Objective-C</td>
</tr>
<tr>
<td>API 연동</td>
<td>Retrofit</td>
<td>Alamofire</td>
</tr>
</tbody></table>
<h3 id="5️⃣-비교">5️⃣ 비교</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/7d685bbd-b419-4a22-b7bb-99c5f4756c78/image.png" alt=""></p>
<p>→ <strong>초기 개발시</strong> 기기에 따라 다르지 않게 <strong>빠른 개발, 재사용성</strong>을 위해서는 <strong>크로스 플랫폼</strong> 추천 ⭐️</p>
<ul>
<li>소셜미디어, 쇼핑, 뉴스, 커뮤니티와 같이 사용자 간의 상호 작용과 페이지 수가 많은 앱을 개발할 경우에 유용</li>
<li><strong>사용자의 앱 이용 패턴을 분석하여, UI의 배치나 문구의 수정 등 빠른 수정 및 업데이트를 하기에 유리</strong></li>
</ul>
<p>→ But, <strong>지속해서 유지하고자 하는 서비스</strong>의 경우 <strong>사용자 대응과 안정성, 성능</strong>을 갖춘 <strong>네이티브 앱</strong> 추천 ⭐️</p>
<p>(ex. Uber, Instagram, Walmart 등의 기업 → 하이브리드 앱이나 크로스 플랫폼 앱에서 네이티브 앱으로 전환)</p>
<ul>
<li>하드웨어의 성능을 최대한으로 사용해야 하는 고성능 게임, 하드웨어의 센서를 사용하는 앱의 경우 네이티브 코드를 사용해야 효율적으로 개발 가능</li>
<li><strong>민감한 데이터를 다루거나, 금융 관련 앱은 더욱 높은 수준의 보안을 확보하기에 네이티브 앱 개발이 유리</strong></li>
</ul>
<h3 id="출처">출처</h3>
<ul>
<li><a href="https://velog.io/@app_school/%EC%95%B1-%EA%B0%9C%EB%B0%9C-%EB%B0%A9%EB%B2%95%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4">https://velog.io/@app_school/앱-개발-방법에-대하여-알아봅시다</a></li>
<li><a href="https://velog.io/@oasis0981/PWA">https://velog.io/@oasis0981/PWA</a></li>
<li><a href="https://www.elancer.co.kr/blog/view?seq=195">https://www.elancer.co.kr/blog/view?seq=195</a></li>
<li><a href="https://blog.naver.com/sw_maestro/223517305858">https://blog.naver.com/sw_maestro/223517305858</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[애자일(Agile) 프로젝트]]></title>
            <link>https://velog.io/@may_05/%EC%95%A0%EC%9E%90%EC%9D%BCAgile-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@may_05/%EC%95%A0%EC%9E%90%EC%9D%BCAgile-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Wed, 31 Jul 2024 06:50:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p> <strong>애자일(Agile)이란?</strong>
: 복잡한 개발 과정을 쉽게 나누고, 조금씩 개선해 나가는 방법</p>
</blockquote>
<h3 id="1️⃣-애자일-프로젝트">1️⃣ 애자일 프로젝트</h3>
<p>→ 작은 단위로 작업을 나누어 빠르게 피드백을 받고, 필요한 부분을 즉시 수정하여 효율적으로 진행</p>
<p>→ <strong><code>포인트</code></strong> 팀원들과의 소통, 적극적인 피드백, 실제 작동하는 소프트웨어를 우선시</p>
<p>→ <strong><code>스크럼(Scrum)</code></strong> 짧은 주기로 작업을 계획하고 실행, 짧은 회의를 통해 진행 상황을 점검하고, 문제를 해결</p>
<blockquote>
<p>📂 <strong>Example</strong>
: 하나의 서비스를 만드는 과정 (프로젝트 기간 : 1달)</p>
</blockquote>
<ol>
<li>서비스를 개발하는 단계를 나누어 지정</li>
<li>회원가입, 로그인<code>(1주)</code> → 주요 기능 1<code>(1주)</code> → 주요 기능 2<code>(1주)</code> → 마무리 및 배포<code>(1주)</code></li>
<li>일정 주기<code>(1주)</code>마다 짧은 회의(스크럼)을 통해 진행상황 공유 및 점검</li>
</ol>
<h3 id="2️⃣-애자일-도구-소개">2️⃣ 애자일 도구 소개</h3>
<ol>
<li><p><strong>플로우 (Flow)</strong> <a href="https://flow.team/kr/index">https://flow.team/kr/index</a></p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/f3b82dee-3d73-43fc-9f4e-70251a0344fc/image.png" alt=""><img src="https://velog.velcdn.com/images/may_05/post/f3add4a7-3f2d-4484-815a-379b87fa5b1d/image.png" alt=""></p>
<p> → 한국형 협업툴</p>
<ul>
<li>업무관리부터 채팅, 화상회의까지 한 번에 가능</li>
<li>프로젝트 내에 보드를 타임라인으로 쌓는 방식</li>
</ul>
</li>
<li><p><strong>지라(Jira)</strong> <a href="https://www.atlassian.com/ko/software/jira">https://www.atlassian.com/ko/software/jira</a></p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/a0d9ffab-0d79-4d00-8821-912a161aec5b/image.png" alt=""><img src="https://velog.velcdn.com/images/may_05/post/497e3cbc-2535-4676-9684-e38b376411d6/image.png" alt=""></p>
</li>
</ol>
<pre><code>→ 아틀라시안이 개발한 프로젝트 관리 소프트웨어

- 대시보드 안에서 팀과 개인에게 맞춤 정보 설정 가능
- 프로젝트 속도와 사이클 기간을 관리하고 각 사용자의 현재 업무 이슈를 추적하고 해결하기에 용이</code></pre><ol start="3">
<li><p><strong>트렐로(Trello)</strong> <a href="https://trello.com/">https://trello.com/</a></p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/724e4f49-bd38-4801-8eb3-cb3633b1ed5a/image.png" alt=""><img src="https://velog.velcdn.com/images/may_05/post/1fec1d3f-ae4c-4686-990c-d81268aab924/image.png" alt=""></p>
<p> → 아틀라시안에서 인수한 협업툴</p>
<ul>
<li>보드에 일정을 적은 포스트잇을 붙인듯한 느낌 → 직관적, 단순한 인터페이스</li>
<li>보드, 리스트, 카드 형식으로 제공되며, 각 보드는 공개 범위 설정 가능 (팀 단위로 공유 가능)</li>
<li>프로젝트 멤버들의 활동을 시간대별로 표기</li>
</ul>
</li>
<li><p><strong>아사나(Asana)</strong> <a href="https://productivity.kr/">https://productivity.kr/</a></p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/11f56562-336a-4786-8a29-e96bc4d606b5/image.png" alt=""><img src="https://velog.velcdn.com/images/may_05/post/1c5b075b-b63a-43cf-9d86-229c3bfe3c6d/image.png" alt=""></p>
<p> → 협업과 프로젝트 관리를 위한 클라우드 기반의 플랫폼</p>
<ul>
<li>세계적인 프로젝트 관리 협업툴</li>
<li>대시보드에서 프로젝트 내 작업을 총괄적으로 제시</li>
</ul>
</li>
</ol>
<h3 id="3️⃣-애자일-도구-비교">3️⃣ 애자일 도구 비교</h3>
<table>
<thead>
<tr>
<th>도구</th>
<th>플로우(Flow)</th>
<th>지라(Jira)</th>
<th>트렐로(Trello)</th>
<th>아사나(Asana)</th>
</tr>
</thead>
<tbody><tr>
<td>개발 국가</td>
<td>한국</td>
<td>호주 외 지사 국가</td>
<td>호주 외 지사 국가</td>
<td>미국</td>
</tr>
<tr>
<td>언어</td>
<td>한국어, 영어</td>
<td>영어, 중국어, 일어, 한국어, 독일어 등</td>
<td>영어, 중국어, 일어, 한국어, 독일어 등</td>
<td>영어, 일어, 한국어, 독일어, 스페인어 등</td>
</tr>
<tr>
<td>특징</td>
<td>프로젝트 관리 올인원 협업툴</td>
<td>업무 이슈 추적</td>
<td>칸반보드</td>
<td>작업 및 협업의 강력한 통합</td>
</tr>
</tbody></table>
<p><strong>→ 협업툴을 사용하여 더 효율적인 애자일 프로젝트 진행을 시도해볼 수 있다❗️</strong></p>
<p>Github에서 프로젝트를 생성하여 지라처럼 사용, 지라와 Github를 연동, 지라와 트렐로를 같이 사용 등 여러 툴을 같이 사용하는 경우도 있으므로 <strong>각자 프로젝트의 성격에 맞게 활용을 추천</strong></p>
<p>개인적으로, <strong>IT 프로젝트에서는 Jira</strong>를 활용하면 더 좋을 것 같아 다음 프로젝트 진행시 활용 예정</p>
<h3 id="출처">출처</h3>
<ul>
<li><a href="https://blog.naver.com/techwhat/223489470910">https://blog.naver.com/techwhat/223489470910</a></li>
<li><a href="https://blog.naver.com/nowayhose1/223492671134">https://blog.naver.com/nowayhose1/223492671134</a></li>
<li><a href="https://blog.naver.com/herwardrobe/222477571835">https://blog.naver.com/herwardrobe/222477571835</a></li>
<li><a href="https://blog.naver.com/dopgi/223253662237">https://blog.naver.com/dopgi/223253662237</a></li>
<li><a href="https://blog.naver.com/keepdmz/222477578334">https://blog.naver.com/keepdmz/222477578334</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP 통신, 라이브러리]]></title>
            <link>https://velog.io/@may_05/HTTP-%ED%86%B5%EC%8B%A0-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@may_05/HTTP-%ED%86%B5%EC%8B%A0-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Wed, 03 Jul 2024 00:00:56 GMT</pubDate>
            <description><![CDATA[<h3 id="️⃣-http-통신">*️⃣ HTTP 통신</h3>
<blockquote>
<p><strong>HTTP 통신이란?</strong>
클라이언트와 서버가 데이터를 주고받는 과정</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/may_05/post/62a2bd9c-1bf7-4c38-9aaa-705a23d3711c/image.png" alt=""></p>
<ul>
<li>요청 Request, 응답 Response으로 이루어짐</li>
<li>클라이언트가 서버에게 요청을 보냄</li>
<li>서버는 요청에 대한 응답 결과를 줌</li>
<li>클라이언트는 사용자에게 응답 받은 결과를 보여줌</li>
</ul>
<blockquote>
<p>비동기 HTTP 통신의 종류 : <strong>Ajax, Fetch, Axios</strong>
→ response와 request를 비동기 식으로 다루는 통신</p>
</blockquote>
<h3 id="1️⃣-ajax">1️⃣ <strong>Ajax</strong></h3>
<p>→ <strong>A</strong>synchronous <strong>J</strong>avaScript <strong>A</strong>nd <strong>X</strong>ML (비동기 자바스크립트와 XML)</p>
<ul>
<li>비동기적으로 자바스크립트 코드로 서버에 request를 보내고 response를 받아오는 기술</li>
<li>JSON, XML 등 다양한 데이터 형식을 사용하여 요청과 응답을 주고 받으나 요즘은 <strong>JSON 형태를 주로 사용</strong></li>
<li>전체 페이지를 새로고침하지 않고, <strong>일부분만 리로드</strong></li>
</ul>
<blockquote>
<p>➕ <strong>Ajax에 대한 오해</strong>
JQuery의 Ajax가 아닌, <strong>Ajax를 JQuery를 통해 보다 더 쉽게 사용할 수 있음</strong>
Jquery를 사용할 경우 브라우저 호환성에 대해서도 보장 가능</p>
</blockquote>
<ul>
<li>순수 Ajax를 사용하는 경우</li>
</ul>
<pre><code class="language-jsx">// use Ajax without Jquery

function reqListener (e) {
    console.log(e.currentTarget.response);
}

var oReq = new XMLHttpRequest();
var serverAddress = &quot;https://jsonplaceholder.typicode.com/posts&quot;;

oReq.addEventListener(&quot;load&quot;, reqListener);
oReq.open(&quot;GET&quot;, serverAddress);
oReq.send();
</code></pre>
<ul>
<li>Jquery를 통해 Ajax를 사용하는 경우</li>
</ul>
<pre><code class="language-jsx">// use Ajax with Jquery

var serverAddress = &#39;https://jsonplaceholder.typicode.com/posts&#39;;

// jQuery의 .get 메소드 사용
$.ajax({
    url: ,
    type: &#39;GET&#39;,
    success: function onData (data) {
        console.log(data);
    },
    error: function onError (error) {
        console.error(error);
    }
});</code></pre>
<h3 id="2️⃣-fetch">2️⃣ Fetch</h3>
<p>→ ES6에 도입된 자바스크립트 내장 라이브러리</p>
<ul>
<li>프로미스(Promise) 기반으로 동작</li>
<li>모던 웹 애플리케이션에서 사용되는 새로운 방식의 네트워크 요청이 가능</li>
</ul>
<pre><code class="language-jsx">//fetch
const url =&#39;http://localhost3000/test`
const option ={
   method:&#39;POST&#39;,
   header:{
     &#39;Accept&#39;:&#39;application/json&#39;,
     &#39;Content-Type&#39;:&#39;application/json&#39;;charset=UTP-8&#39;
  },
  body:JSON.stringify({
      name:&#39;may&#39;,
        age:20
  })

  fetch(url,options)
      .then(response =&gt; console.log(response))</code></pre>
<h3 id="3️⃣-axios">3️⃣ Axios</h3>
<p>→ 웹 브라우저, Node.js를 위한 Promise API를 활용하는 라이브러리</p>
<ul>
<li>데이터를 받아올 때, 자동으로 JSON 형식으로 데이터를 변환</li>
<li>return을 promise 객체로</li>
<li>다른 라이브러리나 모듈과의 협업이 용이</li>
<li>서버와의 요청과 응답에 대한 에러 핸들링 및 디버깅이 용이</li>
</ul>
<pre><code class="language-jsx">axios({
  method: &#39;post&#39;,
  url: &#39;/user/12345&#39;,
  data: {
    firstName: &#39;Seoyoon&#39;,
    lastName: &#39;Kim&#39;
  }
});</code></pre>
<h3 id="4️⃣-http-통신-비교">4️⃣ HTTP 통신 비교</h3>
<table>
<thead>
<tr>
<th></th>
<th>Ajax</th>
<th>Fetch</th>
<th>Axios</th>
</tr>
</thead>
<tbody><tr>
<td>설치</td>
<td>X</td>
<td>X</td>
<td>O (크기가 큼)</td>
</tr>
<tr>
<td>브라우저 호환성</td>
<td>O (← JQuery)</td>
<td>X</td>
<td>O</td>
</tr>
<tr>
<td>JSON 형식 자동 변환</td>
<td>X</td>
<td>X</td>
<td>O</td>
</tr>
<tr>
<td>Promise 기반</td>
<td>X</td>
<td>O</td>
<td>O</td>
</tr>
<tr>
<td>XSRF 방어</td>
<td>X</td>
<td>X</td>
<td>O</td>
</tr>
</tbody></table>
<ul>
<li>XSRF(Cross-Site Request Forgery) : 사용자가 의도하지 않은 요청을 악성 웹 사이트로부터 받는 공격</li>
</ul>
<hr>
<p>→ (개인적인 의견) <strong>웹 프론트엔드 프레임워크(React, Vue.js 등)을 다룰때에는 Axios 사용 추천❗️</strong></p>
<p>→ <strong>(Next.js) App Router의 서버 사이드 로직 처리에서 fetch 사용을 권장</strong>❗️</p>
<h3 id="출처">출처</h3>
<ul>
<li><a href="https://velog.io/@sdc337dc/%EC%9B%B9-%EA%B0%9C%EB%85%90-Http-%ED%86%B5%EC%8B%A0">https://velog.io/@sdc337dc/웹-개념-Http-통신</a></li>
<li>코드잇 강의</li>
<li><a href="https://velog.io/@kysung95/%EA%B0%9C%EB%B0%9C%EC%83%81%EC%8B%9D-Ajax%EC%99%80-Axios-%EA%B7%B8%EB%A6%AC%EA%B3%A0-fetch">https://velog.io/@kysung95/개발상식-Ajax와-Axios-그리고-fetch</a></li>
<li><a href="https://blog.naver.com/leem95/223189747918">https://blog.naver.com/leem95/223189747918</a></li>
<li><a href="https://blog.naver.com/dkdlelql123/222850699523">https://blog.naver.com/dkdlelql123/222850699523</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] 2주차 메타 태그/자바스크립트 웹 개발 기본기 (1)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-2%EC%A3%BC%EC%B0%A8-%EB%A9%94%ED%83%80-%ED%83%9C%EA%B7%B8%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EB%B3%B8%EA%B8%B0-1</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-2%EC%A3%BC%EC%B0%A8-%EB%A9%94%ED%83%80-%ED%83%9C%EA%B7%B8%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9B%B9-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EB%B3%B8%EA%B8%B0-1</guid>
            <pubDate>Mon, 01 Jul 2024 11:31:12 GMT</pubDate>
            <description><![CDATA[<h1 id="ch1-메타-태그">Ch1. 메타 태그</h1>
<hr>
<h2 id="1️⃣-메타-태그">1️⃣ 메타 태그</h2>
<h3 id="01-메타-태그란">01. 메타 태그란?</h3>
<p>→ <code>&lt;meta&gt;</code> 로 작성하는 HTML 태그로 메타데이터(데이터를 설명하는 데이터)</p>
<p>→ HTML 데이터를 설명하는 데이터를 갖는 태그</p>
<h3 id="0203-메타-태그-사용-예시">02~03. 메타 태그 사용 예시</h3>
<ol>
<li><p><strong>웹 페이지에 설정하는 메타 태그</strong></p>
<pre><code class="language-jsx"> &lt;meta charset=&quot;utf-8&quot;&gt;
 HTML 문서의 문자 인코딩을 utf-8로 지정해요.
 브라우저가 웹페이지를 해석하는 방식을 지정해서 문서의 깨짐이 없도록 해요.

 &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, minimum-scale=1, maximum-scale, user-scalable=no&quot;&gt;
 name=&quot;viewport&quot; 설정으로 반응형 웹 사이트를 제작할 수 있어요.
 width=device-width: 장치의 화면 너비를 따르도록 페이지 너비를 설정해요.
 initial-scale=1: 브라우저에서 페이지를 처음 로드할 때 배율을 1로 설정해요.
 minimum-scale=1: 최소사이즈를 1배로 처리해서 축소를 못하게 막아요.
 maximum-scale=1: 최대사이즈를 1배로 처리해서 확대를 못하게 막아요.
 user-scalable=no: 사용자크기변화를 no로 처리해서 크기변화를 못하게 막아요.

 &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
 인터넷 익스플로러에서 최신 표준 모드로 보여주는 코드에요.

 &lt;meta name=&quot;robots&quot; content=&quot;noindex&quot;&gt;
 name=&quot;robots&quot; 설정으로 크롤러의 동작에 대해 규칙을 정할 수 있어요.
 검색결과에 이 페이지, 미디어 또는 리소스를 표시하지 않아요. 이 규칙을 지정하지 않으면 페이지, 미디어 또는 리소스가 색인 생성되어 검색결과에 표시될 수 있어요.</code></pre>
</li>
<li><p><strong>사이트를 설명하는 데 사용하는 메타 태그</strong></p>
<ol>
<li><p><strong>구글 검색 결과, 사이트 설명에 사용</strong></p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/216f2ec8-16c6-432b-ba7e-6fdf79c0671b/image.png" alt=""></p>
<pre><code class="language-jsx"> &lt;title&gt;코드잇 | 코딩, 쉬워질 때도 됐다&lt;/title&gt;
 &lt;meta
     name=&quot;description&quot;
     content=&quot;월 2만원대로 Python, JavaScript, HTML/CSS 등 3,000개 이상 프로그래밍 강의를 배워보세요!&quot;
 &gt;</code></pre>
</li>
<li><p><strong>SNS 공유할 때 링크 미리 보기에 사용</strong></p>
<ol>
<li><p>페이스북</p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/fa4bcdf7-c196-402e-aed4-93e5a5a687ee/image.png" alt=""></p>
<pre><code class="language-jsx"> &lt;meta property=&quot;og:image&quot; content=&quot;/static/images/brand/og_tag.png&quot;&gt;
 &lt;meta property=&quot;og:title&quot; content=&quot;코드잇 | 코딩, 쉬워질 때도 됐다&quot;&gt;
 &lt;meta
     property=&quot;og:description&quot;
     content=&quot;월 2만원대로 Python, JavaScript, HTML/CSS 등 3,000개 이상 프로그래밍 강의를 배워보세요!&quot;
 &gt;
 &lt;meta property=&quot;og:url&quot; content=&quot;https://www.codeit.kr&quot;&gt;</code></pre>
</li>
<li><p>트위터</p>
<p> <img src="https://velog.velcdn.com/images/may_05/post/8adfe136-3d17-4311-8a6c-3b9d414ed45e/image.png" alt=""></p>
<pre><code class="language-jsx"> &lt;meta name=&quot;twitter:card&quot; content=&quot;summary_large_image&quot;&gt;
 &lt;meta name=&quot;twitter:image&quot; content=&quot;/static/images/brand/og_tag.png&quot;&gt;
 &lt;meta
     name=&quot;twitter:title&quot;
     content=&quot;JavaScript 프론트엔드 개발자 - 커리어 강의 | 코드잇&quot;
 &gt;
 &lt;meta
     name=&quot;twitter:description&quot;
     content=&quot;예쁘고 편리한 웹사이트를 뚝딱 만들어 내는 프론트엔드 개발자를 꿈꾸고 게신가요? ...&quot;
 &gt;</code></pre>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<h3 id="04-메타-태그-활용">04. 메타 태그 활용</h3>
<p>→ <code>&lt;head&gt;</code> 안에 문서를 설명하는 <code>&lt;meta&gt;</code> 삽입 (+ 메타 태그는 닫는 태그가 없음)</p>
<ul>
<li>메타 태그의 특성 : <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/meta">https://developer.mozilla.org/ko/docs/Web/HTML/Element/meta</a></li>
<li>메타 태그에 <code>name</code> 으로 설정 가능한 값 : <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/meta/name">https://developer.mozilla.org/ko/docs/Web/HTML/Element/meta/name</a></li>
</ul>
<p><strong>🩶 OG 태그</strong></p>
<p><code>&lt;meta property=&quot;og:OOO&quot; content=&quot;XXXX&quot;&gt;</code></p>
<p>→ <code>OOO</code> 자리는 원하는 속성을, <code>XXXX</code> 자리에는 속성에 해당하는 값을 입력</p>
<p>→ 규약 : <a href="https://ogp.me/">https://ogp.me/</a></p>
<p><strong>🩶 Twitter 태그</strong></p>
<p><code>&lt;meta name=&quot;twitter:OOO&quot; content=&quot;XXXX&quot; &gt;</code></p>
<p>→ <code>OOO</code> 자리는 원하는 속성을, <code>XXXX</code> 자리에는 속성에 해당하는 값을 입력</p>
<p>→ 자세한 안내 : <a href="https://developer.x.com/en/docs/twitter-for-websites/cards/overview/abouts-cards">https://developer.x.com/en/docs/twitter-for-websites/cards/overview/abouts-cards</a></p>
<p>➕ 디버거</p>
<ul>
<li><a href="https://developers.kakao.com/tool/debugger/sharing">카카오톡 디버거</a></li>
<li><a href="https://developers.facebook.com/tools/debug/">페이스북 디버거</a></li>
<li><a href="https://cards-dev.twitter.com/validator">트위터</a></li>
</ul>
<h3 id="05-메타-태그-설정-시-주의사항">05. 메타 태그 설정 시 주의사항</h3>
<ol>
<li><p><strong>동적인 OG 태그 (Twitter 태그도 동일)</strong></p>
<pre><code class="language-jsx"> &lt;head&gt;
     &lt;meta property=&quot;og:title&quot; content={data?.title}&gt;
 &lt;/head&gt;</code></pre>
<p> → 브라우저가 최초로 사이트에 데이터 요청할 때, <code>data?.title</code>의 값은 <code>undefined</code> 인 상태로 HTML을 받고, 이후 브라우저가 데이터를 요청해서 <code>data?.title</code> 값 충족</p>
<p> → <strong>But</strong> SNS 공유에서 링크 미리 보기를 만들 때는 한 번의 요청으로 받아온 데이터를 기준으로 미리 보기를 만들고 끝나기 때문에 <code>content=undefined</code> 인 상태로 링크 미리 보기를 만들어서 미리 보기가 보이지 않거나 원하는 데이터를 볼 수 없음</p>
<p> → <code>data?.title</code> 에 해당하는 데이터를 먼저 받고 나서 HTML을 생성</p>
<ul>
<li>프론트엔드 서버에서 데이터를 받아서 HTML을 생성한 뒤 전달</li>
<li>or 소스 코드를 빌드하는 단계에서 미리 데이터를 받아 HTML을 생성하는 방법</li>
</ul>
</li>
<li><p><strong>카카오톡 링크 미리 보기가 동작하지 않는 경우</strong></p>
<p> <a href="https://devtalk.kakao.com/t/scrap-url/116202">카카오톡 scrap(url 미리 보기) 안될 때 체크 리스트</a></p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] 1주차 인터랙티브 자바스크립트]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-1%EC%A3%BC%EC%B0%A8-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-1%EC%A3%BC%EC%B0%A8-%EC%9D%B8%ED%84%B0%EB%9E%99%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Mon, 01 Jul 2024 11:27:59 GMT</pubDate>
            <description><![CDATA[<h1 id="1주차-인터랙티브-자바스크립트">1주차 인터랙티브 자바스크립트</h1>
<hr>
<h2 id="1️⃣-인터랙티브-자바스크립트-시작하기">1️⃣ 인터랙티브 자바스크립트 시작하기</h2>
<h3 id="01-웹-서비스와-javascript">01. 웹 서비스와 JavaScript</h3>
<p>→ JavaScript를 통해 웹 서비스를 동작</p>
<h3 id="02-htmlcss--javascript-맛보기">02. HTML/CSS + JavaScript 맛보기</h3>
<p>생략</p>
<h3 id="0304-id로-태그-선택하기">03~04. id로 태그 선택하기</h3>
<p>→ <code>id</code>는 하나이기 때문에 하나의 요소를 선택하기에 좋음</p>
<p>→ 잘못된 <code>id</code> 선택시 : undefined</p>
<pre><code class="language-jsx">const myNumberTag = document.getElementById(&quot;myNumber&quot;);
const decreaseBtn = document.getElementById(&quot;decrease&quot;);
const increaseBtn = document.getElementById(&quot;increase&quot;);</code></pre>
<h3 id="05-07-class로-태그-선택하기">05, 07. class로 태그 선택하기</h3>
<p>→ 여러 요소를 선택하기 위해서는 <code>class</code> 선택</p>
<p>→ 잘못된 <code>class</code> 선택시 : undefined</p>
<p>→ ❗️유사 배열 : 여러개의 값을 담고 있는 배열과 형태는 유사하지만, 배열 메소드는 사용할 수 없음</p>
<ul>
<li>(순서는 위에서 아래, 차례대로)</li>
<li><code>index</code>, <code>length</code> 사용</li>
</ul>
<pre><code class="language-jsx">const colorBtns = document.getElementsByClassName(&quot;color-btn&quot;);</code></pre>
<h3 id="06-유사-배열array-like-object이란">06. 유사 배열(Array-Like Object)이란?</h3>
<p>: 배열과 모양은 같지만, 완벽히 배열은 아닌 형태</p>
<ol>
<li>숫자 형태의 indexing이 가능</li>
<li><code>length</code> 프로퍼티 존재</li>
<li>배열의 기본 메소드 사용 불가</li>
<li>Array.isArray(유사배열)은 false</li>
</ol>
<ul>
<li><strong>주의사항: 유사 배열은 다양!</strong></li>
</ul>
<h3 id="08-태그-이름으로-태그-선택하기">08. 태그 이름으로 태그 선택하기</h3>
<p>→ 문서 내에 있는 모든 해당 <strong>태그</strong>를 선택</p>
<pre><code class="language-jsx">const btns = document.getElementsByTagName(&#39;button&#39;);</code></pre>
<h3 id="0910-css-선택자로-태그-선택하기">09~10. css 선택자로 태그 선택하기</h3>
<pre><code class="language-jsx">// const myNumberTag = document.getElementById(&quot;myNumber&quot;);
const myNumberTag = document.querySelector(&#39;#myNumber&#39;);

// const colorBtns = document.getElementsByClassName(&quot;color-btn&quot;);
// const colorBtns = document.querySelector(&quot;.color-btn&quot;);
const colorBtns = document.querySelectorAll(&quot;.color-btn&quot;);</code></pre>
<p>→ <code>querySelector</code>는 <code>class</code>의 경우 첫번째 인덱스만 선택됨 ⚠️ <strong>주의 →</strong> <code>querySelectorAll</code></p>
<h3 id="11-이벤트와-버튼-클릭">11. 이벤트와 버튼 클릭</h3>
<pre><code class="language-jsx">// 이벤트(Event)와 버튼 클릭
const btn = document.querySelector(&quot;#myBtn&quot;);

// 이벤트 핸들링 (Event Handling)
btn.onclick = function () {
  // 이벤트 핸들러 (Event Handler)
  console.log(&quot;Hello Codeit!&quot;);
};</code></pre>
<h3 id="12-정답일까">12. 정답일까?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const myBtn = document.querySelector(&#39;#grade&#39;);

  myBtn.onclick = function() {
    alert(&#39;정답입니다!👏🏻&#39;);
  };</code></pre>
</li>
</ul>
<h3 id="13-종합-정리">13. 종합 정리</h3>
<table>
<thead>
<tr>
<th>메소드</th>
<th>의미</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>document.getElementById(&#39;id&#39;)</td>
<td>HTML id속성으로 태그 선택하기</td>
<td>id에 해당하는 태그 하나</td>
</tr>
<tr>
<td>document.getElementsByClassName(&#39;class&#39;)</td>
<td>HTML class속성으로 태그 선택하기</td>
<td>class에 해당하는 태그 모음(HTMLCollection)</td>
</tr>
<tr>
<td>document.getElementsByTagName(&#39;tag&#39;)</td>
<td>HTML 태그 이름으로 태그 선택하기</td>
<td>tag에 해당하는 태그 모음(HTMLCollection)</td>
</tr>
<tr>
<td>document.querySelector(&#39;css&#39;)</td>
<td>css 선택자로 태그 선택하기</td>
<td>css 선택자에 해당하는 태그 중 가장 첫번째 태그 하나</td>
</tr>
<tr>
<td>document.querySelectorAll(&#39;css&#39;)</td>
<td>css 선택자로 태그 선택하기</td>
<td>css 선택자에 해당하는 태그 모음(NodeList)</td>
</tr>
</tbody></table>
<h2 id="2️⃣-브라우저와-자바스크립트">2️⃣ 브라우저와 자바스크립트</h2>
<h3 id="01-브라우저도-객체다">01. 브라우저도 객체다?</h3>
<p>→ <code>window</code> : 전역객체</p>
<ul>
<li><code>innerWidth</code></li>
<li><code>innerHeight</code></li>
</ul>
<h3 id="02-dom">02. DOM</h3>
<p>→ 문서 객체 모델 (Document Object Model)</p>
<p><code>console.log</code> : dom에 해당하는 html 태그 출력</p>
<p><code>title.style.color = ‘red’;</code> → js를 통해 스타일 적용</p>
<h3 id="03-consoledir">03. console.dir?</h3>
<ol>
<li><strong>문자열 표시 형식으로 콘솔에 출력</strong></li>
<li><code>log</code> 메소드는 <strong>파라미터로 전달받은 값</strong>을 위주로 출력하는 반면, <code>dir</code> 메소드는 <strong>객체의 속성</strong>을 좀 더 자세하게 출력</li>
<li><code>log</code> 메소드는 여러 값을 쉼표로 구분해서 전달하면 전달받은 <strong>모든 값을 출력</strong>하는 반면, <code>dir</code> 메소드는 여러 값을 전달하더라도 <strong>첫 번째 값만 출력</strong></li>
<li><strong>log 메소드는 대상을 HTML 형태로 출력</strong>하고, 객체의 속성에 좀 더 중점을 둔 <strong>dir 메소드는 대상을 객체 형태로 출력</strong></li>
</ol>
<p>→ <strong>콘솔에서 값 자체를 확인하고 싶다면</strong> <code>log</code>메소드를, <strong>객체의 속성들을 살펴보고 싶다면</strong> <code>dir</code> 메소드를 활용</p>
<h3 id="0407-dom-트리">04~07. DOM 트리</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/d928f76f-b7a5-4306-9b38-a52136223355/image.png" alt=""></p>
<p>→ 부모 노드, 자식 노드, 형제 노드 / <strong>요소 노드, 텍스트 노드</strong>, 잎 노드, 코멘트 노드, 문서 노드</p>
<p>: 텍스트 노드는 요소 노드의 자식 노드! 자식 노드를 가질 수 없다.</p>
<pre><code class="language-jsx">const myTag = document.querySelector(&#39;#content&#39;);

console.log(myTag);
//console.log(myTag.parentElement.nextElementSibling);

// 형제 요소 노드
console.log(myTag.previousElementSibling);
console.log(myTag.nextElementSibling);

// 부모 요소 노드
console.log(myTag.parentElement);

// 자식 요소 노드
console.log(myTag.childern[1]);
console.log(myTag.firstElementChild);
console.log(myTag.lastElementChild);</code></pre>
<p><strong>요소 노드에 대한 이동 프로퍼티</strong></p>
<table>
<thead>
<tr>
<th>프로퍼티</th>
<th>유형</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>element.children</td>
<td>자식 요소 노드</td>
<td>element의 자식 요소 모음(HTMLCollection)</td>
</tr>
<tr>
<td>element.firstElementChild</td>
<td>자식 요소 노드</td>
<td>element의 첫 번째 자식 요소 하나</td>
</tr>
<tr>
<td>element.lastElementChild</td>
<td>자식 요소 노드</td>
<td>element의 마지막 자식 요소 하나</td>
</tr>
<tr>
<td>element.parentElement</td>
<td>부모 요소 노드</td>
<td>element의 부모 요소 하나</td>
</tr>
<tr>
<td>element.previousElementSibling</td>
<td>형제 요소 노드</td>
<td>element의 이전(previous) 혹은 좌측(left)에 있는 요소 하나</td>
</tr>
<tr>
<td>element.nextElementSibling</td>
<td>형제 요소 노드</td>
<td>element의 다음(next) 혹은 우측(right)에 있는 요소 하나</td>
</tr>
</tbody></table>
<p><strong>모든 노드에 대한 이동 프로퍼티</strong></p>
<table>
<thead>
<tr>
<th>프로퍼티</th>
<th>유형</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>node.childNodes</td>
<td>자식 노드</td>
<td>node의 자식 노드 모음(NodeList)</td>
</tr>
<tr>
<td>node.firstChild</td>
<td>자식 노드</td>
<td>node의 첫 번째 자식 노드 하나</td>
</tr>
<tr>
<td>node.lastChild</td>
<td>자식 노드</td>
<td>node의 마지막 자식 노드 하나</td>
</tr>
<tr>
<td>node.parentNode</td>
<td>부모 노드</td>
<td>node의 부모 요소 하나</td>
</tr>
<tr>
<td>node.previousSibling</td>
<td>형제 노드</td>
<td>node의 이전(previous) 혹은 좌측(left)에 있는 노드 하나</td>
</tr>
<tr>
<td>node.nextSibling</td>
<td>형제 노드</td>
<td>node의 다음(next) 혹은 우측(right)에 있는 노드 하나</td>
</tr>
</tbody></table>
<h3 id="0810-요소-노드-프로퍼티">08~10. 요소 노드 프로퍼티</h3>
<pre><code class="language-jsx">// 요소 노드 주요 프로퍼티
const myTag = document.querySelector(&#39;#list-1&#39;);

// innerHTML
console.log(myTag.innerHTML);
myTag.innerHTML = &#39;&lt;li&gt;Exotic&lt;/li&gt;&#39;;

// outerHTML -&gt; 요소 자체가 교체 (원래 요소 삭제)
console.log(myTag.outerHTML);
myTag.outerHTML = &#39;&lt;ul id=&quot;new-list&quot;&gt;&lt;li&gt;Exotic&lt;/li&gt;&lt;/ul&gt;&#39;;

// textContent -&gt; innerHTML과 마찬가지로 수정, only 텍스트만 다룸(특수문자도 텍스트로)
console.log(myTag.textContent);
myTag.textContent = &#39;new text!&#39;;</code></pre>
<ol>
<li><strong>element.innerHTML</strong></li>
</ol>
<ul>
<li>요소 노드 내부의 HTML 코드를 문자열로 리턴해 줍니다. (내부에 있는 줄 바꿈이나 들여쓰기 모두 포함합니다.)</li>
</ul>
<ol>
<li><strong>element.outerHTML</strong></li>
</ol>
<ul>
<li>요소 노드 자체의 전체적인 HTML 코드를 문자열로 리턴해줍니다. (내부에 있는 줄 바꿈이나 들여쓰기 모두 포함합니다.)</li>
</ul>
<ol>
<li><strong>element.textContent</strong></li>
</ol>
<ul>
<li>요소 안의 내용들 중에서 HTML 태그 부분은 제외하고 텍스트만 가져옵니다. (내부에 있는 줄 바꿈이나 들여쓰기 모두 포함합니다.)</li>
</ul>
<h3 id="11-요소-노드-추가하기">11. 요소 노드 추가하기</h3>
<pre><code class="language-jsx">// 요소 노드 추가하기
const tomorrow = document.querySelector(&#39;#tomorrow&#39;);

// 1. 요소 노드 만들기: document.createElement(&#39;태그이름&#39;);
const first = document.createElement(&#39;li&#39;);

// 2. 요소 노드 꾸미기: textContent, innerHTML, ...
first.textContent(&#39;처음&#39;);

// 3. 요소 노드 추가하기: NODE.prepend, append, after, before
tomorrow.prepend(first); // 처음 (한번에 순서대로 추가)
tomorrow.prepend(append); // 마지막
tomorrow.prepend(after); // 이전 (한번에 순서대로 추가)
tomorrow.prepend(before); // 다음</code></pre>
<h3 id="12-노드-삭제와-이동하기">12. 노드 삭제와 이동하기</h3>
<pre><code class="language-jsx">// 노드 삭제와 이동
const today = document.querySelector(&#39;#today&#39;);
const tomorrow = document.querySelector(&#39;#tomorrow&#39;);

// 노드 삭제하기: Node.remove();
tomorrow.remove();
today.children[2].remove();

// 노드 이동하기: prepend, append, after, before
today.append(tomorrow.children[1]);
tomorrow.children[1].after(today.children[1]);
tomorrow.lastElementChild.after(today.children[1]);</code></pre>
<h3 id="13-오늘-꼭-해야할-일">13. 오늘 꼭 해야할 일!</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const toDoList = document.querySelector(&#39;#to-do-list&#39;);

  function addNewTodo(text) {
    const li = document.createElement(&quot;li&quot;);
    li.textContent = text;
    toDoList.append(li);
  }

  // 테스트 코드
  addNewTodo(&#39;자바스크립트 공부하기&#39;);
  addNewTodo(&#39;고양이 화장실 청소하기&#39;);
  addNewTodo(&#39;고양이 장난감 쇼핑하기&#39;);</code></pre>
</li>
</ul>
<h3 id="1415-html-속성-다루기">14~15. HTML 속성 다루기</h3>
<pre><code class="language-jsx">// HTML 속성
const tomorrow = document.querySelector(&#39;#tomorrow&#39;);
const item = tomorrow.firstElementChild;
const link = item.firstElementChild;

// id 속성
console.log(tomorrow.id);

// class 속성
console.log(item.className);

// href 속성
console.log(link.href);
console.log(tomorrow.href);

// elem.getAttribute(&#39;속성&#39;): 속성에 접근하기
console.log(tomorrow.getAttribute(&#39;href&#39;));
console.log(item.getAttribute(&#39;class&#39;));

// elem.setAttribute(&#39;속성&#39;, &#39;값&#39;): 속성에 추가(수정)하기
tomorrow.setAttribute(&#39;class&#39;, &#39;list&#39;);
link.setAttribute(&#39;href&#39;, &#39;https://www.codeit.kr&#39;);

// elem.removeAttribute(&#39;속성&#39;): 속성 제거하기
tomorrow.removeAttribute(&#39;href&#39;);
tomorrow.removeAttribute(&#39;class&#39;);</code></pre>
<h3 id="1617-스타일-다루기">16~17. 스타일 다루기</h3>
<pre><code class="language-jsx">// 스타일 다루기
const today = document.querySelector(&#39;#today&#39;);
const tomorrow = document.querySelector(&#39;#tomorrow&#39;);

// style 프로퍼티
today.children[0].style.textDecoration = &#39;line-through&#39;;
today.children[0].style.backgroundColor = &#39;#DDDDDD&#39;;

// elem.className
today.children[1].className = &#39;done&#39;;

// elem.classList: add, remove, toggle
const item = tomorrow.children[1];
item.classList.add(&#39;done&#39;, &#39;other&#39;);
item.classList.remove(&#39;done&#39;);
item.classList.remove(&#39;toggle&#39;); // 없으면 추가, 있으면 제거, 여러개 불가(클래스 1개만을 다룸)</code></pre>
<h3 id="18-비표준-속성-다루기">18. 비표준 속성 다루기</h3>
<ol>
<li><strong>선택자로 활용</strong></li>
</ol>
<p>가장 간단하게는 아래와 같이 <code>querySelector</code>로 태그를 선택할 때 css 선택자를 활용해서 태그를 선택하는 데에 활용 가능</p>
<pre><code class="language-jsx">const fields = document.querySelectorAll(&#39;[field]&#39;);
console.log(fields);</code></pre>
<ol>
<li><strong>값을 표시할 태그를 구분할 때 활용</strong></li>
</ol>
<p>비표준 속성은 객체 형태의 데이터가 있을 때, 각 프로퍼티 값들이 들어갈 태그를 구분하는데 활용 가능</p>
<pre><code>
const fields = document.querySelectorAll(&#39;[field]&#39;);
const task = {
  title: &#39;코드 에디터 개발&#39;,
  manager: &#39;CastleRing, Raccoon Lee&#39;,
  status: &#39;&#39;,
};

for (let tag of fields) {
  const field = tag.getAttribute(&#39;field&#39;);
  tag.textContent = task[field];
}</code></pre><ol>
<li><strong>스타일이나 데이터 변경에 활용</strong></li>
</ol>
<p><code>getAttribute</code> 메소드를 활용해서 속성값을 가져오고, <code>setAttribute</code> 메소드를 활용해서 속성값을 설정해주는 원리로 이벤트를 통해 실시간으로 스타일을 변경하거나 데이터를 변경하는데 활용 가능</p>
<p>때로는 <code>class</code>를 다루는 것보다 <code>setAttribute</code>로 비표준 속성을 변경하는게 스타일을 다루기에 오히려 편리한 경우도 존재</p>
<pre><code class="language-jsx">const fields = document.querySelectorAll(&#39;[field]&#39;);
const task = {
  title: &#39;코드 에디터 개발&#39;,
  manager: &#39;CastleRing, Raccoon Lee&#39;,
  status: &#39;&#39;,
};

for (let tag of fields) {
  const field = tag.getAttribute(&#39;field&#39;);
  tag.textContent = task[field];
}

const btns = document.querySelectorAll(&#39;.btn&#39;);
for (let btn of btns) {
  const status = btn.getAttribute(&#39;status&#39;);
  btn.onclick = function () {
    fields[2].textContent = status;
    fields[2].setAttribute(&#39;status&#39;, status);
  };
}</code></pre>
<p>→ <strong>좀 더 안전하게, dataset 프로퍼티</strong></p>
<p>: <code>data-</code>로 시작하는 속성은 모두 dataset이라는 프로퍼티에 저장</p>
<p>예. <code>data-status</code>라는 속성이 있다면, <code>element.dataset.status</code>라는 프로퍼티에 접근해서 그 값을 가져옴</p>
<pre><code class="language-jsx">const fields = document.querySelectorAll(&#39;[data-field]&#39;);
const task = {
  title: &#39;코드 에디터 개발&#39;,
  manager: &#39;CastleRing, Raccoon Lee&#39;,
  status: &#39;&#39;,
};

for (let tag of fields) {
  const field = tag.dataset.field;
  tag.textContent = task[field];
}

const btns = document.querySelectorAll(&#39;.btn&#39;);
for (let btn of btns) {
  const status = btn.dataset.status;
  btn.onclick = function () {
    fields[2].textContent = status;
    fields[2].dataset.status = status;
  };
}</code></pre>
<h2 id="3️⃣-이벤트-살펴보기">3️⃣ 이벤트 살펴보기</h2>
<h3 id="0103-이벤트-핸들러-등록하기">01~03. 이벤트 핸들러 등록하기</h3>
<pre><code class="language-jsx">// 이벤트 핸들러 등록하기
const btn = document.querySelector(&quot;#myBtn&quot;);

function event1() {
    console.log(&#39;Hi Codeit!&#39;);
}

function event2() {
    console.log(&#39;Hi again!&#39;);
}

// onclick은 하나의 것만 가능 (덮어씌워짐)
// elem.addEventListener(event, handler)
btn.addEventListener(&#39;click&#39;, event1);
btn.addEventListener(&#39;click&#39;, event2);

// elem.removeEventListener(event, handler)
btn.removeEventListener(&#39;click&#39;, event2);</code></pre>
<p><strong>마우스 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>mousedown</td>
<td>마우스 버튼을 누르는 순간</td>
</tr>
<tr>
<td>mouseup</td>
<td>마우스 버튼을 눌렀다 떼는 순간</td>
</tr>
<tr>
<td>click</td>
<td>왼쪽 버튼을 클릭한 순간</td>
</tr>
<tr>
<td>dblclick</td>
<td>왼쪽 버튼을 빠르게 두 번 클릭한 순간</td>
</tr>
<tr>
<td>contextmenu</td>
<td>오른쪽 버튼을 클릭한 순간</td>
</tr>
<tr>
<td>mousemove</td>
<td>마우스를 움직이는 순간</td>
</tr>
<tr>
<td>mouseover</td>
<td>마우스 포인터가 요소 위로 올라온 순간</td>
</tr>
<tr>
<td>mouseout</td>
<td>마우스 포인터가 요소에서 벗어나는 순간</td>
</tr>
<tr>
<td>mouseenter</td>
<td>마우스 포인터가 요소 위로 올라온 순간 (버블링이 일어나지 않음)</td>
</tr>
<tr>
<td>mouseleave</td>
<td>마우스 포인터가 요소에서 벗어나는 순간 (버블링이 일어나지 않음)</td>
</tr>
</tbody></table>
<p><strong>키보드 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>keydown</td>
<td>키보드의 버튼을 누르는 순간</td>
</tr>
<tr>
<td>keypress</td>
<td>키보드의 버튼을 누르는 순간 (&#39;a&#39;, &#39;5&#39; 등 출력이 가능한 키에서만 동작하며, Shift, Esc 등의 키에는 반응하지 않음)</td>
</tr>
<tr>
<td>keyup</td>
<td>키보드의 버튼을 눌렀다 떼는 순간</td>
</tr>
</tbody></table>
<p><strong>포커스 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>focusin</td>
<td>요소에 포커스가 되는 순간</td>
</tr>
<tr>
<td>focusout</td>
<td>요소로부터 포커스가 빠져나가는 순간</td>
</tr>
<tr>
<td>focus</td>
<td>요소에 포커스가 되는 순간 (버블링이 일어나지 않음)</td>
</tr>
<tr>
<td>blur</td>
<td>요소로부터 포커스가 빠져나가는 순간 (버블링이 일어나지 않음)</td>
</tr>
</tbody></table>
<p><strong>입력 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>change</td>
<td>입력된 값이 바뀌는 순간</td>
</tr>
<tr>
<td>input</td>
<td>값이 입력되는 순간</td>
</tr>
<tr>
<td>select</td>
<td>입력 양식의 하나가 선택되는 순간</td>
</tr>
<tr>
<td>submit</td>
<td>폼을 전송하는 순간</td>
</tr>
</tbody></table>
<p><strong>스크롤 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>scroll</td>
<td>스크롤 바가 움직일 때</td>
</tr>
</tbody></table>
<p><strong>윈도우 창 이벤트</strong></p>
<table>
<thead>
<tr>
<th>이벤트 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>resize</td>
<td>윈도우 사이즈를 움직일 때 발생</td>
</tr>
</tbody></table>
<h3 id="0405-이벤트-객체-프로퍼티">04~05. 이벤트 객체 (프로퍼티)</h3>
<pre><code class="language-jsx">// 이벤트 객체 (Event Object)
const myInput = document.querySelector(&quot;#myInput&quot;);
const myBtn = document.querySelector(&quot;#myBtn&quot;);

function printEvent(event) {
  console.log(event);
  event.target.style.color = &#39;red&#39;;
}

myInput.addEventListener(&quot;keydown&quot;, printEvent);
myBtn.addEventListener(&quot;click&quot;, printEvent);</code></pre>
<ol>
<li><strong>공통 프로퍼티</strong></li>
</ol>
<p>아래의 프로퍼티들은 이벤트 타입과 상관없이 모든 이벤트 객체들이 공통적으로 가지고 있는 프로퍼티</p>
<table>
<thead>
<tr>
<th>프로퍼티</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>type</td>
<td>이벤트 이름 (&#39;click&#39;, &#39;mouseup&#39;, &#39;keydown&#39; 등)</td>
</tr>
<tr>
<td>target</td>
<td>이벤트가 발생한 요소</td>
</tr>
<tr>
<td>currentTarget</td>
<td>이벤트 핸들러가 등록된 요소</td>
</tr>
<tr>
<td>timeStamp</td>
<td>이벤트 발생 시각(페이지가 로드된 이후부터 경과한 밀리초)</td>
</tr>
<tr>
<td>bubbles</td>
<td>버블링 단계인지를 판단하는 값</td>
</tr>
<tr>
<td>1. <strong>마우스 이벤트</strong></td>
<td></td>
</tr>
</tbody></table>
<p>마우스와 관련된 이벤트의 경우에는 아래와 같은 이벤트 객체의 프로퍼티들</p>
<table>
<thead>
<tr>
<th>프로퍼티</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>button</td>
<td>누른 마우스의 버튼 (0: 왼쪽, 1: 가운데(휠), 2: 오른쪽)</td>
</tr>
<tr>
<td>clientX, clientY</td>
<td>마우스 커서의 브라우저 표시 영역에서의 위치</td>
</tr>
<tr>
<td>pageX, pageY</td>
<td>마우스 커서의 문서 영역에서의 위치</td>
</tr>
<tr>
<td>offsetX, offsetY</td>
<td>마우스 커서의 이벤트 발생한 요소에서의 위치</td>
</tr>
<tr>
<td>screenX, screenY</td>
<td>마우스 커서의 모니터 화면 영역에서의 위치</td>
</tr>
<tr>
<td>altKey</td>
<td>이벤트가 발생할 때 alt키를 눌렀는지</td>
</tr>
<tr>
<td>ctrlKey</td>
<td>이벤트가 발생할 때 ctrl키를 눌렀는지</td>
</tr>
<tr>
<td>shiftKey</td>
<td>이벤트가 발생할 때 shift키를 눌렀는지</td>
</tr>
<tr>
<td>metaKey</td>
<td>이벤트가 발생할 때 meta키를 눌렀는지 (window는 window키, mac은 cmd키)</td>
</tr>
<tr>
<td>1. <strong>키보드 이벤트</strong></td>
<td></td>
</tr>
</tbody></table>
<p>키보드와 관련된 이벤트의 경우에는 아래와 같은 이벤트 객체의 프로퍼티들</p>
<table>
<thead>
<tr>
<th>프로퍼티</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>key</td>
<td>누른 키가 가지고 있는 값</td>
</tr>
<tr>
<td>code</td>
<td>누른 키의 물리적인 위치</td>
</tr>
<tr>
<td>altKey</td>
<td>이벤트가 발생할 때 alt키를 눌렀는지</td>
</tr>
<tr>
<td>ctrlKey</td>
<td>이벤트가 발생할 때 ctrl키를 눌렀는지</td>
</tr>
<tr>
<td>shiftKey</td>
<td>이벤트가 발생할 때 shift키를 눌렀는지</td>
</tr>
<tr>
<td>metaKey</td>
<td>이벤트가 발생할 때 meta키를 눌렀는지 (window는 window키, mac은 cmd키)</td>
</tr>
</tbody></table>
<h3 id="06-완료한-일-체크하기">06. 완료한 일 체크하기!</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const toDoList = document.querySelector(&#39;#to-do-list&#39;);
  const items = toDoList.children;

  // 1. updateToDo 함수를 완성해 주세요
  function updateToDo(event) {
    event.target.classList.toggle(&#39;done&#39;);
  }

  // 2. 반복문을 활용해서 각 li태그에 이벤트 핸들러를 등록해 주세요
  for (let item of items) {
    item.addEventListener(&#39;click&#39;, updateToDo);
  }

  // 테스트 코드
  items[2].removeEventListener(&#39;click&#39;, updateToDo);</code></pre>
</li>
</ul>
<h3 id="07-09-이벤트-버블링">07, 09. 이벤트 버블링</h3>
<p>→ 부모 요소(최상단까지)의 핸들러도 동작</p>
<pre><code class="language-jsx">// 이벤트 버블링 (Event Bubbling)
const content = document.querySelector(&quot;#content&quot;);
const title = document.querySelector(&quot;#title&quot;);
const list = document.querySelector(&quot;#list&quot;);
const items = document.querySelectorAll(&quot;.item&quot;);

content.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;content Event&quot;);
});

title.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;title Event&quot;);
});

list.addEventListener(&quot;click&quot;, function () {
  console.log(&quot;list Event&quot;);
});

for (let item of items) {
  item.addEventListener(&quot;click&quot;, function () {
    console.log(&quot;item Event&quot;);
  });
}</code></pre>
<p>→ <code>currentTarget</code>은 이벤트가 실제로 실행되는 것을 담고 있음</p>
<p><code>e.stopPropagation();</code> : 버블링을 막는 코드, 지양</p>
<h3 id="08-캡쳐링">08. 캡쳐링</h3>
<ol>
<li><p><strong>캡처링 단계</strong>: 이벤트가 하위 요소로 전파되는 단계</p>
</li>
<li><p><strong>타깃 단계</strong>: 이벤트가 실제 타깃 요소에 전달되는 단계</p>
<p> → <strong>타깃 단계</strong>는 이벤트 객체의 <code>target</code> 프로퍼티가 되는 요소에 등록되어있던 이벤트 핸들러가 동작하는 단계</p>
<p> → 쉽게 생각해서 <strong>가장 처음 이벤트 핸들러가 동작하게 되는 순간</strong></p>
</li>
<li><p><strong>버블링 단계</strong>: 이벤트가 상위 요소로 전파되는 단계</p>
</li>
</ol>
<p><strong>📌 캡쳐링</strong>은 <strong>이벤트가 발생하면 가장 먼저, 그리고 버블링의 반대 방향으로 진행되는 이벤트 전파 방식</strong></p>
<p><img src="https://velog.velcdn.com/images/may_05/post/70a2bc66-1c4c-4e01-82b6-001a8defd92f/image.png" alt=""></p>
<pre><code class="language-jsx">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Codeit Acid Rain&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div&gt;DIV
      &lt;ul&gt;UL
        &lt;li&gt;LI&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;  
    &lt;script&gt;
      for (let elem of document.querySelectorAll(&#39;*&#39;)) {
        elem.addEventListener(&quot;click&quot;, e =&gt; alert(`캡쳐링 단계: ${elem.tagName}`), true);
        elem.addEventListener(&quot;click&quot;, e =&gt; alert(`버블링 단계: ${elem.tagName}`));
      }
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h3 id="10-이벤트-위임">10. 이벤트 위임</h3>
<p>→ 자식 요소의 이벤트를 부모 요소에도 위임 (반대도 포함) : 버블링 활용</p>
<pre><code class="language-jsx">// 이벤트 위임 (Event Delegation)
const list = document.querySelector(&quot;#list&quot;);

list.addEventListener(&quot;click&quot;, function (e) {
  // if (e.target.tagName === &#39;LI&#39;)
  if (e.target.classList.contains(&quot;item&quot;)) {
    e.target.classList.toggle(&quot;done&quot;);
  }
});

const li = document.createElement(&quot;li&quot;);
li.classList.add(&quot;item&quot;);
li.textContent = &quot;일기 쓰기&quot;;
list.append(li);</code></pre>
<h3 id="11-효율적으로-완료한-일-체크하기">11. 효율적으로 완료한 일 체크하기!</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const toDoList = document.querySelector(&#39;#to-do-list&#39;);

  // 1. updateToDo 함수를 완성해 주세요
  function updateToDo(event) {
    if (event.target.classList.contains(&#39;item&#39;)) {
      event.target.classList.toggle(&#39;done&#39;);
    }
  }

  // 2. 각 li 태그가 아닌 하나의 태그에만 이벤트 핸들러를 등록해 주세요
  toDoList.addEventListener(&#39;click&#39;, updateToDo);

  // 테스트 코드
  const newToDo = document.createElement(&#39;li&#39;);
  newToDo.textContent = &#39;가계부 정리하기&#39;;
  newToDo.classList.add(&#39;item&#39;);
  toDoList.append(newToDo);

  toDoList.children[2].addEventListener(&#39;click&#39;, function(e) {e.stopPropagation()});</code></pre>
</li>
</ul>
<h3 id="1213-브라우저의-기본-동작">12~13. 브라우저의 기본 동작</h3>
<pre><code class="language-jsx">// 브라우저의 기본 동작
const link = document.querySelector(&quot;#link&quot;);
const checkbox = document.querySelector(&quot;#checkbox&quot;);
const input = document.querySelector(&quot;#input&quot;);
const text = document.querySelector(&quot;#text&quot;);

// event.preventDefault
link.addEventListener(&quot;click&quot;, function (e) {
  e.preventDefault();
  alert(&quot;지금은 이동할 수 없습니다.&quot;);
});

input.addEventListener(&quot;keydown&quot;, function (e) {
  if (!checkbox.checked) {
    e.preventDefault();
    alert(&quot;체크박스를 먼저 클릭해 주세요.&quot;);
  }
});

document.addEventListener(&quot;contextmenu&quot;, function (e) {
  e.preventDefault();
  alert(&quot;마우스 오른쪽 클릭은 사용할 수 없습니다.&quot;);
});</code></pre>
<h2 id="4️⃣-다양한-이벤트-알아보기">4️⃣ 다양한 이벤트 알아보기</h2>
<h3 id="01-마우스-버튼-이벤트">01. 마우스 버튼 이벤트</h3>
<p>→ 우클릭의 경우 운영체제별로 실행 순서가 변경될 수 있음</p>
<p>[마우스 버튼 이벤트]</p>
<ul>
<li><code>MouseEvent.button</code><ul>
<li>0: 마우스 왼쪽 버튼</li>
<li>1: 마우스 휠</li>
<li>2: 마우스 오른쪽 버튼</li>
</ul>
</li>
<li><code>MouseEvent.type</code><ul>
<li>click: 마우스 왼쪽 버튼을 눌렀을 때</li>
<li>contextmenu: 마우스 오른쪽 버튼을 눌렀을 때</li>
<li>dblclick: 동일한 위치에서 빠르게 두번 click할 때</li>
<li>mousedown: 마우스 버튼을 누른 순간</li>
<li>mouseup: 마우스 버튼을 눌렀다 뗀 순간</li>
</ul>
</li>
</ul>
<h3 id="02-청기-올려-백기-올려">02. 청기 올려?! 백기 올려?!</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const flagBlue = document.querySelector(&#39;.flag-blue&#39;);
  const flagWhite = document.querySelector(&#39;.flag-white&#39;);

  function reset() {
    document.querySelector(&#39;.up&#39;).classList.remove(&#39;up&#39;);
  }

  // 1. flagUp 함수를 완성해 주세요
  function flagUp(e) {
    if (e.button === 0) {
      flagBlue.classList.add(&#39;up&#39;);
    } else if (e.button === 2) {
      flagWhite.classList.add(&#39;up&#39;);
    }

    // 500 밀리초 뒤에 reset함수를 실행
    setTimeout(reset, 500);
  }

  // 2. 마우스 오른쪽 버튼 클릭시 나타나는 메뉴창을 막아주세요
  document.addEventListener(&#39;contextmenu&#39;, function (event) {
    event.preventDefault();
  });

  // 테스트 코드
  document.addEventListener(&#39;mousedown&#39;, flagUp);</code></pre>
</li>
</ul>
<h3 id="03-05-마우스-이동-이벤트">03, 05. 마우스 이동 이벤트</h3>
<p>[마우스 이동 이벤트]</p>
<ul>
<li><p><code>MouseEvent.type</code></p>
<ul>
<li>mousemove: 마우스 포인터가 이동할 때</li>
<li>mouseover: 마우스 포인터가 요소 밖에서 안으로 이동할 때</li>
<li>mouseout: 마우스 포인터가 요소 안에서 밖으로 이동할 때</li>
</ul>
</li>
<li><p><code>MouseEvent.clientX, clientY</code></p>
<p>  : 화면에 표시되는 창 기준 마우스 포인터 위치</p>
</li>
<li><p><code>MouseEvent.pageX, pageY</code></p>
<p>  : 웹 문서 전체 기준 마우스 포인터 위치</p>
</li>
<li><p><code>MouseEvent.offsetX, offsetY</code></p>
<p>  : 이벤트가 발생한 요소 기준 마우스 포인터 위치</p>
</li>
</ul>
<pre><code class="language-jsx">const box1 = document.querySelector(&#39;#box1&#39;);

function onMouseMove(e) {
  console.log(`client: (${e.clientX}, ${e.clientY})`);
  console.log(`page: (${e.pageX}, ${e.pageY})`);
  console.log(`offset: (${e.offsetX}, ${e.offsetY})`);
  console.log(&#39;------------------------------------&#39;);
}

box1.addEventListener(&#39;mousemove&#39;, onMouseMove);</code></pre>
<ul>
<li><p><code>MouseEvent.target</code></p>
<p>  : 이벤트가 발생한 요소</p>
</li>
<li><p><code>MouseEvent.relatedTarget</code></p>
<p>  : 이벤트가 발생하기 직전(또는 직후)에 마우스가 위치해 있던 요소</p>
</li>
</ul>
<pre><code class="language-jsx">const box2 = document.querySelector(&#39;#box2&#39;);

function printEventData(e) {
  console.log(&#39;event:&#39;, e.type);
  console.log(&#39;target:&#39;, e.target);
  console.log(&#39;relatedTarget:&#39;, e.relatedTarget);
  console.log(&#39;------------------------------------&#39;);
  if (e.target.classList.contains(&#39;cell&#39;)) {
    e.target.classList.toggle(&#39;on&#39;);
  }
}

box2.addEventListener(&#39;mouseover&#39;, printEventData);
box2.addEventListener(&#39;mouseout&#39;, printEventData);</code></pre>
<h3 id="04-client-page-offset-차이">04. client, page, offset 차이</h3>
<ol>
<li><strong>clientX, clientY</strong></li>
</ol>
<ul>
<li><code>client</code> 프로퍼티는 말 그대로 <strong>클라이언트 영역 내에서 마우스의 좌표 정보</strong></li>
<li><strong>클라이언트 영역이란 이벤트가 발생한 순간에 브라우저가 콘텐츠를 표시할 수 있는 영역</strong></li>
<li>clientX : 브라우저가 표시하는 화면 내에서 마우스의 X좌표 위치
clientY : 브라우저가 표시하는 화면 내에서 마우스의 Y좌표 위</li>
<li><code>client</code> 값은 <strong>그 순간 보여지는 화면을 기준으로 계산</strong>하기 때문에 스크롤 위치와는 무관하게 <strong>항상 보여지는 화면의 좌측 상단의 모서리 위치를 (0, 0)으로 계산</strong></li>
</ul>
<ol>
<li><strong>offsetX, offsetY</strong></li>
</ol>
<ul>
<li><code>offset</code> 프로퍼티는 <strong>이벤트가 발생한 target이 기준</strong></li>
<li>offsetX : 이벤트가 발생한 <code>target</code> 내에서 마우스의 X좌표 위치
offsetY : 이벤트가 발생한 <code>target</code> 내에서 마우스의 Y좌표 위치</li>
<li><code>offset</code> 값도 <strong>이벤트가 발생한 대상을 기준으로 계산</strong>하기 때문에 스크롤 위치와는 무관하게 <strong>항상 대상의 좌측 상단의 모서리 위치를 (0, 0)으로 계산</strong></li>
</ul>
<ol>
<li><strong>pageX, pageY</strong></li>
</ol>
<ul>
<li>page 프로퍼티는 <strong>전체 문서를 기준</strong>으로 마우스 좌표 정보</li>
<li>스크롤로 인해서 보이지 않게된 화면의 영역까지 포함해서 측정한다는 점이 앞의 두 프로퍼티와의 차이점</li>
<li>pageX : 전체 문서 내에서 마우스의 X좌표 위치
pageY : 전체 문서 내에서 마우스의 Y좌표 위치</li>
</ul>
<p><img src="https://prod-files-secure.s3.us-west-2.amazonaws.com/d399e452-eeb6-4cb2-afa5-615f96cd8780/98648526-0b75-48d8-aecc-8ff873605627/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2024-06-30_%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB_10.45.35.png" alt="스크린샷 2024-06-30 오전 10.45.35.png"></p>
<h3 id="06-mouseenter--mouseleave">06. mouseenter / mouseleave</h3>
<ol>
<li><p><strong>버블링이 일어나지 않는다.</strong></p>
<p> → <code>mouseenter</code>와 <code>mouseleave</code>는 <strong>버블링이 일어나지 않음</strong></p>
</li>
<li><p><strong>자식 요소의 영역을 계산하지 않는다.</strong></p>
<p> → <code>mouseenter</code>와 <code>mouseleave</code>는 <strong>자식 요소의 영역을 계산하지 않음</strong></p>
</li>
</ol>
<p>→ <strong>이벤트가 자식 요소에 영향끼치는지</strong>가 둘의 가장 큰 차이</p>
<ul>
<li>이벤트 핸들러가 자식 요소에까지 영향을 끼치게 하고싶은 경우에는 <code>mouseover/mouseout</code></li>
<li>자식 요소에는 영향을 끼치지 않고 해당 요소에만 이벤트 핸들러를 다루고자 한다면 <code>mouseenter/mouseleave</code>를 활용</li>
</ul>
<h3 id="07-효준이네-집">07. 효준이네 집</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function showTitle(e) {
    if (e.target.dataset.title) {
      const span = document.createElement(&#39;span&#39;);
      span.classList.add(&#39;title&#39;);
      span.textContent = e.target.dataset.title;
      e.target.append(span);
    }
  }

  function removeTitle(e) {
    if (e.target.dataset.title) {
      e.target.lastElementChild.remove();
    }
  }

  const map = document.querySelector(&#39;.map&#39;);
  map.addEventListener(&#39;mouseover&#39;, showTitle);
  map.addEventListener(&#39;mouseout&#39;, removeTitle);</code></pre>
</li>
</ul>
<h3 id="08-키보드-이벤트">08. 키보드 이벤트</h3>
<p>[키보드 이벤트]</p>
<ul>
<li><p><code>KeyboardEvent.type</code></p>
<ul>
<li>keydown: 키보드 버튼을 누른 순간 (권장)</li>
<li>keypress: 키보드 버튼을 누른 순간 (지양)</li>
<li>keyup: 키보드 버튼을 눌렀다 뗀 순간</li>
</ul>
</li>
<li><p><code>KeyboardEvent.key</code></p>
<p>  : 이벤트가 발생한 버튼의 값</p>
</li>
<li><p><code>KeyboardEvent.code</code></p>
<p>  : 이벤트가 발생한 버튼의 키보드에서 물리적인 위치</p>
</li>
</ul>
<h3 id="09-똑talk한-enter키">09. 똑Talk한 Enter키!</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const chatBox = document.querySelector(&#39;#chat-box&#39;);
  const input = document.querySelector(&#39;#input&#39;);
  const send = document.querySelector(&#39;#send&#39;);

  function sendMyText() {
    const newMessage = input.value;
    if (newMessage) {
      const div = document.createElement(&#39;div&#39;);
      div.classList.add(&#39;bubble&#39;, &#39;my-bubble&#39;);
      div.innerText = newMessage;
      chatBox.append(div);
    } else {
      alert(&#39;메시지를 입력하세요...&#39;);
    }

    input.value = &#39;&#39;;
  }

  send.addEventListener(&#39;click&#39;, sendMyText);

  function sendMyTextByEnter (e) {
    if (e.key === &#39;Enter&#39; &amp;&amp; !e.shiftKey) {
      sendMyText();
      e.preventDefault();
    }
  }

  input.addEventListener(&#39;keypress&#39;, sendMyTextByEnter);</code></pre>
</li>
</ul>
<h3 id="10-input-태그-다루기">10. input 태그 다루기</h3>
<p>[input 태그 다루기]</p>
<ul>
<li><code>포커스 이벤트</code><ul>
<li>focusin: 요소에 포커스가 되었을 때</li>
<li>focusout: 요소에 포커스가 빠져나갈 때</li>
<li>focus: 요소에 포커스가 되었을 때 (버블링 X)</li>
<li>blur: 요소에 포커스가 빠져나갈 때 (버블링 X)</li>
</ul>
</li>
</ul>
<h3 id="11-코드잇-산성비">11. 코드잇 산성비</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const input = document.querySelector(&#39;#input&#39;);

  function checker() {
    const words = document.querySelectorAll(&#39;.word&#39;);
    if (words.length === 0) {
      alert(&#39;Success!👏🏻&#39;);
      if(confirm(&#39;retry?&#39;)) {
        window.location.reload();
      }
    }
  }

  function removeWord() {
    const word = document.querySelector(`[data-word=&quot;${input.value}&quot;]`);
    if (word) {
      word.remove();
      checker();
    }

    input.value = &#39;&#39;;
  }

  input.addEventListener(&#39;change&#39;, removeWord);</code></pre>
</li>
</ul>
<h3 id="12-스크롤-이벤트">12. 스크롤 이벤트</h3>
<pre><code class="language-jsx">// Scroll 이벤트
function printEvent(e) {
  const STANDARD = 30;

  const nav = document.querySelector(&quot;#nav&quot;);
  const toTop = document.querySelector(&quot;#to-top&quot;);

  // 스크롤이 30px을 넘었을 때
  if (window.scrollY &gt; STANDARD) {
    nav.classList.add(&quot;shadow&quot;);
    toTop.classList.add(&quot;show&quot;);
  } else {
    nav.classList.remove(&quot;shadow&quot;);
    toTop.classList.remove(&quot;show&quot;);
  }
}

window.addEventListener(&quot;scroll&quot;, printEvent);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 중급 (3)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-3</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-3</guid>
            <pubDate>Wed, 19 Jun 2024 17:37:26 GMT</pubDate>
            <description><![CDATA[<h1 id="ch3-비동기-자바스크립트">Ch3. 비동기 자바스크립트</h1>
<hr>
<h2 id="1️⃣-토픽-시작하기">1️⃣ 토픽 시작하기</h2>
<h3 id="01-토픽-소개">01. 토픽 소개</h3>
<p><strong>JS</strong></p>
<ul>
<li>웹에 사용하기 위해 만들어진 언어</li>
<li>웹에서는 <strong>리퀘스트</strong>를 보내거나 <strong>사용자의 상호 작용</strong>을 기다려야 하는 일이 많음</li>
<li><strong>비동기 프로그래밍</strong>이 특히 많이 쓰임</li>
</ul>
<p><strong>비동기 프로그램</strong></p>
<p>: 주어진 코드를 순서대로 진행하는 것이 아니라 오래 기다려야하는 작업이 있으면 다음 작업을 먼저 처리하고 나중에 처리하던 작업으로 다시 돌아와서 마무리하는 방식</p>
<ol>
<li><strong>콜백 (Callback)</strong></li>
<li><strong>프로미스 (Promise)</strong></li>
</ol>
<h2 id="2️⃣-콜백과-비동기-실행">2️⃣ 콜백과 비동기 실행</h2>
<h3 id="01-파라미터-vs-아규먼트">01. 파라미터 vs 아규먼트</h3>
<pre><code class="language-jsx">function add(x, y) {
  return x + y;
}

add(1, 2);</code></pre>
<p>→ 파라미터 : <code>x</code>, <code>y</code></p>
<p>: 함수에 전달받은 값을 함수 내부로 전달하기 위해 사용하는 변수</p>
<p>→ 아규먼트 : <code>1</code>, <code>2</code></p>
<p>: 함수에 실제로 전달되는 값</p>
<h3 id="02-콜백callback이란">02. 콜백(Callback)이란?</h3>
<p>→ 어떤 함수의 아규먼트로 전달되는 함수를 <strong>콜백</strong> 또는 <strong>콜백 함수</strong></p>
<p>❗<strong>콜백(Callback) 함수</strong> : 아규먼트로 전달되는 함수</p>
<ul>
<li>간단한 콜백에서는 Arrow Function을 자주 사용</li>
</ul>
<pre><code class="language-jsx">function sayHello(name) {
  console.log(`Hello ${name}!`);
}

function sayGoodbye(name) {
  console.log(`Goodbye ${name}!`);
}

function printMessage(func, name) {
  console.log(&quot;Printing message...&quot;);
  func(name);
}

printMessage((name) =&gt; console.log(`Hello ${name}!`), &quot;Bob&quot;);</code></pre>
<h3 id="03-foreach-함수-만들기">03. forEach() 함수 만들기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function forEach(array, callback) {
    for (let elt of array) {
      callback(elt);
    }
  }

  const words = [&#39;JavaScript&#39;, &#39;Java&#39;, &#39;Python&#39;];

  // 배열의 요소를 출력하세요. Arrow Function을 사용하세요.
  forEach(words, (word) =&gt; console.log(word));

  function printUpper(word) {
    const upper = word.toUpperCase();
    console.log(upper);
  }

  // 배열의 요소를 대문자로 출력하세요. function 키워드로 함수를 선언하고 콜백으로 전달하세요.
  forEach(words, printUpper);</code></pre>
</li>
</ul>
<h3 id="04-콜백과-비동기-함수">04. 콜백과 비동기 함수</h3>
<pre><code class="language-jsx">console.log(&quot;1&quot;);

setTimeout(() =&gt; console.log(&quot;2&quot;), 3000);

console.log(&quot;3&quot;);

// 1 3 2</code></pre>
<p><img src="https://velog.velcdn.com/images/may_05/post/6775c825-0a29-4619-bbea-e47d3d227d45/image.png" alt=""></p>
<p>→ 오래 걸리는 작업이 있을 때 <strong>시간을 절약</strong> → 효율적인 코드</p>
<p>⚡️ <strong>비동기 함수 (Asynchronous Function)</strong></p>
<p>: 함수의 내용을 끝까지 쭉 실행하지 않고 <strong>중간에 다른 작업을 처리</strong>하다가 <strong>다시 돌아와서 마무리를 하는 함수</strong></p>
<ul>
<li>자바스크립트나 자바스크립트 라이브러리는 <strong>다양한 비동기 함수를 제공해 줌</strong></li>
<li>제공되는 비동기 함수에 <strong>콜백을 넘겨주기만 하면</strong> 비동기 프로그램을 구현할 수 있음</li>
</ul>
<h3 id="05-settimeout-함수-사용해-보기">05. setTimeout() 함수 사용해 보기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function sayHello(name) {
    console.log(`Hello ${name}!`);
  }

  console.log(&#39;시작&#39;);

  // setTimeout(sayHello, 2000, &#39;Codeit&#39;);
  setTimeout((name) =&gt; console.log(`Hello ${name}!`), 2000, &#39;Codeit&#39;);

  console.log(&#39;끝&#39;);</code></pre>
</li>
</ul>
<h3 id="06-비동기-실행-파헤치기">06. 비동기 실행 파헤치기</h3>
<ol>
<li><strong>비동기 함수는 이후에 있는 코드를 모두 실행하고 콜백을 실행한다</strong>
 <img src="https://velog.velcdn.com/images/may_05/post/cea52676-a921-4aa2-a391-36f8f769799d/image.png" alt=""></li>
</ol>
<ol start="2">
<li><strong>실행할 콜백이 여러 개일 경우, 동기적으로 실행된다</strong>
 <img src="https://velog.velcdn.com/images/may_05/post/6e2d4df3-6276-4b96-bb49-c64dd60084a2/image.png" alt=""></li>
</ol>
<h3 id="07-비동기-함수의-예시들">07. 비동기 함수의 예시들</h3>
<ol>
<li><p><strong><code>setTimeout()</code> 함수</strong></p>
<ol>
<li><code>setTimeout()</code> 이전에 있는 코드 실행</li>
<li><code>setTimeout()</code> 함수 실행: <code>delay</code> 만큼 기다리는 타이머를 시작</li>
<li><code>setTimeout()</code> 이후에 있는 코드 실행</li>
<li><code>delay</code>가 지나면 <code>callback</code> 실행</li>
</ol>
</li>
<li><p><strong><code>setInterval()</code> 함수</strong></p>
<p> : 시간 간격을 두고 콜백을 반복적으로 실행</p>
<p> <code>setInterval(callback, interval)</code> : <code>interval</code> 단위는 밀리초입니다.</p>
<p> <code>setInterval(() =&gt; console.log(&#39;2초가 지났습니다&#39;), 2000);</code></p>
</li>
<li><p><strong>DOM의 <code>addEventListener()</code> 함수</strong></p>
<p> <code>const btn = document.querySelector(&#39;.my-btn&#39;);</code></p>
<p> <code>btn.addEventListener(&#39;click&#39;, () =&gt; console.log(&#39;button clicked!&#39;));</code></p>
</li>
<li><p><strong>React의 <code>useEffect()</code> 함수</strong></p>
<p> : 콜백을 바로 실행하지 않고 일단 화면을 그리기 때문에 웹 페이지가 더 빨리 로딩되는 것처럼 보이게 할 수 있음</p>
<p> <code>useEffect(() =&gt; console.log(&#39;render finished!&#39;), []);</code></p>
</li>
<li><p><strong>Express의 <code>get()</code> 함수</strong></p>
<p> : 리퀘스트가 언제 들어올지를 모르기 때문에 리퀘스트에 대한 처리는 비동기 형태로, 콜백에 파라미터 존재</p>
<pre><code class="language-jsx"> app.get(&#39;/hello&#39;, (req, res) =&gt; {
   res.send(&#39;Success!&#39;);
 });</code></pre>
</li>
</ol>
<h3 id="08-콜백-헬callback-hell">08. 콜백 헬(Callback Hell)</h3>
<p>→ 콜백이 여러번 중첩되는 것</p>
<p>→ 여러 비동기 작업을 연속적으로 처리한다는 문제점</p>
<p>→ 문제를 해결하기 위해 <strong>Promise 문법</strong> 생성</p>
<h2 id="3️⃣-promise">3️⃣ Promise</h2>
<h3 id="01-promise란">01. Promise란?</h3>
<p><strong>Promise 객체</strong> ← <code>fetch(&quot;api 링크&quot;);</code></p>
<ul>
<li>비동기 작업이 완료되면 값을 알려주는 객체</li>
<li>작업이 완료되면 값을 알려줄 것을 ‘약속’함</li>
</ul>
<p>콜백 기반</p>
<pre><code class="language-jsx">getEmployees((response) =&gt; {
    json(response, (data) =&gt; {
        console.log(data);
    });
});</code></pre>
<p>Promise 기반</p>
<pre><code class="language-jsx">const response = await fetch(&#39;...&#39;);
const data = await response.json();
console.log(data);
</code></pre>
<p><strong>Promise를 다루는 방법</strong></p>
<ol>
<li><code>.then()</code> 메소드 + 콜백</li>
<li><code>async</code>와 <code>await</code> 문법</li>
</ol>
<h3 id="02-await-문법">02. await 문법</h3>
<pre><code class="language-jsx">const response = await fetch(&#39;...&#39;);
const data = await response.json();
console.log(data);</code></pre>
<p>→ <code>Promise</code>를 리턴하는 표현식이 있다면, 앞에 <code>await</code> 키워드를 사용하여 결과값(파싱된 데이터)을 받아올 수 있다.</p>
<p>→ <code>await</code>을 사용하면 <code>Promise</code>가 <code>fulfilled</code> 상태가 될 때까지 기다렸다가 결과값을 돌려준다.</p>
<p><strong>✨ Promise의 3가지 상태</strong></p>
<ol>
<li><strong>Pending</strong> : 비동기 작업의 결과를 <strong>기다리고 있는</strong> 상태</li>
<li><strong>Fulfilled</strong> : 비동기 작업이 <strong>성공적으로 완료</strong>된 상태</li>
<li><strong>Rejected</strong> : 비동기 작업이 <strong>중간에 실패</strong>한 상태</li>
</ol>
<h3 id="03-점심-메뉴-받아오기-1">03. 점심 메뉴 받아오기 1</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요.
  const response = await fetch(&#39;...&#39;);
  const data = await response.json();
  console.log(data);</code></pre>
</li>
</ul>
<h3 id="0405-async-함수">04~05. async 함수</h3>
<p>→ 제대로 된 비동기 함수로 사용하려면 추가적인 과정 필요</p>
<p>→ <code>await</code> : async 함수 내에서 or 모듈의 최상위 레벨에서만 사용 가능</p>
<p><strong><code>main.js</code></strong></p>
<pre><code class="language-jsx">import { printEmployees } from &quot;./asyncFunctions&quot;;

printEmployees();

console.log(&quot;Task 2&quot;);

console.log(&quot;Task 3&quot;);

// Task 2
// Task 3
// printEmployees 실행결과</code></pre>
<p><strong><code>asyncFunctions.js</code></strong></p>
<pre><code class="language-jsx">export async function printEmployees() {
  const response = await fetch(&quot;...&quot;);
  const data = await response.json();
  console.log(data);
}

/*
const printEmployees = async () =&gt; {
  const response = await fetch(&quot;...&quot;);
  const data = await response.json();
  console.log(data);
}
*/</code></pre>
<h3 id="06-점심-메뉴-받아오기-2">06. 점심 메뉴 받아오기 2</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요.
  export async function printMenus() {
    const response = await fetch(&#39;...&#39;);
    const data = await response.json();
    console.log(data);
  }</code></pre>
</li>
</ul>
<h3 id="07-효율적인-비동기-코드">07. 효율적인 비동기 코드</h3>
<ul>
<li>비효율적인 코드 (수많은 await문을 호출)</li>
</ul>
<pre><code class="language-jsx">async function getEmployees() {
  for (let i = 1; i &lt; 11; i++) {
    const response = await fetch(`.../${i}`);
    const data = await response.json();
    console.log(data);
  }
}

getEmployees();</code></pre>
<ul>
<li>효율적인 코드 (순서는 지켜지지 않지만 한번에 리퀘스트를 전송)</li>
</ul>
<pre><code class="language-jsx">async function getEmployee(id) {
  const response = await fetch(`.../${id}`);
  const data = await response.json();
  console.log(data);
}

for (let i = 1; i &lt; 11; i++) {
  getEmployee(id);
}</code></pre>
<h3 id="08-async-함수의-리턴값">08. async 함수의 리턴값</h3>
<p>→ <strong>항상 Promise를 리턴한다❗️</strong></p>
<pre><code class="language-jsx">const employees = getEmployees(); // Promise
console.log(employees)</code></pre>
<h3 id="09-점심-메뉴-랜덤-선택기">09. 점심 메뉴 랜덤 선택기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  import { getMenus } from &#39;./asyncFunctions.js&#39;;

  function getRandomElement(arr) {
    const randomIdx = Math.floor(Math.random() * arr.length);
    return arr[randomIdx];
  }

  console.log(&#39;메뉴 고르는 중...&#39;);

  const menus = await getMenus();

  const randomMenu = getRandomElement(menus);

  console.log(`오늘의 랜덤 메뉴는 ${randomMenu.name}입니다!`);</code></pre>
</li>
</ul>
<h3 id="10-신입-직원-추가하기">10. 신입 직원 추가하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  import { getInterviews, getEmployees } from &#39;./asyncFunctions.js&#39;;

  function addNewEmployee(employees, interview) {
    const { name, department } = interview;
    const newEmployee = {
      id: employees.length + 1,
      name,
      department,
      email: `${name}@codeitmall.kr`,
    };
    employees.push(newEmployee);
  }

  const employees = await getEmployees();

  const interviews = await getInterviews();

  interviews.forEach((interview) =&gt; {
    if (interview.result === &#39;pass&#39;) {
      addNewEmployee(employees, interview);
    }
  });

  console.log(employees);</code></pre>
</li>
</ul>
<h3 id="11-try-catch로-오류-처리하기">11. try catch로 오류 처리하기</h3>
<pre><code class="language-jsx">export async function getEmployees() {
  try {
    const response = await fetch(&quot;...&quot;);
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.log(&quot;Error!&quot;);
    return;
  } finally {
    console.log(&quot;Finished&quot;);
  }
}</code></pre>
<p>→ <code>catch</code>문 속에서는 에러 처리 가능</p>
<p>→ <code>return</code> 시 함수를 종료</p>
<p>→ <code>finally</code>는 <code>return</code> 해도 실행하고 함수 종료</p>
<h3 id="12-고장난-점심-메뉴-선택기">12. 고장난 점심 메뉴 선택기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  export async function getMenus() {
    // 여기에 코드를 작성하세요.
    try {
      const response = await fetch(&#39;...&#39;);
      const menus = await response.json();
      return menus;
    } catch(error) {
      console.log(&#39;데이터를 가져오지 못했습니다 :(&#39;);
    } finally {
      console.log(&#39;getMenus() 함수가 끝났습니다.&#39;); 
    }
  }</code></pre>
</li>
</ul>
<h3 id="13-promise와-오류-제대로-이해하기">13. Promise와 오류 제대로 이해하기</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/e6afd7c7-067d-4bcd-8b93-7afc3966ff0a/image.png" alt=""></p>
<h3 id="1415-then-메소드">14~15. .then() 메소드</h3>
<p>→ <code>.then()</code> 메소드 : 앞선 비동기 작업이 완료되면 등록된 콜백을 실행 (Promise 객체의 메소드)</p>
<pre><code class="language-jsx">async function getEmployees() {
  const response = await fetch(&quot;...&quot;);
  const data = await response.json();
  console.log(data);
}

// const dataPromise = fetch(&quot;...&quot;).then((response) =&gt; response.json());
// dataPromise.then((data) =&gt; console.log(data));

fetch(&quot;...&quot;)
    .then((response) =&gt; response.json())
    .then((data) =&gt; console.log(data));</code></pre>
<h3 id="1617-catch와-finally-메소드">16~17. .catch()와 .finally() 메소드</h3>
<pre><code class="language-jsx">fetch(&quot;...&quot;)
  .then((response) =&gt; response.json())
  .then((data) =&gt; console.log(data))
  .**catch((error) =&gt; console.log(&quot;Error!&quot;))
  .finally(() =&gt; console.log(&quot;Finished&quot;));**</code></pre>
<p>→ 위와 같은 역할</p>
<p>→ <code>catch</code>문 속에서는 에러 처리 가능</p>
<p>→ <code>finally</code>는 <code>return</code> 해도 실행하고 함수 종료</p>
<h3 id="18-promiseall-메소드">18. Promise.all() 메소드</h3>
<pre><code class="language-jsx">async function getEmployee(id) {
  const response = await fetch(`.../${id}`);
  const data = await response.json();
  return data;
}

const promises = [];

for (let i = 1; i &lt; 11; i++) {
  promises.push(getEmployee(i));
}

const employees = await Promise.all(promises); // try, catch도 가능
console.log(employees);</code></pre>
<p>→ 여러 <code>Promise</code>를 동시에 기다릴 때 사용</p>
<h3 id="19-리퀘스트-동시에-보내기">19. 리퀘스트 동시에 보내기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  import { getEmployees, getMenus } from &#39;./asyncFunctions.js&#39;;

  const employeesPromise = getEmployees();
  const menusPromise = getMenus();

  const [employees, menus] = await Promise.all([employeesPromise, menusPromise]);

  // 테스트 코드
  console.log(&#39;직원 데이터:&#39;);
  console.log(employees);
  console.log(&#39;메뉴 데이터:&#39;);
  console.log(menus);</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 중급 (2)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-2</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-2</guid>
            <pubDate>Tue, 18 Jun 2024 20:43:43 GMT</pubDate>
            <description><![CDATA[<h1 id="ch2-자바스크립트-객체-지향-기본기">Ch2. 자바스크립트 객체 지향 기본기</h1>
<hr>
<h2 id="1️⃣-객체와-클래스">1️⃣ 객체와 클래스</h2>
<h3 id="01-객체-지향-프로그래밍이란">01. 객체 지향 프로그래밍이란?</h3>
<p>→ ‘<strong>객체</strong>’간의 <strong>상호작용</strong>을 중심으로 하는 프로그래밍</p>
<p>→ <strong>프로퍼티</strong>와 <strong>메소드</strong>로 이루어진 각 <strong>객체</strong>들의 <strong>상호 작용</strong>을 중심으로 코드를 작성하는 것</p>
<ul>
<li>객체의 <strong>상태</strong>를 나타내는 ‘<strong>변수</strong>’</li>
<li>객체의 <strong>행동</strong>을 나타내는 ‘<strong>함수</strong>’</li>
</ul>
<p>VS <strong>절차 지향 프로그래밍</strong></p>
<p>→ <strong>변수</strong>와 <strong>함수</strong>를 가지고 <strong>작업의 순서</strong>에 맞게 코드를 작성하는 것</p>
<h3 id="02-객체-만들기-1-1-object-literal">02. 객체 만들기 1-1: Object-Literal</h3>
<p><strong>Object-Literal</strong></p>
<p>→ 객체를 나타내는 문자열</p>
<p>→ 자바스크립트에서 객체를 생성할 수 있는 가장 기본적인 방법</p>
<h3 id="03-객체-만들기-1-2-factory-function">03. 객체 만들기 1-2: Factory function</h3>
<p><strong>Factory Function</strong></p>
<p>→ 객체를 생성해서 리턴하는 함수</p>
<pre><code class="language-jsx">function createUser(email, birthdate) {
  const user = {
    email,
    birthdate,
    buy(item) {
      console.log(`${this.email} buys ${item.name}`);
    },
  };
  return user;
}

const user1 = createUser(&quot;chirs123@google.com&quot;, &quot;1992-03-21&quot;);</code></pre>
<h3 id="04-객체-만들기-2-constructor-function">04. 객체 만들기 2: Constructor function</h3>
<p><strong>Constructor Function (생성자 함수)</strong></p>
<p>→ 객체를 생성할 수 있는 함수</p>
<p><code>this</code> : 매번 생성되는 해당 객체를 가리키는 역할</p>
<ol>
<li><code>new</code>를 붙여서 호출해야 해야 객체 생성 가능</li>
<li>함수 이름은 <code>대문자</code>로 시작</li>
</ol>
<pre><code class="language-jsx">function User(email, birthdate) {
  (this.email = email),
    (this.birthdate = birthdate),
    (this.buy = function (item) {
      console.log(`${this.email} buys ${item.name}`);
    });
}

const user1 = new User(&quot;chirs123@google.com&quot;, &quot;1992-03-21&quot;);</code></pre>
<h3 id="05-객체-만들기-3-class">05. 객체 만들기 3: Class</h3>
<p><strong>Class</strong></p>
<p><code>constructor</code>(생성자) : 객체가 생성될 때 실행</p>
<p><code>this</code> : 생성되는 객체를 나타냄</p>
<ul>
<li>프로퍼티(constructor 내부)와 메소드를 분리</li>
</ul>
<pre><code class="language-jsx">class User {
  constructor(email, birthdate) {
    this.email = email;
    this.birthdate = birthdate;
  }

  buy(item) {
    console.log(`${this.email} buys ${item.name}`);
  }
}

const user1 = new User(&quot;chirs123@google.com&quot;, &quot;1992-03-21&quot;);</code></pre>
<h3 id="0607-객체-만들기">06~07. 객체 만들기</h3>
<p>생략</p>
<h3 id="08-객체-생성해보기">08. 객체 생성해보기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  class Car {
    constructor(color, speed) {
      this.color = color;
      this.speed = speed;
    }

    run() {
      console.log(`Runs at ${this.speed}`);
    }
  }

  const car1 = new Car(&#39;blue&#39;, &#39;100km/h&#39;);

  car1.run();</code></pre>
</li>
</ul>
<h3 id="09-알고-넘어가야할-부분">09. 알고 넘어가야할 부분</h3>
<p><strong>객체 지향 프로그래밍이 가능한 언어의 2가지 종류</strong></p>
<ol>
<li><strong>클래스</strong> 기반의 객체 지향 언어 → <code>Java</code></li>
<li><strong>프로토타입</strong> 기반의 객체 지향 언어 → <code>JavaScript</code></li>
</ol>
<h2 id="2️⃣-객체-지향-프로그래밍의-4개의-기둥">2️⃣ 객체 지향 프로그래밍의 4개의 기둥</h2>
<blockquote>
<p>🔅 <strong>객체 지향 프로그래밍의 4가지 기둥</strong></p>
</blockquote>
<ol>
<li><strong>추상화</strong></li>
<li><strong>캡슐화</strong></li>
<li><strong>상속</strong></li>
<li><strong>다형성</strong></li>
</ol>
<h3 id="0102-추상화">01~02. 추상화</h3>
<p>→ 어떤 구체적인 존재를 원하는 방향으로 <strong>간략화</strong>해서 나타내는 것</p>
<p>ex. class를 설계하는 것</p>
<ul>
<li>클래스명, 프로퍼티와 메소드 이름에 주의 (직관적)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/may_05/post/1e776363-fe7b-4b26-bf2d-bef53cfd3815/image.png" alt=""></p>
<h3 id="0305-캡슐화">03~05. 캡슐화</h3>
<p>→ 객체의 특정 프로퍼티에 직접 접근하지 못하도록 막는 것</p>
<ul>
<li>프로퍼티에 이상한 값을 설정하는 것을 방지하는 역할</li>
<li><code>getter</code>, <code>setter</code> 메소드</li>
</ul>
<pre><code class="language-jsx">class User {
  constructor(email, birthdate) {
    this.email = email; **// email은 setter 메소드의 이름이 됨**
    this.birthdate = birthdate;
  }

  buy(item) {
    console.log(`${this.email} buys ${item.name}`);
  }

  **// getter 메소드 -&gt; 프로퍼티의 값을 구하는 함수**
  get email() {
    return this._email;
  }

  **// setter 메소드**
  set email(address) {
    **// email 프로퍼티에 값을 설정할 때 사용**
    if (address.includes(&quot;@&quot;)) {
      **// _가 붙은 _email이라는 새로운 프로퍼티, 숨기고자 하는 프로퍼티의 이름**
      this._email = address;
    } else {
      throw new Error(&quot;invalid email address&quot;);
    }
  }
}

const user1 = new User(&quot;chirs123@google.com&quot;, &quot;1992-03-21&quot;);
console.log(user1.email); **// getter 메소드 사용시 _ 없이 변수 사용 가능**</code></pre>
<ol>
<li><p><strong>완벽한 캡슐화를 하는 법</strong></p>
<p> → <strong>클로저(Closure)</strong> : 어떤 함수와 그 함수가 참조할 수 있는 값들로 이루어진 환경을 하나로 묶은 것</p>
<p> 클로저라는 개념으로 해당 환경을 함수와 함께 그대로 유지시켜주어 <code>_email</code> 변수에 접근 가능</p>
<p> 클로저가 아닌 경우에는 아래와 같이 <code>_email</code> 변수에 접근 불가</p>
</li>
</ol>
<pre><code class="language-jsx">function createUser(email, birthdate) {
  let _email = email;

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    set email(address) {
      if (address.includes(&#39;@&#39;)) {
        _email = address;
      } else {
        throw new Error(&#39;invalid email address&#39;);
      }
    },
  };

  return user;
}

const user1 = createUser(&#39;chris123@google.com&#39;, &#39;19920321&#39;);
console.log(user1._email); // _ 추가 -&gt; 접근 불가</code></pre>
<ol>
<li><strong>메소드도 캡슐화할 수 있어요</strong></li>
</ol>
<pre><code class="language-jsx">function createUser(email, birthdate) {
  const _email = email;
  let _point = 0;

  function increasePoint() {
    _point += 1;
  }

  const user = {
    birthdate,

    get email() {
      return _email;
    },

    get point() {
      return _point;
    },

    buy(item) {
      console.log(`${this.email} buys ${item.name}`);
      increasePoint();
    },
  };

  return user;
}

const item = {
  name: &#39;스웨터&#39;,
  price: 30000,
};

const user1 = createUser(&#39;chris123@google.com&#39;, &#39;19920321&#39;);
user1.buy(item);
user1.buy(item);
user1.buy(item);
console.log(user1.point);
user1.increasePoint(); // user1 객체로 increasePoint 직접 호출 불가</code></pre>
<p>→ <code>increasePoint</code>가 유저 객체 안에서 적절한 곳에 사용되어야 하고, 아무렇게나 함부로 호출해서는 안 되는 메소드라고 가정하고 캡슐화</p>
<ul>
<li><code>user1</code> 객체에는 <code>increasePoint</code>라는 메소드가 없기 때문에 직접 호출 불가</li>
</ul>
<h3 id="0608-상속-super">06~08. 상속, super</h3>
<p>→ 하나의 객체가 다른 객체의 <strong>프로퍼티와 메소드</strong>를 물려받는 것</p>
<ul>
<li><code>extends</code>를 통해 상속을 받아 중복 코드 삭제 → 코드의 재사용성이 좋아짐</li>
<li><code>super</code>를 통해 부모 클래스의 <code>constructor</code>를 호출해주어야 실행 가능</li>
</ul>
<pre><code class="language-jsx">class User { // 부모 클래스
  constructor(email, birthdate) {
    this.email = email;
    this.birthdate = birthdate;
  }

  buy(item) {
    console.log(`${this.email} buys ${item.name}`);
  }
}

class PremiumUser extends User { // 자식 클래스
  constructor(email, birthdate, level) {
      super(email, birthdate);
    this.level = level;
  }

  streamMusicForFree() {
    console.log(`Free music streaming for ${this.email}`);
  }
}</code></pre>
<h3 id="0911-다형성">09~11. 다형성</h3>
<p>→ 많은 형태를 갖고 있는 성질</p>
<ul>
<li>그대로 상속받지 않고 수정하는 경우 → 동일한 이름을 새롭게 정의 <strong><code>Overriding(오버라이딩)</code> :</strong> 덮어써서 작성</li>
<li>동일한 이름의 메소드를 <strong>간결하게 호출 가능</strong></li>
</ul>
<pre><code class="language-jsx">class User {
  // 부모 클래스
  constructor(email, birthdate) {
    this.email = email;
    this.birthdate = birthdate;
  }

  buy(item) {
    console.log(`${this.email} buys ${item.name}`);
  }
}

class PremiumUser extends User {
  // 자식 클래스
  constructor(email, birthdate, level, point) {
    super(email, birthdate);
    this.level = level;
    this.point = point;
  }

  buy(item) {
    // console.log(`${this.email} buys ${item.name}`);
    super.buy(item); // 부모 클래스의 buy 메소드를 호출 (동일한 내용을 호출 후 오버라이딩)
    this.point += item.price * 0.05;
  }

  streamMusicForFree() {
    console.log(`Free music streaming for ${this.email}`);
  }
}</code></pre>
<h3 id="12-instanceof-연산자">12. instanceof 연산자</h3>
<p>→ 현재 변수가 가르키는 객체가 어느 클래스로 만든 객체인지 확인하는 역할</p>
<p><code>console.log(user instanceof User); // true, false</code></p>
<p><code>console.log(user instanceof PremiumUser); // true, false</code></p>
<p>→ <strong>자식 클래스로 만든 객체는 부모 클래스로 만든 객체로도 인정됨</strong>❗</p>
<h3 id="13-static-프로퍼티와-static-메소드">13. static 프로퍼티와 static 메소드</h3>
<p>→ 클래스에 직접적으로 딸려있는 프로퍼티와 메소드</p>
<p>→ 객체가 아닌 클래스 자체로 접근!</p>
<pre><code class="language-jsx">class Math {
  static PI = 3.14;

  static getCircleArea(radius) {
    return Math.PI * radius * radius;
  }
}

Math.PI = 3.141592;
Math.getCircleArea = function (width, height) {
  return width * height;
};

console.log(Math.PI);
console.log(Math.getCircleArea(4, 5));</code></pre>
<p>➕ <code>console.log(Date.now());</code></p>
<h3 id="1415-4개의-기둥-정리">14~15. 4개의 기둥 정리</h3>
<p>생략</p>
<h3 id="16-클래스는-파일-하나당-하나씩-넣어주는-게-좋아요">16. 클래스는 파일 하나당 하나씩 넣어주는 게 좋아요</h3>
<ul>
<li>각 클래스와 메인 로직(main.js)을 파일별로 쪼개서 작성</li>
<li>코드를 좀더 편리하게 관리하기 위함</li>
</ul>
<p>→ 파일 하나당 클래스 하나를 작성하고, 이를 외부에 공개해서 사용할 수 있도록 하는 방식을 주로 활용한다❗</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 중급 (1)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-1</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%EC%A4%91%EA%B8%89-1</guid>
            <pubDate>Sat, 08 Jun 2024 13:31:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/may_05/post/89637b69-fc12-4233-9a78-e532605254de/image.jpg" alt=""></p>
<h1 id="ch1-모던-자바스크립트">Ch1. 모던 자바스크립트</h1>
<hr>
<h2 id="1️⃣-모던-자바스크립트-이해하기">1️⃣ 모던 자바스크립트 이해하기</h2>
<h3 id="0102-모던-자바스크립트란">01~02. 모던 자바스크립트란?</h3>
<ul>
<li>ECMAScript → 자바스크립트 표준 명세서 ( JavaScript Specification )<ul>
<li>✨ <strong>ES6</strong> → 정식 명칭 <strong>ECMAScript 2015</strong></li>
</ul>
</li>
<li>Modern JavaScript<ul>
<li>현시점에 사용하기 적합한 범위 내에서 최신 버전의 표준을 준수하는 자바스크립트</li>
<li>JavaScript의 기본 개념 더 견고히!</li>
<li>새롭게 등장한 문법들 중 유용한 문법들?</li>
<li>모던하게 자바스크립트 활용하기!</li>
</ul>
</li>
</ul>
<h3 id="03-ecmascript-더-알아보기">03. ECMAScript 더 알아보기</h3>
<ul>
<li><a href="https://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMA-International 공식 ECMA-262문서</a></li>
<li><a href="https://ko.wikipedia.org/wiki/ECMA%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8">위키백과 - ECMA스크립트</a></li>
<li><a href="https://compat-table.github.io/compat-table/es6/">한눈에 확인하는 호환성 테이블</a></li>
<li><a href="https://caniuse.com/">문법 검색으로 확인하는 호환성 테이블</a></li>
<li><strong>JavaScript vs ECMAScript</strong><ul>
<li>JavaScript는 <strong>프로그래밍 언어(결과물)</strong>이고, ECMAScript는 <strong>프로그래밍 언어의 표준(설명서)</strong></li>
<li><strong>JavaScript는</strong> ECMAScript를 기반으로 하지만 ECMAScript에 정의된 내용뿐만 아니라, <strong>다른 부가적인 기능도 있음</strong></li>
</ul>
</li>
</ul>
<h2 id="2️⃣-자바스크립트의-동작-원리">2️⃣ 자바스크립트의 동작 원리</h2>
<h3 id="01-데이터-타입의-특징과-종류">01. 데이터 타입의 특징과 종류</h3>
<p>→ 데이터 타입이 상황에 따라 변할 수 있다! (유연한 데이터 타입)</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/c4874788-8192-4f3a-9a86-1c63e3d48ccb/image.png" alt=""></p>
<h3 id="02-symbol과-bigint">02. Symbol과 BigInt</h3>
<p>→ Symbol</p>
<ul>
<li>코드 내에서 유일한 값을 가진 변수 이름을 만들 때 사용</li>
<li><strong>다른 어떤 값과 비교해도 true가 될 수 없는 고유한 변수</strong><ul>
<li>똑같은 설명을 붙인 심볼을 만들더라도 두 값을 비교하면 false가 반환</li>
</ul>
</li>
<li><code>const user = Symbol(&#39;this is a user&#39;);</code></li>
</ul>
<p>→ BigInt</p>
<ul>
<li>아주 큰 <strong>정수(Integer)</strong>를 표현하기 위해 등장한 데이터 타입</li>
<li><strong>자바스크립트의 숫자형(number type) 값에는 9000조 정도의 정수 표현의 한계가 존재</strong><ul>
<li><code>2**53 - 1</code> 보다 큰 정숫값도 안전하게 표현 가능</li>
</ul>
</li>
<li><code>console.log(9007199254740993n); // 9007199254740993n
console.log(BigInt(&#39;9007199254740993&#39;)); // 9007199254740993n</code></li>
</ul>
<h3 id="03-typeof-연산자">03. typeof 연산자</h3>
<p>→ typeof 연산자</p>
<ul>
<li>키워드 다음에 공백(띄어쓰기)을 두고 값을 작성해도 되고, 함수를 사용하듯 괄호로 감싸서 사용</li>
<li><code>typeof null</code>을 하면 문자열 <code>null</code>이 리턴되는 게 아니라 문자열 <strong>object</strong>가 리턴되는 문제 (수정 제안 but 아직 반영 X)</li>
<li>함수에 <code>typeof</code> 연산자를 사용하면 <strong>function</strong>이라는 값을 리턴 (객체로 취급하지만 리턴은 function)</li>
</ul>
<h3 id="04-자바스크립트-데이터-타입의-특징-익히기">04. 자바스크립트 데이터 타입의 특징 익히기</h3>
<p>퀴즈 생략</p>
<h3 id="0506-불린인-듯-불린-아닌-불린같은-값">05~06. 불린인 듯 불린 아닌 불린같은 값</h3>
<p><code>undefined</code> <code>number</code> <code>string</code> → 형 변환 → <code>boolean</code> (true or false)</p>
<p><img src="https://velog.velcdn.com/images/may_05/post/e84e4ca9-4ffe-4301-8487-cc27d3be60e8/image.png" alt=""></p>
<p>→ Falsy 값, Truthy 값</p>
<h3 id="0709-and와-or의-연산-방식-우선순위">07~09. AND와 OR의 연산 방식, 우선순위</h3>
<p>→ AND 연산자</p>
<ul>
<li>왼쪽 값이 <code>true</code>일 경우 오른쪽 값, 왼쪽 값이 <code>false</code>일 경우 왼쪽 값 출력</li>
</ul>
<p>→ OR 연산자</p>
<ul>
<li>왼쪽 값이 <code>true</code>일 경우 왼쪽 값, 왼쪽 값이 <code>false</code>일 경우 오른쪽 값 출력</li>
</ul>
<p>❗<strong>AND 연산자가 OR 연산자보다 우선순위가 높음</strong>❗</p>
<h3 id="10-null-병합-연산자-">10. null 병합 연산자 ??</h3>
<p>→ 물음표 두 개(??)를 사용해서 null 혹은 undefined 값을 가려내는 연산자</p>
<ul>
<li><strong>연산자 왼편의 값이</strong> <code>null 이나 undefined라면</code> <strong>연산자 오른편의 값이 리턴</strong></li>
<li><strong>연산자 왼편의 값이</strong> <code>null 이나 undefined가 아니라면</code> <strong>연산자 왼편의 값이 리턴</strong></li>
<li><strong>null이나 undefined인지 확인</strong></li>
</ul>
<h3 id="1112-변수와-스코프">11~12. 변수와 스코프</h3>
<pre><code class="language-jsx">console.log(title); // undefined
var title = &#39;codeit&#39;;
console.log(title); // codeit</code></pre>
<p>→ <code>var</code>의 경우 변수 선언 이전에 접근이 가능하지만 값이 할당되지는 않아서 <code>undefined</code> 출력 + 중복 선언 가능</p>
<p>➕ 함수가 아닌 경우(ex. if문, for문), var은 전역 변수 처리</p>
<pre><code class="language-jsx">var x;    // 함수 스코프 (function scope)
let y;    // 블록 스코프 (block scope)
const z;  // 블록 스코프 (block scope)</code></pre>
<h2 id="3️⃣-함수-다루기">3️⃣ 함수 다루기</h2>
<h3 id="0102-함수를-만드는-방법">01~02. 함수를 만드는 방법</h3>
<ol>
<li><p>함수 선언</p>
</li>
<li><p>함수 표현식</p>
<ol>
<li><p>함수 선언을 변수에 할당</p>
</li>
<li><p><strong>함수 선언을 값처럼 사용</strong></p>
<pre><code class="language-jsx">const printCodeit = function () {
 console.log(&#39;Codeit&#39;);
}

printCodeit();</code></pre>
</li>
</ol>
</li>
</ol>
<h3 id="03-이름이-있는-함수-표현식">03. 이름이 있는 함수 표현식</h3>
<p><strong>Named Function Expression (기명 함수 표현식)</strong></p>
<pre><code class="language-jsx">const sayHi = function printHiInConsole() {
  console.log(&#39;Hi&#39;);
};

console.log(sayHi.name); // printHiInConsole</code></pre>
<h3 id="04-즉시-실행-함수-iife">04. 즉시 실행 함수 (IIFE)</h3>
<p><strong>즉시 실행 함수 (표현) → Immediately Invoked Function Expression</strong>, 줄여서 <strong>IIFE</strong></p>
<pre><code class="language-jsx">(function (x, y) {
  console.log(x + y);
})(3, 5);</code></pre>
<p>➕ 일반적으로 프로그램 <strong>초기화 기능</strong>에 많이 활용</p>
<p>➕ <strong>함수의 리턴값을 바로 변수에 할당하고 싶을 때</strong> 활용</p>
<h3 id="0506-값으로서-함수">05~06. 값으로서 함수</h3>
<p>→ <strong>콜백 함수 (Callback Function)</strong> : 다른 함수의 파라미터에 전달된 함수</p>
<p>→ <strong>고차 함수 (Higher Order Function)</strong> : 함수를 리턴하는 함수</p>
<p>→ <strong>일급 함수 (First Order Function)</strong> : 다른 함수에 할당 가능, 파라미터로 전달 가능, 리턴 가능한 함수</p>
<h3 id="0708-parameter">07~08. Parameter</h3>
<p><strong>파라미터(Parameter)</strong> : 외부로부터 값을 전달받기 위해 힘수를 선언할 때 작성하는 것</p>
<p><strong>아규먼트(Argument)</strong> : 함수를 호출할 때 파라미터로 전달하는 값</p>
<p>→ 파라미터를 전달하지 않고, 기본값이 없을 때 : <code>undefined</code> 전달</p>
<ul>
<li>2개의 값 중 하나만 전달했을 때 : <code>첫번째 값</code>과 <code>undefined</code> 전달</li>
</ul>
<p>→ 두번재 파라미터에 첫번째 파라미터 값을 활용 가능</p>
<h3 id="09-arguments">09. Arguments</h3>
<p><strong>Argument의 개수에 따라 유연한 대처가 가능한 함수</strong></p>
<pre><code class="language-jsx">function printArguments() {
    for (const arg of arguments) {
        console.log(arg);
    }
    console.log(&#39;-----------&#39;);
}

printArguments(&#39;Young&#39;, &#39;Mark&#39;, &#39;Koby&#39;);
printArguments(&#39;Captain&#39;);
printArguments(&#39;Jayden&#39;, &#39;Scott&#39;);
printArguments(&#39;Suri&#39;, &#39;Jack&#39;, &#39;Joy&#39;, &#39;Noel&#39;);</code></pre>
<p>→ 배열의 역할 X</p>
<h3 id="10-줄임말-대잔치">10. 줄임말 대잔치</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function firstWords(words) {
    let word = &#39;&#39;;

    // 여기에 코드를 작성하세요
    for(const arg of arguments) {
      word += arg[0];
    }

    console.log(word);
  }

  firstWords(&#39;나만&#39;, &#39;없어&#39;, &#39;고양이&#39;);
  firstWords(&#39;아니&#39;, &#39;바나나말고&#39;, &#39;라면먹어&#39;);
  firstWords(&#39;만두&#39;, &#39;반으로&#39;, &#39;잘라먹네&#39;, &#39;부지런하다&#39;);
  firstWords(&#39;결국&#39;, &#39;자바스크립트가&#39;, &#39;해피한&#39;, &#39;지름길&#39;);
  firstWords(&#39;빨간색&#39;, &#39;주황색&#39;, &#39;노란색&#39;, &#39;초록색&#39;, &#39;파란색&#39;, &#39;남색&#39;, &#39;보라색&#39;);</code></pre>
</li>
</ul>
<h3 id="11-rest-parameter">11. Rest Parameter</h3>
<pre><code class="language-jsx">function printArguments(...args) {
    for (const arg of args) {
        console.log(arg);
        console.log(args.splice(0, 2));
    }
    console.log(&#39;-----------&#39;);
}

printArguments(&#39;Young&#39;, &#39;Mark&#39;, &#39;Koby&#39;);
printArguments(&#39;Captain&#39;);
printArguments(&#39;Jayden&#39;, &#39;Scott&#39;);
printArguments(&#39;Suri&#39;, &#39;Jack&#39;, &#39;Joy&#39;, &#39;Noel&#39;);</code></pre>
<p>→ Rest Parameter는 <strong>배열</strong>이다❗ → splice 등 사용 가능</p>
<p>➕ 일반 파라미터와 사용 가능 (<strong>반드시</strong> 가장 마지막에 위치) → 필요에 따라 유연하게 사용 가능</p>
<h3 id="12-1세대는-거르는게-답">12. 1세대는 거르는게 답?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function ignoreFirst(...args) {
    for(const arg of args) {
      let last = args.splice(1, args.length);
      for(let i = 0; i &lt; last.length; i++) {
        console.log(last[i]);
      }
    }
  }

  ignoreFirst(&#39;1세대&#39;, &#39;2세대&#39;, &#39;3세대&#39;);
  ignoreFirst(&#39;곰팡이&#39;, &#39;강아지&#39;, &#39;고양이&#39;);
  ignoreFirst(20, 9, 18, 19, 30, 34, 40);</code></pre>
</li>
<li><p>실습 코드 (다른 방법)</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function ignoreFirst(first, ...rest) {
    for (const el of rest) {
      console.log(el);
    }
  }

  ignoreFirst(&#39;1세대&#39;, &#39;2세대&#39;, &#39;3세대&#39;);
  ignoreFirst(&#39;곰팡이&#39;, &#39;강아지&#39;, &#39;고양이&#39;);
  ignoreFirst(20, 9, 18, 19, 30, 34, 40);
</code></pre>
</li>
</ul>
<h3 id="1314-arrow-function">13~14. Arrow Function</h3>
<pre><code class="language-jsx">/*
const getTwice = function(number) {
    return number * 2;
};
*/

// 1번 방법
**const getTwice = (number) =&gt; {
    return number * 2;
};**

// 2번 방법
// const getTwice = number =&gt; number * 2;

console.log(getTwice(5));

const myBtn = document.querySelector(&#39;#myBtn&#39;);

myBtn.addEventListener(&#39;click&#39;, () =&gt; {
    console.log(&#39;button is clicked&#39;);
});</code></pre>
<p>⚠️ <strong>Arrow Function 주의사항</strong></p>
<ul>
<li><code>Argument</code>의 부재 → 대체 불가</li>
</ul>
<p>⚠️ <strong>2번 방법 주의사항</strong></p>
<ul>
<li>함수 내부에서 조건문, 반복문을 사용하거나 변수에 값 할당 등 <strong><code>return문</code></strong>을 제외하고 다른 표현이 필요한 경우 불가</li>
<li>return값이 객체인 경우 불가 (함수의 동작 부분인 중괄호로 해석)<ul>
<li>소괄호를 한 번 감싸주면 사용 가능 ex. <code>({ name: ‘Codeit’, })</code></li>
</ul>
</li>
</ul>
<h3 id="1516-what-is-this">15~16. What is this?</h3>
<pre><code class="language-jsx">function getFullName() {
    return `${this.firstName} ${this.lastName}`;
}

const user = {
    firstName: &#39;Tess&#39;,
    lastName: &#39;Jang&#39;,
    getFullName: getFullName,
}

const admin = {
    firstName: &#39;Alex&#39;,
    lastName: &#39;Kim&#39;,
    getFullName: getFullName,
}

console.log(user.getFullName());
console.log(admin.getFullName());</code></pre>
<p>✨ <strong>This란?</strong></p>
<p>→ 함수를 호출한 객체를 가리키는 키워드</p>
<p>(선언하지 않고 그냥 사용하게 되면 기본값인 window 객체를 가리킴)</p>
<p>➕ <strong>Arrow Function에서 this를 사용하는 방법</strong></p>
<p>→ 일반 함수처럼 호출한 대상에 따라 상대적으로 변화 X</p>
<p>→ Arrow Function이 선언되기 직전에 이용한 this 값과 같은 this 값을 사용</p>
<p>➡️ <strong>일반 함수에서의 사용을 권장함</strong> 👍</p>
<h2 id="4️⃣-자바스크립트의-문법과-표현">4️⃣ 자바스크립트의 문법과 표현</h2>
<h3 id="01-문장과-표현식">01. 문장과 표현식</h3>
<p>#️⃣ <strong>문장 (statements)</strong></p>
<p>→ <strong>어떤 동작이 일어나도록 작성된 최소한의 코드 덩어리</strong></p>
<p>#️⃣ <strong>표현식 (expressions)</strong></p>
<p>→ <strong>결과적으로 하나의 값이 되는 모든 코드</strong></p>
<p>➡️ 일반적으로 표현식인 문장은 세미콜론으로, 표현식이 아닌 문장은 문장 자체의 코드 블록(중괄호)로 그 문장의 범위가 구분</p>
<h3 id="0203-조건을-다루는-표현식-조건-연산자">02~03. 조건을 다루는 표현식 (조건 연산자)</h3>
<ol>
<li><p>if문</p>
</li>
<li><p>switch문</p>
</li>
<li><p><strong>조건 연산자 = 삼항 연산자</strong></p>
<pre><code class="language-jsx"> // 조건 ? truthy 할 때 표현식 : falsy 할 때 표현식
 // 삼항 연산자

 const CUT_OFF = 80;

 const passChecker(score) {
     return score &gt; CUT_OFF ? &#39;합격!&#39; : &#39;불합격!&#39;;
 }

 console.log(passChecker(90));</code></pre>
<p> ❌ 조건에 따라 변수를 선언하거나 반복문 사용 불가 (모든 if문 대체 불가)</p>
</li>
</ol>
<h3 id="0406-spread-구문">04~06. Spread 구문</h3>
<p>→ 하나로 묶여있는 값을 각각의 개별 값으로 펼치는 방식 (Spread문 자체가 값 X, 여러 값의 목록으로 평가)</p>
<p>↔️ Rest Parameter : 여러개의 Argument를 하나로 묶는 방식</p>
<pre><code class="language-jsx">const numbers = [1, 2, 3];

console.log(**...numbers**);  // 1 2 3
console.log(1, 2, 3);     // 1 2 3</code></pre>
<p>➕ Slice를 사용하지 않고도 배열 복사 가능 <strong>(바로 요소 추가도 가능)</strong></p>
<pre><code class="language-jsx">const webPublishing = [&#39;HTML&#39;, &#39;CSS&#39;];
const interactiveWeb = [...webPublishing, &#39;JavaScript&#39;];

// const interactiveWeb = [...webPublishing];
// interactiveWeb.push(&#39;JavaScript&#39;);

console.log(webPublishing);   // [&#39;HTML&#39;, &#39;CSS&#39;]
console.log(interactiveWeb);  // [&#39;HTML&#39;, &#39;CSS&#39;, &#39;JavaScript&#39;]</code></pre>
<p><em>️⃣ *</em>객체 Spread**</p>
<pre><code class="language-jsx">const latte = {
  esspresso: &#39;30ml&#39;,
  milk: &#39;150ml&#39;
};

const cafeMocha = {
  ...latte,
  chocolate: &#39;20ml&#39;,
}

console.log(latte); // {esspresso: &quot;30ml&quot;, milk: &quot;150ml&quot;}
console.log(cafeMocha); // {esspresso: &quot;30ml&quot;, milk: &quot;150ml&quot;, chocolate: &quot;20ml&quot;}</code></pre>
<p>→ 객체로는 <strong>새로운 배열</strong>을 만들거나 <strong>함수의 아규먼트</strong>로 <strong>사용 불가</strong></p>
<p>→ <strong>반드시 객체를 표현하는 중괄호 안에서 활용</strong></p>
<h3 id="0708-모던한-프로퍼티-표기법">07~08. 모던한 프로퍼티 표기법</h3>
<pre><code class="language-jsx">const title = &#39;Codeit&#39;;
const birth = 2024;
const job = &#39;프로그래밍 강사&#39;;

const user = {
    title,
    birth,
    job,
};

console.log(user);</code></pre>
<p>→ 변수나 함수의 이름이 같다면 이렇게 표기 가능</p>
<p>→ 내부에서 사용하는 함수의 경우 function과 : 생략 가능</p>
<pre><code class="language-jsx">// 계산된 속성명 (computed property name)
const user = {
    // [표현식]: 값,
    [&#39;Code&#39; + &#39;it&#39;]: &#39;value&#39;,
};

console.log(user); // {Codeit: &quot;value&quot;}</code></pre>
<h3 id="09-옵셔널-체이닝">09. 옵셔널 체이닝</h3>
<p>중첩된 객체의 프로퍼티를 다룰 때 <code>null</code> 혹은 <code>undefined</code>가 아니라는 것을 검증하고 접근해야 에러를 방지 가능</p>
<p>→ AND 연산자를 활용한 방법도 객체의 이름이나 프로퍼티의 이름이 길어질수록 가독성이 나빠지는 문제 발생</p>
<p>→ 훨씬 더 코드를 간결하게 사용할 수 있는 문법이 <strong>옵셔널 체이닝(Optional Chaining)</strong></p>
<pre><code>옵셔널 체이닝 연산자 `?.`</code></pre><pre><code class="language-jsx">function printCatName(user) {
  console.log(user.cat?.name);
}

function printCatName(user) {
  console.log((user.cat === null || user.cat === undefined) ? undefined : user.cat.name);
}

function printCatName(user) {
  console.log(user.cat?.name ?? &#39;함께 지내는 고양이가 없습니다.&#39;);
}</code></pre>
<h3 id="1015-destructuring-구조-분해">10~15. Destructuring (구조 분해)</h3>
<p><strong>구조 분해</strong></p>
<pre><code class="language-jsx">const rank = [&#39;유나&#39;, &#39;효준&#39;, &#39;민환&#39;, &#39;재하&#39;, &#39;규식&#39;];

const [macbook, ipad, airpods, ...coupon] = rank; // 적을 경우 undefined 값 할당

console.log(macbook);
console.log(ipad);
console.log(airpods);
console.log(coupon);</code></pre>
<pre><code class="language-jsx">[macbook, ipad] = [ipad, mackbook]; // 다른 변수를 생성하지 않고도 값을 바꿔서 할당 가능</code></pre>
<p><strong>객체 구조 분해</strong></p>
<pre><code class="language-jsx">const macbook = {
    title: &#39;맥북 프로 16형&#39;,
    price: 3690000,
    memory: &#39;16GB&#39;,
    storage: &#39;1TB SSD 저장 장치&#39;,
    display: &#39;16형 Retina 디스플레이&#39;,
}

// const title = macbook.title;
// const price = macbook.price;
const { title, price } = macbook; // 같은 변수의 이름이 있으면 그 값이 할당됨 아니라면 undefined 값
const { title, ...rest } = macbook; // 앞에 선언된 것을 제외한 프로퍼티를 할당
const { title: product, price } = macbook; // 프로퍼티를 다른 이름으로 선언하고 싶다면 : 사용
const { [propertyName]: product, price } = macbook;

console.log(title);
console.log(price);
console.log(product);</code></pre>
<p><strong>함수 구조 분해</strong></p>
<pre><code class="language-jsx">function getArray() {
    return [&#39;컴퓨터&#39;, &#39;냉장고&#39;, &#39;세탁기&#39;]; // 위에서 바로 활용 가능
}

const [el1, el2, el3] = getArray();

console.log(el1);
console.log(el2);
console.log(el3);</code></pre>
<p><strong>객체 구조 분해</strong></p>
<pre><code class="language-jsx">function printSummary(object) {
    const { title, color, price } = object; // 위에서 바로 활용 가능

    console.log(`선택한 상품은 &#39;$title}&#39;입니다.`);
    console.log(`색상은 ${color}이며,`);
    console.log(`가격은 ${price}원 입니다.`);
};

printSummary(macbook);</code></pre>
<pre><code class="language-jsx">const btn = document.querySelector(&#39;#btn&#39;);

btn.addEventListener(&#39;click&#39;, ({ target }) =&gt; {
    target.classList.toggle(&#39;checked&#39;);
});

// + 중첩 객체 구조 분해
btn.addEventListener(&#39;click&#39;, ({ target: { classList } }) =&gt; {
    classList.toggle(&#39;checked&#39;);
});

btn.addEventListener(&#39;click&#39;, ({ target }) =&gt; {
    const { classList } = target;
    classList.toggle(&#39;checked&#39;);
});</code></pre>
<h3 id="1619-에러와-에러-객체-try-catch문">16~19. 에러와 에러 객체, try catch문</h3>
<p>→ Syntax Error, Type Error 등 발생하는 에러</p>
<pre><code class="language-jsx">// try catch 문

try {
    // 코드 (에러가 발생한 이후 시점의 코드는 작동 X)
} catch(error) {
    // 에러가 발생했을 때 동작할 코드

    console.error(error);
    /*
    console.log(error);
    console.log(error.name);
    console.log(error.message);
    */
}</code></pre>
<h3 id="20-finally문">20. finally문</h3>
<pre><code class="language-jsx">try {
  // 실행할 코드
} catch (err) {
  // 에러가 발생했을 때 실행할 코드
} finally {
  // 항상 실행할 코드
}</code></pre>
<p>→ finally문에서도 에러 처리가 필요하다면 중첩해서 활용</p>
<pre><code class="language-jsx">try {
  try {
    // 실행할 코드
  } catch (err) {
    // 에러가 발생했을 때 실행할 코드
  } finally {
    // 항상 실행할 코드
  }
} catch (err) {
  // finally문에서 에러가 발생했을 때 실행할 코드
}</code></pre>
<h3 id="21-퀴즈왕의-길은-험난하다">21. 퀴즈왕의 길은 험난하다</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const quiz1 = {
    question: &#39;다음 중 스승의 날과 생일이 같은 인물은 누구일까요?&#39;,
    example: [ &#39;율곡 이이&#39;, &#39;퇴계 이황&#39;, &#39;세종대왕&#39;, &#39;신사임당&#39;],
    answer: 3,
    solution: &#39;훈민정음 창제 등 우리나라 문화와 교육 발전에 남긴 업적이 가장 큰 인물이라는 평가와 함께, 이 시대의 스승이 세종대왕처럼 존경받았으면 하는 바람으로 세종대왕의 탄생일이 스승의 날로 지정되었습니다.&#39;,
  };

  const quiz2 = {
    question: &#39;다음 중 희노애락에 속하지 않는 것은 무엇일까요?&#39;,
    example: [&#39;사랑&#39;, &#39;기쁨&#39;, &#39;즐거움&#39;],
    answer: 1,
    solution: &#39;희노애락에서의 애를 사랑 애(愛)라고 자칫 오해할 수가 있지만, 희노애락의 애는 슬플 애(哀)입니다. 기쁨은 기쁠 희(喜), 즐거움은 즐거울 락(樂)에 담겨 있습니다.&#39;,
  };

  function printQuiz({ question, example }) {
    let exMsg = &#39;&#39;;

    try {
      for (let i = 0; i &lt; example.length; i++) {
        exMsg += `${i + 1}. ${example[i]}  `;
      }

      console.log(question);
      console.log(exMsg);
    } catch(error) {
      console.log(error.name);
    }
  }

  // 테스트 코드
  printQuiz(quiz1);
  printQuiz(1);
  printQuiz(&quot;&quot;);
  printQuiz({});
  printQuiz(quiz2);</code></pre>
</li>
</ul>
<h2 id="5️⃣-자바스크립트의-유용한-내부-기능">5️⃣ 자바스크립트의 유용한 내부 기능</h2>
<h3 id="❗01-배열-메소드-1--foreach와-map">❗01. 배열 메소드 1 : forEach와 map</h3>
<ul>
<li><p><strong><code>forEach</code></strong></p>
<pre><code class="language-jsx">  const members = [&#39;영훈&#39;, &#39;윤수&#39;, &#39;동욱&#39;, &#39;태호&#39;];

  for (let member of members) {
      console.log(`{members}님이 입장하셨습니다.`);
  }

  members.forEach((member, i) =&gt; {
      console.log(`${i} ${member}님이 입장하셨습니다.`);
  });</code></pre>
<p>  → <code>forEach</code>에서 첫번째 인자는 필수, index는 선택</p>
<pre><code class="language-jsx">  const firstNames = [&#39;영훈&#39;, &#39;윤수&#39;, &#39;동욱&#39;, &#39;태호&#39;];
  const lastNames = [&#39;강&#39;, &#39;이&#39;, &#39;손&#39;, &#39;성&#39;];

  firstNames.forEach((firstName, i) =&gt; {
      console.log(`${lastNames[i]}${firstName}님이 입장하셨습니다.`);
  });</code></pre>
<p>  → 여러 배열에서 같은 위치의 값을 사용하도록 활용 가능</p>
</li>
<li><p><strong><code>map</code></strong></p>
<pre><code class="language-jsx">  const firstNames = [&#39;영훈&#39;, &#39;윤수&#39;, &#39;동욱&#39;, &#39;태호&#39;];
  const lastNames = [&#39;강&#39;, &#39;이&#39;, &#39;손&#39;, &#39;성&#39;];

  const fullNames = firstNames.map((firstName, i) =&gt; {
      return lastNames[i] + firstName;
  });

  console.log(fullNames);</code></pre>
<p>  → 새로운 배열을 <strong>return</strong> 한다는 차이점❗</p>
</li>
</ul>
<h3 id="02-할-일-정리">02. 할 일 정리</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const list = document.querySelector(&#39;.list&#39;);
  const data = [{
      title: &#39;자바스크립트 공부하기&#39;,
      isClear: true,
    }, {
      title: &#39;쓰레기 분리수거&#39;,
      isClear: false,
    }, {
      title: &#39;고양이 밥주기&#39;,
      isClear: true,
    }, {
      title: &#39;독서하기&#39;,
      isClear: false,
    }, {
      title: &#39;영어 공부하기&#39;,
      isClear: false,
    }
  ];

  // 여기에 코드를 작성해 주세요.
  data.forEach((todo, i) =&gt; { // 1번 조건
    const li = document.createElement(&#39;li&#39;); // 2번 조건

    if (todo.isClear) {
      li.classList.add(&#39;item&#39;, &#39;done&#39;); // 4번 조건
    } else {
      li.classList.add(&#39;item&#39;); // 3번 조건
    }

    li.textContent = `${i + 1}. ${todo.title}`; // 5번 조건
    list.appendChild(li); // 6번 조건
  });</code></pre>
</li>
</ul>
<h3 id="03-셜록-훈즈">03. 셜록 훈즈</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const quiz = [&#39;YUMMY&#39;, &#39;COUNT&#39;, &#39;ABUSE&#39;, &#39;SOUND&#39;, &#39;SWING&#39;];

  // 여기에 코드를 작성하세요
  const answer = quiz.map((word, i) =&gt; {
    return word[i];
  });

  // 테스트 코드
  console.log(answer);</code></pre>
</li>
</ul>
<h3 id="❗04-배열-메소드-2--filter와-find">❗04. 배열 메소드 2 : filter와 find</h3>
<ul>
<li><p><strong><code>filter</code></strong></p>
<pre><code class="language-jsx">  const devices = [
      { name: &#39;GalaxyNote&#39;, brand: &#39;Samsung&#39; },
      { name: &#39;MacbookPro&#39;, brand: &#39;Apple&#39; },
      { name: &#39;iPad&#39;, brand: &#39;Apple&#39; },
      { name: &#39;GalaxyWatch&#39;, brand: &#39;Samsung&#39; },
      { name: &#39;iMac&#39;, brand: &#39;Apple&#39; },
      { name: &#39;GalaxyBuds&#39;, brand: &#39;Samsung&#39; },
      { name: &#39;Gram&#39;, brand: &#39;LG&#39; },
      { name: &#39;GalaxyBook&#39;, brand: &#39;Samsung&#39; },
      { name: &#39;SurfacePro&#39;, brand: &#39;Microsoft&#39; },
      { name: &#39;ZenBook&#39;, brand: &#39;Asus&#39; },
      { name: &#39;MacbookAir&#39;, brand: &#39;Apple&#39; },
  ];

  const apples = devices.filter((el) =&gt; el.brand === &#39;Apple&#39;);

  console.log(apples);</code></pre>
<p>  → filtering 된 새로운 <strong>배열</strong> 생성</p>
</li>
<li><p><strong><code>find</code></strong></p>
<pre><code class="language-jsx">  const myLaptop = devices.find((el) =&gt; el.name === &#39;MacbookAir&#39;);

  console.log(myLaptop);</code></pre>
<p>  → 한가지의 <strong>값</strong>을 찾기 (같은 값이 여러개라면 가장 위에 있는 것을 기준으로 선택) → 반복문이 중단</p>
</li>
</ul>
<h3 id="05-서울-김서방-찾지-않기">05. 서울 김서방 찾지 않기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const seoul = [&#39;김영훈&#39;, &#39;김윤수&#39;, &#39;김동욱&#39;, &#39;강대위&#39;, &#39;김영준&#39;,
    &#39;김규식&#39;, &#39;김태호&#39;, &#39;김효신&#39;, &#39;손효준&#39;, &#39;김현승&#39;, &#39;김재하&#39;, &#39;김유나&#39;,
    &#39;김재훈&#39;, &#39;김혜선&#39;, &#39;김민환&#39;, &#39;김규리&#39;, &#39;김소원&#39;, &#39;김우재&#39;, &#39;최영준&#39;,
    &#39;김태순&#39;, &#39;김종훈&#39;, &#39;김성환&#39;, &#39;김승용&#39;, &#39;김지혜&#39;, &#39;이승욱&#39;, &#39;김도현&#39;,
    &#39;김승규&#39;, &#39;윤하은&#39;, &#39;김유진&#39;, &#39;김정민&#39;, &#39;김혜정&#39;, &#39;김예진&#39;, &#39;김여진&#39;,
    &#39;김성희&#39;, &#39;김혜수&#39;, &#39;김인선&#39;, &#39;김상필&#39;, &#39;김혜진&#39;, &#39;서상원&#39;, &#39;김상혜&#39;,
    &#39;김민기&#39;, &#39;김그루&#39;, &#39;김희지&#39;];

  // 여기에 코드를 작성하세요
  const notKims = seoul.filter((name) =&gt; {
    return name[0] !== &#39;김&#39;;
  });

  console.log(notKims); // (6) [&quot;강대위&quot;, &quot;손효준&quot;, &quot;최영준&quot;, &quot;이승욱&quot;, &quot;윤하은&quot;, &quot;서상원&quot;]</code></pre>
</li>
</ul>
<h3 id="06-이메일-찾기">06. 이메일 찾기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const nameInput = document.querySelector(&#39;#user-name&#39;);
  const phoneInput = document.querySelector(&#39;#phone-number&#39;);
  const findBtn = document.querySelector(&#39;#find&#39;);

  const data = [
    { userName: &#39;막대기&#39;, phoneNumber: &#39;01012341111&#39;, email: &#39;stick@go_do_it.kr&#39; },
    { userName: &#39;young&#39;, phoneNumber: &#39;01012342222&#39;, email: &#39;kang@go_do_it.kr&#39; },
    { userName: &#39;코린이&#39;, phoneNumber: &#39;01012343333&#39;, email: &#39;corin2@go_do_it.kr&#39; },
    { userName: &#39;captain&#39;, phoneNumber: &#39;01012344444&#39;, email: &#39;crew@go_do_it.kr&#39; },
    { userName: &#39;YH&#39;, phoneNumber: &#39;01012345555&#39;, email: &#39;whyH@go_do_it.kr&#39; },
    { userName: &#39;망고쥬스&#39;, phoneNumber: &#39;01012346666&#39;, email: &#39;drinkMango@go_do_it.kr&#39; },
    { userName: &#39;nemoming&#39;, phoneNumber: &#39;01012347777&#39;, email: &#39;ractAngle@go_do_it.kr&#39; },
    { userName: &#39;강그루&#39;, phoneNumber: &#39;01012348888&#39;, email: &#39;riverTree@go_do_it.kr&#39; },
    { userName: &#39;개룩발룩&#39;, phoneNumber: &#39;01012349999&#39;, email: &#39;checkShirts@go_do_it.kr&#39; },
    { userName: &#39;오렌지쥬스&#39;, phoneNumber: &#39;01012341010&#39;, email: &#39;delmonte@go_do_it.kr&#39; },
  ];

  function findEmail() {
    const nameValue = nameInput.value;
    const phoneValue = phoneInput.value;

    // 여기에 코드를 작성하세요
    const user = data.find((el) =&gt; nameValue === el.userName &amp;&amp; phoneValue === el.phoneNumber);

    const message = user
      ? `${user.userName}님의 이메일은 ${user.email} 입니다.`
      : &#39;이메일을 찾을 수 없습니다. 입력 정보를 다시 확인해 주세요.&#39;;

    alert(message);
  }

  findBtn.addEventListener(&#39;click&#39;, findEmail);</code></pre>
</li>
</ul>
<h3 id="❗07-배열-메소드-3--some과-every">❗07. 배열 메소드 3 : some과 every</h3>
<pre><code class="language-jsx">// some과 every
const numbers = [1, 3, 5, 7, 9];

// some: 조건을 만족하는 요소가 1개 이상 있는지
const someReturn = numbers.some((el, i) =&gt; {
    console.log(&#39;some: &#39;, i);
    return el &gt; 5;
});

// every: 모든 요소가 조건을 만족하는지 -&gt; 조건을 만족하지 않는 요소가 있다면 바로 중단
const everyReturn = numbers.every((el, i) =&gt; {
    console.log(&#39;every: &#39;, i);
    return el &gt; 5;
});

console.log(&#39;some: &#39;, someReturn);
console.log(&#39;every: &#39;, everyReturn);</code></pre>
<h3 id="08-이중-스파이가-있다">08. 이중 스파이가 있다</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const spait = [
    { codeName: &#39;ApplePie&#39;, members: [&#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;] },
    { codeName: &#39;BigBoss&#39;, members: [&#39;스파이&#39;, &#39;스파이&#39;, &#39;스과이&#39;, &#39;스파이&#39;, &#39;스파이&#39;] },
    { codeName: &#39;CEO&#39;, members: [&#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;습하이&#39;, &#39;스파이&#39;] },
    { codeName: &#39;DeathNote&#39;, members: [&#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;] },
    { codeName: &#39;EarlyBird&#39;, members: [&#39;스파이&#39;, &#39;스마이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;] },
    { codeName: &#39;Faker&#39;, members: [&#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;, &#39;스파이&#39;] },
  ];

  function checkSpy(team) {
    // 여기에 코드를 작성하세요
    const result = team.members.some((member) =&gt; member !== &#39;스파이&#39;);
    let message = &#39;&#39;;

    if (result) {
      message = `[주의!] 팀 ${team.codeName} 에 이중 스파이가 있습니다!`;
    } else {
      message = `팀 ${team.codeName} 에는 이중 스파이가 없습니다.`;
    }

    console.log(message);
  }

  // 테스트 코드
  spait.forEach((team) =&gt; checkSpy(team));</code></pre>
</li>
</ul>
<h3 id="❗09-배열-메소드-4--reduce">❗09. 배열 메소드 4 : reduce</h3>
<pre><code class="language-jsx">// reduce
const numbers = [1, 2, 3, 4];

numbers.reduce((acc, el, i, arr) =&gt; {
    return nextAccValue;
}, initialAccValue);</code></pre>
<h3 id="10-세계적인-경력의-소유자">10. 세계적인 경력의 소유자</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const data = [ 
    { company: &#39;Naber&#39;, month: 3 },
    { company: &#39;Amajohn&#39;, month: 12 },
    { company: &#39;Coogle&#39;, month: 10 },
    { company: &#39;Ittel&#39;, month: 6 },
    { company: &#39;Sasung&#39;, month: 4 },
    { company: &#39;CaCao&#39;, month: 3 },
    { company: &#39;Microhard&#39;, month: 17 },
  ];

  // 여기에 코드를 작성하세요
  const totalCareer = data.reduce((acc, el) =&gt; acc + el.month, 0);

  console.log(`상원이의 경력은 총 ${totalCareer}개월입니다.`);</code></pre>
</li>
</ul>
<h3 id="11-sort-reverse">11. sort, reverse</h3>
<ul>
<li><p><strong><code>sort</code></strong></p>
<pre><code class="language-jsx">  const numbers = [1, 10, 4, 21, 36000];

  // 오름차순 정렬
  numbers.sort((a, b) =&gt; a - b);
  console.log(numbers); // (5) [1, 4, 10, 21, 36000]

  // 내림차순 정렬
  numbers.sort((a, b) =&gt; b - a);
  console.log(numbers); // (5) [36000, 21, 10, 4, 1]</code></pre>
<p>  → 메소드를 실행하는 원본 배열의 요소들을 정렬</p>
</li>
<li><p><strong><code>reverse</code></strong></p>
<pre><code class="language-jsx">  const letters = [&#39;a&#39;, &#39;c&#39;, &#39;b&#39;];
  const numbers = [421, 721, 353];

  letters.reverse();
  numbers.reverse();

  console.log(letters); // (3) [&quot;b&quot;, &quot;c&quot;, &quot;a&quot;]
  console.log(numbers); // (3) [353, 721, 421]
</code></pre>
<p>  → 배열의 순서를 뒤집어 주는 메소드</p>
<p>  → 원본 배열의 요소들을 뒤집어 정렬</p>
</li>
</ul>
<h3 id="12-map-set">12. Map, Set</h3>
<ul>
<li><p><strong><code>Map</code></strong></p>
<ul>
<li><p>map.set(key, value): key를 이용해 value를 추가하는 메소드.</p>
</li>
<li><p>map.get(key): key에 해당하는 값을 얻는 메소드. key가 존재하지 않으면 undefined를 반환.</p>
</li>
<li><p>map.has(key): key가 존재하면 <code>true</code>, 존재하지 않으면 <code>false</code>를 반환하는 메소드.</p>
</li>
<li><p>map.delete(key): key에 해당하는 값을 삭제하는 메소드.</p>
</li>
<li><p>map.clear(): Map 안의 모든 요소를 제거하는 메소드.</p>
</li>
<li><p>map.size: 요소의 개수를 반환하는 프로퍼티. (메소드가 아닌 점 주의! 배열의 length 프로퍼티와 같은 역할)</p>
<p>→ 메소드를 통해 값을 다루기 때문에, 다양한 자료형을 key로 활용할 수 있다는 장점</p>
</li>
</ul>
</li>
<li><p><strong><code>Set</code></strong></p>
<ul>
<li><p>set.add(value): 값을 추가하는 메소드. (메소드를 호출한 자리에는 추가된 값을 가진 Set 자신을 반환.)</p>
</li>
<li><p>set.has(value): Set 안에 값이 존재하면 <code>true</code>, 아니면 <code>false</code>를 반환하는 메소드.</p>
</li>
<li><p>set.delete(value): 값을 제거하는 메소드. (메소드를 호출한 자리에는 셋 내에 값이 있어서 제거에 성공하면 true, 아니면 false를 반환.)</p>
</li>
<li><p>set.clear(): Set 안의 모든 요소를 제거하는 메소드.</p>
</li>
<li><p>set.size: 요소의 개수를 반환하는 프로퍼티. (메소드가 아닌 점 주의! 배열의 length 프로퍼티와 같은 역할)</p>
<p>→ ❗<strong>중복을 허용하지 않는 값들을 모을 때 유용</strong></p>
</li>
</ul>
</li>
</ul>
<h2 id="6️⃣-자바스크립트-모듈">6️⃣ 자바스크립트 모듈</h2>
<h3 id="01-모듈이란">01. 모듈이란?</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/a54f46b7-f1d8-4634-99a7-3deb5f106918/image.png" alt=""></p>
<ol>
<li>코드를 효율적으로 관리할 수 있다!</li>
<li>다른 프로그램에서 재사용할 수 있다!</li>
</ol>
<h3 id="02-04-모듈-파일의-조건">02, 04. 모듈 파일의 조건</h3>
<p>→ 다른 파일과 함수명이 동일하면 안 됨</p>
<p>→ 따라서, 모듈 스코프를 가지고 있어야 함 (위의 문제 해결) <code>&lt;script type=”module” src=”index.js”&gt;&lt;/script&gt;</code></p>
<h3 id="03-live-server-설치하기">03. Live Server 설치하기</h3>
<p><code>type=”module”</code>을 사용했을 때 발생하는 에러 → Live Server로 서버를 통해 실행 시 해결</p>
<h3 id="05-모듈-문법">05. 모듈 문법</h3>
<p><code>export</code>를 통해 다른 파일에서 사용할 수 있도록 ➕ <code>import { title, print } from ‘./other.js’;</code>처럼 다른 파일에서 불러와서 사용</p>
<p>→ 여러개의 파일을 하나의 파일에 불러와서 html에서는 하나의 js만 사용</p>
<h3 id="06-메뉴-추가-기능-붙이기">06. 메뉴 추가 기능 붙이기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  const addInput = document.querySelector(&#39;.add-input&#39;);
  const list = document.querySelector(&#39;.list&#39;);

  function add(data) {
    const inputValue = addInput.value;
    const index = data.length;

    const li = document.createElement(&#39;li&#39;);
    li.classList.add(&#39;item&#39;);
    li.innerHTML = `&lt;b&gt;${index + 1}&lt;/b&gt;${inputValue}&lt;button class=&quot;del-btn&quot; data-index=&quot;${index}&quot;&gt;x&lt;/button&gt;`;
    list.append(li);

    data.push(inputValue);

    addInput.value = &#39;&#39;;
    addInput.focus();
  }

  function emptyAlert() {
    alert(&#39;고민되는 메뉴를 입력해 주세요.&#39;);
    addInput.focus();
  }

  function maxAlert() {
    alert(&#39;메뉴는 최대 5개까지만 고민할 수 있습니다.&#39;);
    addInput.value = &#39;&#39;;
  }

  // 아래 코드를 수정해 주세요
  export function addMenu(data) {
    const inputValue = addInput.value;

    if (inputValue === &#39;&#39;) {
      emptyAlert();
    } else if (data.length &gt; 4) {
      maxAlert();
    } else {
      add(data);
    }
  }</code></pre>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  import { addMenu } from &quot;./add.js&quot;;

  const data = [];
  const addBtn = document.querySelector(&#39;.add-btn&#39;);
  const addInput = document.querySelector(&#39;.add-input&#39;);

  addBtn.addEventListener(&#39;click&#39;, () =&gt; addMenu(data));
  addInput.addEventListener(&#39;keypress&#39;, (e) =&gt; e.code === &#39;Enter&#39; &amp;&amp; addMenu(data));</code></pre>
</li>
</ul>
<h3 id="0708-이름-바꾸기">07~08. 이름 바꾸기</h3>
<p><code>import { title **as** printerTitle, print } from ‘./other.js’;</code></p>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  import { addMenu } from &#39;./add.js&#39;;
  // 여기에 코드를 작성하세요
  import { deleteMenuByIndex as deleteMenu } from &#39;./delete.js&#39;;

  const data = [];
  const addBtn = document.querySelector(&#39;.add-btn&#39;);
  const addInput = document.querySelector(&#39;.add-input&#39;);
  const list = document.querySelector(&#39;.list&#39;);

  addBtn.addEventListener(&#39;click&#39;, () =&gt; addMenu(data));
  addInput.addEventListener(&#39;keypress&#39;, (e) =&gt; e.code === &#39;Enter&#39; &amp;&amp; addMenu(data));
  list.addEventListener(&#39;click&#39;, ({ target }) =&gt; target.tagName === &#39;BUTTON&#39; &amp;&amp; deleteMenu(data, target.dataset.index));</code></pre>
</li>
</ul>
<h3 id="09-한꺼번에-다루기">09. 한꺼번에 다루기</h3>
<p><code>import * as otherJS from ‘./other.js’;</code></p>
<p>→ <code>console.log(otherJS.title);</code></p>
<p><code>export { title, print };</code></p>
<p>→ <strong>이름 변경</strong>시 export할 때 미리 변경하기
     ex. <code>export { title **as** printerTitle , print };</code></p>
<h3 id="10-태그-정리하기">10. 태그 정리하기</h3>
<ul>
<li><p>실습 코드</p>
<p>  <code>import { addBtn, addInput, list } from &#39;./tags.js&#39;;</code></p>
<p>  <code>import { addInput, list } from &#39;./tags.js&#39;;</code></p>
<p>  <code>import { list } from &#39;./tags.js&#39;;</code></p>
<pre><code class="language-jsx">  const addBtn = document.querySelector(&#39;.add-btn&#39;);
  const addInput = document.querySelector(&#39;.add-input&#39;);
  const list = document.querySelector(&#39;.list&#39;);

  // 여기에 코드를 작성해 주세요. ( 모든 변수를 한 번에 export해 주세요. )
  export { addBtn, addInput, list };</code></pre>
</li>
</ul>
<h3 id="11-default-export">11. default export</h3>
<p><code>export default title;</code></p>
<p>→ 딱 한번만 사용 가능 (하나의 대상만을 export)</p>
<p><code>import title from ‘./other.js’;</code></p>
<p>→ 중괄호 없이 사용 가능</p>
<h3 id="12-간결하게-기능-붙이기">12. 간결하게 기능 붙이기</h3>
<ul>
<li><p>실습 코드</p>
<p>  <code>export default addMenu;</code></p>
<p>  <code>export default deleteMenu;</code></p>
<p>  <code>export default rollMenu;</code></p>
<pre><code class="language-jsx">  import { addBtn, addInput, list, rollBtn } from &#39;./tags.js&#39;;
  // 여기에 코드를 작성하세요
  import addMenu from &#39;./add.js&#39;;
  import deleteMenu from &#39;./delete.js&#39;;
  import rollMenu from &#39;./roll.js&#39;;

  const data = [];

  addBtn.addEventListener(&#39;click&#39;, () =&gt; addMenu(data));
  addInput.addEventListener(&#39;keypress&#39;, (e) =&gt; e.code === &#39;Enter&#39; &amp;&amp; addMenu(data));
  list.addEventListener(&#39;click&#39;, ({ target }) =&gt; target.tagName === &#39;BUTTON&#39; &amp;&amp; deleteMenu(data, target.dataset.index));
  rollBtn.addEventListener(&#39;click&#39;, () =&gt; list.classList.contains(&#39;rolling&#39;) || rollMenu(data));</code></pre>
</li>
</ul>
<h3 id="13-복습과-활용">13. 복습과 활용</h3>
<p>생략</p>
<h3 id="14-가져와서-다시-내보내기">14. 가져와서 다시 내보내기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  import { addBtn, addInput, list, rollBtn } from &#39;./tags.js&#39;;
  // 여기에 코드를 작성하세요
  import { addMenu, deleteMenu, rollMenu } from &#39;./functions.js&#39;;

  const data = [];

  addBtn.addEventListener(&#39;click&#39;, () =&gt; addMenu(data));
  addInput.addEventListener(&#39;keypress&#39;, (e) =&gt; e.code === &#39;Enter&#39; &amp;&amp; addMenu(data));
  list.addEventListener(&#39;click&#39;, ({ target }) =&gt; target.tagName === &#39;BUTTON&#39; &amp;&amp; deleteMenu(data, target.dataset.index));
  rollBtn.addEventListener(&#39;click&#39;, () =&gt; list.classList.contains(&#39;rolling&#39;) || rollMenu(data));</code></pre>
<pre><code class="language-jsx">  // 여기에 코드를 작성해 주세요.
  import addMenu from &#39;./functions/add.js&#39;;
  import deleteMenu from &#39;./functions/delete.js&#39;;
  import rollMenu from &#39;./functions/roll.js&#39;;

  export { addMenu, deleteMenu, rollMenu };</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[이미지 프레임 캡쳐 다운 (html2canvas, html-to-image, object-fit, heic2any, file-saver) feat.네컷사진, React]]></title>
            <link>https://velog.io/@may_05/%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%94%84%EB%A0%88%EC%9E%84-%EC%BA%A1%EC%B3%90-%EB%8B%A4%EC%9A%B4-html2canvas-html-to-image-object-fit-heic2any-feat.%EB%84%A4%EC%BB%B7%EC%82%AC%EC%A7%84-React</link>
            <guid>https://velog.io/@may_05/%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%94%84%EB%A0%88%EC%9E%84-%EC%BA%A1%EC%B3%90-%EB%8B%A4%EC%9A%B4-html2canvas-html-to-image-object-fit-heic2any-feat.%EB%84%A4%EC%BB%B7%EC%82%AC%EC%A7%84-React</guid>
            <pubDate>Fri, 31 May 2024 19:19:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/may_05/post/8fd8ec48-1aed-4a5c-aeef-02b21b40768f/image.png" alt=""></p>
<h2 id="이미지-프레임을-캡쳐하고-다운하는-라이브러리">이미지 프레임을 캡쳐하고 다운하는 라이브러리</h2>
<blockquote>
<p>html2canvas</p>
</blockquote>
<p>→ 여러 벨로그를 통해 이번에 진행한 프로젝트에서 이미지 프레임 부분을 캡쳐 후 다운한 방법, 그리고 라이브러리를 소개하려고 한다.</p>
<hr>
<h3 id="문제-발생-html-to-image">문제 발생 (html-to-image)</h3>
<p>사실 기존에는,, html-to-image라는 라이브러리를 사용하려고 했다. html2canvas 라이브러리를 사용하면서 적용해준 css가 작동하지 않는 경우를 서치를 통해 보았기 때문이다. 하지만 가장 큰 이슈로 인해 html2canvas를 사용하게 되었다.</p>
<blockquote>
<p>safari 및 ios 에서 제대로 저장되지 않는 이슈</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/may_05/post/b7fe91f7-3f71-4ad1-b9de-46be426331c3/image.JPEG" alt=""></p>
<p>→ 위의 사진과 같이 프레임 없이 사진의 공간 부분만, 혹은 프레임과 라벨까지만 저장되는 경우가 대다수였고 랜덤으로 저장이 잘 되는 것을 확인할 수 있다.</p>
<ul>
<li><a href="https://velog.io/@shinpanda/IOS-%ED%99%98%EA%B2%BD%EC%84%9C-html-to-image-png-%EB%8B%A4%EC%9A%B4%EB%A1%9C%EB%93%9C-%EB%AC%B8%EC%A0%9C1">https://velog.io/@shinpanda/IOS-환경서-html-to-image-png-다운로드-문제1</a></li>
<li><a href="https://velog.io/@uuuuooii/html-to-image-iOS-Safari%EC%97%90%EC%84%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80%EA%B0%80-%ED%91%9C%EC%8B%9C%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%8A%88">https://velog.io/@uuuuooii/html-to-image-iOS-Safari에서-이미지가-표시되지-않는-이슈</a></li>
</ul>
<p>→ 위의 두 벨로그를 참고하여 <strong>일부 사파리에서는 캔버스를 제대로 렌더링하기 위해 약간의 지연이 생긴다</strong>는 것을 알 수 있었다. 하지만 렌더링 시간을 과하게 늘리는 방법도, 여러번 렌더링해서 시간을 늘리는 방법도 바람직하지 않으며 safari 환경에서만 수정한다고 해서 만능적인 해결이 될 순 없다는 것을 깨닫고 과감하게 라이브러리를 바꿔보기로 결정했다.</p>
<h3 id="문제-해결-과정-html2canvas">문제 해결 과정 (html2canvas)</h3>
<p>정말 하루동안 붙잡고 있었던 게 무색하게도,, html2canvas를 사용하자마자 safari에서도 원하던 대로 잘 실행되기 시작했다. 하지만 바로 다른 에러를 마주할 수 있었다 🥲</p>
<blockquote>
<p>html2canvas의 object-fix 미지원으로 인한 이미지 비율 문제</p>
</blockquote>
<p><a href="https://html2canvas.hertzen.com/features">공식 문서</a>에 따르면 현재 지원하지 않는 CSS 리스트는 다음과 같다.</p>
<ul>
<li><a href="https://github.com/niklasvh/html2canvas/issues/966">background-blend-mode</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/1287">border-image</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/552">box-decoration-break</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/pull/1086">box-shadow</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/493">filter</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/pull/1085">font-variant-ligatures</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/580">mix-blend-mode</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/1064">object-fit</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/1162">repeating-linear-gradient()</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/1258">writing-mode</a></li>
<li><a href="https://github.com/niklasvh/html2canvas/issues/732">zoom</a></li>
</ul>
<p>하지만 프레임의 크기에 맞추어 사진을 넣어주고 싶었고 그렇기에 사용하고 있던 <code>object-fit: cover;</code> 라는 코드를 대체하여 코드를 작성할 필요가 있었다.</p>
<p>내가 사용한 방법은 2가지이고 그 중에서 2번 방법을 사용하였다.</p>
<ol>
<li>div 태그의 background-image 의 url 에 이미지를 삽입하여 다운</li>
<li>props를 전달하여 경우에 따라 width, height 조절</li>
</ol>
<ul>
<li><a href="https://velog.io/@rachel28/next-image-html2canvas-html-to-image">https://velog.io/@rachel28/next-image-html2canvas-html-to-image</a></li>
</ul>
<p>→ 위의 벨로그를 참고하여 background-image 의 url 에 이미지를 삽입하여 (props로 url 전달) 이미지 비율을 맞추는 것에는 성공했지만 <strong>이미지의 해상도가 저하되는 문제</strong>가 발생하였다. 🙃 따라서, 다른 방법을 고안해야했고 그게 바로 2번 방법이었다</p>
<p>→ 벨로그에 추천한 patch-package를 사용해 직접 라이브러리에 object-fit 속성 코드를 삽입하는 방법은 배포 환경에서 사용해야하는 서비스이기 때문에 패스했다</p>
<h2 id="object-fit-cover-를-대체하는-방법">object-fit: cover; 를 대체하는 방법</h2>
<p>상위 요소에 overflow: hidden;을 적용을 한 후</p>
<blockquote>
<p>가로가 긴 사진인지 세로가 긴 사진인지 판단 후 props를 전달하여 100%가 될 경우를 적용</p>
</blockquote>
<pre><code class="language-jsx">useEffect(() =&gt; {
    const setDirection = (image) =&gt; {
      const width = image.naturalWidth;
      const height = image.naturalHeight;

      if (width === height) {
        // 가로와 세로 크기가 같을 경우
        setHorizontalImage(true); // 가로로 처리
      } else if (width &gt; height) {
        setHorizontalImage(true); // 가로 이미지
      } else {
        setHorizontalImage(false); // 세로 이미지
      }
    };

    const image = document.getElementById(`img${index}`);
    if (image) {
      image.onload = () =&gt; {
        setDirection(image);
      };
    }
  }, [imagePreview]);


// 구조 부분
            &lt;P.FilePreview $horizontal={horizontalImage}&gt;
        {imagePreview &amp;&amp; &lt;img id={`img${index}`} src={imagePreview} alt=&quot;Preview&quot; /&gt;}
      &lt;/P.FilePreview&gt;</code></pre>
<p>위와 같이 naturalWidth를 받아 이미지의 사이즈를 판단한 후 props를 전달하는 방식을 선택했다. styled-component를 사용하고 있었고 따라서 css는 다음과 같이 적용시켜주었다.</p>
<pre><code class="language-jsx">export const FilePreview = styled.div`
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 5;

  ${({ $horizontal }) =&gt;
    $horizontal
      ? `
    img {
      height: 100%;
      width: auto;
    }
  `
      : `
    img {
      height: auto;
      width: 100%;
    }
  `}
`;</code></pre>
<h2 id="input-→-heic-확장자-파일-문제-해결">Input → heic 확장자 파일 문제 해결</h2>
<p>테스트를 진행하다가 마주친 기묘한 문제,,</p>
<p>Input에서 아래와 같이 type을 파일로 받을 때 image/* 을 accept 시켜주어도 현재 아이폰 카메라로 찍히는 사진의 확장자인 heic는 허용해주지 않는 문제를 발견하였다. 따라서 .heic도 추가해주도록 코드를 추가적으로 작성했다.</p>
<pre><code class="language-jsx">&lt;P.File
    type=&quot;file&quot;
    name={`file${index}`}
    id={`file${index}`}
    accept=&quot;image/*, .heic&quot;
    onChange={handleProfileImageChange}
/&gt;</code></pre>
<p>heic 이미지를 받을 수 있게 처리해주는 handleProfileImageChange 함수는 다음과 같다.</p>
<blockquote>
<p>heic2any 라는 라이브러리를 사용</p>
</blockquote>
<pre><code class="language-jsx">const handleProfileImageChange = async (event) =&gt; {
    const file = event.target.files[0];
    if (file) {
      // HEIC 이미지인지 확인
      const isHeic = file.type === &quot;image/heic&quot;;

      if (isHeic) {
        // HEIC 이미지일 경우에만 디코딩
        const imageBuffer = await file.arrayBuffer();

        // 이미지를 Blob으로 변환
        const imageBlob = new Blob([imageBuffer]);
        const jpegBlob = await heic2any({ blob: imageBlob, toType: &quot;image/jpeg&quot; });

        // Blob URL 생성
        const imageUrl = URL.createObjectURL(jpegBlob);
        setImagePreview(index, imageUrl);
      } else {
        // HEIC가 아닌 경우는 기존 방식으로 처리
        const reader = new FileReader();
        reader.onloadend = () =&gt; {
          setImagePreview(index, reader.result);
        };
        reader.readAsDataURL(file);
      }
    }
  };</code></pre>
<h2 id="전체-해상도-문제-개선">전체 해상도 문제 개선</h2>
<p>사실 이 문제의 경우, 라이브러리를 변경해서 사용하고 싶어 서치하다가 <a href="https://velog.io/@sumi-0011/html2canvas">해당 글</a>을 발견하고 미리 적용해준 부분이다.</p>
<blockquote>
<p>const canvas = await html2canvas(ref.current, { scale: 4 });</p>
</blockquote>
<p>→ 중요한 부분은 <code>{ scale: 4 }</code>을 통해서 다운받는 이미지의 사이즈를 4배로 키워 출력한 것이다.</p>
<pre><code class="language-jsx">const onCaptureClick = async () =&gt; {
    if (ref.current === null) {
      return;
    }

    const captureImg = async () =&gt; {
      if (ref.current) {
        const canvas = await html2canvas(ref.current, { scale: 4 });
        const element = document.createElement(&quot;a&quot;);
        element.href = canvas.toDataURL(&quot;image/png&quot;);
        element.download = &quot;2024 근화제 찬란.png&quot;;
        element.click();
      }
    };

    captureImg();
  };</code></pre>
<h2 id="브라우저-별-다운로드-문제-해결">브라우저 별 다운로드 문제 해결</h2>
<p>QA를 진행하면서 발견된 문제로,, PC와 아이폰 기본 브라우저인 사파리와 등을 제외하고 모바일 크롬 등에서 사진 다운로드가 진행되지 않은 문제가 있는 것을 발견할 수 있었다. 그래서 추가로 라이브러리를 사용해주었다.</p>
<blockquote>
<p>file-saver</p>
</blockquote>
<p>그래서 위의 코드를 아래와 같은 코드로 수정해주었다.</p>
<pre><code class="language-jsx">const onCaptureClick = async () =&gt; {
    if (ref.current === null) {
      return;
    }

    const captureImg = async () =&gt; {
      if (ref.current) {
        const canvas = await html2canvas(ref.current, { scale: 4 });
        canvas.toBlob((blob) =&gt; {
          if (blob !== null) {
            saveAs(blob, &quot;2024 근화제 찬란.png&quot;);
          }
        });
      }
    };

    captureImg();
  };</code></pre>
<h2 id="최종-결과">최종 결과</h2>
<p><img src="https://velog.velcdn.com/images/may_05/post/5877ce2e-eda7-4c80-8cc3-20f3753f9253/image.png" alt=""></p>
<p>위와 같이 원하는 프레임에 원하는 사진을 비율에 맞추어 잘 저장시켜준 것을 볼 수 있다.</p>
<blockquote>
<p>즉, 설치해야 하는 라이브러리는 총 3가지이다.</p>
</blockquote>
<ol>
<li>html2canvas</li>
<li>heic2any</li>
<li>file-saver<blockquote>
</blockquote>
</li>
</ol>
<p><strong>일부 코드</strong> (프레임 속 사진 박스 컴포넌트)</p>
<pre><code class="language-jsx">import React, { useState, useEffect } from &quot;react&quot;;
import heic2any from &quot;heic2any&quot;;
import * as P from &quot;../styles/PhotoBoxStyle&quot;;

import PhotoCam from &quot;../img/photo_cam_32x32.png&quot;;

function PhotoBox({ index, setImagePreview, imagePreview }) {
  const [horizontalImage, setHorizontalImage] = useState(false);

  const handleProfileImageChange = async (event) =&gt; {
    const file = event.target.files[0];
    if (file) {
      // HEIC 이미지인지 확인
      const isHeic = file.type === &quot;image/heic&quot;;

      if (isHeic) {
        // HEIC 이미지일 경우에만 디코딩
        const imageBuffer = await file.arrayBuffer();

        // 이미지를 Blob으로 변환
        const imageBlob = new Blob([imageBuffer]);
        const jpegBlob = await heic2any({ blob: imageBlob, toType: &quot;image/jpeg&quot; });

        // Blob URL 생성
        const imageUrl = URL.createObjectURL(jpegBlob);
        setImagePreview(index, imageUrl);
      } else {
        // HEIC가 아닌 경우는 기존 방식으로 처리
        const reader = new FileReader();
        reader.onloadend = () =&gt; {
          setImagePreview(index, reader.result);
        };
        reader.readAsDataURL(file);
      }
    }
  };

  useEffect(() =&gt; {
    const setDirection = (image) =&gt; {
      const width = image.naturalWidth;
      const height = image.naturalHeight;

      if (width === height) {
        // 가로와 세로 크기가 같을 경우
        setHorizontalImage(true); // 가로로 처리
      } else if (width &gt; height) {
        setHorizontalImage(true); // 가로 이미지
      } else {
        setHorizontalImage(false); // 세로 이미지
      }
    };

    const image = document.getElementById(`img${index}`);
    if (image) {
      image.onload = () =&gt; {
        setDirection(image);
      };
    }
  }, [imagePreview]);

  return (
    &lt;P.PhotoBox&gt;
      &lt;P.UploadLabel htmlFor={`file${index}`}&gt;
        {!imagePreview &amp;&amp; &lt;img src={PhotoCam} alt=&quot;이미지 업로드&quot; /&gt;}
      &lt;/P.UploadLabel&gt;
      &lt;P.File
        type=&quot;file&quot;
        name={`file${index}`}
        id={`file${index}`}
        accept=&quot;image/*, .heic&quot;
        onChange={handleProfileImageChange}
      /&gt;
      &lt;P.FilePreview $horizontal={horizontalImage}&gt;
        {imagePreview &amp;&amp; &lt;img id={`img${index}`} src={imagePreview} alt=&quot;Preview&quot; /&gt;}
      &lt;/P.FilePreview&gt;
    &lt;/P.PhotoBox&gt;
  );
}

export default PhotoBox;
</code></pre>
<pre><code class="language-jsx">import styled from &quot;styled-components&quot;;

export const PhotoBox = styled.div`
  width: 152px;
  height: 184px;
  background-color: rgba(255, 255, 255, 0.8);
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  overflow: hidden;

  input[type=&quot;file&quot;] {
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }
`;

export const UploadLabel = styled.label`
  width: 100%;
  height: 100%;
  cursor: pointer;

  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 15;

  position: absolute;
  left: 50%;
  transform: translateX(-50%);

  img {
    width: 32px;
    height: 32px;
  }

  &amp;:hover {
    background-color: rgba(0, 0, 0, 0.2);
  }
`;

export const File = styled.input``;

export const FilePreview = styled.div`
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 5;

  ${({ $horizontal }) =&gt;
    $horizontal
      ? `
    img {
      height: 100%;
      width: auto;
    }
  `
      : `
    img {
      height: auto;
      width: 100%;
    }
  `}
`;
</code></pre>
<p>화면을 캡쳐하여 프로젝트를 진행하고 싶은 누군가에게 도움이 되길,,, 🤧</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 프로그래밍 기초 (5)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-5</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-5</guid>
            <pubDate>Fri, 31 May 2024 19:02:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/may_05/post/7e4d1052-90dd-4fb7-bcad-d33cea6a2e45/image.jpg" alt=""></p>
<h1 id="ch5-프로그래밍과-데이터-in-javascript">Ch5. 프로그래밍과 데이터 in JavaScript</h1>
<hr>
<h2 id="1️⃣-객체">1️⃣ 객체</h2>
<h3 id="0102-객체와-프로퍼티">01~02. 객체와 프로퍼티</h3>
<p>→ 객체 (object) : 다양한 값을 저장할 수 있음</p>
<pre><code class="language-jsx">{
    brandName: &#39;코드잇&#39;,
    bornYear: 2017,
    isVeryNice: true,
    worstCourse: null
    // 값의 이름(key, property name): 값(value, property value) -&gt; 속성(property)
}</code></pre>
<p><em>️⃣ *</em>Property Name 주의 사항!**</p>
<ol>
<li><strong>첫 번째 글자</strong>는 반드시</li>
</ol>
<p><strong>문자, 밑줄(_), 달러 기호($)</strong> 중 하나로 시작!
2. <strong>띄어쓰기 금지!</strong>
3. <strong>하이픈(-) 금지!</strong>
4. But <code>‘1stCousre’</code>처럼 따옴표로 감싸준다면 가능 → 문자열이기 때문</p>
<p>#️⃣ <strong>Property Value</strong></p>
<ol>
<li>모든 자료형 가능</li>
<li>값에 객체도 가능 (객체 안에 객체)</li>
</ol>
<h3 id="03-객체에서-데이터-접근하기">03. 객체에서 데이터 접근하기</h3>
<ol>
<li><p>점 표기법 (objectName.propertyName) → 위의 1~3번을 지키지 않았을 경우 사용이 어려움</p>
<p> ex. <code>console.log(codeit.bornYear);</code></p>
</li>
<li><p>대괄호 표기법 (objectName[’propertyName’])</p>
<p> ex. <code>console.log(codeit[’born Year’]);</code> &amp; <code>console.log(codeit.bestCourse[’title’]);</code></p>
</li>
</ol>
<ul>
<li>없는 값을 표기하려고 한다면 <code>undefined</code> 출력</li>
</ul>
<h3 id="04-영어-단어장-1">04. 영어 단어장 1</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let myVoca = {
      // 여기에 코드를 작성하세요
    function: &#39;함수&#39;,
    variable: &#39;변수&#39;,
    constant: &#39;상수&#39;,
    local: &#39;지역의&#39;,
    global: &#39;전반적인&#39;
  };

  console.log(myVoca);
  console.log(myVoca.local);
  console.log(myVoca.constant);
  console.log(myVoca.function);</code></pre>
</li>
</ul>
<h3 id="05-객체-다루기">05. 객체 다루기</h3>
<ol>
<li>값 재할당 <code>codeit.name = ‘codeit’;</code></li>
<li>추가 가능 (마지막에 추가) <code>codeit.ceo = ‘강영훈’;</code></li>
<li>삭제 가능 <code>delete codeit.worstCourse;</code></li>
<li>객체 내부에 property 값 여부 확인하여 불린형 출력 <code>console.log(’name’ in codeit);</code> → <code>true</code></li>
</ol>
<h3 id="06-영어-단어장-2">06. 영어 단어장 2</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let myVoca = {
      function: &#39;함수&#39;,
      variable: &#39;변수&#39;,
      constant: &#39;상수&#39;,
      local: &#39;지역의&#39;,
      global: &#39;전반적인&#39;,
  };

  // 1. 이미 외운 단어 3개를 삭제해 주세요
  // 여기에 코드를 작성하세요
  delete myVoca.function;
  delete myVoca.constant;
  delete myVoca.local;

  console.log(myVoca);
  console.log(myVoca.constant);

  // 2. 오늘 외울 단어 4개를 추가해 주세요
  // 여기에 코드를 작성하세요
  myVoca.extend = &#39;확장하다&#39;;
  myVoca.export = &#39;내보내다&#39;;
  myVoca.import = &#39;불러오다&#39;;
  myVoca[&#39;default value&#39;] = &#39;기본값&#39;;

  console.log(myVoca);
  console.log(myVoca.export);

  // 3. default value의 뜻을 출력해 주세요
  // 여기에 코드를 작성하세요
  console.log(myVoca[&#39;default value&#39;])</code></pre>
</li>
</ul>
<h3 id="07-객체와-메소드">07. 객체와 메소드</h3>
<p>메소드 (Method) : property 값으로 함수를 넣은 것</p>
<pre><code class="language-jsx">let greetings = {
    sayHello: function (name) {
        console.log(`Hello ${name}!`);
    },
    sayHi: function () {
        console.log(&#39;Hi!&#39;);
    },
    sayBye: function () {
        console.log(&#39;Bye!&#39;);
    },
}

greetings.sayHello(&#39;Codeit&#39;);
greetings[&#39;sayHello&#39;](&#39;Codeit&#39;);</code></pre>
<h3 id="08-영어-단어장-3">08. 영어 단어장 3</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let myVoca = {
    // 코드를 작성해 주세요.
    addVoca: function (eng, kor) {
      myVoca[eng] = kor;
    },
    deleteVoca: function (eng) {
      delete myVoca[eng];
    },
    printVoca: function (eng) {
      console.log(`&quot;${eng}&quot;의 뜻은 &quot;${myVoca[eng]}&quot;입니다.`);
    }
  };

  // addVoca메소드 테스트 코드
  myVoca.addVoca(&#39;parameter&#39;, &#39;매개 변수&#39;);
  myVoca.addVoca(&#39;element&#39;, &#39;요소&#39;);
  myVoca.addVoca(&#39;property&#39;, &#39;속성&#39;);
  console.log(myVoca);

  // deleteVoca메소드 테스트 코드
  myVoca.deleteVoca(&#39;parameter&#39;);
  myVoca.deleteVoca(&#39;element&#39;);
  console.log(myVoca);

  // printVoca메소드 테스트 코드
  myVoca.printVoca(&#39;property&#39;);</code></pre>
</li>
</ul>
<h3 id="0910-forin-반복문">09~10. for…in 반복문</h3>
<pre><code class="language-jsx">let codeit = {
    name: &#39;코드잇&#39;,
    bornYear: 2017,
    isVeryNice: true,
    worstCourse: null,
    bestCourse: &#39;자바스크립트 프로그래밍 기초&#39;
}

for (let k in codeit) {
    console.log(k);
    console.log(codeit[k]);
}</code></pre>
<h3 id="11-순이들의-시험-결과">11. 순이들의 시험 결과</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let hyesoonScore = {
      &#39;데이터 모델링의 이해&#39;: 10,
      &#39;데이터 모델과 성능&#39;: 8,
      &#39;SQL 기본&#39;: 22,
      &#39;SQL 활용&#39;: 18,
      &#39;SQL 최적화 기본 원리&#39;: 20,
  };

  let minsoonScore = {
      &#39;데이터 모델링의 이해&#39;: 14,
      &#39;데이터 모델과 성능&#39;: 8,
      &#39;SQL 기본&#39;: 12,
      &#39;SQL 활용&#39;: 4,
      &#39;SQL 최적화 기본 원리&#39;: 16,
  };

  function passChecker(scoreObject) {
      // 여기에 코드를 작성하세요]
      let scoreTotal = 0;

    for (let key in scoreObject) {
      scoreTotal += scoreObject[key];
    }

    if(scoreTotal &gt;= 60) {
      console.log(&#39;축하합니다! 합격입니다!&#39;);
    } else {
      console.log(&#39;아쉽지만 불합격입니다..&#39;);
    }
  }

  passChecker(hyesoonScore);
  passChecker(minsoonScore);</code></pre>
</li>
</ul>
<h3 id="1213-date-객체">12~13. Date 객체</h3>
<ul>
<li>내장 객체 : 자바스크립트가 기본으로 가지고 있는 객체</li>
</ul>
<p>1️⃣</p>
<pre><code class="language-jsx">// Date
let myDate = new Date();

console.log(myDate);</code></pre>
<p>→ <code>Thu May 30 2024 00:00:00 GMT+0900 (대한민국 표준시)</code></p>
<p>→ 요일 월 일 년도 시간 시간대</p>
<p>2️⃣</p>
<pre><code class="language-jsx">new Date(특정한 값); // 원하는 날짜 생성

// new Date(milliseconds)
let myDate = new Date(1000);</code></pre>
<p>→ 1970년 1월 1일 00:00:00 UTC + 1000밀리초</p>
<p>3️⃣</p>
<pre><code class="language-jsx">// new Date(&#39;YYYY-MM-DD&#39;)
let myDate = new Date(&#39;2024-05-30&#39;);

// new Date(&#39;YYYY-MM-DDThh:mm:ss&#39;)
let myDate = new Date(&#39;2024-05-30T18:30:59&#39;);</code></pre>
<p>→ <code>Thu May 30 2024 00:00:00 GMT+0900 (대한민국 표준시)</code></p>
<p>→ <code>Thu May 30 2024 18:30:59 GMT+0900 (대한민국 표준시)</code></p>
<p>4️⃣</p>
<pre><code class="language-jsx">new Date(YYYY, MM, DD, hh, mm, ss, ms);</code></pre>
<p>→ 년도와 월 <code>필수</code>, 나머지 <code>생략 가능</code> : <code>new Date(YYYY, MM, 1, 0, 0, 0, 0);</code></p>
<p><strong>🚨 month는 0부터 시작</strong></p>
<p>5️⃣</p>
<pre><code class="language-jsx">// Date.getTime()
let myDate = newDate(2024, 05, 30, 18, 30, 59);

console.log(myDate.getTime());</code></pre>
<p>→ <code>myDate</code> 객체가 <code>1970년 1월 1일 00:00:00 UTC</code> 부터 몇 밀리초  지났는지? (타임스탬프 <strong>Time Stamp</strong>)</p>
<p><em>️⃣ *</em>지금으로부터 몇 초, 몇 분, 몇 시간이 차이나는지 계산**</p>
<pre><code class="language-jsx">let myDate = newDate(2024, 05, 30, 18, 30, 59);
let today = new Date();

let timeDiff = myDate.getTime() - today.getTime();

console.log(timeDiff + &#39;밀리초&#39;);
console.log(timeDiff + &#39;초&#39;);
console.log(timeDiff / 1000 / 60 + &#39;분&#39;);
console.log(timeDiff / 1000 / 60 / 60 + &#39;시간&#39;);</code></pre>
<p>➕ <strong>추가적인 메서드</strong></p>
<ol>
<li><code>myDate.getFullYear();</code></li>
<li><code>myDate.getMonth();</code> → 0부터 시작하는 것 주의</li>
<li><code>myDate.getDate();</code> → 일자</li>
<li><code>myDate.getDay();</code> → 요일 (일요일부터 0 ~ 6까지)</li>
<li><code>myDate.getHours();</code></li>
<li><code>myDate.getMinutes();</code></li>
<li><code>myDate.getSeconds();</code></li>
<li><code>myDate.getMilliseconds();</code></li>
<li><code>myDate.toLocaleDateString();</code> → myDate가 가진 날짜에 대한 정보 (년. 월. 일)</li>
<li><code>myDate.toLocaleTimeString();</code> → myDate가 가진 시간에 대한 정보 (시:분:초)</li>
<li><code>myDate.toLocaleString();</code> → myDate가 가진 날짜와 시간에 대한 정보 (년. 월. 일 시:분:초)</li>
<li><code>Date.now() === myDate.getTime()</code> → <code>Date.now()</code> 현 시점의 날짜 값</li>
</ol>
<p>etc..</p>
<h3 id="14-우수사원-재상이">14. 우수사원 재상이</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let today = new Date(2112, 7, 24);
  let jaeSangStart = new Date(2109, 6, 1);

  function workDayCalc(startDate) {
      // 여기에 코드를 작성하세요
      let timeDiff = today - startDate;
      let timeDate = timeDiff / 1000 / 60 / 60 / 24 + 1;
      console.log(`오늘은 입사한 지 ${timeDate}일째 되는 날 입니다.`);
  }

  workDayCalc(jaeSangStart);</code></pre>
</li>
</ul>
<h2 id="2️⃣-배열">2️⃣ 배열</h2>
<h3 id="01-배열">01. 배열</h3>
<pre><code class="language-jsx">// 배열 (Array)
let courseRanking = [
    &#39;자바스크립트 프로그래밍 기초&#39;,
    &#39;Git으로 배우는 버전 관리&#39;,
    &#39;컴퓨터 개론&#39;,
    &#39;파이썬 프로그래밍 기초&#39;
]

// index == PropertyName (0~...)
console.log(배열이름[index])
console.log(courseRanking[0]);</code></pre>
<p>→ 값 : 요소 (element)</p>
<h3 id="02-배열-인덱싱-연습하기">02. 배열 인덱싱 연습하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let dataType = [&#39;number&#39;, &#39;string&#39;, &#39;boolean&#39;, &#39;null&#39;, &#39;undefined&#39;, &#39;object&#39;];

  // 여기에 코드를 작성하세요
  for(let i = 0; i &lt; 6; i++) {
    console.log(dataType[i]);
  }</code></pre>
</li>
</ul>
<h3 id="03-배열-다루기">03. 배열 다루기</h3>
<ol>
<li><code>배열명.length</code>, <code>배열명[’length’]</code> 배열의 길이</li>
<li><code>배열명[없는 인덱스] = ‘새로운 값’</code> 배열에 요소 추가 → 없는 인덱스를 건너뛴다면 empty로 표시, 문제 발생 가능성 높음</li>
<li><code>배열명[수정할 값의 인덱스] = ‘수정 값’</code> 배열 값의 재할당 가능</li>
<li><code>delete 배열명[삭제할 값의 인덱스]</code> empty로 값만 삭제되고 제대로된 삭제 X</li>
</ol>
<h3 id="04-온도-바꾸기">04. 온도 바꾸기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let celsiusTemps = [27, 25, 26, 22, 28, 27, 21];
  let fahrenheitTemps = [];

  // 여기에 코드를 작성하세요
  for (let i = 0; i &lt; celsiusTemps.length; i++) {
    fahrenheitTemps[i] = ( celsiusTemps[i] * 9 / 5 ) + 32;
  }

  // fahrenheitTemps 테스트
  console.log(fahrenheitTemps);</code></pre>
</li>
</ul>
<h3 id="0509-배열-메소드">05~09. 배열 메소드</h3>
<p><em>️⃣ *</em>splice**</p>
<ol>
<li><code>members.splice(4);</code> 배열의 5번째 값을 완전히 삭제 <strong>but</strong> 5번째부터 마지막 값까지 모든 값을 삭제한다는 문제</li>
<li><code>members.splice(2, 3);</code> 삭제할 개수를 조절 가능 → 2번 인덱스부터 3개의 값 삭제</li>
<li><code>members.splice(2, 3, &#39;NiceCodeit&#39;, &#39;HiCodeit&#39;);</code> 삭제한 자리에 요소 추가 (여러개 가능 → 이때 뒤는 순서가 밀림)</li>
<li><code>members.splice(2, 0, &#39;NiceCodeit&#39;, &#39;HiCodeit&#39;);</code> 삭제되지 않고 2번 인덱스에 요소 추가</li>
<li><code>members.splice(2, 1, &#39;NiceCodeit&#39;);</code> 2번 인덱스의 값을 수정 (삭제하고 추가함으로써, 여러개 수정도 가능)</li>
</ol>
<p>#️⃣ <strong>경우에 따라 더 간편한 메소드</strong></p>
<ol>
<li><code>members.shift();</code> 배열의 첫 요소를 삭제</li>
<li><code>members.pop();</code> 배열의 마지막 요소를 삭제</li>
<li><code>members.unshift(추가할 값);</code> 배열의 첫 요소로 값 추가</li>
<li><code>members.push(추가할 값);</code> 배열의 마지막 요소로 값 추가</li>
</ol>
<p>▶️ <strong>추가 메소드</strong></p>
<ol>
<li><strong>배열에서 특정 값 찾는 메소드</strong><ol>
<li><code>brands.indexOf(&#39;Kakao&#39;)</code><ol>
<li>만약 포함되어 있다면, <code>item</code>이 있는 인덱스가 리턴</li>
<li>포함되어 있지 않다면, <code>-1</code>이 리턴</li>
<li>여러 번 포함되어 있으면, 처음 발견된 인덱스가 리턴</li>
</ol>
</li>
<li><code>brands.lastIndexOf(&#39;Kakao&#39;)</code> 탐색을 뒤에서부터 진행</li>
<li><code>brands.includes(&#39;Kakao&#39;)</code> true/false로 여부만 확인</li>
</ol>
</li>
<li><strong>배열 뒤집기</strong><ol>
<li><code>brands.reverse();</code> 배열의 순서를 뒤집는 메소드</li>
</ol>
</li>
</ol>
<h3 id="10-forof-반복문">10. for…of 반복문</h3>
<pre><code class="language-jsx">// for...of

for (변수 of 변수) {
    동작부분;
}

let influencer = [&#39;suwonlog&#39;, &#39;small.tiger&#39;, &#39;Minam.ludens&#39;, &#39;cu_convenience24&#39;]

for (let element of influencer) {
    console.log(element);
}

for (let index in influencer) {
    console.log(influencer[index]);
}</code></pre>
<h3 id="11-투표-집계하기">11. 투표 집계하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 투표 결과 리스트
  let votes = [
    &#39;이재식&#39;, &#39;이재식&#39;, &#39;이규하&#39;, &#39;이규하&#39;, &#39;이규하&#39;,
    &#39;이재식&#39;, &#39;이재식&#39;, &#39;이규하&#39;, &#39;이규하&#39;, &#39;이재식&#39;,
    &#39;이규하&#39;, &#39;이규하&#39;, &#39;이규하&#39;, &#39;이규하&#39;, &#39;이재식&#39;,
    &#39;이재식&#39;, &#39;이규하&#39;, &#39;이재식&#39;, &#39;이재식&#39;, &#39;이재식&#39;,
    &#39;이재식&#39;, &#39;이재식&#39;, &#39;이규하&#39;, &#39;이규하&#39;, &#39;이규하&#39;,
    &#39;이규하&#39;, &#39;이규하&#39;, &#39;이재식&#39;, &#39;이규하&#39;, &#39;이규하&#39;,
    &#39;이규하&#39;, &#39;이규하&#39;, &#39;이재식&#39;, &#39;이규하&#39;, &#39;이규하&#39;,
    &#39;이규하&#39;, &#39;이재식&#39;, &#39;이재식&#39;, &#39;이재식&#39;, &#39;이규하&#39;,
  ];

  // 후보별 득표수 객체
  let voteCounter = {};

  // votes 배열을 이용해서 voteCounter 객체를 정리하기
  for (let name of votes) {
    // 여기에 코드를 작성하세요
    if (voteCounter[name]) {
      voteCounter[name]++;
    } else {
      voteCounter[name] = 1;
    }
  }

  // 후보별 득표수 출력
  console.log(voteCounter);</code></pre>
</li>
</ul>
<h3 id="12-다차원-배열">12. 다차원 배열</h3>
<pre><code class="language-jsx">// 다차원 배열 (multidimenstional array)
let twoDimensional = [[1, 2], [3, 4]];

console.log(twoDimensional[0][1]); // 2</code></pre>
<h3 id="13-팀-나누기">13. 팀 나누기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let groups = [
      [&#39;영준&#39;, &#39;캡틴&#39;], 
      [&#39;태순&#39;, &#39;우재&#39;],
      [&#39;재훈&#39;, &#39;지웅&#39;],
      [&#39;윤형&#39;, &#39;동욱&#39;],
      [&#39;규식&#39;, &#39;소원&#39;],
  ];

  let teams = [
      [],
      [],
  ];

  // 여기에 코드를 작성하세요
  for(let i = 0; i &lt; groups.length; i++) {
    for(let j = 0; j &lt; groups[i].length; j++) {
      teams[j][i] = groups[i][j];
    }
  }

  // 테스트 코드
  console.log(teams[0]);
  console.log(teams[1]);</code></pre>
</li>
</ul>
<h2 id="3️⃣-자료형-심화">3️⃣ 자료형 심화</h2>
<h3 id="01-다양한-숫자-표기법">01. 다양한 숫자 표기법</h3>
<ol>
<li><code>let millionaire = 1000000000;</code></li>
<li><code>let myNumber = 1e9;</code> 지수 표기법</li>
<li><code>let hex1 = 0xff;</code> &amp; <code>let hex2 = 0xFF;</code> <code>// 255</code> 16진법 (Hexadecimal)</li>
<li><code>let octal = 0o377;</code> <code>// 255</code> 8진법 (Octal)</li>
<li><code>let binary = 0b11111111;</code> <code>// 255</code> 2진법 (binary numeral system)</li>
</ol>
<h3 id="0203-숫자형-메소드">02~03. 숫자형 메소드</h3>
<ol>
<li><code>myNumber.toFixed(3);</code> 0~100 사이의 숫자만큼 소수점 아래의 자릿수를 고정 (반올림, 없는 숫자는 0으로 표시)<ol>
<li><code>Number(myNumber.toFixed(3));</code> string 값으로 변환시키기 때문에 다시 number로 전환해주는 처리 필요 → 이때는 0 표시 X</li>
<li><code>+myNumber.toFixed(3);</code> 위의 Number와 같은 역할</li>
</ol>
</li>
<li><code>myNumber.toString(2);</code> 파라미터에 전달하는 숫자(2~36 사이)의 진법으로 변환해주는 메소드<ol>
<li><code>255..toString(2);</code> 위와 같은데 변수를 정의하지 않고 사용하는 방법</li>
<li><code>(255).toString(2);</code> 위와 동일</li>
</ol>
</li>
</ol>
<h3 id="04-math-객체">04. Math 객체</h3>
<ol>
<li><code>Math.abs(10);</code> &amp;&amp; <code>Math.abs(-10);</code> <code>// 10</code> 절댓값</li>
<li><code>Math.max(2, -1, 4, 5, 0);</code> 최댓값</li>
<li><code>Math.min(2, -1, 4, 5, 0);</code> 최솟값</li>
<li><code>Math.pow(2, 3);</code> 거듭제곱 (2의 3제곱)</li>
<li><code>Math.sqrt(25);</code> <code>//5</code> 제곱근</li>
<li><code>Math.round(2.3);</code> 소수점 부분 반올림</li>
<li><code>Math.floor(2.4);</code> 소수점 부분 버림</li>
<li><code>Math.ceil(2.4);</code> 소수점 부분 올림</li>
<li><code>Math.random();</code> 0 이상 1 미만의 값이 랜덤으로 리턴</li>
</ol>
<h3 id="05-바보-자바스크립트">05. 바보 자바스크립트?</h3>
<p>→ 0과 1로 코드를 변환하면서 생기는 무한 소수 문제로 인해 오류 발생</p>
<h3 id="06-이자-계산기">06. 이자 계산기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function interestCalculator(rate, payment, term) {
    let interest = payment * term * (term + 1) / 2 * rate / 12;
    console.log(Math.round(interest));
  }

  // 이율이 4.3%일 때 매월 80만원씩 24개월 납입할 경우
  interestCalculator(0.043, 800000, 24);

  // 이율이 4.3%일 때 매월 60만원씩 24개월 납입할 경우
  interestCalculator(0.043, 600000, 24);</code></pre>
</li>
</ul>
<h3 id="0708-문자열-심화">07~08. 문자열 심화</h3>
<ol>
<li><code>myString.length;</code> length 프로퍼티, 문자열의 길이 (공백 포함)</li>
<li>문자열 요소 접근<ol>
<li><code>myString[3];</code> 대괄호 표기법</li>
<li><code>myString.charAt(3);</code> charAt 메소드</li>
</ol>
</li>
<li>문자열 요소 탐색<ol>
<li><code>myString.indexOf(’i’);</code> 앞 부터 탐색</li>
<li><code>myString.lastIndexOf(’i’);</code> 뒤 부터 탐색</li>
</ol>
</li>
<li>문자열 대소문자 변환 (통일)<ol>
<li><code>myString.toUpperCase();</code> 대문자</li>
<li><code>myString.toLowerCase();</code> 소문자</li>
</ol>
</li>
<li>양 끝 공백 제거<ol>
<li><code>myString.trim();</code> trim 메서드</li>
</ol>
</li>
<li>부분 문자열 접근 slice(start, end)<ol>
<li><code>myString.slice(0, 2);</code> 0~1번 인덱스의 문자열 접근</li>
<li><code>myString.slice(3);</code> 시작 지점부터 끝까지 접근</li>
<li><code>myString.slice();</code> 문자열 전체 접근</li>
</ol>
</li>
</ol>
<p>→ 배열은 &#39;mutable(바뀔 수 있는)&#39; 자료형 <strong>VS</strong> 문자열은 &#39;immutable(바뀔 수 없는)&#39; 자료형</p>
<h3 id="09-그래-우리-함께">09. 그래, 우리 함께</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  let lyrics = &quot;[재석]너에게 나 하고 싶었던 말 고마워 미안해 함께 있어서 할 수 있어서 웃을 수 있어[준하] 정말 고마웠어 내 손을 놓지 않아줘서 힘을 내볼게 함께 있다면 두렵지 않아[홍철] 내가 늘 웃으니까 내가 우습나 봐 하지만 웃을 거야 날 보고 웃는 너 좋아[명수] 자꾸만 도망치고 싶은데 저 화려한 큰 무대 위에 설 수 있을까? 자신 없어..[하하] 지금까지 걸어온 이 길을 의심하지는 마 잘못 든 길이 때론 지도를 만들었잖아[형돈] 혼자 걷는 이 길이 막막하겠지만 느리게 걷는 거야 천천히 도착해도 돼[길] 술 한 잔 하자는 친구의 말도 의미 없는 인사처럼 슬프게 들릴 때 날 찾아와&quot;;

  let hyungdon = null;

  // 여기에 코드를 작성하세요
  let startIndex = lyrics.indexOf(&#39;[형돈]&#39;);
  let endIndex = lyrics.indexOf(&#39;[길]&#39;);

  hyungdon = lyrics.slice(startIndex, endIndex);

  // 테스트 코드
  console.log(hyungdon);</code></pre>
</li>
</ul>
<h3 id="1011-기본형과-참조형">10~11. 기본형과 참조형</h3>
<ul>
<li><p>기본형 (Primitive Type) → <code>변수 = 값</code></p>
<p>  : Number, String, Boolean, Null, Undefined</p>
</li>
<li><p>참조형 (Reference Type) → <code>변수 = 주소값</code></p>
<p>  : Object</p>
</li>
</ul>
<h3 id="12-참조형-복사하기">12. 참조형 복사하기</h3>
<pre><code class="language-jsx">// 참조형 복사하기 (Reference Type Copy) -&gt; 복사하여 독립적으로 사용
let numbers1 = [1, 2, 3];
let numbers2 = numbers1.slice(); // slice의 특성을 이용하여 복사

numbers2.push(4);

console.log(numbers1);
console.log(numbers2);

// 객체의 경우 사용할 수 없는 slice를 대체
let course1 = {
    title: &#39;파이썬 프로그래밍 기초&#39;,
    language: &#39;Python&#39;
}

let course2 = {};

for (let key in course1) {
    course2[key] = course1[key];
}

course2.title = &#39;알고리즘의 정석&#39;;

console.log(course1);
console.log(course2);

// 위의 for문을 함수로 만들어 효율적으로 작성
function cloneObject(object) {
    let temp = {};

    for (let key in object) {
        temp[key] = object[key];
    }

    return temp;
}

let course1 = {
    title: &#39;파이썬 프로그래밍 기초&#39;,
    language: &#39;Python&#39;
}

let course2 = cloneObject(course1);

course2.title = &#39;알고리즘의 정석&#39;;

console.log(course1);
console.log(course2);</code></pre>
<p><strong>But</strong> 이 경우 객체 안에 배열이 있다면 참조형이 적용되어 <code>course1</code>에도 추가되는 문제 발생</p>
<p>아래의 코드로 해결 가능</p>
<pre><code class="language-jsx">function cloneObject(object) {
    if (object == null || typeof object !== &#39;object&#39;) {
        return object;
    }

    let temp;
    if (Array.isArray(object)) {
        temp = [];
    } else {
        temp = {};
    }

    for (let key of Object.keys(object)) {
        temp[key] = cloneObject(object[key]);
    }

    return temp;
}</code></pre>
<h3 id="13-레시피-만들기">13. 레시피 만들기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 아래 코드중 잘못된 부분을 수정해 주세요
  let espresso = [&#39;espresso&#39;];

  let americano = espresso.slice();
  americano.push(&#39;water&#39;);

  let caffeLatte = espresso.slice();
  caffeLatte.push(&#39;milk&#39;);

  // 여기에 caffeMocha와 vanillaLatte 레시피를 만들어 주세요
  let caffeMocha = caffeLatte.slice();
  caffeMocha.push(&#39;chocolateSyrup&#39;);

  let vanillaLatte = caffeLatte.slice();
  vanillaLatte.push(&#39;vanillaSyrup&#39;);

  // 테스트 코드
  console.log(espresso);
  console.log(americano);
  console.log(caffeLatte);
  console.log(caffeMocha);
  console.log(vanillaLatte);</code></pre>
</li>
</ul>
<h3 id="1415-const-변수와-상수-사이">14~15. const, 변수와 상수 사이</h3>
<p>상수 (constant) → const → 변수 (variable)</p>
<ul>
<li>변수로 입력받아서 상수로 사용하는 경우가 많음</li>
</ul>
<p><strong>변수 const</strong></p>
<p>myName</p>
<p><strong>VS</strong></p>
<p><strong>상수 const</strong></p>
<p>MY_NAME</p>
<h3 id="16-변수-그땐-그랬지">16. 변수, 그땐 그랬지</h3>
<p><strong><code>var</code></strong> 변수</p>
<ul>
<li><strong>키워드 다음에 변수이름</strong>을 써서 선언</li>
<li><strong>키워드와 변수이름, 그리고 할당연산자와 값</strong>으로 선언과 동시에 값을 할당 가능</li>
<li>중복 선언이 가능 → 값 재할당 X</li>
<li><strong>Scope의 문제</strong><ul>
<li>지역변수의 구분이 <strong>함수</strong>에만 있기 때문에 <code>if, for, while, switch</code> 등 다양한 상황에서 선언한 변수가 자칫, 전역변수의 역할</li>
</ul>
</li>
<li>변수가 끌어올려 지는 현상을 <strong>&#39;호이스팅(hoisting)&#39;</strong></li>
</ul>
<h2 id="4️⃣-과제로-복습하기">4️⃣ 과제로 복습하기</h2>
<h3 id="01-팩토리얼">01. 팩토리얼</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function factorial(n) {
    let result = 1;

      // 여기에 코드를 작성해 주세요.
    for(let i = 1; i &lt;= n; i++) {
      result *= i;
    }

    return result;
  }

  // 테스트 코드
  console.log(factorial(12));
  console.log(factorial(6));
  console.log(factorial(3));
  console.log(factorial(0));</code></pre>
</li>
</ul>
<h3 id="02-거스름돈-구하기">02. 거스름돈 구하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function calculateChange(payment, cost) {
    // 여기에 코드를 작성하세요
    let leftMoney = payment - cost;
    let bigFive = 0, bigOne = 0, five = 0, one = 0;

    if (leftMoney % 50000 != 0) {
      bigFive += Math.floor(leftMoney / 50000);
      leftMoney -= 50000 * bigFive;
    }
    if (leftMoney % 10000 != 0) {
      bigOne += Math.floor(leftMoney / 10000);
      leftMoney -= 10000 * bigOne;
    }
    if (leftMoney % 5000 != 0) {
      five += Math.floor(leftMoney / 5000);
      leftMoney -= 5000 * five;
    }
    one += Math.floor(leftMoney / 1000);

    console.log(`50000원 지폐: ${bigFive}장`);
    console.log(`10000원 지폐: ${bigOne}장`);
    console.log(`5000원 지폐: ${five}장`);
    console.log(`1000원 지폐: ${one}장`);
  }

  // 테스트 코드
  calculateChange(100000, 33000);
  console.log(&#39;&#39;);
  calculateChange(500000, 378000);</code></pre>
</li>
</ul>
<h3 id="03-팰린드롬">03. 팰린드롬</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function isPalindrome(word) {
    // 여기에 코드를 작성하세요
    for (let i = 0; i &lt; Math.floor(word.length / 2); i++) {
      let left = word[i];
      let right = word[word.length - 1 - i];
      if (left !== right) {
        return false;
      }
    }
    return true;
  }

  // 테스트 코드
  console.log(isPalindrome(&quot;racecar&quot;));
  console.log(isPalindrome(&quot;stars&quot;));
  console.log(isPalindrome(&quot;기러기&quot;));
  console.log(isPalindrome(&quot;123321&quot;));
  console.log(isPalindrome(&quot;hello&quot;));
  console.log(isPalindrome(&quot;kayak&quot;));
</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 프로그래밍 기초 (4)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-4</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-4</guid>
            <pubDate>Fri, 31 May 2024 19:00:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/may_05/post/62701d62-2f23-44eb-875d-9da7cc972468/image.jpg" alt=""></p>
<h1 id="ch4-프로그래밍-핵심-개념-in-javascript">Ch4. 프로그래밍 핵심 개념 in JavaScript</h1>
<hr>
<h2 id="1️⃣-자료형">1️⃣ 자료형</h2>
<h3 id="0102-숫자형">01~02. 숫자형</h3>
<ul>
<li>기본적인 사칙 연산의 우선순위를 따름</li>
</ul>
<p>→ 나머지 : <code>%</code></p>
<p>→ 거듭제곱 : <code>**</code></p>
<h3 id="0306-문자열">03~06. 문자열</h3>
<ul>
<li>코드 내에서 구분하기 위한 ‘’ “”</li>
</ul>
<p>→ 문자열에서 따옴표를 사용하는 방법</p>
<ol>
<li><code>console.log(”I’m Iron man”);</code></li>
<li><code>console.log(”He said “I\’m Iron man\””);</code></li>
<li><code>console.log(’He said “I\’m Iron man\”‘);</code></li>
<li><code>console.log(”He said \“I\’m Iron man\””);</code></li>
<li><code>console.log(’He said \“I\’m Iron man\”’);</code></li>
<li><code>console.log(</code>He said \“I\’m Iron man\”<code>);</code>g</li>
</ol>
<h3 id="0710-불린형">07~10. 불린형</h3>
<p>→ 불린 (Boolean)</p>
<p>같다 : <code>===</code> / 같지 않다 : <code>!==</code></p>
<p>AND : <code>&amp;&amp;</code> / OR : <code>||</code> / NOT : <code>!</code></p>
<h3 id="1112-typeof-연산자">11~12. typeof 연산자</h3>
<p><code>typeof 값</code> → 값의 자료형을 표시 (number string boolean function 등)</p>
<ul>
<li>NaN : not a number</li>
</ul>
<h3 id="13-연산자-우선순위">13. 연산자 우선순위</h3>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Operator_precedence">https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Operator_precedence</a></p>
<table>
<thead>
<tr>
<th>우선순위</th>
<th>연산자 유형</th>
<th>기호</th>
</tr>
</thead>
<tbody><tr>
<td>21</td>
<td>그룹</td>
<td>(...)</td>
</tr>
<tr>
<td>...</td>
<td></td>
<td></td>
</tr>
<tr>
<td>17</td>
<td>논리 NOT</td>
<td>! ...</td>
</tr>
<tr>
<td>17</td>
<td>typeof</td>
<td>typeof ...</td>
</tr>
<tr>
<td>16</td>
<td>거듭제곱</td>
<td>... ** ...</td>
</tr>
<tr>
<td>15</td>
<td>곱셈</td>
<td>... * ...</td>
</tr>
<tr>
<td>15</td>
<td>나눗셈</td>
<td>... / ...</td>
</tr>
<tr>
<td>15</td>
<td>나머지</td>
<td>... % ...</td>
</tr>
<tr>
<td>14</td>
<td>덧셈</td>
<td>... + ...</td>
</tr>
<tr>
<td>14</td>
<td>뺄셈</td>
<td>... - ...</td>
</tr>
<tr>
<td>...</td>
<td></td>
<td></td>
</tr>
<tr>
<td>12</td>
<td>미만</td>
<td>... &lt; ...</td>
</tr>
<tr>
<td>12</td>
<td>이하</td>
<td>... &lt;= ...</td>
</tr>
<tr>
<td>12</td>
<td>초과</td>
<td>... &gt; ...</td>
</tr>
<tr>
<td>12</td>
<td>이상</td>
<td>... &gt;= ...</td>
</tr>
<tr>
<td>11</td>
<td>동등</td>
<td>... == ...</td>
</tr>
<tr>
<td>11</td>
<td>부등</td>
<td>... != ...</td>
</tr>
<tr>
<td>11</td>
<td>일치</td>
<td>... === ...</td>
</tr>
<tr>
<td>11</td>
<td>불일치</td>
<td>... !== ...</td>
</tr>
<tr>
<td>...</td>
<td></td>
<td></td>
</tr>
<tr>
<td>6</td>
<td>논리 AND</td>
<td>... &amp;&amp; ...</td>
</tr>
<tr>
<td>5</td>
<td>논리 OR</td>
<td>... II ...</td>
</tr>
<tr>
<td>...</td>
<td></td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>할당</td>
<td>... = ...</td>
</tr>
</tbody></table>
<h3 id="1417-형-변환-type-conversion">14~17. 형 변환 (Type Conversion)</h3>
<p>String, Number, Boolean</p>
<p><code>console.log(Number(’10’) + Number(’5’));</code> → 15</p>
<p><code>console.log(String(10) + String(5));</code> → 105</p>
<p>true → 1 / false → 0, 빈 문자열, NaN (falsy 값)</p>
<p>산술 연산 (+, -, <em>, /, %, *</em>)</p>
<ul>
<li>문자열 계산이 우선 순위 : <code>console.log(4 + ‘2’);</code> → 42</li>
<li>boolean의 경우 true false에 따라 숫자로 변환 후 계산</li>
</ul>
<p>관계 비교 연산 (&lt;, &lt;=, &gt;, &gt;=)</p>
<ul>
<li>비교가 불가능한 경우에도 false</li>
</ul>
<p>같음 비교 연산 (===, !==, ==, !=)</p>
<ul>
<li>일치, 불일치 (!==)</li>
<li>동등, 부등 (!=)</li>
</ul>
<h3 id="1819-템플릿-문자열">18~19. 템플릿 문자열</h3>
<p>→ template : 일정한 틀, 형식</p>
<pre><code class="language-jsx">let year = 2024;
let month = 5;
let day = 30;

console.log(`생년월일은 ${year}년 ${month}월 ${day}일 입니다.`)</code></pre>
<pre><code class="language-jsx">let myNumber = 3;

function getTwice(x) {
    return x * 2;
}

console.log(`${myNumber}의 두 배는 ${getTwice(myNumber)}입니다.`);</code></pre>
<h3 id="2021-null과-undefined">20~21. null과 undefined</h3>
<ul>
<li>값이 없다<ul>
<li>null : 의도적으로 값을 비우는 경우 (의도적인 없음!)</li>
<li>undefined : 값이 주어지지 않은 경우 (처음부터 없음!)</li>
</ul>
</li>
</ul>
<h3 id="22-자료형-응용하기">22. 자료형 응용하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 숫자형과 문자열 재료
  let material1 = 3;
  let material2 = &#39;3&#39;;
  let material3 = 10;
  let material4 = &#39;4&#39;;
  let material5 = 4;

  // 연산 결과
  let result1;
  let result2;

  // 연산을 통해 result1에 문자열 &#39;34&#39;를, result2에 숫자형 34를 할당
  // 여기에 코드를 작성하세요
  result1 = material2 + material4;
  result2 = material1 * material3 + material5

  // 테스트 코드
  console.log(result1);
  console.log(typeof result1);
  console.log(result2);
  console.log(typeof result2);</code></pre>
</li>
</ul>
<h2 id="2️⃣-추상화">2️⃣ 추상화</h2>
<h3 id="01-할당-연산자">01. 할당 연산자</h3>
<pre><code class="language-jsx">// 할당 연산자 (Assignment operators)
let x = 5;

x = x - 2;
console.log(x);</code></pre>
<h3 id="02-복합-할당-연산자">02. 복합 할당 연산자</h3>
<pre><code class="language-jsx">// 다음 세 줄은 같은 의미입니다
x = x + 1;
x += 1;
x++;</code></pre>
<h3 id="03-함수의-실행-순서">03. 함수의 실행 순서</h3>
<ul>
<li>위 → 아래로 실행</li>
<li>함수는 선언했을 때가 끝이 아니라 실행 필요</li>
</ul>
<h3 id="0405-함수-부려먹기">04~05. 함수 부려먹기</h3>
<ul>
<li><p>실습 코드 1</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function logParticipant(name) {
    console.log(`${name}(이)가 대화에 참여했습니다.`);
  }

  // 테스트 코드
  logParticipant(&#39;동수&#39;);
  logParticipant(&#39;윤하&#39;);
  logParticipant(&#39;재준&#39;);
  logParticipant(&#39;동훈&#39;);
  logParticipant(&#39;영희&#39;);
  logParticipant(&#39;신욱&#39;);</code></pre>
</li>
<li><p>실습 코드 2</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function expressMultiplication(num1, num2) {
    let result = num1 * num2;

    console.log(`${num1} * ${num2} = ${result}`);
  }

  // 테스트 코드
  expressMultiplication(3, 4);
  expressMultiplication(3, 2);
  expressMultiplication(7, 5);
  expressMultiplication(8, 9);
  expressMultiplication(5, 5);
  expressMultiplication(9, 9);</code></pre>
</li>
</ul>
<h3 id="06-return문-제대로-이해하기">06. return문 제대로 이해하기</h3>
<ul>
<li>return문의 역할<ol>
<li>결과값을 반환</li>
<li>함수의 실행을 중단 (이후에 작성된 코드를 Dead Code라고 함)</li>
</ol>
</li>
</ul>
<h3 id="0708-return과-consolelog의-차이">07~08. return과 console.log의 차이</h3>
<p><strong>return</strong></p>
<p>: 함수를 실행하고 어떤 값을 돌려주는 것</p>
<p><strong>VS</strong></p>
<p><strong>console.log</strong></p>
<p>: 콘솔의 어떤 값을 출력해주는 것</p>
<h3 id="09-함수-부려먹기">09. 함수 부려먹기</h3>
<ul>
<li><p>실습 코드 3</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function calculateRectangleArea(num1, num2) {
    return num1 * num2;
  }

  // 테스트 코드
  let area1 = calculateRectangleArea(3, 4);  // 가로 3, 세로 4인 직사각형의 넓이 계산
  let area2 = calculateRectangleArea(5, 8);  // 가로 5, 세로 8인 직사각형의 넓이 계산
  let area3 = calculateRectangleArea(7, 2);  // 가로 7, 세로 2인 직사각형의 넓이 계산

  console.log(`Area1: ${area1}, Area2: ${area2}, Area3: ${area3}`);</code></pre>
</li>
</ul>
<h3 id="10-옵셔널-파라미터">10. 옵셔널 파라미터</h3>
<ul>
<li>값을 전달하지 않았을 때 설정해두는 기본 파라미터</li>
</ul>
<p><code>function introduce(nationality = ‘한국’) {}</code></p>
<h3 id="11-세트-메뉴-주문하기">11. 세트 메뉴 주문하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function orderSetMenu(sandwich, drink = &#39;스프라이트&#39;) {
    console.log(`주문하신 ${sandwich}, ${drink} 세트 메뉴 나왔습니다!`);
  }

  // 테스트 코드
  orderSetMenu(&#39;코드웨잇 클럽&#39;);
  orderSetMenu(&#39;터키베이컨 아보카도&#39;, &#39;코카콜라&#39;);
  orderSetMenu(&#39;코드웨잇 멜트&#39;);
  orderSetMenu(&#39;이탈리안 비엠티&#39;, &#39;닥터페퍼&#39;);
  orderSetMenu(&#39;에그마요&#39;, &#39;환타 오렌지&#39;);</code></pre>
</li>
</ul>
<h3 id="1213-변수의-scope">12~13. 변수의 scope</h3>
<ul>
<li>Scope : 범위, 영역</li>
<li>{} : 블록문 (Block Statement)<ul>
<li>로컬 변수, <strong>지역 변수</strong> (Local Variable) → <strong>전역 변수보다 우선순위가 상위</strong></li>
</ul>
</li>
<li>전체 영역 → 글로벌 변수, <strong>전역 변수</strong> (Global Variable)</li>
</ul>
<h3 id="1415-상수">14~15. 상수</h3>
<ul>
<li><p>상수 (Constant) : 절대 변하지 않는 일정한 값</p>
<p>  <code>const pi = 3.14;</code> → 값 재할당 불가</p>
<p>  이름 규칙 필요</p>
</li>
</ul>
<h3 id="16-함수-변수-복습하기">16. 함수 변수 복습하기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 아래에 adultTag, teenagerTag, errorTag, transferTag라는 변수들을 작성해 주세요
  let adultTag = &#39;삑!&#39;;
  let teenagerTag = &#39;삑삑!&#39;;
  let transferTag = &#39;환승입니다.&#39;
  let errorTag = &#39;삑삑삑!&#39;

  // 아래에 tagCase파라미터를 가지는 tagNotification() 함수를 작성해 주세요
  function tagNotification(notice) {
    console.log(`${notice}`)
  }

  // 테스트 코드
  tagNotification(adultTag);
  tagNotification(teenagerTag);
  tagNotification(transferTag);
  tagNotification(errorTag);
  tagNotification(adultTag);</code></pre>
</li>
</ul>
<h2 id="3️⃣-제어문">3️⃣ 제어문</h2>
<h3 id="01-if문">01. if문</h3>
<pre><code class="language-jsx">if (조건부분) {
    동작부분
} else {
    조건이 아닐 때 동작부분
}</code></pre>
<h3 id="02-롤러코스터-탈-수-있을까">02. 롤러코스터, 탈 수 있을까?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 파라미터 height을 활용하는 checkHeight 함수를 완성하세요
  function checkHeight(height) {
      // 여기에 코드를 작성하세요
      if(height &gt;= 140) {
        console.log(&#39;탑승이 가능합니다.&#39;);
      } else {
        console.log(&#39;탑승이 불가능합니다.&#39;);
      }
  }

  // 테스트 코드
  checkHeight(140);
  checkHeight(135);
  checkHeight(170);</code></pre>
</li>
</ul>
<h3 id="03-else-if문">03. else if문</h3>
<pre><code class="language-jsx">if (조건부분) {
    동작부분
} else if (다른 조건부분) {
    다른 조건일 때 동작부분
} else {
    모든 조건이 아닐 때 동작부분
}</code></pre>
<p>→ 간결하고 읽기 쉬운 코드 작성 가능 (not 중첩)</p>
<h3 id="04-학점-계산기">04. 학점 계산기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  function printGrade(midtermScore, finalScore){
      let totalScore = midtermScore + finalScore;
    // 여기에 코드를 작성하세요
    if (totalScore &gt;= 90) {
      console.log(&#39;A&#39;);
    } else if (totalScore &gt;= 80) {
      console.log(&#39;B&#39;);
    } else if (totalScore &gt;= 70) {
      console.log(&#39;C&#39;);
    } else if (totalScore &gt;= 60) {
      console.log(&#39;D&#39;);
    } else {
      console.log(&#39;F&#39;);
    }
  }

  // 테스트 코드
  printGrade(25, 35);
  printGrade(50, 45);
  printGrade(29, 24);
  printGrade(37, 42);</code></pre>
</li>
</ul>
<h3 id="05-서열-정리">05. 서열 정리</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 나의 나이와, 나의 성별을 저장하는 변수
  let myAge = 26;
  let myGender = &#39;male&#39;;

  // 호칭을 담은 변수
  let callOlderBrother = &#39;형&#39;;
  let callOlderSister = &#39;누나&#39;;
  let callFriend = &#39;친구&#39;;
  let callYoungerSister = &#39;여동생&#39;;
  let callYoungerBrother = &#39;남동생&#39;;

  // 상대방의 나이와 성별에 따른 호칭을 리턴하는 함수 whatShouldICall를 완성하세요
  function whatShouldICallYou(yourAge, yourGender) {
    // 여기에 코드를 작성하세요
    if(yourAge == 26) {
      return callFriend;
    } else if(yourAge &lt; 26) {
      if(yourGender == &#39;male&#39;) {
        return callYoungerBrother;
      } else {
        return callYoungerSister;
      }
    } else {
      if(yourGender == &#39;male&#39;) {
        return callOlderBrother;
      } else {
        return callOlderSister;
      }
    }
  }

  // 테스트 코드
  let result1 = whatShouldICallYou(25, &#39;female&#39;);
  let result2 = whatShouldICallYou(20, &#39;male&#39;);
  let result3 = whatShouldICallYou(26, &#39;female&#39;);
  let result4 = whatShouldICallYou(30, &#39;male&#39;);
  let result5 = whatShouldICallYou(31, &#39;female&#39;);

  console.log(result1);
  console.log(result2);
  console.log(result3);
  console.log(result4);
  console.log(result5);</code></pre>
</li>
</ul>
<h3 id="06-switch문">06. switch문</h3>
<pre><code class="language-jsx">switch (비교할 값) {
    case 조건값 1 :
        동작부분;
        break;
    case 조건값 2 :
        동작부분;
        break;
    default :
        동작부분;
}</code></pre>
<p>→ <code>break</code> : case별로 동작을 하고 끊어주는 역할</p>
<p>→ <code>default</code> : 위의 모든 조건을 만족하지 않을 경우 실행</p>
<h3 id="07-switch문-vs-if문">07. switch문 vs if문</h3>
<p><strong>범위를 만족하는 조건식</strong>을 만들 때는 <code>if</code>문을 활용하는 것이 효과적이고, <strong>특정값을 만족하는 조건식</strong>을 만들 때는 <code>switch</code>문이 효과적</p>
<ul>
<li><strong><code>if</code>문으로 대체할 때는 반드시 등호 세 개를 사용해 일치 비교를 해야 한다</strong></li>
<li><strong><code>switch</code>문은 값들을 비교할 때 자료형을 엄격하게 구분한다</strong></li>
</ul>
<h3 id="08-등급별-티켓-가격">08. 등급별 티켓 가격</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 각 등급별 가격
  let VIPPrice = 15;
  let RPrice = 13;
  let SPrice = 10;
  let APrice = 8;

  // 각 등급에 맞는 가격을 출력하는 함수 checkPrice를 완성하세요
  function checkPrice(grade) {
      // 여기에 코드를 작성하세요
      let price;

      switch(grade) {
        case &#39;VIP&#39; :
          price = VIPPrice;
          console.log(`${grade}석은 ${price}만 원입니다.`)
          break;
        case &#39;R&#39; :
          price = RPrice;
          console.log(`${grade}석은 ${price}만 원입니다.`)
          break;
        case &#39;S&#39; :
          price = SPrice;
          console.log(`${grade}석은 ${price}만 원입니다.`)
          break;
        case &#39;A&#39; :
          price = APrice;
          console.log(`${grade}석은 ${price}만 원입니다.`)
          break;
        default :
          console.log(&#39;VIP, R, S, A 중에서 하나를 선택해 주세요.&#39;);
      }
  }

  // 테스트 코드
  checkPrice(&#39;R&#39;);
  checkPrice(&#39;VIP&#39;);
  checkPrice(&#39;S&#39;);
  checkPrice(&#39;A&#39;);
  checkPrice(&#39;B&#39;);</code></pre>
</li>
</ul>
<h3 id="0912-for-반복문">09~12. for 반복문</h3>
<pre><code class="language-jsx">for(초기화 부분; 조건부분; 추가동작부분;) {
    동작부분;
}

for(let i = 0; i &lt; 10; i++) {
    console.log(`${i} 코드잇 최고!`);
}</code></pre>
<p>→ 초기화 부분 : 생성한 변수는 for문의 로컬 변수, 지역 변수</p>
<ul>
<li>필수 X → 글로벌 변수, 전역 변수를 사용해도 ok</li>
<li>ex. <code>for (; i &lt;= 10; i++)</code></li>
</ul>
<p>→ 추가 동작 부분</p>
<ul>
<li>필수 X but <code>i++;</code> 과 같이 증가시키는 부분이 들어가도록 → 조건과 관련된 부분은 소괄호에 모아두는 것이 적합</li>
</ul>
<h3 id="1315-while-반복문">13~15. while 반복문</h3>
<pre><code class="language-jsx">while (조건부분) {
    동작부분
}

let i = 0;
while (i &lt;= 10) {
    console.log(`${i} 코드잇 최고!`);
    i++;
}</code></pre>
<p>→ 조건 부분이 충족하지 않을 때까지 동작 부분을 반복하여 실행</p>
<h3 id="1617-break와-continue">16~17. break와 continue</h3>
<ul>
<li><code>break</code> : 반복이 실행되는 중에 중단할 수 있는 역할</li>
<li><code>continue</code> : 아래 동작이 실행되지 않고 다음 단계로 넘어가게 해주는 역할</li>
</ul>
<h3 id="18-구구단-만들기">18. 구구단 만들기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  let result;

  for(let i = 1; i &lt; 10; i++) {
    for(let j = 1; j &lt; 10; j++) {
      result = i * j;
      console.log(`${i} * ${j} = ${result}`);
    }
  }</code></pre>
</li>
</ul>
<h3 id="19-피보나치-수열">19. 피보나치 수열</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  let num1 = 1;
  let num2 = 1;
  console.log(num1);
  console.log(num2);

  for (let i = 2; i &lt; 50; i++) {
      let result = num1 + num2;
      console.log(result);
      num1 = num2;
      num2 = result;
  }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Codeit boost 1기] JS 프로그래밍 기초 (3)]]></title>
            <link>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-3</link>
            <guid>https://velog.io/@may_05/Codeit-boost-1%EA%B8%B0-JS-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%B4%88-3</guid>
            <pubDate>Fri, 31 May 2024 18:57:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/may_05/post/dc7c2c7f-6600-41dc-afa2-1c2f02fac660/image.jpg" alt=""></p>
<h1 id="ch3-프로그래밍-시작하기-in-javascript">Ch3. 프로그래밍 시작하기 in JavaScript</h1>
<hr>
<h2 id="1️⃣-자바스크립트-첫-걸음">1️⃣ 자바스크립트 첫 걸음</h2>
<h3 id="01-자바스크립트-소개">01. 자바스크립트 소개</h3>
<p>→ 웹사이트를 만들고 싶다면 <strong>반드시</strong> 배워야 하는 프로그래밍 언어</p>
<ul>
<li>web 개발 및 다양한 분야에도 사용</li>
</ul>
<h3 id="02-첫-번째-자바스크립트-코드">02. 첫 번째 자바스크립트 코드</h3>
<p>→ <code>console.log(15)</code></p>
<h3 id="03-자바스크립트-프로그래밍-도구들">03. 자바스크립트 프로그래밍 도구들</h3>
<p>→ VSCode 사용</p>
<h2 id="2️⃣-프로그래밍-기본-개념">2️⃣ 프로그래밍 기본 개념</h2>
<h3 id="01-세미콜론-">01. 세미콜론 (;)</h3>
<p>→ 문장을 종료하는 방법</p>
<ul>
<li>자바스크립트의 경우 줄 바꿈일 때 자동으로 세미콜론 처리를 해줌 (같은 줄에서는 사용하여 구분)</li>
<li>문장 끝에 반드시 사용</li>
</ul>
<h3 id="02-코멘트">02. 코멘트</h3>
<p>→ 주석</p>
<ul>
<li>필요한만큼만 간결하게 사용<ul>
<li>어떤 의도로 코드가 작성 되었는지 설명할 때</li>
<li>구현한 코드가 어떤 동작을 하는지 기록할 때</li>
</ul>
</li>
<li><code>console.log(10 + 5); // 15를 출력하는 코드입니다.</code></li>
<li><code>console.log(10 + 5); /* 15를 출력하는 코드입니다. */</code></li>
</ul>
<h3 id="03-자료형-개요">03. 자료형 개요</h3>
<ul>
<li>프로그래밍이란?<ul>
<li>컴퓨터를 통해 복잡한 계산을 하는 것</li>
</ul>
</li>
</ul>
<p><strong>→ 자료형 (Data Type)</strong></p>
<ul>
<li>숫자 (Number)<ul>
<li>정수 (Integer)</li>
<li>소수 (floating point)</li>
</ul>
</li>
<li>문자열 (String) : 양 끝의 따옴표를 통일하여 사용<ul>
<li>ex. “Hello” + “Codeit” → HelloCodeit</li>
</ul>
</li>
<li>불린 (Boolean)<ul>
<li>true &amp; false : 어떤 조건에 의한 결과값</li>
</ul>
</li>
</ul>
<h3 id="04-추상화-개요">04. 추상화 개요</h3>
<p>→ 추상화(Abstraction) : 구체적인 정보에서 꼭 필요한 핵심만 뽑아내는 것</p>
<p>ex. 지도</p>
<ul>
<li>복잡한 것들을 목적에 맞게 단순화하는 것<ul>
<li>목적을 명확히</li>
<li>불필요한 것들은 숨기기</li>
<li>핵심만 드러내기</li>
</ul>
</li>
</ul>
<h3 id="05-변수-variable">05. 변수 (Variable)</h3>
<p>→ 변수를 먼저 선언 / 값을 저장하는 것</p>
<ul>
<li><code>let 변수명;</code></li>
</ul>
<h3 id="06-작명-가이드">06. 작명 가이드</h3>
<p><strong>Rules</strong></p>
<p>(1) JavaScript 식별자는 &#39;문자(<code>a</code>-<code>z</code>, <code>A</code>-<code>Z</code>)&#39;, &#39;밑줄(<code>_</code>)&#39; 혹은 &#39;달러 기호(<code>$</code>)&#39;로 시작해야 합니다. 두 번째 글자부터는 &#39;숫자(<code>0</code>-<code>9</code>)&#39;도 가능합니다.</p>
<p>(2) &#39;대문자&#39;와 &#39;소문자&#39;는 구별합니다. <code>myname</code>과 <code>myName</code>은 다른 이름입니다.</p>
<p>(3) &#39;예약어(JavaScript가 찜해놓은 단어)&#39;는 사용하면 안 됩니다. 예를 들어서 <code>if</code>, <code>for</code>, <code>let</code> 같은 것들이 있습니다. 강의를 듣다 보면 어떤 예약어가 있는지 차차 알게 되실 겁니다.</p>
<p><strong>Recommend</strong></p>
<p>(1) 의미 없는 이름은 좋지 않습니다.</p>
<p>(2) 너무 추상적인 이름은 좋지 않습니다.</p>
<p>(3) 모든 변수 이름은 &#39;camelCase&#39;로 쓰는 것이 좋습니다.</p>
<p>→ camelCase : 첫 번째 글자는 소문자로 하고, 띄어쓰기가 있는 각 단어의 첫 문자를 대문자로 표기하는 방식</p>
<h3 id="07-칼로리-계산기">07. 칼로리 계산기</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  let espresso = 10;
  let milk = 170;
  let chocolateSyrup = 50;
  let whippedCream = 60;

  // 메뉴별 칼로리 테스트
  console.log(espresso); // 에스프레소 칼로리
  console.log(espresso + milk); // 라떼 칼로리
  console.log(espresso + chocolateSyrup + milk); // 모카 칼로리
  console.log(espresso + chocolateSyrup + milk + whippedCream); // 모카(휘핑 추가) 칼로리</code></pre>
</li>
</ul>
<h3 id="08-함수">08. 함수</h3>
<pre><code class="language-jsx">// 함수 선언
function 함수이름() { 
    명령;
    명령;
};

// 함수 호출
함수이름();</code></pre>
<h3 id="09-자랑스러운-애국가">09. 자랑스러운 애국가</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function printChorus() {
    console.log(&#39;무궁화 삼천리 화려 강산&#39;);
    console.log(&#39;대한 사람 대한으로 길이 보전하세&#39;);
  }

  // 애국가 가사
  console.log(&#39;1절&#39;);
  console.log(&#39;동해 물과 백두산이 마르고 닳도록&#39;);
  console.log(&#39;하느님이 보우하사 우리나라 만세&#39;);
  printChorus();

  console.log(&#39;2절&#39;);
  console.log(&#39;남산 위에 저 소나무 철갑을 두른 듯&#39;);
  console.log(&#39;바람서리 불변함은 우리 기상일세&#39;);
  printChorus();

  console.log(&#39;3절&#39;);
  console.log(&#39;가을 하늘 공활한데 높고 구름 없이&#39;);
  console.log(&#39;밝은 달은 우리 가슴 일편단심일세&#39;);
  printChorus();

  console.log(&#39;4절&#39;);
  console.log(&#39;이 기상과 이 맘으로 충성을 다하여&#39;);
  console.log(&#39;괴로우나 즐거우나 나라 사랑하세&#39;);
  printChorus();</code></pre>
</li>
</ul>
<h3 id="10-파라미터">10. 파라미터</h3>
<p>→ Parameter (매개변수)</p>
<pre><code class="language-jsx">// 함수 선언
function 함수이름(파라미터) { 
    console.log(파라미터);
};

// 함수 호출
함수이름(값);</code></pre>
<h3 id="11-내-노트북-용량은">11. 내 노트북 용량은?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function teraToGiga(data) {
    let resultGiga = data * 1024;
    console.log(&#39;2TB는&#39;);
    console.log(resultGiga + &#39;GB 입니다.&#39;);
  }

  function teraToMega(data) {
    let resultMega = data * 1024 * 1024;
    console.log(&#39;2TB는&#39;);
    console.log(resultMega + &#39;MB 입니다.&#39;);
  }

  // TB -&gt; GB 테스트
  teraToGiga(2);
  // TB -&gt; MB 테스트
  teraToMega(2);</code></pre>
</li>
</ul>
<h3 id="12-여러-개의-파라미터">12. 여러 개의 파라미터</h3>
<pre><code class="language-jsx">// 함수 선언
function 함수이름(파라미터, 파라미터2) { 
    console.log(파라미터 + 파라미터2);
};

// 함수 호출
함수이름(값, 값2);</code></pre>
<h3 id="13-나의-체질량지수는">13. 나의 체질량지수는?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function bmiCalculator(name, weight, height) {
    let bmi = weight / (height * height / 10000);
    console.log(name + &#39;님의 체질량지수는 &#39; + bmi + &#39;입니다.&#39;);
  }

  // 테스트 코드
  bmiCalculator(&#39;홀쭉이&#39;, 43.52, 160);
  bmiCalculator(&#39;코린이&#39;, 61.25, 175);
  bmiCalculator(&#39;통통이&#39;, 77.76, 180);</code></pre>
</li>
</ul>
<h3 id="14-return문">14. return문</h3>
<p>Input → 정해진 일(함수 function) → <strong>Output (return - 반환 값)</strong></p>
<pre><code class="language-jsx">// 함수 선언
function 함수이름() { 
    return 값;
};

// 함수 호출
console.log(함수이름());</code></pre>
<h3 id="15-1년-뒤엔-얼마를-받을까">15. 1년 뒤엔 얼마를 받을까?</h3>
<ul>
<li><p>실습 코드</p>
<pre><code class="language-jsx">  // 여기에 코드를 작성하세요
  function interestCalculator(amount, term, rate) {
    return amount * term * rate / 100;
  }

  // 조건 입력 테스트
  let myMoney = 3650000; // 맡긴 금액 (원)
  let saveTerm = 1; // 맡기는 기간 (년)
  let interestRate = 4; // 이자율 (%)

  // 수령액 계산 테스트
  let myInterest = interestCalculator(myMoney, saveTerm, interestRate);
  let totalMoney = myMoney + myInterest;

  // 출력 테스트
  console.log(&#39;맡긴 금액은 &#39; + myMoney + &#39;원 입니다.&#39;);
  console.log(&#39;이자는 &#39; + myInterest + &#39;원 입니다.&#39;);
  console.log(&#39;최종 받을 금액은 &#39; + totalMoney + &#39;원 입니다.&#39;);</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 프레임워크]]></title>
            <link>https://velog.io/@may_05/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC</link>
            <guid>https://velog.io/@may_05/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC</guid>
            <pubDate>Tue, 28 May 2024 17:06:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>프론트엔드 프레임워크란?</strong>
웹사이트나 애플리케이션의 사용자 인터페이스를 쉽게 디자인, 구축하도록 돕는 소프트웨어 도구 모음</p>
</blockquote>
<h3 id="1️⃣-프론트엔드-프레임워크가-제공하는-요소들">1️⃣ 프론트엔드 프레임워크가 제공하는 요소들</h3>
<ul>
<li><p><strong>UI 컴포넌트</strong></p>
<p>  → 재사용 가능한 UI 컴포넌트(버튼, 폼, 카드 등)를 제공 → 일일이 다시 개발할 필요 X</p>
</li>
<li><p><strong>상태 관리</strong></p>
<p>  → 사용자와 상호작용하는 동안 다루는 상태를 효과적으로 관리하기 위한 방법이 포함 가능</p>
</li>
<li><p><strong>라우팅</strong></p>
<p>  → 싱글 페이지 애플리케이션(SPA)에서는 클라이언트 측 라우팅 관리를 위한 라이브러리나 모듈을 제공</p>
</li>
<li><p><strong>데이터 바인딩</strong></p>
<p>  → UI는 애플리케이션의 상태가 변경될 때 자동으로 업데이트 및 관리</p>
</li>
<li><p><strong>생명주기 메서드</strong></p>
<p>  → 컴포넌트ㆍ페이지가 생성, 업데이트, 소멸하는 과정에서 특정 로직을 실행 가능하도록 제공</p>
</li>
<li><p><strong>유틸리티와 헬퍼</strong></p>
<p>  → DOM 조작, Ajax 요청, 데이터 처리 등의 복잡한 작업을 쉽게 처리할 수 있도록 제공</p>
</li>
</ul>
<h3 id="2️⃣-프론트엔드-프레임워크-사용-순위-2022-기준">2️⃣ 프론트엔드 프레임워크 사용 순위 (2022 기준)</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/362ce732-f370-42f0-878d-3b687a3629bd/image.png" alt=""></p>
<p>→ 2022년 기준으로 실제 사용하는 상위 3개의 프론트엔드 프레임워크는 <strong>React, Angular, Vue.js</strong></p>
<p>→ 이외에도 라이징 프레임워크인 <strong>Next.js</strong> 존재</p>
<h3 id="3️⃣-프레임워크-비교">3️⃣ 프레임워크 비교</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/b0391683-11d7-47f8-be07-556687825d0b/image.png" alt=""></p>
<p>→ <strong>CSR(Client-side Rendering)</strong> : SPA(Single Page Application) 기법을 사용하여 페이지를 렌더링</p>
<ul>
<li>화면을 그리는 렌더링이 클라이언트에게서 발생 (클라이언트의 브라우저에서 페이지 발생)</li>
<li>페이지 간 전환이 부드러워지는 <strong>장점</strong></li>
<li>HTML과 JS를 다운로드 받는동안 클라이언트는 렌더링이 불가능, 즉 첫 페이지의 로딩이 느리다는 <strong>단점</strong></li>
</ul>
<p>→ <strong>SSR(Server Side Rendering)</strong></p>
<ul>
<li>서버 측에서 즉시 렌더링 가능하게끔 가공한 html 파일을 만들어 브라우저에게 보내고, 브라우저는 이를 다운하여 즉각 화면에 렌더링할 수 있는 방식</li>
<li>초기 로드 시 필요한 최소한의 코드만 다운로드하여 실행 → 앱의 초기 로딩 속도를 개선함</li>
</ul>
<p><strong>[출처]</strong></p>
<ul>
<li><a href="https://blog.naver.com/codeitofficial/223426788231">2024에 가장 핫한 프론트엔드 프레임워크 순위는?</a> | 작성자 <a href="https://blog.naver.com/codeitofficial">코드잇</a></li>
<li><a href="https://velog.io/@dev_harrison/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACFront-End-Frameworks">https://velog.io/@dev_harrison/프론트엔드-프레임워크Front-End-Frameworks</a></li>
<li><a href="https://2022.stateofjs.com/en-US/libraries/front-end-frameworks/">https://2022.stateofjs.com/en-US/libraries/front-end-frameworks/</a></li>
<li><a href="https://megastudyitacademy.tistory.com/64">https://megastudyitacademy.tistory.com/64</a></li>
<li><a href="https://haesoo9410.tistory.com/329">https://haesoo9410.tistory.com/329</a></li>
<li><a href="https://blog.naver.com/hello-assemble/223406523154">https://blog.naver.com/hello-assemble/223406523154</a></li>
<li><a href="https://yeongjaekong.tistory.com/32#google_vignette">https://yeongjaekong.tistory.com/32#google_vignette</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[PC에만 CSS 적용하기 (ft. 갤럭시 에러)]]></title>
            <link>https://velog.io/@may_05/PC%EC%97%90%EB%A7%8C-CSS-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-ft.-%EA%B0%A4%EB%9F%AD%EC%8B%9C-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@may_05/PC%EC%97%90%EB%A7%8C-CSS-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0-ft.-%EA%B0%A4%EB%9F%AD%EC%8B%9C-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Tue, 30 Apr 2024 13:52:33 GMT</pubDate>
            <description><![CDATA[<h3 id="pc에만-특정-css-적용하기">PC에만 특정 CSS 적용하기</h3>
<p>모바일 웹 사이트를 만들어줄 때 모든 페이지를 반응형으로 제작하기에는 어려움이 따른다. 그렇기 때문에 PC에만 특정 CSS 스타일을 적용하여 PC 환경에서 특정 값(ex- 375px)의 화면 크기를 가지고 배경에는 색을 넣어주는 작업을 종종 해준다.</p>
<p>그럼 이때 PC와 모바일 환경을 어떻게 구분해서 특정 CSS 값을 적용해주는 걸까?</p>
<h3 id="css의-미디어쿼리">CSS의 미디어쿼리</h3>
<p>CSS의 미디어쿼리를 통해서 PC와 모바일 환경을 구분할 수 있다. 그 중에서도 중요한 속성은 @media 중 <strong>hover</strong>와 <strong>pointer</strong>이다.</p>
<ol>
<li><strong>hover</strong><ul>
<li>사용자의 주 입력 장치(마우스 등)이 요소 위에 호버할 수 있는지 구분하는 속성이다.</li>
<li><strong>none</strong> → 호버 X → <strong>모바일 환경</strong></li>
<li><strong>hover</strong> → 호버 O → <strong>PC 환경</strong></li>
</ul>
</li>
</ol>
<p>호버의 여부에 따라 가능하다면 PC 환경, 가능하지 않다면 모바일 환경이라고 생각할 수 있다. 그것을 바탕으로 아래와 같이 코드를 작성한다면 어딘가에선 문제가 발생한다,,</p>
<pre><code class="language-css">@media (hover: hover) {
 /* PC에 적용할 CSS */
}</code></pre>
<p>“나는 잘 되는데?”라고 생각할 수 있지만 <strong>갤럭시 유저</strong>라면 “왜 PC에만 적용되는 것이 아니라 모바일에도 이 CSS가 적용이 되었지?”라는 문제에 직면할 수 있다 🤧</p>
<p>(실제로 배포를 위한 프로젝트를 진행하면서 이 문제를 해결하기 위해 며칠을 서치하여 해결했다,,)</p>
<p>그러나 <strong>일부 Android 버전</strong>에는 길게 누를 때 호버링을 에뮬레이트하는 기능이 있어 hover를 지원하는 것으로 판단한다. 따라서 같은 코드라도 아이폰과 갤럭시 유저가 다른 화면을 가지게 되는 결과가 나타난다. 모든 사용자에게 동일한 UX를 제공하려면 두 번째 조건을 추가해야한다.</p>
<ol>
<li><strong>pointer</strong><ul>
<li>사용자가 포인팅 장치(마우스 등)를 가지는지 구분하는 속성이다.</li>
<li><strong>none</strong> → 포인팅 장치 X → <strong>모바일 환경</strong></li>
<li><strong>coarse</strong> → 부정확한 포인팅 장치(ex- 터치 스크린의 손가락) → <strong>모바일 환경</strong></li>
<li><strong>fine</strong> → 정확한 포인팅 장치 (ex- 마우스) → <strong>PC 환경</strong></li>
</ul>
</li>
</ol>
<p>마우스처럼 정확한 포인팅 장치가 있다는 것을 확인한다면, 정확히 PC에만 CSS 적용이 가능해진다.</p>
<pre><code class="language-css">@media (hover: hover) and (pointer: fine) {
 /* PC에 적용할 CSS */
}</code></pre>
<p><code>@media (hover: hover) and (pointer: fine)</code> 안에 들어가는 CSS 내용들은 이제 정확히 PC에만 적용이 된다! 드디어 갤럭시 유저에게도 PC 버전 스타일이 아닌 모바일 스타일이 적용된다.</p>
<h3 id="pc에만-css가-적용된-최종-화면">PC에만 CSS가 적용된 최종 화면</h3>
<p>이번 프로젝트에서는 PC 화면 뒤에 다른 디자인 없이 페이지의 크기(375px)만 지정해주었다. (각 페이지에 배경색이 주어진 경우가 대부분이었어서 구분선이 필요하지 않았다)</p>
<ul>
<li>해당 부분 관련 코드</li>
</ul>
<pre><code class="language-css">@media (hover: hover) and (pointer: fine) {
  .page-space {
    width: 375px;
  }
}</code></pre>
<ul>
<li>PC 화면
<img src="https://velog.velcdn.com/images/may_05/post/55f0205b-4a2f-4828-b9ce-8fea9394ab72/image.png" alt=""></li>
</ul>
<ul>
<li>모바일 화면
<img src="https://velog.velcdn.com/images/may_05/post/8ed9395a-1458-4914-a46e-938103e83bbc/image.png" alt=""></li>
</ul>
<h3 id="결론">결론</h3>
<blockquote>
<p>갤럭시 에러를 만나지 않고 <strong>정확히 PC에만 CSS를 적용</strong>해주고 싶다면 아래의 코드를 사용하면 된다 😎</p>
</blockquote>
<pre><code class="language-css">@media (hover: hover) and (pointer: fine) {
 /* PC에 적용할 CSS */
}</code></pre>
<blockquote>
</blockquote>
<h3 id="참고-링크">참고 링크</h3>
<ul>
<li><a href="https://ykwan0714.github.io/%ED%84%B0%EC%B9%98-%EB%94%94%EB%B0%94%EC%9D%B4%EC%8A%A4-%EB%AA%A8%EB%B0%94%EC%9D%BC%EC%97%90%EC%84%9C-hover-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0/">https://ykwan0714.github.io/터치-디바이스-모바일에서-hover-제거하기/</a></li>
<li><a href="https://doqtqu.tistory.com/355">https://doqtqu.tistory.com/355</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[노마드코더] React JS Ch.3~6]]></title>
            <link>https://velog.io/@may_05/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94-React-JS-Ch.36</link>
            <guid>https://velog.io/@may_05/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94-React-JS-Ch.36</guid>
            <pubDate>Mon, 22 Jan 2024 00:15:49 GMT</pubDate>
            <description><![CDATA[<h2 id="3-state">#3 STATE</h2>
<h3 id="30-understanding-state">3.0 Understanding State</h3>
<p>State → (값이 바뀔) 데이터가 저장되는 곳</p>
<ul>
<li><p>index.html → not good</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      let counter = 0;
      function countUp() {
        counter = counter + 1;
        render();
      }
      function render() {
        ReactDOM.render(&lt;Container /&gt;, root);
      }
      const Container = () =&gt; (
        &lt;div&gt;
          &lt;h3&gt;Total clicks: {counter}&lt;/h3&gt;
          &lt;button onClick={countUp}&gt;Click me&lt;/button&gt;
        &lt;/div&gt;
      );
      render();
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <code>Total clicks: {counter}</code> : <code>{counter}</code>로 변수를 가져올 수 있음</p>
<p>→ 초기의 렌더링만으로 끝내는 것이 아니라 <strong>리렌더링</strong>을 해줘야 변하는 UI 렌더링 가능</p>
<p>→ 현재 코드는 계속해서 모든 부분을 render 해주기 때문에 좋은 방식 X</p>
<p>→ vanillaJS와 달리 React.js는 <strong>UI에서 바뀐 부분만</strong> 업데이트 가능
(ex. button 업데이트 X, click 숫자만 업데이트)</p>
<h3 id="31-setstate-part-one">3.1 setState part One</h3>
<ul>
<li><p>index.html → Best way (not final)</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [counter, modifier] = React.useState(0);
        return (
          &lt;div&gt;
            &lt;h3&gt;Total clicks: {counter}&lt;/h3&gt;
            &lt;button&gt;Click me&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ 함수를 계속 불러줄 필요 없이 데이터를 보관하고 자동으로 리렌더링하는 최고의 방법</p>
<p>→ <code>const data = React.useState(0);</code> : [초기값(0), 함수] 2개가 담겨있는 배열, 함수의 역할</p>
<h3 id="32-setstate-part-two">3.2 setState part Two</h3>
<ul>
<li><p>index.html → Best way (final)</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [counter, setCounter] = React.useState(0);
        const onClick = () =&gt; {
          setCounter(counter + 1);
        };
        return (
          &lt;div&gt;
            &lt;h3&gt;Total clicks: {counter}&lt;/h3&gt;
            &lt;button onClick={onClick}&gt;Click me&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <code>React.useState</code> : counter데이터를 숫자형 데이터로 전달, 데이터 값 바꿀 함수 같이 전달
                              (+ 함수로 바꾼 값 리렌더링)</p>
<h3 id="33-recap">3.3 Recap</h3>
<p>위와 동일</p>
<h3 id="34-state-functions">3.4 State Functions</h3>
<ul>
<li><p>index.html</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [counter, setCounter] = React.useState(0);
        const onClick = () =&gt; {
          // setCounter(counter + 1);
          setCounter((current) =&gt; current + 1);
        };
        return (
          &lt;div&gt;
            &lt;h3&gt;Total clicks: {counter}&lt;/h3&gt;
            &lt;button onClick={onClick}&gt;Click me&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ 1. <code>setCounter(10);</code> : 새 값으로 변경 (하지만 더 이상의 업데이트 X)</p>
<p>→ 2. <code>setCounter(counter + 1);</code> : 이전 값을 이용해서 현재 값을 계산 (계속 업데이트 O)</p>
<p>→ 3. <code>setCounter((current) =&gt; current + 1);</code> : <strong>Best Way</strong> / 확실히 현재 값 보장 (안전)</p>
<h3 id="35-inputs-and-state">3.5 Inputs and State</h3>
<ul>
<li><p>index.html → Super Converter 中 <strong>Minutes ↔ Hours (1)</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [minutes, setMinutes] = React.useState(0);
        const onChange = (event) =&gt; {
          setMinutes(event.target.value);
        };
        return (
          &lt;div&gt;
            &lt;h1&gt;Super Converter&lt;/h1&gt;
            &lt;label htmlFor=&quot;minutes&quot;&gt;Minutes&lt;/label&gt;
            &lt;input value={minutes} id=&quot;minutes&quot; placeholder=&quot;Minutes&quot; type=&quot;number&quot; onChange={onChange} /&gt;
            &lt;h4&gt;You want to convert {minutes}&lt;/h4&gt;
            &lt;label htmlFor=&quot;hours&quot;&gt;Hours&lt;/label&gt;
            &lt;input id=&quot;hours&quot; placeholder=&quot;Hours&quot; type=&quot;number&quot; /&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <strong>NOT</strong> <code>class</code> <strong>YES</strong> <code>className</code> / <strong>NOT</strong> <code>for</code> <strong>YES</strong> <code>htmlFor</code></p>
<p>→ 기본 input은 uncontrolled : value 값을 통제할 수 없음 → state 생성 필요</p>
<p>→ <code>event.target.value</code> : event를 사용하여 input 값 중 target의 value값 사용</p>
<h3 id="36-state-practice-part-one">3.6 State Practice part One</h3>
<ul>
<li><p>index.html → Super Converter 中 <strong>Minutes ↔ Hours (2)</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [minutes, setMinutes] = React.useState(0);
        const onChange = (event) =&gt; {
          setMinutes(event.target.value);
        };
        const reset = () =&gt; setMinutes(0);

        return (
          &lt;div&gt;
            &lt;h1&gt;Super Converter&lt;/h1&gt;
            &lt;div&gt;
              &lt;label htmlFor=&quot;minutes&quot;&gt;Minutes&lt;/label&gt;
              &lt;input value={minutes} id=&quot;minutes&quot; placeholder=&quot;Minutes&quot; type=&quot;number&quot; onChange={onChange} /&gt;
            &lt;/div&gt;

            &lt;div&gt;
              &lt;label htmlFor=&quot;hours&quot;&gt;Hours&lt;/label&gt;
              &lt;input value={Math.round(minutes / 60)} id=&quot;hours&quot; placeholder=&quot;Hours&quot; type=&quot;number&quot; disabled /&gt;
            &lt;/div&gt;

            &lt;button onClick={reset}&gt;Reset&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <code>Math.round()</code> : 값 반올림해주는 함수</p>
<p>→ <code>const reset = () =&gt; setMinutes(0);</code> : 0으로 초기화</p>
<p>→ Hours : onChange 리스너가 없기 때문에 input 값 변경 불가
                 <code>disabled</code> 로 인해 입력 불가</p>
<h3 id="37-state-practice-part-two">3.7 State Practice part Two</h3>
<ul>
<li><p>index.html → Super Converter 中 <strong>Minutes ↔ Hours (3)</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [amount, setAmount] = React.useState(0);
        const [flipped, setFlipped] = React.useState(false);
        const onChange = (event) =&gt; {
          setAmount(event.target.value);
        };
        const reset = () =&gt; setAmount(0);
        const onFlip = () =&gt; {
          reset();
          setFlipped((current) =&gt; !current);
        };

        return (
          &lt;div&gt;
            &lt;h1&gt;Super Converter&lt;/h1&gt;
            &lt;div&gt;
              &lt;label htmlFor=&quot;minutes&quot;&gt;Minutes&lt;/label&gt;
              &lt;input value={flipped ? amount * 60 : amount} id=&quot;minutes&quot; placeholder=&quot;Minutes&quot; type=&quot;number&quot; onChange={onChange} disabled={flipped} /&gt;
            &lt;/div&gt;

            &lt;div&gt;
              &lt;label htmlFor=&quot;hours&quot;&gt;Hours&lt;/label&gt;
              &lt;input value={flipped ? amount : Math.round(amount / 60)} id=&quot;hours&quot; placeholder=&quot;Hours&quot; type=&quot;number&quot; onChange={onChange} disabled={!flipped} /&gt;
            &lt;/div&gt;

            &lt;button onClick={reset}&gt;Reset&lt;/button&gt;
            &lt;button onClick={onFlip}&gt;Flip&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <code>filp</code> click : minutes 입력 hours 입력 불가 ↔ minutes 입력 불가 hours 입력</p>
<p>→ <code>disabled={flipped === true}</code>/<code>disabled={!flipped}</code> : disabled를 통해 flipped props 전달</p>
<h3 id="38-recap">3.8 Recap</h3>
<ul>
<li><p>index.html → Super Converter 中 <strong>Minutes ↔ Hours (4)</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function App() {
        const [amount, setAmount] = React.useState(0);
        const [inverted, setInverted] = React.useState(false);
        const onChange = (event) =&gt; {
          setAmount(event.target.value);
        };
        const reset = () =&gt; setAmount(0);
        const onInvert = () =&gt; {
          reset();
          setInverted((current) =&gt; !current);
        };

        return (
          &lt;div&gt;
            &lt;h1&gt;Super Converter&lt;/h1&gt;
            &lt;div&gt;
              &lt;label htmlFor=&quot;minutes&quot;&gt;Minutes&lt;/label&gt;
              &lt;input value={inverted ? amount * 60 : amount} id=&quot;minutes&quot; placeholder=&quot;Minutes&quot; type=&quot;number&quot; onChange={onChange} disabled={inverted} /&gt;
            &lt;/div&gt;

            &lt;div&gt;
              &lt;label htmlFor=&quot;hours&quot;&gt;Hours&lt;/label&gt;
              &lt;input value={inverted ? amount : Math.round(amount / 60)} id=&quot;hours&quot; placeholder=&quot;Hours&quot; type=&quot;number&quot; onChange={onChange} disabled={!inverted} /&gt;
            &lt;/div&gt;

            &lt;button onClick={reset}&gt;Reset&lt;/button&gt;
            &lt;button onClick={onInvert}&gt;{inverted ? &quot;Turn back&quot; : &quot;Invert&quot;}&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ flipped를 inverted로 변경 및 버튼 <code>{inverted ? &quot;Turn back&quot; : &quot;Invert&quot;}</code> 추가</p>
<h3 id="39-final-practice-and-recap">3.9 Final Practice and Recap</h3>
<ul>
<li><p>index.html → Super Converter 中 <strong>Minutes ↔ Hours + Km ↔ Miles</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function MinutesToHours() {
        const [amount, setAmount] = React.useState(0);
        const [inverted, setInverted] = React.useState(false);
        const onChange = (event) =&gt; {
          setAmount(event.target.value);
        };
        const reset = () =&gt; setAmount(0);
        const onInvert = () =&gt; {
          reset();
          setInverted((current) =&gt; !current);
        };

        return (
          &lt;div&gt;
            &lt;div&gt;
              &lt;label htmlFor=&quot;minutes&quot;&gt;Minutes&lt;/label&gt;
              &lt;input value={inverted ? amount * 60 : amount} id=&quot;minutes&quot; placeholder=&quot;Minutes&quot; type=&quot;number&quot; onChange={onChange} disabled={inverted} /&gt;
            &lt;/div&gt;

            &lt;div&gt;
              &lt;label htmlFor=&quot;hours&quot;&gt;Hours&lt;/label&gt;
              &lt;input value={inverted ? amount : Math.round(amount / 60)} id=&quot;hours&quot; placeholder=&quot;Hours&quot; type=&quot;number&quot; onChange={onChange} disabled={!inverted} /&gt;
            &lt;/div&gt;

            &lt;button onClick={reset}&gt;Reset&lt;/button&gt;
            &lt;button onClick={onInvert}&gt;{inverted ? &quot;Turn back&quot; : &quot;Invert&quot;}&lt;/button&gt;
          &lt;/div&gt;
        );
      }
      function KmToMiles() {
        return &lt;h3&gt;KM 2 M&lt;/h3&gt;;
      }
      function App() {
        const [index, setIndex] = React.useState(&quot;xx&quot;);
        const onSelect = (event) =&gt; {
          setIndex(event.target.value);
        };

        return (
          &lt;div&gt;
            &lt;h1&gt;Super Converter&lt;/h1&gt;
            &lt;select value={index} onChange={onSelect}&gt;
              &lt;option value=&quot;xx&quot;&gt;Select your units&lt;/option&gt;
              &lt;option value=&quot;0&quot;&gt;Minutes &amp; Hours&lt;/option&gt;
              &lt;option value=&quot;1&quot;&gt;Km &amp; Miles&lt;/option&gt;
            &lt;/select&gt;
            &lt;hr /&gt;
            {index === &quot;xx&quot; ? &quot;Please select your units&quot; : null}
            {index === &quot;0&quot; ? &lt;MinutesToHours /&gt; : null}
            {index === &quot;1&quot; ? &lt;KmToMiles /&gt; : null}
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ select, value를 활용하여 메뉴바에서 선택하는 것으로 컴포넌트 불러오기</p>
<p>→ <code>const [index, setIndex] = React.useState();</code>
    : useState에 아무 값도 지정해주지 않았기 때문에 처음에는 어느 화면도 X</p>
<h2 id="4-props">#4 PROPS</h2>
<h3 id="40-props">4.0 Props</h3>
<ul>
<li><p>index.html → 버튼 속 text만 변경해서 같은 컴포넌트 사용 中 using <strong>props.banana</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function Btn(props) {
        return (
          &lt;button
            style={{
              backgroundColor: &quot;tomato&quot;,
              color: &quot;white&quot;,
              padding: &quot;10px 20px&quot;,
              border: 0,
              borderRadius: 10,
            }}
          &gt;
            {props.banana}
          &lt;/button&gt;
        );
      }

      function App() {
        return (
          &lt;div&gt;
            &lt;Btn banana=&quot;Save Changes&quot; /&gt;
            &lt;Btn banana=&quot;Continue&quot; /&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ <strong>컴포넌트</strong> : 어떤 JSX를 반환하는 함수</p>
<p>→ <strong>props</strong> : 버튼으로부터 전달받는 properties / 인자</p>
<p>→ <code>Btn({banana:&quot;Save Changes&quot;})</code> = <code>&lt;Btn banana=&quot;Save Changes&quot; /&gt;</code></p>
<p>→ 현재 이 코드에서 props는 버튼이 전달 받는 유일한, 첫번째 인자 → 값은 모두 가져옴</p>
<ul>
<li><p>index.html → using <strong>{text, big}</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function Btn({ text, big }) {
        return (
          &lt;button
            style={{
              backgroundColor: &quot;tomato&quot;,
              color: &quot;white&quot;,
              padding: &quot;10px 20px&quot;,
              border: 0,
              borderRadius: 10,
              fontSize: big ? 18 : 16,
            }}
          &gt;
            {text}
          &lt;/button&gt;
        );
      }

      function App() {
        return (
          &lt;div&gt;
            &lt;Btn text=&quot;Save Changes&quot; big={true} /&gt;
            &lt;Btn text=&quot;Continue&quot; big={false} /&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ props는 오브젝트이기 때문에 property를 오브젝트로부터 꺼내는 <strong>shortcut</strong> 사용</p>
<h3 id="41-memo">4.1 Memo</h3>
<ul>
<li><p>index.html → (+) <strong>function</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function Btn({ text, changeValue }) {
        return (
          &lt;button
            onClick={changeValue}
            style={{
              backgroundColor: &quot;tomato&quot;,
              color: &quot;white&quot;,
              padding: &quot;10px 20px&quot;,
              border: 0,
              borderRadius: 10,
            }}
          &gt;
            {text}
          &lt;/button&gt;
        );
      }
      const MemorizedBtn = React.memo(Btn);

      function App() {
        const [value, setValue] = React.useState(&quot;Save Changes&quot;);
        const changeValue = () =&gt; setValue(&quot;Revert Changes&quot;);

        return (
          &lt;div&gt;
            &lt;MemorizedBtn text={value} changeValue={changeValue} /&gt;
            &lt;MemorizedBtn text=&quot;Continue&quot; /&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ props에 넣을 수 있는 것 : string, boolean, function 등</p>
<p>→ props는 일일이 추가해줘야 사용 가능</p>
<p>→ <code>&lt;Btn text=&quot;{value}&quot; onClick={changeValue} /&gt;</code> : onClick은 이벤트리스너 X 하나의 props
    이해를 위해 <code>changeValue={changeValue}</code>로 작성</p>
<p>→ <strong>React Memo</strong> : props가 변경되지 않을 때 컴포넌트를 리렌더링 하지 않고 싶을 때 사용</p>
<p>→ <code>const MemorizedBtn = React.memo(Btn);</code> : Btn을 Memo하여 변경된 것만 리렌더링</p>
<h3 id="42-prop-types">4.2 Prop Types</h3>
<ul>
<li><p>index.html → using <strong>Prop Types</strong></p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.development.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/prop-types@15.7.2/prop-types.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function Btn({ text, fontSize = 16 }) {
        return (
          &lt;button
            style={{
              backgroundColor: &quot;tomato&quot;,
              color: &quot;white&quot;,
              padding: &quot;10px 20px&quot;,
              border: 0,
              borderRadius: 10,
              fontSize,
            }}
          &gt;
            {text}
          &lt;/button&gt;
        );
      }
      Btn.propTypes = {
        text: PropTypes.string.isRequired,
        fontSize: PropTypes.number,
      };

      function App() {
        return (
          &lt;div&gt;
            &lt;Btn text=&quot;Save Changes&quot; fontSize={18} /&gt;
            &lt;Btn text=&quot;Continue&quot; /&gt;
          &lt;/div&gt;
        );
      }
      ReactDOM.render(&lt;App /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<p>→ props에 타입을 지정해주어서 콘솔에서 오류 확인 가능 (다른 타입 작성하는 실수 방지)</p>
<h3 id="43-recap">4.3 Recap</h3>
<p>위와 동일</p>
<h2 id="5-create-react-app">#5 CREATE REACT APP</h2>
<h3 id="50-introduction">5.0 Introduction</h3>
<p><img src="https://velog.velcdn.com/images/may_05/post/719926b9-0069-4fd9-a353-6e9cf3473568/image.png" alt=""></p>
<p>→ create-react-app : React.js를 만드는 쉬운 방법</p>
<p>→ <code>npx create-react-app 폴더명</code> : 리액트 앱 생성 명령어</p>
<p>→ npm start : 리액트 실행</p>
<p>→ package.json : 대부분의 내용이 담겨있음</p>
<p>→ 모든 폴더는 src 폴더 안에 위치</p>
<p>→ <strong>index.js</strong> : 가장 중요한 파일</p>
<p>→ 필요없는 파일 삭제 후 깨끗하게 시작 (App.js, index.js만 필요)</p>
<h3 id="51-tour-of-cra">5.1 Tour of CRA</h3>
<ul>
<li><p>App.js</p>
<pre><code class="language-jsx">  import Button from &quot;./Button&quot;;
  import styles from &quot;./App.module.css&quot;;

  function App() {
    return (
      &lt;div&gt;
        &lt;h1 className={styles.title}&gt;Welcome back!!!&lt;/h1&gt;
        &lt;Button text={&quot;Continue&quot;} /&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
<li><p>App.module.css</p>
<pre><code class="language-css">  .title {
    font-family: system-ui, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Oxygen, Ubuntu, Cantarell, &quot;Open Sans&quot;, &quot;Helvetica Neue&quot;, sans-serif;
    font-size: 18px;
  }</code></pre>
</li>
<li><p>Button.js</p>
<pre><code class="language-jsx">  import PropTypes from &quot;prop-types&quot;;
  import styles from &quot;./Button.module.css&quot;;

  function Button({ text }) {
    return &lt;button className={styles.btn}&gt;{text}&lt;/button&gt;;
  }

  Button.propTypes = {
    text: PropTypes.string.isRequired,
  };

  export default Button;</code></pre>
</li>
<li><p>Button.module.css</p>
<pre><code class="language-css">  .btn {
    color: white;
    background-color: tomato;
  }</code></pre>
</li>
<li><p>index.js</p>
<pre><code class="language-jsx">  import React from &quot;react&quot;;
  import ReactDOM from &quot;react-dom/client&quot;;
  import App from &quot;./App&quot;;

  const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;));
  root.render(
    &lt;React.StrictMode&gt;
      &lt;App /&gt;
    &lt;/React.StrictMode&gt;
  );</code></pre>
</li>
</ul>
<p>→ <code>npm install prop-types</code> : prop types를 사용하기 위해 설치하는 명령어</p>
<p>→ style을 모듈로 사용함으로써 같은 btn이라는 이름을 사용해도 다르게 적용 가능
    (랜덤 방식으로 자동 생성 기능 존재)</p>
<h2 id="6-effects">#6 <strong>EFFECTS</strong></h2>
<h3 id="60-introduction">6.0 Introduction</h3>
<ul>
<li><p>App.js</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  function App() {
    const [counter, setValue] = useState(0);
    const onClick = () =&gt; setValue((prev) =&gt; prev + 1);
    console.log(&quot;call an api&quot;);

    return (
      &lt;div&gt;
        &lt;h1&gt;{counter}&lt;/h1&gt;
        &lt;button onClick={onClick}&gt;click me&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→  state가 변경될 때마다 리렌더링을 하게 되면 렌더링을 하고 싶지 않은 순간에도 진행</p>
<p>→ ex) API를 가져올 때 처음에만 렌더링하고 이후에 다시 정보를 가져올 필요 X</p>
<p>→ 첫번째 component render에서만 특정 코드들이 실행 (state 변화해도 코드 재실행 X)</p>
<p>→ <strong>useEffect</strong> 사용</p>
<h3 id="61-useeffect">6.1 useEffect</h3>
<ul>
<li><p>App.js</p>
<pre><code class="language-jsx">  import { useState, useEffect } from &quot;react&quot;;

  function App() {
    const [counter, setValue] = useState(0);
    const onClick = () =&gt; setValue((prev) =&gt; prev + 1);
    console.log(&quot;i run all the time&quot;);

    const iRunOnlyOnce = () =&gt; {
      console.log(&quot;call the API&quot;);
    };
    useEffect(iRunOnlyOnce, []);

    return (
      &lt;div&gt;
        &lt;h1&gt;{counter}&lt;/h1&gt;
        &lt;button onClick={onClick}&gt;click me&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→ useEffect : 두 개의 argument를 가지는 function
    (1. 우리가 실행하고 싶은 코드 / 2. dependency(ies) : 리액트가 변화를 지켜볼 인자)</p>
<p>→ 코드가 딱 한번만 실행될 수 있도록 보호하는 역할</p>
<h3 id="62-deps">6.2 Deps</h3>
<ul>
<li><p>App.js</p>
<pre><code class="language-jsx">  import { useState, useEffect } from &quot;react&quot;;

  function App() {
    const [counter, setValue] = useState(0);
    const onClick = () =&gt; setValue((prev) =&gt; prev + 1);
    // console.log(&quot;i run all the time&quot;);

    const [keyword, setKeyword] = useState(&quot;&quot;);
    const onChange = (event) =&gt; setKeyword(event.target.value);

    const iRunOnlyOnce = () =&gt; {
      // console.log(&quot;call the API&quot;);
      console.log(&quot;I run only once.&quot;);
    };
    useEffect(iRunOnlyOnce, []);

    useEffect(() =&gt; {
      // if (keyword !== &quot;&quot; &amp;&amp; keyword.length &gt; 5) {
      //   console.log(&quot;SEARCH FOR&quot;, keyword);
      // }
      console.log(&quot;I run when &#39;keyword&#39; changes.&quot;);
    }, [keyword]);

    useEffect(() =&gt; {
      console.log(&quot;I run when &#39;counter&#39; changes.&quot;);
    }, [counter]);

    useEffect(() =&gt; {
      console.log(&quot;I run when keyword &amp; counter changes.&quot;);
    }, [keyword, counter]);

    return (
      &lt;div&gt;
        &lt;input value={keyword} onChange={onChange} type=&quot;text&quot; placeholder=&quot;Search here...&quot; /&gt;
        &lt;h1&gt;{counter}&lt;/h1&gt;
        &lt;button onClick={onClick}&gt;click me&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→ useEffect를 사용하지 않았을 때 검색어를 입력할 때마다 모든게 리렌더링됨
    (혹은 click 버튼을 누를 때마다 입력되어 있는 검색어를 같이 리렌더링)</p>
<pre><code>useEffect(() =&gt; {
    console.log(&quot;SEARCH FOR&quot;, keyword);
  }, **[keyword]**);</code></pre><p>→ 키워드가 변화할 때만 코드를 실행(리렌더링)</p>
<p>→ <code>[]</code> 처럼 두번째 argument가 비어있을 때, 지켜볼게 없기 때문에 처음 한번만 실행</p>
<p>→ <code>if (keyword !== &quot;&quot; &amp;&amp; keyword.length &gt; 5)</code> : 키워드가 없거나 짧을 때 실행 X 조건</p>
<p>→ <code>[keyword, counter]</code> : array이기 때문에 2가지의 변화를 확인할 수도 O</p>
<p><strong>Memo</strong> <strong>VS</strong> <strong>useEffect</strong></p>
<p>→ Memo : props가 변경되지 않았을 때 리렌더링 X</p>
<p>→ useEffect : props가 변경될 때 함수 실행
                     혹은 컴포넌트의 시작, 끝에만 실행</p>
<h3 id="63-recap">6.3 Recap</h3>
<p>→ state를 변화시킬 때 component를 재실행</p>
<p>→ useEffect는 react.js가 동작하는 관점에서 <strong>방어막</strong></p>
<h3 id="64-cleanup">6.4 Cleanup</h3>
<ul>
<li><p>App.js</p>
<pre><code class="language-jsx">  import { useState, useEffect } from &quot;react&quot;;

  function Hello() {
    // function byFn() {
    //   console.log(&quot;bye :(&quot;);
    // }
    // function hiFn() {
    //   console.log(&quot;created :)&quot;);
    //   return byFn;
    // }

    useEffect(() =&gt; {
      console.log(&quot;hi :)&quot;);
      return () =&gt; console.log(&quot;bye :(&quot;);
    }, []);
    return &lt;h1&gt;Hello&lt;/h1&gt;;
  }

  function App() {
    const [showing, setShowing] = useState(false);
    const onClick = () =&gt; setShowing((prev) =&gt; !prev);
    return (
      &lt;div&gt;
        {showing ? &lt;Hello /&gt; : null}
        &lt;button onClick={onClick}&gt;{showing ? &quot;Hide&quot; : &quot;Show&quot;}&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→ <code>{showing ? &lt;Hello /&gt; : null}</code> : 코드를 숨기는 것이 아니라 destroy 시키고 새로 생성</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(&quot;created :)&quot;);
    **return** () =&gt; console.log(&quot;destroyed :(&quot;);
  }, []);</code></pre>
<p>→ Cleanup function <code>return</code> : 함수인데 component가 destroy될 때 뭔가 할 수 있도록 해 줌</p>
<p>→ ex) 컴포넌트가 없어질 때 분석 결과를 보내고 싶으면 분석 API 사용 등</p>
<p>→ 자주 사용하지는 X</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[노마드코더] React JS Ch.1~2]]></title>
            <link>https://velog.io/@may_05/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94-React-JS-Ch.12</link>
            <guid>https://velog.io/@may_05/%EB%85%B8%EB%A7%88%EB%93%9C%EC%BD%94%EB%8D%94-React-JS-Ch.12</guid>
            <pubDate>Mon, 22 Jan 2024 00:10:46 GMT</pubDate>
            <description><![CDATA[<h2 id="1-introduction">#1 INTRODUCTION</h2>
<h3 id="11-why-react">1.1 Why React</h3>
<p>React JS 자체가 작고, 대부분의 경우 React JS는 그냥 Javascript</p>
<h3 id="12-requirements">1.2 Requirements</h3>
<p>바닐라 JS (HTML, CSS, Javascript)</p>
<p>Node JS</p>
<p>브라우저 &amp; Visual Studio Code</p>
<h2 id="2-the-basics-of-react">#2 THE BASICS OF REACT</h2>
<h3 id="21-before-react">2.1 Before React</h3>
<ul>
<li><p>vanilla.html</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;span&gt;Total clicks: 0&lt;/span&gt;
      &lt;button id=&quot;btn&quot;&gt;Click me&lt;/button&gt;
    &lt;/body&gt;
    &lt;script&gt;
      let counter = 0;
      const button = document.getElementById(&quot;btn&quot;);
      const span = document.querySelector(&quot;span&quot;);
      function handleClick() {
        //   console.log(&quot;i have been clicked&quot;);
        counter = counter + 1;
        span.innerText = `Total clicks: ${counter}`;
      }
      button.addEventListener(&quot;click&quot;, handleClick);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
<li><p>index.html → bring react src</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;&lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;&lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<h3 id="22-our-first-react-element">2.2 Our First React Element</h3>
<p><strong>React JS</strong> : Interactive한 UI 만들 수 있는 역할</p>
<p><strong>React-dom</strong> : React element를 HTML에 두는 역할</p>
<p>주로 사용하지는 않는 방식</p>
<ul>
<li><p>index.html → using react hard way</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      const root = document.getElementById(&quot;root&quot;);
      const span = React.createElement(&quot;span&quot;, { id: &quot;sexy-span&quot;, style: { color: &quot;red&quot; } }, &quot;Hello I&#39;m a span&quot;);
      ReactDOM.render(span, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
<p>  render : React element를 가지고 HTML로 만들어 배치</p>
</li>
</ul>
<h3 id="23-events-in-react">2.3 Events in React</h3>
<p>주로 사용하지는 않는 방식</p>
<ul>
<li><p>index.html → extra about property &amp; eventListener</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script&gt;
      const root = document.getElementById(&quot;root&quot;);
      const span = React.createElement(
        &quot;h3&quot;,
        {
          onMouseEnter: () =&gt; console.log(&quot;mouse enter&quot;),
        },
        &quot;Hello I&#39;m a span&quot;
      );
      const btn = React.createElement(
        &quot;button&quot;,
        {
          onClick: () =&gt; console.log(&quot;im clicked&quot;),
          style: {
            backgroundColor: &quot;tomato&quot;,
          },
        },
        &quot;Click me&quot;
      );
      const container = React.createElement(&quot;div&quot;, null, [span, btn]);
      ReactDOM.render(container, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<h3 id="24-recap">2.4 Recap</h3>
<p>createElement → 사용 X</p>
<blockquote>
<p>❗ <strong>props</strong> 안에서 eventListener 등록 가능</p>
</blockquote>
<h3 id="25-jsx">2.5 JSX</h3>
<p>createElement를 대체할 코드 → JSX (JavaScript를 확장한 문법)</p>
<ul>
<li>createElement, 이름, props, 내용 → html 코드와 가깝게</li>
</ul>
<p>JSX : 브라우저가 이해할 수 있게 변환해주는 Babel(코드 변환 역할) 필요</p>
<ul>
<li><p>index.html → using JSX</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      const Title = (
        &lt;h3 id=&quot;title&quot; onMouseEnter={() =&gt; console.log(&quot;mouse enter&quot;)}&gt;
          Hello I&#39;m a h3
        &lt;/h3&gt;
      );
      const Button = (
        &lt;button style={{ backgroundColor: &quot;tomato&quot; }} onClick={() =&gt; console.log(&quot;im clicked&quot;)}&gt;
          Click me
        &lt;/button&gt;
      );
      const container = React.createElement(&quot;div&quot;, null, [Title, Button]);
      ReactDOM.render(container, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
<h3 id="26-jsx-part-two">2.6 JSX part Two</h3>
<blockquote>
<p>❗ <strong>Component</strong> → 반드시 <strong>대문자</strong>로 시작</p>
</blockquote>
<p>(소문자일 경우 React와 JSX는 HTML 태그라고 생각)</p>
<ul>
<li>내가 만든 요소 → 전부 대문자로 시작</li>
<li>HTML 요소 → 소문자로 작성</li>
</ul>
<p>컴포넌트를 다른 컴포넌트에 넣는 방법</p>
<ul>
<li><p><strong>index.html</strong> → <strong>final code</strong> with <strong>JSX</strong></p>
<p>  function(함수)로 만드는 방법은 2가지 모두 가능</p>
<pre><code class="language-html">  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
    &lt;body&gt;
      &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;
    &lt;script src=&quot;https://unpkg.com/react@17.0.2/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;
    &lt;script src=&quot;https://unpkg.com/@babel/standalone/babel.min.js&quot;&gt;&lt;/script&gt;
    &lt;script type=&quot;text/babel&quot;&gt;
      const root = document.getElementById(&quot;root&quot;);
      function Title() {
        return (
          &lt;h3 id=&quot;title&quot; onMouseEnter={() =&gt; console.log(&quot;mouse enter&quot;)}&gt;
            Hello I&#39;m a h3
          &lt;/h3&gt;
        );
      }
      const Button = () =&gt; (
        &lt;button style={{ backgroundColor: &quot;tomato&quot; }} onClick={() =&gt; console.log(&quot;im clicked&quot;)}&gt;
          Click me
        &lt;/button&gt;
      );
      const Container = () =&gt; (
        &lt;div&gt;
          &lt;Title /&gt;
          &lt;Button /&gt;
        &lt;/div&gt;
      );
      ReactDOM.render(&lt;Container /&gt;, root);
    &lt;/script&gt;
  &lt;/html&gt;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩앙마] React JS 10~17차]]></title>
            <link>https://velog.io/@may_05/%EC%BD%94%EB%94%A9%EC%95%99%EB%A7%88-React-JS-1017%EC%B0%A8</link>
            <guid>https://velog.io/@may_05/%EC%BD%94%EB%94%A9%EC%95%99%EB%A7%88-React-JS-1017%EC%B0%A8</guid>
            <pubDate>Mon, 22 Jan 2024 00:01:48 GMT</pubDate>
            <description><![CDATA[<h2 id="라우터-구현">라우터 구현</h2>
<h3 id="react-router-dom">react-router-dom</h3>
<ul>
<li><p><em>App.js</em></p>
<pre><code class="language-cpp">  import DayList from &quot;./component/DayList&quot;;
  import Header from &quot;./component/Header&quot;;
  import Day from &quot;./component/Day&quot;;
  import { BrowserRouter, Route, Routes } from &quot;react-router-dom&quot;;

  function App() {
    return (
      &lt;BrowserRouter&gt;
        &lt;div className=&quot;App&quot;&gt;
          &lt;Header /&gt;
          &lt;Routes&gt;
            &lt;Route exact path=&quot;/&quot; element={&lt;DayList /&gt;} /&gt;
            &lt;Route path=&quot;/day&quot; element={&lt;Day /&gt;} /&gt;
          &lt;/Routes&gt;
        &lt;/div&gt;
      &lt;/BrowserRouter&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→ 강의에서는 switch 사용 but 오류 발생</p>
<p>→ Routes로 변경 후 element 사용 → 해결</p>
<p>→ 버전 차이?</p>
<h3 id="link-to-→-a-href-역할">Link to → a href 역할</h3>
<ul>
<li><p>Header.js</p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;

  export default function Header() {
    return (
      &lt;div className=&quot;header&quot;&gt;
        &lt;h1&gt;
          &lt;Link to=&quot;/&quot;&gt;토익 영단어(고급)&lt;/Link&gt;
        &lt;/h1&gt;
        &lt;div className=&quot;menu&quot;&gt;
          &lt;a href=&quot;#x&quot; className=&quot;link&quot;&gt;
            단어 추가
          &lt;/a&gt;
          &lt;a href=&quot;#x&quot; className=&quot;link&quot;&gt;
            Day 추가
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>import { Link } from &quot;react-router-dom&quot;;</code> : 라우터의 Link 기능 임포트</p>
<p>→ <code>&lt;Link to=&quot;/&quot;&gt;</code> : 처음의 화면</p>
<ul>
<li><p><em>DayList.js</em></p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;
  import dummy from &quot;../db/data.json&quot;;

  export default function DayList() {
    console.log(dummy);
    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {dummy.days.map((day) =&gt; (
          &lt;li key={day.id}&gt;
            &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>{</code>/day/${day.day}<code>}</code> : 각 day 별 페이지로 연결</p>
<ul>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import dummy from &quot;../db/data.json&quot;;
  import { useParams } from &quot;react-router-dom&quot;;

  export default function Day() {
    //   dummy.words;

    const day = useParams().day;
    const wordList = dummy.words.filter((word) =&gt; word.day === Number(day));

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            {wordList.map((word) =&gt; (
              &lt;tr key={word.id}&gt;
                &lt;td&gt;{word.eng}&lt;/td&gt;
                &lt;td&gt;{word.kor}&lt;/td&gt;
              &lt;/tr&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>useParams</code> : 각 day별 단어를 가져올 수 있게 하는 기능</p>
<p>→ <code>Number(day)</code> : json에 day를 숫자값으로 저장해줬기 때문에 숫자로 입력해야 데이터 사용 가능</p>
<ul>
<li><p><em>EmptyPage.js</em></p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;

  export default function EmptyPage() {
    return (
      &lt;&gt;
        &lt;h2&gt;잘못된 접근입니다.&lt;/h2&gt;
        &lt;Link to=&quot;/&quot;&gt;돌아가기&lt;/Link&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ 없는 주소에 접속했을 때 나오는 페이지</p>
<ul>
<li><p><em>App.js</em></p>
<pre><code class="language-jsx">  import DayList from &quot;./component/DayList&quot;;
  import Header from &quot;./component/Header&quot;;
  import Day from &quot;./component/Day&quot;;
  import { BrowserRouter, Route, Routes } from &quot;react-router-dom&quot;;
  import EmptyPage from &quot;./component/EmptyPage&quot;;

  function App() {
    return (
      &lt;BrowserRouter&gt;
        &lt;div className=&quot;App&quot;&gt;
          &lt;Header /&gt;
          &lt;Routes&gt;
            &lt;Route exact path=&quot;/&quot; element={&lt;DayList /&gt;} /&gt;
            &lt;Route path=&quot;/day/:day&quot; element={&lt;Day /&gt;} /&gt;
            &lt;Route path=&quot;*&quot; element={&lt;EmptyPage /&gt;} /&gt;
          &lt;/Routes&gt;
        &lt;/div&gt;
      &lt;/BrowserRouter&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>→ <code>&lt;Route path=&quot;*&quot; element={&lt;EmptyPage /&gt;} /&gt;</code> : 맨 아래에 없는 주소의 페이지에 대한 정의</p>
<h2 id="json-server-rest-api">json-server, REST API</h2>
<h3 id="word-컴포넌트-생성">Word 컴포넌트 생성</h3>
<ul>
<li><p><em>Word.js</em></p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Word({ word }) {
    const [isShow, setIsShow] = useState(false);
    const [isDone, setIsDone] = useState(word.isDone);

    function toggleShow() {
      setIsShow(!isShow);
    }

    function toggleDone() {
      setIsDone(!isDone);
    }

    return (
      &lt;tr className={isDone ? &quot;off&quot; : &quot;&quot;}&gt;
        &lt;td&gt;
          &lt;input type=&quot;checkbox&quot; checked={isDone} onChange={toggleDone} /&gt;
        &lt;/td&gt;
        &lt;td&gt;{word.eng}&lt;/td&gt;
        &lt;td&gt;{isShow &amp;&amp; word.kor}&lt;/td&gt;
        &lt;td&gt;
          &lt;button onClick={toggleShow}&gt;뜻 {isShow ? &quot;숨기기&quot; : &quot;보기&quot;}&lt;/button&gt;
          &lt;button className=&quot;btn_del&quot;&gt;삭제&lt;/button&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>isShow</code>, <code>isDone</code> → useState로 값 설정</p>
<p>→ <code>toggleShow</code>, <code>toggleDone</code> → 함수로 체크 박스 설정</p>
<ul>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import dummy from &quot;../db/data.json&quot;;
  import { useParams } from &quot;react-router-dom&quot;;
  import Word from &quot;./Word&quot;;

  export default function Day() {
    //   dummy.words;

    const day = useParams().day;
    const wordList = dummy.words.filter((word) =&gt; word.day === Number(day));

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            {wordList.map((word) =&gt; (
              &lt;Word word={word} key={word.id} /&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>import Word from &quot;./Word&quot;;</code> : Word 컴포넌트 임포트</p>
<p>→ <code>&lt;Word word={word} key={word.id} /&gt;</code> : Word 컴포넌트를 key 값을 설정해주며 가져오기</p>
<h3 id="json-server-사용">json-server 사용</h3>
<p>: 명령어 사용 후 port를 3001로 수정하면 json 값이 넘어온 것 확인 가능 (명령어로 port 3001로 설정해줌)</p>
<h3 id="rest-api">REST API</h3>
<p>→ method로 CRUD 기능을 하는 것</p>
<ul>
<li>Create : POST</li>
<li>Read : GET</li>
<li>Update : PUT</li>
<li>Delete : DELETE</li>
</ul>
<h2 id="useeffect-fetch로-api-호출">useEffect, fetch()로 API 호출</h2>
<p>→ dummy 값을 지우고 json 사용</p>
<h3 id="useeffect">useEffect</h3>
<p>: Hook → useState와 마찬가지로 리액트에서 임포트</p>
<p>: 어떤 상태값이 바뀌었을 때 동작하는 함수 작성 가능</p>
<ul>
<li><p><em>DayList.js</em> → 설명을 위한 코드 작성</p>
<pre><code class="language-jsx">  import { useEffect, useState } from &quot;react&quot;;
  import { Link } from &quot;react-router-dom&quot;;

  export default function DayList() {
    const [days, setDays] = useState([]);
    const [count, setCount] = useState(0);

    function onClick() {
      setCount(count + 1);
    }

    function onClick2() {
      setDays([
        ...days,
        {
          id: Math.random(),
          day: 1,
        },
      ]);
    }

    useEffect(() =&gt; {
      console.log(&quot;Count change&quot;);
    }, []);

    return (
      &lt;&gt;
        &lt;ul className=&quot;list_day&quot;&gt;
          {days.map((day) =&gt; (
            &lt;li key={day.id}&gt;
              &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
        &lt;button onClick={onClick}&gt;{count}&lt;/button&gt;
        &lt;button onClick={onClick2}&gt;Day change&lt;/button&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(&quot;Count change&quot;);
  }, [count]);</code></pre>
<p>→ count(의존성 배열의 값)이 변경되었을 때만 함수(useEffect)가 실행</p>
<p>→ 의존성 배열</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(&quot;Count change&quot;);
  }, []);</code></pre>
<p>→ 현재는 API 호출을 위해 사용하기 때문에 한번만 호출</p>
<p>→ <code>[count]</code> 부분(의존성 배열 부분)을 빈 배열을 입력</p>
<h3 id="useeffect--api-호출">useEffect + API 호출</h3>
<ul>
<li><p><em>DayList.js</em></p>
<pre><code class="language-jsx">  import { useEffect, useState } from &quot;react&quot;;
  import { Link } from &quot;react-router-dom&quot;;

  export default function DayList() {
    const [days, setDays] = useState([]);

    useEffect(() =&gt; {
      fetch(&quot;http://localhost:3001/days&quot;)
        .then((res) =&gt; {
          return res.json();
        })
        .then((data) =&gt; {
          setDays(data);
        });
    }, []);

    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {days.map((day) =&gt; (
          &lt;li key={day.id}&gt;
            &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import { useEffect, useState } from &quot;react&quot;;
  import { useParams } from &quot;react-router-dom&quot;;
  import Word from &quot;./Word&quot;;

  export default function Day() {
    const day = useParams().day;
    const [words, setWords] = useState([]);

    useEffect(() =&gt; {
      fetch(`http://localhost:3001/words?day=${day}`)
        .then((res) =&gt; {
          return res.json();
        })
        .then((data) =&gt; {
          setWords(data);
        });
    }, [day]);

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            {words.map((word) =&gt; (
              &lt;Word word={word} key={word.id} /&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→  두 코드의 api를 가져와서 사용하는 useEffect 코드가 비슷</p>
<p>→ Custom Hook 제작 가능</p>
<h2 id="custom-hooks">Custom Hooks</h2>
<h3 id="hook-만들기">Hook 만들기</h3>
<p>→ src &gt; hooks 폴더 만들기</p>
<p>→ useFetch.js 파일 생성</p>
<ul>
<li><p><em>useFetch.js</em></p>
<pre><code class="language-jsx">  import { useEffect, useState } from &quot;react&quot;;

  export default function useFetch(url) {
    const [data, setData] = useState([]);

    useEffect(() =&gt; {
      fetch(url)
        .then((res) =&gt; {
          return res.json();
        })
        .then((data) =&gt; {
          setData(data);
        });
    }, [url]);

    return data;
  }</code></pre>
</li>
</ul>
<p>→ 변하는 부분이 <code>url</code>이기 때문에 입력받는 값으로</p>
<p>→ 공통되는 함수이므로 <code>data, setData</code> 로 변경</p>
<p>→ <code>data</code> 값 return</p>
<p>useFetch를 사용하여 수정한 파일</p>
<ul>
<li><p><em>DayList.js</em></p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;

  export default function DayList() {
    const days = useFetch(&quot;http://localhost:3001/days&quot;);

    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {days.map((day) =&gt; (
          &lt;li key={day.id}&gt;
            &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import { useParams } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;
  import Word from &quot;./Word&quot;;

  export default function Day() {
    const day = useParams().day;
    const words = useFetch(`http://localhost:3001/words?day=${day}`);

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            {words.map((word) =&gt; (
              &lt;Word word={word} key={word.id} /&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<h2 id="put수정-delete삭제">PUT(수정), DELETE(삭제)</h2>
<h3 id="put수정">PUT(수정)</h3>
<ul>
<li><p><em>Word.js</em></p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Word({ word }) {
    const [isShow, setIsShow] = useState(false);
    const [isDone, setIsDone] = useState(word.isDone);

    function toggleShow() {
      setIsShow(!isShow);
    }

    function toggleDone() {
      // setIsDone(!isDone);
      fetch(`http://localhost:3001/words/${word.id}`, {
        method: &quot;PUT&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
        body: JSON.stringify({
          ...word,
          isDone: !isDone,
        }),
      }).then((res) =&gt; {
        if (res.ok) {
          setIsDone(!isDone);
        }
      });
    }

    return (
      &lt;tr className={isDone ? &quot;off&quot; : &quot;&quot;}&gt;
        &lt;td&gt;
          &lt;input type=&quot;checkbox&quot; checked={isDone} onChange={toggleDone} /&gt;
        &lt;/td&gt;
        &lt;td&gt;{word.eng}&lt;/td&gt;
        &lt;td&gt;{isShow &amp;&amp; word.kor}&lt;/td&gt;
        &lt;td&gt;
          &lt;button onClick={toggleShow}&gt;뜻 {isShow ? &quot;숨기기&quot; : &quot;보기&quot;}&lt;/button&gt;
          &lt;button className=&quot;btn_del&quot;&gt;삭제&lt;/button&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>function toggleDone()</code> : useFetch 사용 및 수정 가능하게 변경</p>
<p>→ <code>method: &quot;PUT&quot;</code> : 게시글 수정</p>
<p>→ <code>&quot;Content-Type&quot;: &quot;application/json&quot;</code> : 보내는 리소스의 타입이 json</p>
<h3 id="delete삭제">DELETE(삭제)</h3>
<ul>
<li><p><em>Word.js</em></p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Word({ word: w }) {
    const [word, setWord] = useState(w);
    const [isShow, setIsShow] = useState(false);
    const [isDone, setIsDone] = useState(word.isDone);

    function toggleShow() {
      setIsShow(!isShow);
    }

    function toggleDone() {
      // setIsDone(!isDone);
      fetch(`http://localhost:3001/words/${word.id}`, {
        method: &quot;PUT&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
        body: JSON.stringify({
          ...word,
          isDone: !isDone,
        }),
      }).then((res) =&gt; {
        if (res.ok) {
          setIsDone(!isDone);
        }
      });
    }

    function del() {
      if (window.confirm(&quot;삭제 하시겠습니까?&quot;)) {
        fetch(`http://localhost:3001/words/${word.id}`, {
          method: &quot;DELETE&quot;,
        }).then((res) =&gt; {
          if (res.ok) {
            setWord({ id: 0 });
          }
        });
      }
    }

    if (word.id === 0) {
      return null;
    }

    return (
      &lt;tr className={isDone ? &quot;off&quot; : &quot;&quot;}&gt;
        &lt;td&gt;
          &lt;input type=&quot;checkbox&quot; checked={isDone} onChange={toggleDone} /&gt;
        &lt;/td&gt;
        &lt;td&gt;{word.eng}&lt;/td&gt;
        &lt;td&gt;{isShow &amp;&amp; word.kor}&lt;/td&gt;
        &lt;td&gt;
          &lt;button onClick={toggleShow}&gt;뜻 {isShow ? &quot;숨기기&quot; : &quot;보기&quot;}&lt;/button&gt;
          &lt;button onClick={del} className=&quot;btn_del&quot;&gt;
            삭제
          &lt;/button&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>method: &quot;DELETE&quot;</code> : 게시글 삭제</p>
<p>→ 삭제하는 값은 return 할 값이 없음</p>
<p>→ <code>{ word: w }</code> : 새로운 변수명 가능</p>
<p>→ <code>return null;</code> : null 값을 줌으로써 공간을 비우고 새로고침하지 않고도 페이지에 바로 반영</p>
<h2 id="post생성-usehistory">POST(생성), <del>useHistory()</del></h2>
<h3 id="post생성-usenavigate">POST(생성), useNavigate()</h3>
<ul>
<li><p><em>Header.js</em></p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;

  export default function Header() {
    return (
      &lt;div className=&quot;header&quot;&gt;
        &lt;h1&gt;
          &lt;Link to=&quot;/&quot;&gt;토익 영단어(고급)&lt;/Link&gt;
        &lt;/h1&gt;
        &lt;div className=&quot;menu&quot;&gt;
          &lt;Link to=&quot;/create_word&quot; className=&quot;link&quot;&gt;
            단어 추가
          &lt;/Link&gt;
          &lt;Link to=&quot;/create_day&quot; className=&quot;link&quot;&gt;
            Day 추가
          &lt;/Link&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
<li><p><em>App.js</em></p>
<pre><code class="language-jsx">  import DayList from &quot;./component/DayList&quot;;
  import Header from &quot;./component/Header&quot;;
  import Day from &quot;./component/Day&quot;;
  import { BrowserRouter, Route, Routes } from &quot;react-router-dom&quot;;
  import EmptyPage from &quot;./component/EmptyPage&quot;;
  import CreateWord from &quot;./component/CreateWord&quot;;
  import CreateDay from &quot;./component/CreateDay&quot;;

  function App() {
    return (
      &lt;BrowserRouter&gt;
        &lt;div className=&quot;App&quot;&gt;
          &lt;Header /&gt;
          &lt;Routes&gt;
            &lt;Route exact path=&quot;/&quot; element={&lt;DayList /&gt;} /&gt;
            &lt;Route path=&quot;/day/:day&quot; element={&lt;Day /&gt;} /&gt;
            &lt;Route path=&quot;/create_word&quot; element={&lt;CreateWord /&gt;} /&gt;
            &lt;Route path=&quot;/create_day&quot; element={&lt;CreateDay /&gt;} /&gt;
            &lt;Route path=&quot;*&quot; element={&lt;EmptyPage /&gt;} /&gt;
          &lt;/Routes&gt;
        &lt;/div&gt;
      &lt;/BrowserRouter&gt;
    );
  }

  export default App;</code></pre>
</li>
<li><p><em>CreateWord.js</em></p>
<pre><code class="language-jsx">  import { useRef } from &quot;react&quot;;
  import { useNavigate } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;

  export default function CreateWord() {
    const days = useFetch(&quot;http://localhost:3001/days&quot;);
    const navigate = useNavigate();

    function onSubmit(e) {
      e.preventDefault();

      fetch(`http://localhost:3001/words/`, {
        method: &quot;POST&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
        body: JSON.stringify({
          day: dayRef.current.value,
          eng: engRef.current.value,
          kor: korRef.current.value,
          isDone: false,
        }),
      }).then((res) =&gt; {
        if (res.ok) {
          alert(&quot;생성이 완료 되었습니다&quot;);
          navigate(`/day/${dayRef.current.value}`);
        }
      });
    }

    const engRef = useRef(null);
    const korRef = useRef(null);
    const dayRef = useRef(null);

    return (
      &lt;form onSubmit={onSubmit}&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Eng&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;computer&quot; ref={engRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Kor&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;컴퓨터&quot; ref={korRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Day&lt;/label&gt;
          &lt;select ref={dayRef}&gt;
            {days.map((day) =&gt; (
              &lt;option key={day.id} value={day.day}&gt;
                {day.day}
              &lt;/option&gt;
            ))}
          &lt;/select&gt;
        &lt;/div&gt;
        &lt;button&gt;저장&lt;/button&gt;
      &lt;/form&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ <code>useRef()</code> : <code>dom</code>에 접근할 수 있게 해줌 (ex. 스크롤 위치 확인, 포커스를 줄 때)</p>
<p>→ <code>current</code> : 해당 요소에 접근 가능</p>
<p>→ <code>vaule</code> : input에 입력된 값을 얻을 수 있음</p>
<p>→ 현재 버전에서 <code>history</code> 지원 X <code>navigate</code> 사용 : 해당 페이지로 이동 기능</p>
<ul>
<li><p><em>CreateDay.js</em></p>
<pre><code class="language-jsx">  import useFetch from &quot;../hooks/useFetch&quot;;
  import { useNavigate } from &quot;react-router-dom&quot;;

  export default function CreateWord() {
    const days = useFetch(&quot;http://localhost:3001/days&quot;);
    const navigate = useNavigate();

    function addDay() {
      fetch(`http://localhost:3001/days/`, {
        method: &quot;POST&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
        body: JSON.stringify({
          day: days.length + 1,
        }),
      }).then((res) =&gt; {
        if (res.ok) {
          alert(&quot;생성이 완료 되었습니다&quot;);
          navigate(`/`);
        }
      });
    }

    return (
      &lt;div&gt;
        &lt;h3&gt;현재 일수 : {days.length}일&lt;/h3&gt;
        &lt;button onClick={addDay}&gt;Day 추가&lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ 단어 추가와 비슷하지만 day만 추가해주는 기능</p>
<h2 id="마무리-추가-강의">마무리 (추가 강의)</h2>
<h3 id="느린-네트워크-환경">느린 네트워크 환경</h3>
<ul>
<li><p><em>DayList.js</em></p>
<pre><code class="language-jsx">  import { Link } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;

  export default function DayList() {
    const days = useFetch(&quot;http://localhost:3001/days&quot;);

    if (days.length === 0) {
      return &lt;span&gt;Loading...&lt;/span&gt;;
    }

    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {days.map((day) =&gt; (
          &lt;li key={day.id}&gt;
            &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import { useParams } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;
  import Word from &quot;./Word&quot;;

  export default function Day() {
    const day = useParams().day;
    const words = useFetch(`http://localhost:3001/words?day=${day}`);

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        {words.length === 0 &amp;&amp; &lt;span&gt;Loading...&lt;/span&gt;}
        &lt;table&gt;
          &lt;tbody&gt;
            {words.map((word) =&gt; (
              &lt;Word word={word} key={word.id} /&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<h3 id="통신-중-추가-불가능하게-하는-기능">통신 중 추가 불가능하게 하는 기능</h3>
<ul>
<li><p><em>CreateWord.js</em></p>
<pre><code class="language-jsx">  import { useRef, useState } from &quot;react&quot;;
  import { useNavigate } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;

  export default function CreateWord() {
    const days = useFetch(&quot;http://localhost:3001/days&quot;);
    const navigate = useNavigate();
    const [isLoading, setIsLoading] = useState(false);

    function onSubmit(e) {
      e.preventDefault();

      if (!isLoading) {
        setIsLoading(true);
        fetch(`http://localhost:3001/words/`, {
          method: &quot;POST&quot;,
          headers: {
            &quot;Content-Type&quot;: &quot;application/json&quot;,
          },
          body: JSON.stringify({
            day: dayRef.current.value,
            eng: engRef.current.value,
            kor: korRef.current.value,
            isDone: false,
          }),
        }).then((res) =&gt; {
          if (res.ok) {
            alert(&quot;생성이 완료 되었습니다&quot;);
            navigate(`/day/${dayRef.current.value}`);
            setIsLoading(false);
          }
        });
      }
    }

    const engRef = useRef(null);
    const korRef = useRef(null);
    const dayRef = useRef(null);

    return (
      &lt;form onSubmit={onSubmit}&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Eng&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;computer&quot; ref={engRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Kor&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;컴퓨터&quot; ref={korRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Day&lt;/label&gt;
          &lt;select ref={dayRef}&gt;
            {days.map((day) =&gt; (
              &lt;option key={day.id} value={day.day}&gt;
                {day.day}
              &lt;/option&gt;
            ))}
          &lt;/select&gt;
        &lt;/div&gt;
        &lt;button
          style={{
            opacity: isLoading ? 0.3 : 1,
          }}
        &gt;
          {isLoading ? &quot;Saving...&quot; : &quot;저장&quot;}
        &lt;/button&gt;
      &lt;/form&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ 여러번 클릭하여 빈 값이 추가되는 것을 막는 역할 (Loading 관련 부분)</p>
<h2 id="부록--타입스크립트">부록 : 타입스크립트</h2>
<p>→ 프로젝트 초기부터 사용하는 것이 좋음</p>
<p>→ but 이후에도 적용 가능하니 늦었다고 생각 X</p>
<h3 id="타입스크립트">타입스크립트</h3>
<p><code>js</code> 파일 → <code>.ts</code></p>
<p><code>jsx</code> 파일 (html 사용 파일) → <code>.tsx</code>로 변경</p>
<ul>
<li><p><em>Word.tsx</em></p>
<pre><code class="language-tsx">  import { useState } from &quot;react&quot;;

  interface IProps {
    word: IWord;
  }

  export interface IWord {
    day: string;
    eng: string;
    kor: string;
    isDone: boolean;
    id: number;
  }

  export default function Word({ word: w }: IProps) {
    const [word, setWord] = useState(w);
    const [isShow, setIsShow] = useState(false);
    const [isDone, setIsDone] = useState(word.isDone);

    function toggleShow() {
      setIsShow(!isShow);
    }

    function toggleDone() {
      // setIsDone(!isDone);
      fetch(`http://localhost:3001/words/${word.id}`, {
        method: &quot;PUT&quot;,
        headers: {
          &quot;Content-Type&quot;: &quot;application/json&quot;,
        },
        body: JSON.stringify({
          ...word,
          isDone: !isDone,
        }),
      }).then((res) =&gt; {
        if (res.ok) {
          setIsDone(!isDone);
        }
      });
    }

    function del() {
      if (window.confirm(&quot;삭제 하시겠습니까?&quot;)) {
        fetch(`http://localhost:3001/words/${word.id}`, {
          method: &quot;DELETE&quot;,
        }).then((res) =&gt; {
          if (res.ok) {
            setWord({
              ...word,
              id: 0,
            });
          }
        });
      }
    }

    if (word.id === 0) {
      return null;
    }

    return (
      &lt;tr className={isDone ? &quot;off&quot; : &quot;&quot;}&gt;
        &lt;td&gt;
          &lt;input type=&quot;checkbox&quot; checked={isDone} onChange={toggleDone} /&gt;
        &lt;/td&gt;
        &lt;td&gt;{word.eng}&lt;/td&gt;
        &lt;td&gt;{isShow &amp;&amp; word.kor}&lt;/td&gt;
        &lt;td&gt;
          &lt;button onClick={toggleShow}&gt;뜻 {isShow ? &quot;숨기기&quot; : &quot;보기&quot;}&lt;/button&gt;
          &lt;button onClick={del} className=&quot;btn_del&quot;&gt;
            삭제
          &lt;/button&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    );
  }</code></pre>
</li>
</ul>
<p><code>type</code> → <code>any</code> : 남발 X</p>
<p><code>interface</code> → 여러개의 <code>property</code>에 각각 다른 타입 입력 가능</p>
<p><code>typescript</code> → <code>property</code> 사용의 편리성 향상</p>
<p><code>setWord({ id: 0 })</code> → <code>id</code> 외의 값들을 옵션(ex. <code>day?: string;</code>)으로 하여 오류 해결</p>
<p><strong>but</strong> 삭제 외에는 모든 값들이 필요해서 좋은 방법 X → <code>...word,</code> 로 다른 값들을 넣어주는 방법으로 해결</p>
<p><code>export interface</code> → 다른 파일에서도 인터페이스 사용 가능</p>
<ul>
<li><p><em>Day.tsx</em></p>
<pre><code class="language-tsx">  import { useParams } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;
  import Word, { IWord } from &quot;./Word&quot;;

  export default function Day() {
    // const day = useParams().day;
    const { day } = useParams&lt;{ day: string }&gt;();
    const words: IWord[] = useFetch(`http://localhost:3001/words?day=${day}`);

    return (
      &lt;&gt;
        &lt;h2&gt;Day {day}&lt;/h2&gt;
        {words.length === 0 &amp;&amp; &lt;span&gt;Loading...&lt;/span&gt;}
        &lt;table&gt;
          &lt;tbody&gt;
            {words.map((word) =&gt; (
              &lt;Word word={word} key={word.id} /&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
</ul>
<p><code>key={word.id}</code> → word가 IWord라는 것을 못 찾기 때문에 오류 발생</p>
<p>→ Word에서 export로 해주고 임포트하여 설정 후 해결 가능</p>
<p>{ day } → useParams에서 가져오는 객체 내부에 day가 있는지 확신 X로 인한 오류 발생</p>
<p>→ &lt;&gt; generic 속에 타입을 설정하여 오류 해결</p>
<ul>
<li><p><em>DayList.tsx</em></p>
<pre><code class="language-tsx">  import { Link } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;

  export interface IDay {
    id: number;
    day: number;
  }

  export default function DayList() {
    const days: IDay[] = useFetch(&quot;http://localhost:3001/days&quot;);

    if (days.length === 0) {
      return &lt;span&gt;Loading...&lt;/span&gt;;
    }

    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {days.map((day) =&gt; (
          &lt;li key={day.id}&gt;
            &lt;Link to={`/day/${day.day}`}&gt;Day {day.day}&lt;/Link&gt;
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
</ul>
<p><code>IDay</code> 라는 인터페이스를 만들어서 사용</p>
<ul>
<li><p><em>CreateWord.tsx</em></p>
<pre><code class="language-tsx">  import React, { useRef, useState } from &quot;react&quot;;
  import { useNavigate } from &quot;react-router-dom&quot;;
  import useFetch from &quot;../hooks/useFetch&quot;;
  import { IDay } from &quot;./DayList&quot;;

  export default function CreateWord() {
    const days: IDay[] = useFetch(&quot;http://localhost:3001/days&quot;);
    const navigate = useNavigate();
    const [isLoading, setIsLoading] = useState(false);

    function onSubmit(e: React.FormEvent) {
      e.preventDefault();

      if (!isLoading &amp;&amp; dayRef.current &amp;&amp; engRef.current &amp;&amp; korRef.current) {
        setIsLoading(true);

        const day: dayRef.current.value;
        const eng: engRef.current.value;
        const kor: korRef.current.value;

        fetch(`http://localhost:3001/words/`, {
          method: &quot;POST&quot;,
          headers: {
            &quot;Content-Type&quot;: &quot;application/json&quot;,
          },
          body: JSON.stringify({
            day,
            eng,
            kor,
            isDone: false,
          }),
        }).then((res) =&gt; {
          if (res.ok) {
            alert(&quot;생성이 완료 되었습니다&quot;);
            navigate(`/day/${day}`);
            setIsLoading(false);
          }
        });
      }
    }

    const engRef = useRef&lt;HTMLInputElement&gt;(null);
    const korRef = useRef&lt;HTMLInputElement&gt;(null);
    const dayRef = useRef&lt;HTMLSelectElement&gt;(null);

    return (
      &lt;form onSubmit={onSubmit}&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Eng&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;computer&quot; ref={engRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Kor&lt;/label&gt;
          &lt;input type=&quot;text&quot; placeholder=&quot;컴퓨터&quot; ref={korRef} /&gt;
        &lt;/div&gt;
        &lt;div className=&quot;input_area&quot;&gt;
          &lt;label&gt;Day&lt;/label&gt;
          &lt;select ref={dayRef}&gt;
            {days.map((day) =&gt; (
              &lt;option key={day.id} value={day.day}&gt;
                {day.day}
              &lt;/option&gt;
            ))}
          &lt;/select&gt;
        &lt;/div&gt;
        &lt;button
          style={{
            opacity: isLoading ? 0.3 : 1,
          }}
        &gt;
          {isLoading ? &quot;Saving...&quot; : &quot;저장&quot;}
        &lt;/button&gt;
      &lt;/form&gt;
    );
  }</code></pre>
</li>
</ul>
<p><code>submit</code>하는 이벤트 → <code>React.FormEvent</code></p>
<p><code>Ref</code>의 <code>current</code>는 렌더링이 완료된 이후에도 없을 수 있음 → null인지 아닌지 체크해주는 것이 필요</p>
<p><code>dayRef.current &amp;&amp; engRef.current &amp;&amp; korRef.current</code> → 값이 없으면 실행하지 X</p>
<ul>
<li><p><em>useFetch.ts</em></p>
<pre><code class="language-tsx">  import { useEffect, useState } from &quot;react&quot;;

  export default function useFetch(url: string) {
    const [data, setData] = useState([]);

    useEffect(() =&gt; {
      fetch(url)
        .then((res) =&gt; {
          return res.json();
        })
        .then((data) =&gt; {
          setData(data);
        });
    }, [url]);

    return data;
  }</code></pre>
</li>
</ul>
<h2 id="핵심-요약">핵심 요약</h2>
<blockquote>
<p>💻 <strong>라우터 설치 명령어</strong>
<code>npm install react-router-dom</code></p>
</blockquote>
<blockquote>
<p>💻 <strong>json 서버 설치 명령어</strong>
<code>npm install -g json-server</code>
💻 <strong>서버 위치, port 설정 명령어</strong>
<code>json-server --watch ./src/db/data.json --port 3001</code>
→ 두 명령어 동시 사용</p>
</blockquote>
<blockquote>
<p>💻 <strong>typescript 설치 명령어</strong>
+
<code>npm install typescript @types/node @types/react/ @types/react-dom @types/jest</code>
→ <code>create-react-app</code>으로 만들어진 프로젝트에  적용하려면 뒤에까지 꼭 입력
+
<code>npm install typescript @types/node @types/react @types/react-dom @types/jest @types/react-router-dom</code>
→ 추가 설치한 라우터 돔까지</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코딩앙마] React JS 1~9차]]></title>
            <link>https://velog.io/@may_05/%EC%BD%94%EB%94%A9%EC%95%99%EB%A7%88-react.js-19%EC%B0%A8</link>
            <guid>https://velog.io/@may_05/%EC%BD%94%EB%94%A9%EC%95%99%EB%A7%88-react.js-19%EC%B0%A8</guid>
            <pubDate>Sun, 21 Jan 2024 23:55:56 GMT</pubDate>
            <description><![CDATA[<h2 id="react-start">React Start</h2>
<h3 id="node_modules">node_modules</h3>
<p>: 필요한 모듈이 설치되어 있는 폴더 (git 업로드 X)</p>
<p>package.json → <code>“dependencies”</code>에 모듈 기록</p>
<p><code>npm install</code> → 모듈 설치 가능</p>
<h3 id="public">public</h3>
<pre><code class="language-html">&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code></pre>
<p><code>div id=&quot;root&quot;</code> → 리액트 코드가 실행돼서 만들어진 dom이 구현</p>
<h3 id="src">src</h3>
<p>: 대부분의 작업이 src 폴더 내부에서 진행</p>
<pre><code class="language-jsx">import App from &#39;./App&#39;;</code></pre>
<p>→ 초기화면이 App.js이 사용된 페이지</p>
<ul>
<li><p><em>App.js</em></p>
<pre><code class="language-jsx">  import logo from &quot;./logo.svg&quot;;
  import &quot;./App.css&quot;;

  function App() {
    return (
      &lt;div className=&quot;App&quot;&gt;
        &lt;header className=&quot;App-header&quot;&gt;
          &lt;img src={logo} className=&quot;App-logo&quot; alt=&quot;logo&quot; /&gt;
          &lt;p&gt;Coding angma&lt;/p&gt;
          &lt;a className=&quot;App-link&quot; href=&quot;https://reactjs.org&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;
            Learn React
          &lt;/a&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p><code>class</code>가 자바스크립트 예약어 → <code>className</code>으로 사용</p>
<p>JSX → 자바스크립트 내부에 html 코드를 작성하는 것</p>
<p>Hot Module Replacement(HMR)</p>
<h2 id="명령어">명령어</h2>
<ul>
<li><code>npm start</code> : 개발모드로 프로그램을 실행</li>
<li><code>npm build</code> : 실제 배포모드로 만들어줌</li>
<li><code>npm test</code> : 테스트</li>
<li><code>npm eject</code> : 내부 설정파일을 꺼내는 역할 / 웹페이지 설정을 변경하고 싶을 때 사용</li>
</ul>
<h2 id="컴포넌트">컴포넌트</h2>
<p>: 각 부분을 컴포넌트로 만들어서 조립해서 사용</p>
<p>→ 코드 재사용 O / 유지 보수 수월</p>
<ul>
<li><p>함수명 대문자로 시작</p>
</li>
<li><p>스타일 → 객체로 전달해야 적용 가능</p>
</li>
<li><p><strong><em>App.js →</em></strong> 객체 생성 및 첫 시도</p>
<pre><code class="language-jsx">  import &quot;./App.css&quot;;

  function App() {
    const name = &quot;Tom&quot;;
    const naver = {
      name: &quot;네이버&quot;,
      url: &quot;https://naver.com&quot;,
    };
    return (
      &lt;div className=&quot;App&quot;&gt;
        &lt;h1 style={{ color: &quot;#f0f&quot;, backgroundColor: &quot;green&quot; }}&gt;
          Hello, {name}.&lt;p&gt;(2 + 3)&lt;/p&gt;
        &lt;/h1&gt;
        &lt;a href={naver.url}&gt;{naver.name}&lt;/a&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
<p>  <img src="https://velog.velcdn.com/images/may_05/post/bb49f0b2-3aee-49da-8a9d-149346f523b4/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><p><strong><em>Hello.js</em></strong> → src &gt; component 폴더 생성 &gt; Hello.js</p>
<pre><code class="language-jsx">  const Hello = function() {
      &lt;p&gt;Hello&lt;/p&gt;
  };

  export default Hello;</code></pre>
<pre><code class="language-jsx">  const Hello = () =&gt; {
      &lt;p&gt;Hello&lt;/p&gt;
  };

  export default Hello;</code></pre>
<pre><code class="language-jsx">  export default function Hello() {
    return &lt;p&gt;Hello&lt;/p&gt;;
  }</code></pre>
<p>  <strong>App.js 에 반영</strong></p>
<pre><code class="language-jsx">  import &quot;./App.css&quot;;
  import Hello from &quot;./component/Hello&quot;;

  function App() {
    return (
      &lt;div className=&quot;App&quot;&gt;
        &lt;Hello /&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
</ul>
<p>JSX → 하나의 태그만 받음 → div 태그로 묶어서 사용</p>
<h2 id="css-작성법-module-css">CSS 작성법 (module css)</h2>
<h3 id="1-inline-style"><strong>1. inline style</strong></h3>
<ul>
<li><p><em>Hello.js</em> → inline style</p>
<pre><code class="language-jsx">  import World from &quot;./World&quot;;

  export default function Hello() {
    return (
      &lt;div&gt;
        &lt;h1
          style={{
            color: &quot;#f00&quot;,
            borderRight: &quot;2px soldid #000&quot;,
            marginBottom: &quot;30px&quot;,
            opacity: 1,
          }}
        &gt;
          Hello
        &lt;/h1&gt;
        &lt;World /&gt;
        &lt;World /&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ sytle은 객체로 처리해 작성</p>
<h3 id="2-css-파일">2. CSS 파일</h3>
<p>index.css → 전체에 해당하는 css</p>
<p>App.css → App이라는 컴포넌트에 해당하는 css</p>
<p>→ 각 컴포넌트에 스타일이 적용되는 것이 아니라 hd 안에 전체 스타일이 작성되어 <strong>오버레이</strong></p>
<blockquote>
<p>❗ <strong>개별 컴포넌트 스타일</strong>
css 파일명 → <code>Hello.module.css</code>
<code>import sytles from &quot;./Hello.module.css&quot;;</code>
<code>&lt;div className={sytles.box}&gt;Hello&lt;/div&gt;</code></p>
</blockquote>
<ul>
<li><p><em>Hello.js</em> → Css file</p>
<pre><code class="language-jsx">  import World from &quot;./World&quot;;
  import sytles from &quot;./Hello.module.css&quot;;

  export default function Hello() {
    return (
      &lt;div&gt;
        &lt;h1
          style={{
            color: &quot;#f00&quot;,
            borderRight: &quot;2px soldid #000&quot;,
            marginBottom: &quot;30px&quot;,
            opacity: 1,
          }}
        &gt;
          Hello
        &lt;/h1&gt;
        &lt;div className={sytles.box}&gt;Hello&lt;/div&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<p>→ 같은 class명을 사용해도 다른 스타일 적용 가능</p>
<h2 id="이벤트-처리-handling-events">이벤트 처리 (Handling Events)</h2>
<ul>
<li><p><em>Hello.js</em> → Handling Events / 2 ways</p>
<pre><code class="language-jsx">  import World from &quot;./World&quot;;
  import sytles from &quot;./Hello.module.css&quot;;

  export default function Hello() {
    function showName() {
      console.log(&quot;Mike&quot;);
    }

    return (
      &lt;div&gt;
        &lt;h1&gt;Hello&lt;/h1&gt;
        &lt;button onClick={showName}&gt;Show name&lt;/button&gt;
        &lt;button
          onClick={() =&gt; {
            console.log(30);
          }}
        &gt;
          Show age
        &lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<p>2가지의 방식 → inline의 경우 매개변수를 전달하기 편함</p>
<ul>
<li><p><em>Hello.js</em> → 다른 방법으로 같은 코드 작성</p>
<pre><code class="language-jsx">      function showText(e) {
      console.log(e.target.value);
    }

      &lt;input type=&quot;text&quot; onChange={showText} /&gt;

  // =

      &lt;input
      type=&quot;text&quot;
      onChange={(e) =&gt; {
        console.log(e.target.value);
      }}
     /&gt;

  // =

    function showText(txt) {
      console.log(txt);
    }

    &lt;input
      type=&quot;text&quot;
      onChange={(e) =&gt; {
        const txt = e.target.value;
        showText(txt);
      }}
    /&gt;</code></pre>
</li>
</ul>
<h2 id="state-usestate">state, useState</h2>
<p><strong>state</strong> : 컴포넌트가 가지고 있는 <strong>상태값</strong></p>
<p>→ 속성값이 변하면 리액트는 자동으로 ui를 업데이트</p>
<h3 id="hooks-api-→-usestate">Hooks API → useState</h3>
<ul>
<li><p><em>Hello.js</em> → useState</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Hello() {
    // let name = &quot;Mike&quot;;
    const [name, setName] = useState(&quot;Mike&quot;);

    function changeName() {
      const newName = name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;;
      // document.getElementById(&quot;name&quot;).innerText = name;
      setName(newName);
    }

    return (
      &lt;div&gt;
        &lt;h1&gt;state&lt;/h1&gt;
        &lt;h2 id=&quot;name&quot;&gt;{name}&lt;/h2&gt;
        &lt;button onClick={changeName}&gt;Change&lt;/button&gt;
      &lt;/div&gt;
    );
  }

  // =
    function changeName() {
      setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
    }

  // =
   &lt;button
     onClick={() =&gt; {
       setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
     }}
    &gt;
    Change
    &lt;/button&gt;</code></pre>
</li>
</ul>
<p><strong>동일한 컴포넌트라도 state는 각각 관리</strong></p>
<p>→ 반복해서 3번을 쓰더라도 가운데 버튼을 누르면 가운데의 이름만 변경</p>
<h2 id="props">props</h2>
<p><strong>props(properties)</strong> : <strong>속성값</strong></p>
<p>→ 컴포넌트 내부에서 변경 불가능</p>
<p>→ 변경하고 싶다면 컴포넌트 내부에서 state를 다시 만들어야 됨</p>
<ul>
<li><p><em>Hello.js</em> → props로 age를 가져오는 원본 코드 / 2가지</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Hello(props) {
    const [name, setName] = useState(&quot;Mike&quot;);

    return (
      &lt;div&gt;
        &lt;h2 id=&quot;name&quot;&gt;
          {name}({props.age})
        &lt;/h2&gt;
        &lt;button
          onClick={() =&gt; {
            setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
          }}
        &gt;
          Change
        &lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
<ul>
<li><p>props → age 사용 코드</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Hello({ age }) {
    const [name, setName] = useState(&quot;Mike&quot;);

    return (
      &lt;div&gt;
        &lt;h2 id=&quot;name&quot;&gt;
          {name}({age})
        &lt;/h2&gt;
        &lt;button
          onClick={() =&gt; {
            setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
          }}
        &gt;
          Change
        &lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
</li>
</ul>
<pre><code>원래 코드에서 props를 age만 사용하고 있기 때문에 이 코드도 사용 가능</code></pre><ul>
<li><p><em>Hello.js</em> → age값 변경</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Hello(props) {
    const [name, setName] = useState(&quot;Mike&quot;);
    const [age, setAge] = useState(props.age);

    return (
      &lt;div&gt;
        &lt;h2 id=&quot;name&quot;&gt;
          {name}({age})
        &lt;/h2&gt;
        &lt;button
          onClick={() =&gt; {
            setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
            setAge(age + 1);
          }}
        &gt;
          Change
        &lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<ul>
<li><p><em>Hello.js</em> → age 값 조건으로 msg 출력</p>
<pre><code class="language-jsx">  import { useState } from &quot;react&quot;;

  export default function Hello({ age }) {
    const [name, setName] = useState(&quot;Mike&quot;);
    const msg = age &gt; 19 ? &quot;성인 입니다.&quot; : &quot;미성년자 입니다.&quot;;

    return (
      &lt;div&gt;
        &lt;h2 id=&quot;name&quot;&gt;
          {name}({age}) : {msg}
        &lt;/h2&gt;
        &lt;button
          onClick={() =&gt; {
            setName(name === &quot;Mike&quot; ? &quot;Jane&quot; : &quot;Mike&quot;);
          }}
        &gt;
          Change
        &lt;/button&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<h2 id="더미-데이터-구현-map-반복문">더미 데이터 구현, map() 반복문</h2>
<p><strong>dummy data</strong> → <strong>json</strong> 파일</p>
<h3 id="map">map</h3>
<p><strong>반복문</strong> → <strong>map</strong> 사용</p>
<p>: 배열을 받아서 또 다른 배열을 반환</p>
<p>  → 반환되는 배열의 요소는 jsx로 작성</p>
<p>날짜 필러팅을 통해 날짜의 단어 출력</p>
<ul>
<li><p><em>App.js</em></p>
<pre><code class="language-jsx">  import DayList from &quot;./component/DayList&quot;;
  import Header from &quot;./component/Header&quot;;
  import Day from &quot;./component/Day&quot;;

  function App() {
    return (
      &lt;div className=&quot;App&quot;&gt;
        &lt;Header /&gt;
        &lt;DayList /&gt;
        &lt;Day /&gt;
      &lt;/div&gt;
    );
  }

  export default App;</code></pre>
</li>
<li><p><em>Header.js</em></p>
<pre><code class="language-jsx">  export default function Header() {
    return (
      &lt;div className=&quot;header&quot;&gt;
        &lt;h1&gt;
          &lt;a href=&quot;/&quot;&gt;토익 영단어(고급)&lt;/a&gt;
        &lt;/h1&gt;
        &lt;div className=&quot;menu&quot;&gt;
          &lt;a href=&quot;#x&quot; className=&quot;link&quot;&gt;
            단어 추가
          &lt;/a&gt;
          &lt;a href=&quot;#x&quot; className=&quot;link&quot;&gt;
            Day 추가
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }</code></pre>
</li>
<li><p><em>DayList.js</em></p>
<pre><code class="language-jsx">  import dummy from &quot;../db/data.json&quot;;

  export default function DayList() {
    console.log(dummy);
    return (
      &lt;ul className=&quot;list_day&quot;&gt;
        {dummy.days.map((day) =&gt; (
          &lt;li key={day.id}&gt;Day {day.day}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    );
  }</code></pre>
</li>
<li><p><em>Day.js</em></p>
<pre><code class="language-jsx">  import dummy from &quot;../db/data.json&quot;;

  export default function Day() {
    //   dummy.words;
    const day = 3;
    const wordList = dummy.words.filter((word) =&gt; word.day === day);

    return (
      &lt;&gt;
        &lt;table&gt;
          &lt;tbody&gt;
            {wordList.map((word) =&gt; (
              &lt;tr key={word.id}&gt;
                &lt;td&gt;{word.eng}&lt;/td&gt;
                &lt;td&gt;{word.kor}&lt;/td&gt;
              &lt;/tr&gt;
            ))}
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/&gt;
    );
  }</code></pre>
</li>
<li><p><em>data.json</em></p>
<pre><code class="language-json">  {
    &quot;days&quot;: [
      { &quot;id&quot;: 1, &quot;day&quot;: 1 },
      { &quot;id&quot;: 2, &quot;day&quot;: 2 },
      { &quot;id&quot;: 3, &quot;day&quot;: 3 },
      { &quot;id&quot;: 4, &quot;day&quot;: 4 }
    ],
    &quot;words&quot;: [
      { &quot;id&quot;: 1, &quot;day&quot;: 1, &quot;eng&quot;: &quot;book&quot;, &quot;kor&quot;: &quot;책&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 2, &quot;day&quot;: 2, &quot;eng&quot;: &quot;car&quot;, &quot;kor&quot;: &quot;자동차&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 3, &quot;day&quot;: 3, &quot;eng&quot;: &quot;school&quot;, &quot;kor&quot;: &quot;학교&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 4, &quot;day&quot;: 3, &quot;eng&quot;: &quot;pencil&quot;, &quot;kor&quot;: &quot;연필&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 5, &quot;day&quot;: &quot;3&quot;, &quot;eng&quot;: &quot;window&quot;, &quot;kor&quot;: &quot;창문&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 6, &quot;day&quot;: &quot;3&quot;, &quot;eng&quot;: &quot;house&quot;, &quot;kor&quot;: &quot;집&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 7, &quot;day&quot;: &quot;2&quot;, &quot;eng&quot;: &quot;mouse&quot;, &quot;kor&quot;: &quot;쥐&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 8, &quot;day&quot;: &quot;4&quot;, &quot;eng&quot;: &quot;monkey&quot;, &quot;kor&quot;: &quot;원숭이&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 9, &quot;day&quot;: &quot;4&quot;, &quot;eng&quot;: &quot;apple&quot;, &quot;kor&quot;: &quot;사과&quot;, &quot;isDone&quot;: false },
      { &quot;id&quot;: 10, &quot;day&quot;: &quot;3&quot;, &quot;eng&quot;: &quot;apple&quot;, &quot;kor&quot;: &quot;사과&quot;, &quot;isDone&quot;: false }
    ]
  }</code></pre>
</li>
</ul>
<h2 id="핵심-요약">핵심 요약</h2>
<blockquote>
<p>💻 <strong>리액트 프로젝트 생성 명령어</strong>
<code>npx create-react-app 프로젝트명(폴더명)</code></p>
</blockquote>
<blockquote>
<p>❗ <strong>브라우저 실행 / 종료 명령어</strong>
<code>npm start</code> / <code>Ctrl + C</code></p>
</blockquote>
<blockquote>
<p>🔖 <strong>개별 컴포넌트 스타일</strong>
css 파일명 → <code>Hello.module.css</code>
<code>import sytles from &quot;./Hello.module.css&quot;;</code>
<code>&lt;div className={sytles.box}&gt;Hello&lt;/div&gt;</code></p>
</blockquote>
<blockquote>
<p>⭐ <strong>State, Props</strong>
화면에 데이터를 갱신 → 두가지 사용해 처리</p>
</blockquote>
<br>

<h2 id="✏️-다음-스터디">✏️ 다음 스터디</h2>
<p>날짜별로 클릭했을 때 해당 단어 출력 → 새로운 페이지 생성 &amp; 라우터 사용</p>
]]></description>
        </item>
    </channel>
</rss>