<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>CSE PEBBLE'S VELOG</title>
        <link>https://velog.io/</link>
        <description>ꜱɪɴᴄᴇ ２０２１.０９.０１</description>
        <lastBuildDate>Tue, 21 May 2024 07:53:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>CSE PEBBLE'S VELOG</title>
            <url>https://images.velog.io/images/cse_pebb/profile/77422857-fabf-4f80-a023-3f0e5d33bbbf/KakaoTalk_20210901_190131916.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. CSE PEBBLE'S VELOG. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cse_pebb" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[리액트] 프로젝트 시작 전 필수! 유용한 프로젝트 초기 세팅 방법]]></title>
            <link>https://velog.io/@cse_pebb/Tailwind-CSS-Tailwind-CSS-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@cse_pebb/Tailwind-CSS-Tailwind-CSS-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 21 May 2024 07:53:14 GMT</pubDate>
            <description><![CDATA[<p>프로젝트를 할 때 개발 능률을 올리기 위해서는 초기 프로젝트 세팅이 중요하다. 초기 세팅에 시간 투자를 하고 조금만 고통 받으면 이후 프로젝트를 진행하면서 쭉 만족스럽고 빠르게 개발을 할 수 있다. 하지만 어떤 것부터 해야 하는지 막막한 것도 사실이다. </p>
<p>이 글을 보는 초기 세팅에 어려움을 겪는 사람들에게 조금이나마 도움이 되고자, 내가 이번 졸업 프로젝트를 본격적으로 시작하기 전에 했던 <code>Tailwind CSS</code> 설치 및 초기 세팅 방법과 <code>CRA</code> 절대 경로 설정 방법에 대해 소개한다.</p>
<h1 id="tailwind-css를-설치하고-세팅해보자">Tailwind CSS를 설치하고 세팅해보자</h1>
<h2 id="tailwind-css란">Tailwind CSS란?</h2>
<p><code>Tailwind CSS</code>가 생소할 사람들을 위해 간단히 <code>Tailwind CSS</code>에 대해 소개한다. </p>
<p><code>Tailwind CSS</code>란 CSS 프레임워크로, 인라인 스타일을 사용하여 쉽고 빠르게 스타일링을 할 수 있으면서도 디자인 시스템만큼이나 일관된 디자인을 가능하게 해준다. <code>styled-components</code> 등과 같이 작은 스타일 변경에도 컴포넌트를 만들어야 하는 번거로움에 지쳤거나 매번 클래스명을 고민하는 것이 힘들었다면 이 <code>Tailwind CSS</code>를 적극적으로 추천한다. </p>
<p><code>Tailwind CSS</code>는 Utility-First 컨셉을 가진 CSS 프레임워크다.<code>m-1</code>, <code>flex</code>와 같이 미리 세팅된 유틸리티 클래스를 활용하는 방식으로 HTML 코드 내에서 스타일링을 할 수 있다.</p>
<ul>
<li>Utility-First: 미리 세팅된 유틸리티 클래스를 활용하여 HTML 코드 내에서 스타일링</li>
</ul>
<p>예시를 보면 좀 더 이해가 잘 될 것이다.</p>
<pre><code class="language-js">&lt;button class=&quot;py-2 px-4 rounded-lg shadow-md text-white bg-blue-500&quot;&gt;
  Click me
&lt;/button&gt;</code></pre>
<h2 id="tailwind-css-설치-및-초기-세팅-방법">Tailwind CSS 설치 및 초기 세팅 방법</h2>
<p><code>Tailwind CSS</code>가 무엇인지 알았으니 이제 본격적으로 설치하고 초기 세팅하면 좋을 팁들을 알아보자.</p>
<h3 id="tailwind-css-설치">Tailwind CSS 설치</h3>
<p><a href="https://tailwindcss.com/docs/installation">공식 문서</a>를 보고 설치하는 것이 가장 정확하지만 귀찮은 사람들을 위해 2024년 5월 기준 설치 방법을 소개한다. </p>
<ol>
<li><p>터미널에서 <code>Tailwind CSS</code> 설치
명령어는 아래와 같다. VSC 코드의 터미널 등에서 아래 명령어를 입력해주면 된다.</p>
<pre><code class="language-bash">npm install -D tailwindcss
npx tailwindcss init</code></pre>
</li>
<li><p><code>tailwind.config.js</code> 파일에서 path 설정해주기</p>
<pre><code class="language-js">/** @type {import(&#39;tailwindcss&#39;).Config} */
module.exports = {
 content: [&quot;./src/**/*.{html,js}&quot;],
 theme: {
   extend: {},
 },
 plugins: [],
}</code></pre>
<p>1번 설치 과정을 거쳤다면 프로젝트 root 폴더에 자동으로<code>tailwind.config.js</code> 파일이 생성되었을 것이다. 
이 파일의 content 부분에 tailwind를 사용할 파일의 위치를 잘 작성해주어야 한다. 맨 뒤에 나오는 파일 확장자명은 자신의 프로젝트에 맞게 설정해주어야 하는데, 내가 진행한 프로젝트의 경우 <code>typescript</code>를 사용했기 때문에 아래와 같이 세팅해주었다.</p>
<pre><code class="language-js">content: [&quot;./src/**/*.{tsx, ts}&quot;],
</code></pre>
<ol start="3">
<li><p>기본 CSS 파일에 <code>@tailwind</code> directives 추가</p>
<p><code>main.css</code>, <code>index.css</code> 등 자신의 프로젝트에 따라 기본 CSS 파일이 있을 것이다. 해당 CSS 파일의 맨 위에 아래의 내용을 추가해준다.  </p>
<pre><code class="language-css">@tailwind base;
@tailwind components;
@tailwind utilities;</code></pre>
</li>
</ol>
</li>
</ol>
<h3 id="tailwind-css-초기-세팅-방법">Tailwind CSS 초기 세팅 방법</h3>
<p><strong>이 포스트 주제의 핵심 부분이다.</strong> 보다 편하게 작업을 할 수 있도록 도와주는 Tailwind CSS의 초기 세팅 방법에 대해서 소개한다. </p>
<p>Tailwind CSS의 장점 중 하나는 커스터마이제이션이 쉽다는 것이다. 이 장점을 활용하여 초기 세팅을 해보자.</p>
<ol>
<li><p>자주 쓰는 스타일링 class 정의해두기
Tailwind CSS는 클래스를 활용하여 스타일링한다고 앞서 소개했다. 미리 정의된 클래스를 이용하는 것 뿐만 아니라 내가 class를 직접 정의해서 사용할 수도 있다.
나의 경우 <code>main.css</code>, <code>index.css</code> 등 기본 CSS 파일에 커스텀 클래스를 정의해준다. 실제 프로젝트에서 정의해둔 커스텀 클래스는 아래와 같다.</p>
<pre><code class="language-css">// App.css 
...

.flex-column {
 display: flex;
 flex-direction: column;
}

.flex-center {
 display: flex;
 justify-content: center;
 align-items: center;
}

.custom-grid-template-rows {
 grid-template-rows: min-content auto;
}

.custom-grid-template-columns {
 grid-template-columns: 70px auto;
}
</code></pre>
<p>특히 <code>.flex-column</code>과 <code>.flex-center</code>의 경우 어떤 프로젝트에서든 아주 많이 쓰이기 때문에 꼭 정의해두는 것을 추천한다. </p>
</li>
<li><p>프로젝트에서 사용되는 색상 정의하기</p>
<p><code>tailwind.config.js</code> 파일의 theme 섹션에서는 프로젝트의 색상 팔레트, 타입 스케일, 폰트, breakpoints, border radius values 등 다양한 스타일 정보를 커스텀하여 정의할 수 있다. </p>
<p>나는 매번 색상 코드를 작성해주는 것이 귀찮아서 색상 팔레트를 정의해주었다. 그 방법은 아래와 같다.</p>
<pre><code class="language-js"> /** @type {import(&#39;tailwindcss&#39;).Config} */
module.exports = {
 content: [&quot;./src/**/*.{tsx, ts}&quot;],
 theme: {
   extend: {
     colors: {
       white: &quot;#ffffff&quot;,
       black: &quot;#000000&quot;,
       &quot;dark-gray&quot;: &quot;#525252&quot;,
       blue: {
         base: &quot;#6979F8&quot;, // 기본 버튼 색상
         highlight: &quot;#3647A7&quot;, // 클릭 시 버튼 색상
         pitch: &quot;#A1A1FF&quot;, // 음성 듣기 및 포기하기
         &quot;bar-1&quot;: &quot;#D7D6FF&quot;, // 목표 음정 바
         &quot;bar-2&quot;: &quot;#A1C1FF&quot;, // 현재 음정 바,결과 음역대 범위 바
         &quot;bg-bar&quot;: &quot;#C7D3EB&quot;,
         result: &quot;#E1E1FA&quot;,
       },
     },
   },
 },
 plugins: [],
};
</code></pre>
</li>
</ol>
<pre><code>theme 섹션 안의 extend에 보면 색상 팔레트를 정의한 것을 확인할 수 있다. 사실 extend 안에 colors를 쓰지 않고 theme 안에 바로 colors를 작성해주어도 되지만, 이렇게 작성해준 이유는 `Tailwind CSS`에서 기본적으로 제공되는 colors를 사용하기 위해서이다. 

theme 안의 colors에는 `Tailwind CSS`에서 기본적으로 제공되는 색상이 내장되어 있기 때문에 그곳에 직접 내가 정의한 색상을 넣어주면 기본 색상을 덮어씌우면서 더 이상 기본 색상은 사용할 수 없게 된다. 
그렇기 때문에 기본 제공되는 색상에 &quot;확장하여&quot; 내가 정의한 색상도 쓰겠다는 의미로 extend 안에 colors를 작성해준 것이다.

실제로 내가 정의한 색상을 이용할 때는 아래와 같이 작성해주면 된다.

```js
&lt;h2 className=&quot;text-dark-gray&quot;&gt;&lt;/h2&gt;
&lt;div className=&quot;bg-blue-result&quot;&gt;&lt;/div&gt;

```</code></pre><h1 id="절대경로를-설정하여-파일을-쉽게-불러오자">절대경로를 설정하여 파일을 쉽게 불러오자</h1>
<h2 id="절대경로-설정의-필요성">절대경로 설정의 필요성</h2>
<p>우리는 리액트 프로젝트를 할 때 수많은 모듈 및 파일을 불러오고(import) 내보낸다(export). 파일 외부에 위치한 자원을 현재 파일에서 사용하기 위해선 JS가 제공하는 import 구문을 사용해야 하는데, 이 때 import 구문 뒷 부분에 가져오려는 자원에 대한 위치를 명시해야 한다. </p>
<p>별도의 설정이 없다면 경로의 앞 부분에 <code>./</code>이 붙은 형태인 상대경로를 사용하게 된다. 하지만 상대경로는 현재 파일의 위치를 기준으로 외부 파일의 위치를 명시하는 것이기 때문에 프로젝트의 규모가 커지고 폴더 구조가 깊어지면 경로 부분이 길어지게 되어 가독성을 해칠 수 있을 뿐만 아니라 작성이 매우 귀찮아진다(<del>상대경로 지옥</del>). 또한, 만약 현재 파일의 위치를 변경하게 되었을 때는 파일 내부에서 사용하는 모든 import 경로를 다시 변경해주어야하는 불편함이 따르게 된다. </p>
<p>예를 들어,</p>
<pre><code>└ src
  ├ a1
  │  └─ b1
  │     └─ c1
  │         └─ f1
  ├ a2
  │  └─ b2
  │     └─ f1</code></pre><p> 위와 같은 구조에서 b2의 f1파일에서 c1의 f1파일을 가져오려면
<code>import * from &#39;../../a1/b1/c1/f1&#39;;</code> 처럼 경로가 길어지게 된다.</p>
<p>이러한 단점을 해결하기 위해 절대경로 설정 방법에 대해 소개한다. 나는 <code>CRA</code>로 리액트 초기 설치를 해주었기 때문에, <code>CRA</code> 환경 기준으로 절대경로를 설정하는 방법에 대해 작성하겠다.</p>
<h2 id="cra--craco로-절대경로-설정하기">CRA + Craco로 절대경로 설정하기</h2>
<p><code>CRA</code> 환경에서는 <code>Craco</code> 라이브러리로 쉽게 절대경로를 설정해줄 수 있다.</p>
<p><a href="https://craco.js.org/docs/getting-started/">공식 문서</a>를 보고 설치하는 것이 가장 정확하지만 귀찮은 사람들을 위해 2024년 5월 기준 설치 방법을 소개한다. </p>
<ol>
<li><p>터미널에서 <code>Craco</code> 설치</p>
<pre><code class="language-bash"> npm i -D @craco/craco</code></pre>
</li>
<li><p><code>package.json</code> 파일 수정하기
 <code>package.json</code> 파일을 보면 아래와 같이 작성된 부분이 있을 것이다.</p>
<pre><code class="language-json">   &quot;scripts&quot;: {
     &quot;start&quot;: &quot;react-scripts start&quot;,
     &quot;build&quot;: &quot;react-scripts build&quot;,
     &quot;test&quot;: &quot;react-scripts test&quot;,
        &quot;eject&quot;: &quot;react-scripts eject&quot;
   }</code></pre>
<p> 이 부분을 아래와 같이 수정한다. </p>
<pre><code class="language-json"> &quot;scripts&quot;: {
     &quot;start&quot;: &quot;craco start&quot;,
     &quot;build&quot;: &quot;craco build&quot;,
     &quot;test&quot;: &quot;craco test&quot;
   },</code></pre>
</li>
<li><p><code>craco.config.js</code> 파일 생성하기
 <code>craco.config.js</code> 파일은 <code>craco</code>를 설치할 때 자동으로 생성되지 않는다. 직접 프로젝트의 root 경로에 파일을 생성해주어야 한다.</p>
</li>
<li><p>생성한 <code>craco.config.js</code> 파일에 절대경로 설정하기</p>
<pre><code class="language-js">const path = require(&quot;path&quot;);

module.exports = {
 webpack: {
   alias: {
     &quot;@&quot;: path.resolve(__dirname, &quot;src&quot;),
   },
 },
};</code></pre>
<p>경로에서 <code>@</code>를 작성해주면 <code>src</code> 폴더를 의미한다. 리액트 프로젝트에서는 거의 모든 모듈과 파일들을 <code>src</code> 폴더 안에 넣기 때문에 이 <code>src</code>를 base를 나타내는 <code>@</code> 기호로 세팅해주는 것이 일반적이다. 나는 <code>src</code> 자체만 세팅해주었지만 아래와 같은 방법이 많이 쓰이는 것 같다.</p>
<pre><code class="language-js">const path = require(&#39;path&#39;);

 module.exports = {
   webpack: {
     alias: {
       &#39;@components&#39;: path.resolve(__dirname, &#39;src/components&#39;),
       &#39;@pages&#39;: path.resolve(__dirname, &#39;src/pages&#39;),
       &#39;@hooks&#39;: path.resolve(__dirname, &#39;src/hooks&#39;),
     },
   },
 };</code></pre>
<p><code>src</code> 폴더의 직속 폴더 경로를 모두 세팅해주는 것이다.</p>
</li>
<li><p><code>tsconfig.json</code>(또는 <code>jsconfig.json</code>) 파일 수정하기</p>
<p><code>typescript</code>는 <code>tsconfig.json</code> 파일, <code>javascript</code>는 <code>jsconfig.json</code> 파일을 보면 <code>compilerOptions</code> 섹션이 있을 것이다. 이 부분에 아래와 같은 내용을 추가해주면 된다.</p>
<pre><code class="language-js"> {
   &quot;compilerOptions&quot;: {
     &quot;baseUrl&quot;: &quot;./src&quot;,
     &quot;paths&quot;: {
           &quot;@/*&quot;: [&quot;./*&quot;]
     }
   }
 }</code></pre>
<p> 나는 <code>src</code> 폴더만 절대경로를 설정해주었기 때문에 이렇게만 작성했지만, 4번에서 소개한 일반적인 방법으로는 아래와 같이 설정해주면 된다.</p>
<pre><code class="language-js"> {
   &quot;compilerOptions&quot;: {
     &quot;baseUrl&quot;: &quot;./src&quot;,
     &quot;paths&quot;: {
       &quot;@pages/*&quot;: [&quot;./pages/*&quot;],
       &quot;@components/*&quot;: [&quot;./components/*&quot;],
       &quot;@hooks/*&quot;: [&quot;./hooks/*&quot;]
     }
   }
 }</code></pre>
<p><code>baseUrl</code>은 작성할 경로의 base가 되는 경로를 의미하고, <code>paths</code>는 <code>craco.config.js</code>에 작성한 alias path 정보들을 <code>typescript</code> 또는 <code>javascript</code>가 이해할 수 있도록 한번 더 작성해주는 것이다.</p>
</li>
</ol>
<p>이렇게 하면 절대경로 세팅이 모두 완료되었다! 실제 코드에서 절대경로를 사용하는 예시를 보자.</p>
<pre><code class="language-js">import MikeButton from &quot;@/components/home/MikeButton&quot;;</code></pre>
<p><code>src/components/home</code> 폴더에 있는 <code>MikeButton.tsx</code> 모듈을 불러오는 코드이다. 상대경로 지옥 탈출 성공!</p>
<hr>
<p>여기까지가 내가 소개하는 프로젝트 초기 세팅 방법이다. 나는 프로젝트 초기 세팅을 할 때 정보가 한곳에 모여져 있지 않아 꽤나 많은 시간과 노력을 들였는데, 이 글을 보는 사람들이 조금이라도 더 빠르게 초기 세팅을 해서 개발 시간을 아끼는데 도움이 되었으면 좋겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] find, findIndex 함수]]></title>
            <link>https://velog.io/@cse_pebb/Javascript-find-findIndex-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@cse_pebb/Javascript-find-findIndex-%ED%95%A8%EC%88%98</guid>
            <pubDate>Thu, 25 Jan 2024 12:55:36 GMT</pubDate>
            <description><![CDATA[<h2 id="🎶-find">🎶 find</h2>
<blockquote>
<p>판별 함수를 만족하는 첫 <strong>요소</strong> 반환</p>
</blockquote>
<h3 id="형태">형태</h3>
<pre><code class="language-js">arr.findIndex(callback)</code></pre>
<h3 id="설명">설명</h3>
<p><strong>1. callback 함수</strong></p>
<ul>
<li>개발자가 직접 작성</li>
<li>원하는 조건을 만족하면 true를 반환, 아니면 false를 반환하도록 작성해준다. </li>
<li>조건을 만족시키는 첫 번째 요소를 찾자마자 true를 반환한다. 즉 첫번째 요소만 찾아낸다는 뜻이다.</li>
</ul>
<p><strong>2. findIndex 함수</strong></p>
<ul>
<li>callback 함수가 true를 반환하면 해당 조건을 만족시킨 요소를 반환. false를 반환하면 undefined를 반환.</li>
</ul>
<p>*<em>3. callback 함수가 받는 인자 *</em></p>
<pre><code class="language-js">callback(element, index, array)</code></pre>
<ul>
<li>배열의 모든 요소를 순회하며 체크한다.</li>
</ul>
<h3 id="예시">예시</h3>
<pre><code class="language-js">const array1 = [5, 12, 8, 130, 44];

const found = array1.find((element) =&gt; element &gt; 10);

console.log(found); // 12</code></pre>
<h2 id="🎶-findindex">🎶 findIndex</h2>
<blockquote>
<p>find와 비슷하지만,
판별 함수를 만족하는 첫 <strong>인덱스</strong> 반환</p>
</blockquote>
<h3 id="형태-1">형태</h3>
<pre><code class="language-js">arr.findIndex(callback)</code></pre>
<h3 id="설명-1">설명</h3>
<p><strong>1. callback 함수</strong></p>
<ul>
<li>개발자가 직접 작성</li>
<li>원하는 조건을 만족하면 true를 반환, 아니면 false를 반환하도록 작성해준다. </li>
<li>조건을 만족시키는 첫 번째 요소를 찾자마자 true를 반환한다. 즉 첫번째 요소만 찾아낸다는 뜻이다.</li>
</ul>
<p><strong>2. findIndex 함수</strong></p>
<ul>
<li>callback 함수가 true를 반환하면 해당 조건을 만족시킨 요소의 index(Number 타입)를 반환. false를 반환하면 -1을 반환.</li>
</ul>
<p>*<em>3. callback 함수가 받는 인자 *</em></p>
<pre><code class="language-js">callback(element, index, array)</code></pre>
<ul>
<li>배열의 모든 요소를 순회하며 체크한다.</li>
</ul>
<h3 id="예시-1">예시</h3>
<pre><code class="language-js">const hobbies = [&quot;Sports&quot;, &quot;Cooking&quot;, &quot;날 찾아&quot;, &quot;Reading&quot;];

const index = hobbies.findIndex((item) =&gt; item === &quot;날 찾아&quot;); //요소 순회
/* 얘랑 동일
hobbies.findIndex((item) =&gt; {
  return item === &quot;날 찾아&quot;;
});
 */

console.log(index); // 2</code></pre>
<p>👉 callback 함수인 <code>(item) =&gt; item === &quot;날 찾아&quot;</code>가 true를 반환하면 요소의 index인 2를 <code>findIndex</code> 함수가 반환한다.
<br></p>
<pre><code class="language-js">const arr = [5, 6, 9, 1, 6, 3, 2, 1, 2, 7, 9, 4, 3];

const find = arr.findIndex((element, index, array) =&gt; {
  return index &lt; 7 &amp;&amp; index &gt; 5; // 결국 index가 6인애 찾는거임
});

console.log(find); // 6
</code></pre>
<hr>
<p>참고 링크
<a href="https://bbaktaeho-95.tistory.com/40">https://bbaktaeho-95.tistory.com/40</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] String]]></title>
            <link>https://velog.io/@cse_pebb/Javascript-String</link>
            <guid>https://velog.io/@cse_pebb/Javascript-String</guid>
            <pubDate>Sun, 14 Jan 2024 13:41:18 GMT</pubDate>
            <description><![CDATA[<h3 id="특정-위치에-접근">특정 위치에 접근</h3>
<p>문자열도 배열처럼 특정 위치에 접근할 수는 있지만, 특정 위치의 값을 변경하는 것은 안된다.</p>
<pre><code class="language-js">let desc = &quot;안녕하세요&quot;;

desc[2]; // &quot;하&quot; -&gt; 가능

desc[4]; = &quot;용&quot;;
console.log(desc); // &quot;안녕하세요&quot; -&gt; 변함없음. 불가능</code></pre>
<h3 id="touppercase--tolowercase">toUpperCase() / toLowerCase()</h3>
<pre><code class="language-js">let desc = &quot;Hi guys. Nice to meet you.&quot;;

//toUpperCase() : 대문자로
desc.toUpperCase(); // &quot;HI GUYS. NICE TO MEET YOU.&quot;

//toLowerCase() : 소문자로
desc.toLowerCase(); // &quot;hi guys. nice to meet you.&quot;</code></pre>
<h3 id="strindexoftext">str.indexOf(text)</h3>
<pre><code class="language-js">let desc = &quot;Hi guys. Nice to meet you.&quot;;

// 당연히 0부터 셈.
desc.indexOf(&quot;to&quot;); //14
desc.indexOf(&quot;man&quot;); // -1 -&gt; 없는 문자열을 찾으면 -1 반환</code></pre>
<p>주의!</p>
<pre><code class="language-js">let desc = &quot;Hi guys. Nice to meet you.&quot;;

if (desc.indexOf(&quot;Hi&quot;)) {
  console.log(&quot;Hi가 포함된 문장입니다.&quot;);
}</code></pre>
<p>우리가 원하는 대로 동작하지 않음. <code>indexOf(&quot;Hi&quot;)</code>는 0이고, falsy한 값이기 때문에 if문 안이 실행되지 않음. </p>
<p>이런 경우를 막기 위해서는 아래와 같이 작성해주면 됨</p>
<pre><code class="language-js">let desc = &quot;Hi guys. Nice to meet you.&quot;;

if (desc.indexOf(&quot;Hi&quot;) &gt; -1) {
  console.log(&quot;Hi가 포함된 문장입니다.&quot;);
}</code></pre>
<h3 id="strslienm">str.slie(n,m)</h3>
<blockquote>
<p>n부터 m 전까지만 남김! (숫자는 물론 인덱스 기준)</p>
</blockquote>
<ul>
<li><code>n</code> : 시작점</li>
<li><code>m</code> : 인수를 안 넣으면 문자열 끝까지라는 의미이고, 양수면 그 숫자 전까지, 음수면 끝에서부터 셈</li>
</ul>
<pre><code class="language-js">let desc = &quot;abcdefg&quot;;

// 2부터 끝까지만 남김
desc.slice(2); // &quot;cdefg&quot;

// 0부터 5전까지(4까지) 남김
desc.slice(0,5); // &quot;abcde&quot;;

// 2부터 끝에서 2번째까지 자르고 남김 -&gt; 헷갈림 주의!
desc.slice(2,-2); // &quot;cde&quot;</code></pre>
<h3 id="strsubstringnm">str.substring(n,m)</h3>
<blockquote>
<p> n부터 m 전까지만 남김! 
<code>str.slie(n,m)</code>과 유사하지만 n과 m을 바꿔도 동작함
음수는 허용 X. 음수는 0으로 인식함</p>
</blockquote>
<pre><code class="language-js">let desc = &quot;abcdefg&quot;;

desc.substring(2,5); // &quot;cde&quot;
desc.substring(5,2); // &quot;cde&quot;</code></pre>
<h3 id="strsubstrnm">str.substr(n,m)</h3>
<blockquote>
<p>n부터 시작하여 m&quot;개&quot;를 가져옴</p>
</blockquote>
<pre><code class="language-js">let desc = &quot;abcdefg&quot;;

desc.substr(2,4); // &quot;cdef&quot;
desc.substr(-4,2); // &quot;de&quot;</code></pre>
<h3 id="strtrim">str.trim()</h3>
<p>문자열 앞뒤 공백 제거</p>
<pre><code class="language-js">let desc = &quot;   coding    &quot;;

desc.trim(); // &quot;coding&quot;</code></pre>
<h3 id="strrepeatn">str.repeat(n)</h3>
<p>문자열 n번 반복</p>
<pre><code class="language-js">let hello = &quot;hello!&quot;;
hello.repeat(3); // &quot;hello!hello!hello!&quot;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javscript] 숫자, 수학 method]]></title>
            <link>https://velog.io/@cse_pebb/Javscript-%EC%88%AB%EC%9E%90-%EC%88%98%ED%95%99-method</link>
            <guid>https://velog.io/@cse_pebb/Javscript-%EC%88%AB%EC%9E%90-%EC%88%98%ED%95%99-method</guid>
            <pubDate>Sun, 14 Jan 2024 13:21:54 GMT</pubDate>
            <description><![CDATA[<h2 id="tostring">toString()</h2>
<pre><code class="language-js">let num = 10;
num.toString(); // &quot;10&quot; -&gt; 숫자를 문자열로 바꿔줌
num.toString(2); // 10진수 &quot;10&quot;을 2진수 &quot;1010&quot;으로 바꿔줌

let num2 = 255;
num2.toString(16); // 10진수 &quot;255&quot;를 16진수 &quot;ff&quot;로 바꿔줌</code></pre>
<h2 id="수학">수학</h2>
<h3 id="mathpi">Math.PI</h3>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/d681c06f-07d0-4188-88e8-298bc8a6be9d/image.png" alt=""></p>
<h3 id="mathceil">Math.ceil()</h3>
<p>올림</p>
<pre><code class="language-js">let num1 = 5.1;
let num2 = 5.7;

Math.ceil(num1); // 6
Math.ceil(num2); // 6</code></pre>
<h3 id="mathfloor">Math.floor()</h3>
<p>내림 </p>
<pre><code class="language-js">let num1 = 5.1;
let num2 = 5.7;

Math.ceil(num1); // 5
Math.ceil(num2); // 5</code></pre>
<h3 id="mathround">Math.round()</h3>
<p>반올림</p>
<pre><code class="language-js">let num1 = 5.1;
let num2 = 5.7;

Math.ceil(num1); // 5
Math.ceil(num2); // 6</code></pre>
<h3 id="소수점-자릿수">소수점 자릿수</h3>
<ol>
<li><code>Math.round()</code> 이용 <pre><code class="language-js">let userRate = 30.1237;
</code></pre>
</li>
</ol>
<p>//소수점 둘째자리까지 표현(셋째자리에서 반올림)
Math.round(userRate * 100) / 100 //30.12</p>
<p>//소수점 셋째자리까지 표현(넷째자리에서 반올림)
Math.round(userRate * 1000) / 1000 //30.124</p>
<pre><code>
2. `toFixed()` 이용
```js
let userRate = 30.1237;

//소수점 둘째자리까지 표현(셋째자리에서 반올림)
userRate.toFixed(2); //30.12

//소수점 셋째자리까지 표현(넷째자리에서 반올림)
userRate.toFixed(3); //30.124

//그 외
userRate.toFixed(0); //&quot;30&quot;
userRate.toFixed(6); //&quot;30.123700&quot;</code></pre><p>단, 주의할 점은 <code>toFixed()</code>는 <strong>문자열을 반환</strong>한다. </p>
<h3 id="isnan">isNaN()</h3>
<p>숫자인지 아닌지 판단. 
<code>==NaN</code>이나 <code>===NaN</code>으로 하면 안됨! </p>
<pre><code class="language-js">let x = Number(&quot;x&quot;); //x는 NaN임

//isNaN() 이용 안할 경우, 우리가 원하는 결과가 안 나옴
x == NaN //false
x === NaN // false
NaN == NaN // false -&gt; 심지어 이것도 false라고 함

//따라서 NaN 판단은 무조건 isNaN()으로 해야한다.
isNaN(x) // true
isNaN(3) // false</code></pre>
<h3 id="parseint">parseInt()</h3>
<p>문자열을 숫자로 바꿔줌. <code>Number()</code>와 다른 점은, 문자가 포함되어 있어도 동작을 한다는 것이다. 읽을 수 있는 부분까지 읽고, 문자를 만나면 읽은 부분까지를 반환한다. 즉 처음부터 문자로 시작하면 숫자를 반환하지 못하고 <code>NaN</code>을 반환한다. <code>Number()</code>는 어디에든 문자가 포함되어 있으면 <code>NaN</code>을 반환한다.(단 공백은 있어도 상관없음)</p>
<pre><code class="language-js">let margin = &quot;10px&quot;;

parseInt(margin); //10
Number(margin); // NaN

// 이 경우에는 parseInt도 NaN을 반환한다
let redColor = &quot;f3&quot;;
parseInt(redColor); //NaN</code></pre>
<p><code>parseInt()</code>는 두 번째 인수로 진수를 설정해줄 수 있다.</p>
<pre><code class="language-js">//위에서 작성한 예제
let redColor = &quot;f3&quot;;
parseInt(redColor); //NaN

//16진수로 설정. 16진수에서 f는 숫자이다.
let redColor = &quot;f3&quot;;
parseInt(redColor, 16); //243</code></pre>
<h3 id="parsefloat">parseFloat()</h3>
<p><code>parseInt()</code>와 동일하게 동작하지만, 부동소수점을 반환한다. </p>
<pre><code class="language-js">let padding = &quot;18.5%&quot;;
parseInt(padding); // 18
parseFloat(padding); // 18.5</code></pre>
<h3 id="mathrandom">Math.random()</h3>
<p>0~1 사이 무작위 숫자 생성</p>
<pre><code class="language-js">Math.random(); // 0.45930103294789837
Math.random(); // 0.26114731261519153
Math.random(); // 0.8677601709129028</code></pre>
<p>그럼 1~100 사이 무작위 숫자를 뽑고 싶다면? </p>
<pre><code class="language-js">Math.floor(Math.random() * 100) + 1;</code></pre>
<h3 id="mathmax">Math.max()</h3>
<pre><code class="language-js">Math.max(1, 4, -1, 5, 10, 9, 5.54); // 10
Math.min(1, 4, -1, 5, 10, 9, 5.54); // -1</code></pre>
<h3 id="mathabs">Math.abs()</h3>
<p>절대값(absolute)</p>
<pre><code class="language-js">Math.abs(-1); // 1</code></pre>
<h3 id="mathpownm">Math.pow(n,m)</h3>
<p>n^m </p>
<pre><code class="language-js">Math.pow(2,10); // 1024</code></pre>
<h3 id="mathsqrt">Math.sqrt()</h3>
<p>제곱근</p>
<pre><code class="language-js">Math.sqrt(16); // 4</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] var, let, const 차이점과 호이스팅]]></title>
            <link>https://velog.io/@cse_pebb/Javascript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@cse_pebb/Javascript-var-let-const-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Sun, 14 Jan 2024 11:11:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/cse_pebb/post/2cadb469-8aed-4201-b025-60db551b8413/image.png" alt=""></p>
<h3 id="범위scope">범위(scope)</h3>
<p>변수가 접근할 수 있는 유효범위이다.</p>
<p><strong>1. function scope
*<em>var만의 특징. 유효범위가 *</em>함수 단위</strong>이다. 즉 함수에서만 지역변수가 된다. </p>
<pre><code class="language-js">const func = () =&gt; {
  var a = 1;
}
console.log(a); // 함수 안에서 선언된 변수 a를 함수 밖에서 접근했으므로 오류 발생! </code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/8edfbe08-8d3f-4a0d-b35e-3cab8109dfd7/image.png" alt=""></p>
<pre><code class="language-js">if(true) {
  var a = 1;
}
console.log(a); // if문에서 선언된 a를 if문 밖에서 접근. 문제 없음~</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/bb88506e-0435-46b8-b995-b35ef1300c83/image.png" alt=""></p>
<p><strong>2. block scope</strong>
유효범위가 함수 뿐만 아니라 중괄호(함수, if-else문, while문, for문, try-catch문)를 기준으로 나뉘는 것. 변수는 <strong>중괄호를 범위</strong>로 기억한다는 점 인지하고 자바스크립트 코드를 짜자!</p>
<pre><code class="language-js">const func = () =&gt; {
  const a = 1;
}
console.log(a); // 함수 안에서 선언된 변수 a를 함수 밖에서 접근했으므로 오류 발생! </code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/b20bc758-dac5-4fa5-8b9f-6573b9142aea/image.png" alt=""></p>
<pre><code class="language-js">if(true) {
  let a = 1;
}
console.log(a); // if문에서 선언된 a를 if문 밖에서 접근했으므로 오류 발생!</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/31844753-15ae-45c0-9faf-c6ae54cc65c2/image.png" alt=""></p>
<h3 id="변수-재선언redelcaration">변수 재선언(redelcaration)</h3>
<p>좋지 않은 var만의 특징이다. 
말도 안되는 기능. 이런 선언 방식은 볼 일 없을 듯!</p>
<pre><code class="language-js">var name = &quot;Mike&quot;;
console.log(name); // Mike

var name = &quot;Jane&quot;; // 변수 재선언. 오류가 발생하지 않는다.
console.log(name); // Jane </code></pre>
<h3 id="변수값-재할당can-be-reassigned">변수값 재할당(can be reassigned)</h3>
<p>당연한 변수의 특징.
constant는 상수니까 당연히 재할당이 안된다.</p>
<pre><code class="language-js">//var
var name = &quot;Mike&quot;;
name = &quot;Jane&quot;;
console.log(name); // Jane 

//let
let name = &quot;Mike&quot;;
name = &quot;Jane&quot;;
console.log(name); // Jane 

//const
const name = &quot;Mike&quot;;
name = &quot;Jane&quot;; // const는 재할당 불가. 오류발생!</code></pre>
<h3 id="초기화-필요initializer">초기화 필요(initializer)</h3>
<p>constant는 재할당이 안되니까 당연히 초기값을 설정해주어야 한다.</p>
<pre><code class="language-js">const name; // const는 초기값 설정 필수. 오류 발생!</code></pre>
<h3 id="호이스팅hoisting">호이스팅(hoisting)</h3>
<blockquote>
<p><strong>호이스팅이란?</strong></p>
</blockquote>
<ul>
<li>호이스팅이란 스코프 안에 존재하는 모든 &quot;선언&quot;들을 해당 스코프의 최상단으로 끌어올리는 것을 말함. (호이스팅은 스코프 단위로 일어난다!)</li>
<li>자바스크립트 엔진은 코드를 실행하기 전에 실행 가능한 코드를 형상화하고 구분하는 과정을 거침.</li>
<li>이 과정에서 자바스크립트 엔진은 코드 실행을 위한 모든 선언들을 스코프에 등록(메모리에 저장)함.</li>
</ul>
<p><code>var</code>, <code>let</code>, <code>const</code> 모두 호이스팅된다. 하지만 차이점이 있다.</p>
<p><code>var</code> 예시를 보자.</p>
<pre><code class="language-js">console.log(name); // undefined
var name = &#39;hello&#39;;</code></pre>
<p>이 코드는 참조 에러가 나지 않고, <code>undefined</code>를 리턴한다. 그 이유는 자바스크립트가 호이스팅을 하면서 아래와 같은 방식으로 코드를 해석하기 때문이다.</p>
<pre><code class="language-js">var name; // undefined
console.log(name);
name = &#39;hello&#39;;</code></pre>
<p>선언만 호이스팅되고, 할당은 호이스팅 되지 않은 것이다.</p>
<p>다음으로 <code>let</code>, <code>const</code> 예시를 보자.</p>
<pre><code class="language-js">console.log(name); // 에러 발생! 
let name = &#39;hello&#39;;</code></pre>
<pre><code class="language-js">console.log(name); // 에러 발생! 
const name = &#39;hello&#39;;</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/79e7aac5-f746-4563-81ee-fa394b2fde38/image.png" alt=""></p>
<p>분명 <code>var</code> 예시와 같은 코드인데, <code>let</code>이나 <code>const</code>으로 바꾸면 에러가 난다. 이것만 보면 <code>let</code>과 <code>const</code>는 호이스팅이 일어나지 않는 것처럼 보인다.</p>
<p>하지만 둘다 분명히 호이스팅이 일어난다. 그럼 왜 이런 차이점이 발생할까? 바로 Temporal Dead Zone 때문이다. </p>
<p><strong>Temporal Dead Zone</strong>
선언은 되었으나 초기화되지 않은 변수가 있는 곳을 Temporal Dead Zone이라고 한다. Temporal Dead Zone에 있는 변수에 접근하면 Reference Error가 발생한다.</p>
<p><code>var</code>는 변수의 선언과 동시에 초기화가 일어난다. 선언을 하면 자동으로 <code>undefined</code>가 할당된다. 따라서 Temporal Dead Zone에 들어갈 일이 없다. </p>
<p>반면 <code>let</code>과 <code>const</code>는 변수를 선언한다고 해서 자동으로 초기화가 이루어지지 않는다. 따라서 선언은 되어있지만, 초기화가 되지 않아 Temporal Dead Zone에 들어가게 된다.</p>
<p>예시들을 통해 이해하자.</p>
<pre><code class="language-js">// 호이스팅 때문에 선언이 끌어올려져서 오류 안남.
console.log(text); // undefined (선언+undefined로 자동 초기화)
text = &#39;Hi!&#39;; // 할당
var text; // 선언과 동시에 초기화. 호이스팅됨.
console.log(text); // Hi!</code></pre>
<pre><code class="language-js">// 호이스팅 때문에 선언이 끌어올려졌지만 초기화 안된 상태에서 참조해서 오류 남.
console.log(text); // ReferenceError: text is not defined
let text; // 선언되어 호이스팅. 초기화는 안됨</code></pre>
<hr>
<p>참조
<a href="https://yceffort.kr/2020/05/var-let-const-hoisting">https://yceffort.kr/2020/05/var-let-const-hoisting</a>
<a href="https://hanamon.kr/javascript-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80-hoisting/">https://hanamon.kr/javascript-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85%EC%9D%B4%EB%9E%80-hoisting/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] for 관련 함수 + map 함수]]></title>
            <link>https://velog.io/@cse_pebb/Javascript-for-%EA%B4%80%EB%A0%A8-%ED%95%A8%EC%88%98-map-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@cse_pebb/Javascript-for-%EA%B4%80%EB%A0%A8-%ED%95%A8%EC%88%98-map-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 14 Jan 2024 11:03:36 GMT</pubDate>
            <description><![CDATA[<h1 id="⭐-이젠-좀-외워라-for-관련-함수--map-함수-⭐">⭐ 이젠 좀 외워라... for 관련 함수 &amp; map 함수 ⭐</h1>
<h2 id="for--in">for ... in</h2>
<blockquote>
<p><strong>key/index</strong>
<strong>객체</strong>의 key, <strong>배열</strong>의 index를 순환할 때 사용</p>
</blockquote>
<pre><code class="language-js">
let user = {
  name: &quot;John&quot;,
  age: 30,
  isAdmin: true
};

for (let key in user) {
  // 키
  alert( key );  // name, age, isAdmin
  // 키에 해당하는 값
  alert( user[key] ); // John, 30, true
}</code></pre>
<p>객체의 key, value를 추출하고 싶을 때 사용하자.
배열에는 굳이 사용할 일이 없을듯. forEach로 대체 가능</p>
<h2 id="for--of">for ... of</h2>
<blockquote>
<p><strong>element(값)</strong>
배열의 element(값)을 순환할 때 사용</p>
</blockquote>
<pre><code class="language-js">let days = [&quot;mon&quot;,&quot;tue&quot;,&quot;wed&quot;];

days.push(&quot;thu&quot;);
days.unshift(&quot;sun&quot;); // 배열 앞에 추가

for (let days of days) {
    console.log(day); // &quot;sun&quot; &quot;mon&quot; &quot;tue&quot; &quot;wed&quot; &quot;thu&quot;
}
</code></pre>
<p>크게 사용할 일이 없을듯.. forEach로 대체가 되니까. </p>
<p>cf) 배열 shift, unshift</p>
<ul>
<li>unshift : 배열 앞에 추가(여러개 추가 가능)</li>
<li>shift : 배열 앞에 제거</li>
</ul>
<h2 id="foreach-함수-vs-map-함수">forEach 함수 vs. map 함수</h2>
<h3 id="foreach-map-함수의-공통점">forEach, map 함수의 공통점</h3>
<blockquote>
<p><strong>index &amp; element 모두</strong>
배열의 index, element 모두를 순환할 때 사용
인수를 가짐! : <code>forEach((요소, 인덱스, 배열)=&gt;{...});</code>, <code>map((요소, 인덱스, 배열)=&gt;{...});</code></p>
</blockquote>
<p><strong>1. 첫 번째 인수 : element</strong></p>
<pre><code class="language-js">//forEach
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.forEach((day) =&gt; {
  console.log(day);
});

//map
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.map((day) =&gt; {
  console.log(day);
});</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/98d3869f-037a-4fef-8459-0ae962009e70/image.png" alt=""></p>
<p>**
2. 두 번째 인수(optional) : index**</p>
<pre><code class="language-js">//forEach
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.forEach((day, index) =&gt; {
  console.log(`Index: ${index}, Value: ${day}`);
});

//map
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.map((day, index) =&gt; {
  console.log(`Index: ${index}, Value: ${day}`);
});
</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/8ba9ebd3-307e-408b-b4ea-f201f92a38a9/image.png" alt=""></p>
<p><strong>3. 세 번째 인수(optional) : 원본 배열 그 자체</strong></p>
<pre><code class="language-js">//forEach
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.forEach((day, index, array) =&gt; {
  console.log(`Index: ${index}, Value: ${day}`);
  console.log(array);
});

//map
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

days.map((day, index, array) =&gt; {
  console.log(`Index: ${index}, Value: ${day}`);
  console.log(array);
});
</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/b37a1664-8836-469e-af10-260dbd73eafd/image.png" alt=""></p>
<h3 id="foreach-map-함수의-차이점">forEach, map 함수의 차이점</h3>
<p><strong>1. return 값의 유무</strong></p>
<blockquote>
<p>forEach는 return 값이 없고, 
map은 return 값이 있다!(단, 반드시 return문을 통해 return 값을 작성해주어야 함!)</p>
</blockquote>
<pre><code class="language-js">//forEach
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

let a = days.forEach((day) =&gt; day); // return day
console.log(a);
</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/e939382e-1292-4602-ba6b-c4777399093f/image.png" alt=""></p>
<pre><code class="language-js">//map
const days = [&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;];

let a = days.map((day) =&gt; day); // return day
console.log(a);</code></pre>
<p><strong>days 배열의 요소들을 담은 새로운 배열을 return</strong>하여 a에 저장한다.</p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/fc7b9cba-c788-4fe8-ae23-9c66942632a5/image.png" alt=""></p>
<p>아래의 예시를 보면 차이를 확실히 느낄 수 있다.</p>
<pre><code class="language-js">//forEach
const numbers = [1, 2, 3, 4, 5];

const a = numbers.forEach((number) =&gt; number+1);
console.log(a);</code></pre>
<p>콜백함수가 <code>element+1</code>을 반환한다고 해도, forEach 함수는 아무것도 반환하지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/33801c1e-f446-47cf-b1fc-4f0e28461e66/image.png" alt=""></p>
<pre><code class="language-js">//map
const numbers = [1, 2, 3, 4, 5];

const a = numbers.map((number) =&gt; number+1);
console.log(a);</code></pre>
<p><strong>numbers 배열의 요소들에 +1을 해준 새로운 배열을 return</strong>하여 a에 저장한다.</p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/048b1336-9c34-4096-ac92-6dcc52a78e8d/image.png" alt=""></p>
<br>

<p>즉, map 함수는</p>
<ul>
<li>콜백함수에 반환값을 작성해준다면, 그 반환값은 &quot;각 요소를 이렇게 바꾸겠다&quot;라는 의미이다. </li>
<li>콜백함수의 반환 값에 따라 바뀐 배열이 map 함수의 반환값이 된다.</li>
</ul>
<h2 id="map-함수의-활용">map 함수의 활용</h2>
<h3 id="특정-값-꺼내기">특정 값 꺼내기</h3>
<pre><code class="language-js">const users = [ //객체 배열
  { name: &quot;원빈&quot;, age: 22 },
  { name: &quot;현빈&quot;, age: 32 },
  { name: &quot;강동원&quot;, age: 21 },
  { name: &quot;안재현&quot;, age: 35 },
];
const ages = users.map((user) =&gt; user.age);
console.log(ages); </code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/1c74da40-2723-4b24-9a59-7d63c3860be1/image.png" alt=""></p>
<h1 id="⭐-총정리-⭐">⭐ 총정리 ⭐</h1>
<ul>
<li>객체는 for...in 사용 / key</li>
<li>배열은 forEach나 map 사용 / element, index, array</li>
<li>배열을 단순히 순회하려면 forEach, 배열을 순회하고 새 배열을 얻고 싶다면 map!</li>
</ul>
<hr>
<p>참고
<a href="https://velog.io/@kms0206/Map-ForEach%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">https://velog.io/@kms0206/Map-ForEach%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공 자바스크립트 25-29강 ]]></title>
            <link>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-25-29%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-25-29%EA%B0%95</guid>
            <pubDate>Wed, 29 Nov 2023 14:23:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>윤인성 님의 <a href="https://www.youtube.com/watch?v=pXuyfvJPENA&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl">혼공 자바스크립트</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🍇-api">🍇 API</h2>
<p>Application Programming Interface.</p>
<blockquote>
<p>애플리케이션 프로그램을 만들 때의 약속</p>
</blockquote>
<p>단순한 파일 형식, 함수의 이름 등 &#39;약속&#39;의 범위는 매우 넓다. Web API, WinAPI, JavaScript API, Node API 등 종류가 방대하다.</p>
<p>ex) <code>alert()</code>의 구현을 몰라도 쓸 수 있는 이유는 &quot;약속을 그렇게 해줬으니까&quot;이다. 내부 구조를 몰라도 된다.</p>
<p>ex) <code>console.log()</code>도 마찬가지이다. </p>
<h2 id="🍇-나머지-매개변수rest-parameter">🍇 나머지 매개변수(rest parameter)</h2>
<blockquote>
<p>함수를 만들 때 매개변수에 <code>...매개변수</code>와 같이 작성해주면 남은 매개변수들이 모두 이 나머지 매개변수에 <strong>배열</strong>의 형태로 들어오게 된다.</p>
</blockquote>
<p>예시를 보자.</p>
<pre><code class="language-js">const 함수 = function(...매개변수) {
  console.log(매개변수)
}

함수() // []
함수(1) // [1] -&gt; 매개변수가 1개일 때도 배열로 들어온다
함수(1,2) // [1,2]
함수(1,2,3) // [1,2,3]
함수(1,2,3,4) // [1,2,3,4]</code></pre>
<p>나머지 매개변수는 일반 매개변수와 함께 쓰일 수 있다. 일반 매개변수에 할당되고 남은 것이 모두 나머지 매개변수에 들어오게 된다. </p>
<pre><code class="language-js">const 함수 = function(a, b, ...매개변수) {
  console.log(a, b, 매개변수);
}

함수() // undefined undefined []
함수(1) // 1 undefined []
함수(1,2) // 1 2 []
함수(1,2,3) // 1 2 [3]
함수(1,2,3,4) // 1 2 [3, 4] </code></pre>
<p>나머지 매개변수는 항상 맨 뒤에 와야한다(일반 매개변수가 나머지 매개변수보다 뒤에 올 수 없다.) 아래의 예시는 오류가 발생한다.</p>
<pre><code class="language-js">const 잘못된예 = function(...매개변수, a, b) {}</code></pre>
<h2 id="🍇-전개-연산자-함수-호출">🍇 전개 연산자: 함수 호출</h2>
<pre><code class="language-js">const 함수 = function(a, b, c) {
  console.log(a, b, c)
}

const a = [1, 2, 3]
함수(...a) // 1 2 3 -&gt; a 배열의 값이 매개변수에 각각 분리되어 들어간다. 
// 함수(a[0], a[1], a[2] -&gt; 이 코드와 완전히 동일하다.</code></pre>
<h2 id="🍇-기본-매개변수">🍇 기본 매개변수</h2>
<p>매개변수가 있는 함수를 매개변수 없이 호출했을 경우 오류가 발생한다.</p>
<pre><code class="language-js">const isLeapYear = function(연도) {
  return (연도 % 4 === 0) 
      &amp;&amp; (연도 % 100 !== 0) 
      || (연도 % 400 === 0)
}

isLeapYear();</code></pre>
<p>이럴 경우 매개변수가 없이 호출해도 매개변수가 기본값을 지닐 수 있도록 해주는 것이 기본 매개변수이다.</p>
<pre><code class="language-js">const isLeapYear = function(연도 = new Date().getFullYear()) {
  return (연도 % 4 === 0) 
      &amp;&amp; (연도 % 100 !== 0) 
      || (연도 % 400 === 0)
}

isLeapYear(); // 기본값으로 올해 연도가 들어가게 된다</code></pre>
<p>이것은 모던 JS에서 가능해졌고, 과거에는 직접 코드로 기본 매개변수를 설정해주었다.</p>
<ol>
<li><p>typeof 사용</p>
<pre><code class="language-js">const isLeapYear = function(연도) {
if (typeof(연도) === &#39;undefined&#39;) {
 연도 = new Date().getFullYear()
}

return (연도 % 4 === 0) 
   &amp;&amp; (연도 % 100 !== 0) 
   || (연도 % 400 === 0)
}
</code></pre>
</li>
</ol>
<p>isLeapYear(); // 기본값으로 올해 연도가 들어가게 된다</p>
<pre><code>
2. typeof + 삼항 연산자 사용
```js
const isLeapYear = function(연도) {
  연도 = typeof(연도) === &#39;undefined&#39; ? new Date().getFullYear() : 연도;

  return (연도 % 4 === 0) 
      &amp;&amp; (연도 % 100 !== 0) 
      || (연도 % 400 === 0)
}

isLeapYear(); // 기본값으로 올해 연도가 들어가게 된다</code></pre><ol start="3">
<li><p>|| 사용</p>
<pre><code class="language-js">const isLeapYear = function(연도) {
연도 = 연도 || new Date().getFullYear();

return (연도 % 4 === 0) 
   &amp;&amp; (연도 % 100 !== 0) 
   || (연도 % 400 === 0)
}
</code></pre>
</li>
</ol>
<p>isLeapYear(); // 기본값으로 올해 연도가 들어가게 된다
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python을 이용한 오디오 신호 분석 - 오디오 신호 pitch 추출하기]]></title>
            <link>https://velog.io/@cse_pebb/PitchFinder</link>
            <guid>https://velog.io/@cse_pebb/PitchFinder</guid>
            <pubDate>Fri, 24 Nov 2023 07:57:57 GMT</pubDate>
            <description><![CDATA[<p>실제 오디오 데이터를 이용하여 pitch를 추출하는 과정을 정리하겠습니다.</p>
<p>일단 신호처리적으로 pitch를 추출하는 2가지 방법이 떠오릅니다.</p>
<ol>
<li>오토코릴레이션을 이용하여 peak(혹은 최댓값)를 찾는다</li>
<li>FFT를 이용하여 magnitude의 peak(혹은 최댓값)를 찾는다.</li>
</ol>
<p>정확도를 높이기 위해선 피치 더블링이나 신호의 주기성을 고려한 방법을 추가해야 겠죠.</p>
<ul>
<li>주파수 범위를 한정한다던가, </li>
<li>신호가 얼마 이상의 크기이여야 피치로 결정한다던가</li>
</ul>
<p>간단한 것 같지만, 이것 저것 생각하다보면 구현이 복잡해 집니다.
그런데, 파이썬은 이런 구현 조차도 라이브러리로 제공합니다.
실제 사용되는 함수는 <code>librosa.core.piptrack</code> 입니다.</p>
<p>다음은 위 함수를 이용해 오디오 파일의 pitch를 추출하는 코드 입니다.</p>
<pre><code class="language-python">import librosa
import scipy.signal as signal
import numpy as np

audio_sample, sampling_rate = librosa.load(&quot;sine.wav&quot;, sr = None)

S = np.abs(librosa.stft(audio_sample, n_fft=1024, hop_length=512, win_length = 1024, window=signal.hann))
pitches, magnitudes = librosa.piptrack(S=S, sr=sampling_rate)

shape = np.shape(pitches)
nb_samples = shape[0]
nb_windows = shape[1]

for i in range(0, nb_windows):
    index = magnitudes[:,i].argmax()
    pitch = pitches[index,i]
    print(pitch)

# FFT 결과를 plot
import matplotlib.pyplot as plt
import librosa.display

#normalize_function
min_level_db = -100
def _normalize(S):
    return np.clip((S-min_level_db)/(-min_level_db), 0, 1)

mag_db = librosa.amplitude_to_db(S)
mag_n = _normalize(mag_db)
plt.subplot(311)
librosa.display.specshow(mag_n, y_axis=&#39;linear&#39;, x_axis=&#39;time&#39;, sr=sampling_rate)
plt.title(&#39;spectrogram&#39;)

t = np.linspace(0, 24000, mag_db.shape[0])
plt.subplot(313)
plt.plot(t, mag_db[:, 100].T)
plt.title(&#39;magnitude (dB)&#39;)
plt.show()</code></pre>
<p>결과는 아래와 같습니다.</p>
<blockquote>
<p> 263Hz -&gt;  291Hz -&gt; 329Hz -&gt; 347Hz</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/351f1bb2-f095-4dbb-b497-497726e3e60d/image.png" alt=""></p>
<p>matplot을 이용해서 스펙트럼을 그리는 것 까지 넣었습니다.</p>
<p>실제 pitches 배열에는 pitch 후보들이 있는데,
이 중 가장 큰 값을 갖는 주파수를 출력하는 코드를 작성했습니다.</p>
<p>librosa.core.piptrack` 에 인자로 min, max를 넣어 pitch의 범위를 한정하는 것도 가능합니다.</p>
<p>이제 음성/오디오 신호의 주요 파라미터인 pitch를 추출 할 수 있게 되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모던 JS 튜토리얼 Part 1. 4강 객체 기본]]></title>
            <link>https://velog.io/@cse_pebb/%EB%AA%A8%EB%8D%98-JS-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-Part-1.-4%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%EB%AA%A8%EB%8D%98-JS-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-Part-1.-4%EA%B0%95</guid>
            <pubDate>Wed, 22 Nov 2023 16:06:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://ko.javascript.info/">모던 JS 튜토리얼</a> Part 1. 코어 자바스크립트 문서를 읽고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🌝-객체">🌝 객체</h2>
<h3 id="객체란">객체란?</h3>
<p>앞서 배운 원시형(primitive type) 자료형은 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있다. </p>
<p>그러나 객체형은 원시형과 달리 다양한 데이터를 담을 수 있다. 키로 구분된 데이터 집합이나 복잡한 개체(entity)를 저장할 수 있다. </p>
<p>객체는 중괄호 {}를 이용해 만들 수 있고, 중괄호 안에는 ‘키(key): 값(value)’ 쌍으로 구성된 <code>프로퍼티(property)</code>를 여러 개 넣을 수 있다. </p>
<p>키(key)엔 문자형, 값(value)엔 모든 자료형이 허용된다. 프로퍼티 키(key)는 ‘프로퍼티 이름’, &#39;식별자&#39;라고도 부른다. </p>
<ul>
<li>함수도 객체이다.</li>
</ul>
<h3 id="예시로-객체의-개념-이해하기">예시로 객체의 개념 이해하기</h3>
<p>서랍장 예시로 객체를 이해해보자. 
<img src="https://velog.velcdn.com/images/cse_pebb/post/003740be-6758-4de7-aaa8-e12550b71775/image.png" alt=""></p>
<p>서랍장에 파일이 꽂혀있을 때, 파일에 붙어있는 이름표가 객체의 키(key), 파일의 내용이 값(value)이라고 생각하면 된다. 서랍장에서 파일 이름을 보고 파일을 쉽게 찾을 수 있듯이, 객체에서는 키(key)를 이용하여 프로퍼티를 쉽게 찾는다.</p>
<h3 id="빈-객체빈-서랍장를-만드는-2가지-방법">빈 객체(빈 서랍장)를 만드는 2가지 방법</h3>
<pre><code class="language-js">//1. &#39;객체 생성자&#39; 문법
let user = new Object();

//2. &#39;객체 리터럴&#39; 문법
let user = {};</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/0f9095f8-7122-4c6c-99ed-a3c8a53c9713/image.png" alt=""></p>
<blockquote>
<p>2번째 방법으로 객체를 선언하는 것을 <code>객체 리터럴(object literal)</code>이라고 부른다. 객체를 선언할 때는 주로 이 방법을 사용한다.</p>
</blockquote>
<h3 id="객체-리터럴과-프로퍼티">객체 리터럴과 프로퍼티</h3>
<p>중괄호 {} 안에는 &quot;키:값&quot; 쌍으로 구성된 프로퍼티가 들어간다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,   //프로퍼티: name과 John, key: name, value: John
  age: 30 //프로퍼티: age와 30, key: age, value: 30
}</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/bb46d31d-5647-4a35-a1e1-6a55b34ca34f/image.png" alt=""></p>
<p>프로퍼티 키(key)는 문자형만 올 수 있다. 단, 띄어쓰기가 있는 경우에는 아래와 같이 따옴표로 묶어줘야 한다. 프로퍼티 값(value)에는 모든 자료형이 올 수 있다. 아래와 같이 불린형도 가능하다.</p>
<pre><code class="language-js">let user = {
  &quot;likes birds&quot;: true
}</code></pre>
<h3 id="프로퍼티-값을-읽고-프로퍼티를-추가하고-삭제하기">프로퍼티 값을 읽고, 프로퍼티를 추가하고, 삭제하기</h3>
<p><strong>프로퍼티 값을 읽는 방법 2가지</strong></p>
<ol>
<li><p>점 표기법(dot notation)</p>
<pre><code class="language-js">alert(user.name); // John
alert(user.age); // 30</code></pre>
</li>
<li><p>대괄호 표기법</p>
</li>
</ol>
<p>띄어쓰기가 있는 프로퍼티 키(key)의 경우 1번 표기법을 사용할 수 없다. </p>
<pre><code class="language-js">user.likes birds = true // 에러 발생</code></pre>
<p>이럴 때 대괄호 표기법을 사용할 수 있다. 단, 대괄호 표기법 안에서 문자열을 사용할 땐 문자열을 따옴표로 묶어줘야 한다.</p>
<pre><code class="language-js">user[&quot;likes birds&quot;] = true</code></pre>
<p>아래와 같은 방법도 가능하다. 1번 표기법은 불가능하다.</p>
<pre><code class="language-js">let key = &quot;likes birds&quot;;

user[key] = true;</code></pre>
<p><strong>프로퍼티 값 추가하기</strong></p>
<p>단순히 아래와 같이 작성해주면 된다.</p>
<pre><code class="language-js">//점 표기법
user.isAdmin = true;

//대괄호 표기법
user[&quot;isAdmin&quot;] = true;</code></pre>
<p><strong>프로퍼티 삭제하기</strong></p>
<p><code>delete</code> 연산자를 사용하면 프로퍼티를 삭제할 수 있다.</p>
<pre><code class="language-js">//점 표기법
delete user.age;

//대괄호 표기법
delete user[&quot;age&quot;];</code></pre>
<p><strong>cf) 상수 객체는 수정될 수 있다!</strong>
<code>const</code>로 선언된 객체는 수정될 수 없을 것 같지만, 수정될 수 있다.</p>
<pre><code class="language-js">const user = {
  name: &quot;John&quot;
};

user.name = &quot;Pete&quot;;

laert(user.name); // Pete</code></pre>
<p><code>const</code>는 user의 값을 고정하지만, 그 내용은 고정하지 않는다. 즉 <code>user=...</code>를 전체적으로 설정하려고 할 때만 오류가 발생한다.</p>
<h3 id="계산된-프로퍼티">계산된 프로퍼티</h3>
<p>객체 리터럴 안의 프로퍼티 키(key)가 대괄호로 둘러싸여 있는 경우, 이를 <code>계산된 프로퍼티(computed property)</code>라고 부른다.</p>
<p>대괄호로 둘러싸인 프로퍼티 키(key)를, 대괄호 안에 있는 변수에서 가져오겠다는 것을 의미한다.</p>
<p>예시를 보자.</p>
<pre><code class="language-js">let fruit = prompt(&quot;어떤 과일을 구매하시겠습니까?&quot;);

let bag = {
  [fruit]: 5 // 변수 fruit에서 프로퍼티 키(key)를 동적으로 받아온다.
};

alert(bag.apple);</code></pre>
<p>사용자가 prompt 창에 apple이라고 입력하면, 결과는 5가 출력된다. 위 코드는 아래와 같은 코드이다.</p>
<pre><code class="language-js">let fruit = prompt(&quot;어떤 과일을 구매하시겠습니까?&quot;);
let bag = {};

bag[fruit] = 5;</code></pre>
<p>한편, 대괄호 안에는 복잡한 표현식이 올 수도 있다.</p>
<pre><code class="language-js">let fruit = &quot;apple&quot;;
let bag = {
  [fruit + &quot;Computers&quot;]: 5 // bag.appleComputers = 5
}</code></pre>
<p>대괄호 표기법은 프로퍼티 이름과 값의 제약을 없애주기 때문에 점 표기법보다 훨씬 강력하다. 그런데 작성하기 번거롭다는 단점이 있다.</p>
<blockquote>
<p>프로퍼티 이름이 확정된 상황이고, 단순한 이름이라면 처음엔 점 표기법을 사용하다가 뭔가 복잡한 상황이 발생했을 때 대괄호 표기법으로 바꾸는 경우가 많다.</p>
</blockquote>
<h3 id="단축-프로퍼티">단축 프로퍼티</h3>
<p>아래의 예시를 보자.</p>
<pre><code class="language-js">function makeUser(name, age) {
  return {
    name: name,
    age: age,
  };
}</code></pre>
<p>이렇게 프로퍼티 키(key)와 값(value)의 이름이 동일할 경우, 코드를 아래와 같이 짧게 줄일 수 있다.</p>
<pre><code class="language-js">function makeUser(name, age) {
  return {
    name, // name: name 과 같음
    age,  // age: age 와 같음
  };
}</code></pre>
<h3 id="프로퍼티-이름의-제약사항">프로퍼티 이름의 제약사항</h3>
<p>프로퍼티 키(key)는 어떤 문자형이나 될 수 있다. (사실 심볼형도 되는데 이는 뒤에서 다룰 예정이다.)</p>
<p>예를 들어 아래처럼 객체 프로퍼티 키(key) 이름을 예약어로 설정할 수 있다!</p>
<pre><code class="language-js">// 예약어를 키로 사용해도 괜찮습니다.
let obj = {
  for: 1,
  let: 2,
  return: 3
};

alert( obj.for + obj.let + obj.return );  // 6</code></pre>
<p>만약 문자형이 아닌 다른 자료형으로 설정할 경우 문자열로 자동 형 변환된다.</p>
<pre><code class="language-js">let obj = {
  0: &quot;test&quot; // &quot;0&quot;: &quot;test&quot;와 동일합니다.
};

// 숫자 0은 문자열 &quot;0&quot;으로 변환되기 때문에 두 얼럿 창은 같은 프로퍼티에 접근합니다,
alert( obj[&quot;0&quot;] ); // test
alert( obj[0] ); // test (동일한 프로퍼티)</code></pre>
<ul>
<li><code>__proto__</code> 관련된 내용은 문서 참고</li>
</ul>
<h3 id="in-연산자로-프로퍼티-존재-여부-확인하기">&#39;in&#39; 연산자로 프로퍼티 존재 여부 확인하기</h3>
<p>2가지 방법이 있다.</p>
<ol>
<li>객체의 <code>undefined</code> 반환 특징 이용하기
객체는 존재하지 않는 프로퍼티에 접근하려고 해도 에러 발생 없이 <code>undefined</code> 값을 반환한다. 이러한 특징을 이용하면 프로퍼티 존재 여부를 확인할 수 있다.</li>
</ol>
<pre><code class="language-js">let user = {};

alert( user.noSuchProperty === undefined ); // true. true는 &#39;프로퍼티가 존재하지 않음&#39;을 의미합니다.</code></pre>
<ol start="2">
<li>연산자 <code>in</code> 사용하기</li>
</ol>
<p>문법은 아래와 같다.</p>
<pre><code class="language-js">&quot;key&quot; in 객체</code></pre>
<p>예시를 보자.</p>
<pre><code class="language-js">let user = { name: &quot;John&quot;, age: 30 };

alert( &quot;age&quot; in user ); // user.age가 존재하므로 true가 출력됩니다.
alert( &quot;blabla&quot; in user ); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.</code></pre>
<p>아래와 같이 변수로 접근해도 된다.</p>
<pre><code class="language-js">let user = { age: 30 };

let key = &quot;age&quot;;
alert( key in user ); // true, 변수 key에 저장된 값(&quot;age&quot;)을 사용해 프로퍼티 존재 여부를 확인합니다.</code></pre>
<p>프로퍼티 값(value) 자체에 <code>undefined</code>가 할당된다면 1번이 원하는대로 동작하지 않을 수 있기 때문에, 2번이 존재한다. (자세한 것은 문서 참고)</p>
<h3 id="객체의-모든-키를-순회하는-forin-반복문">객체의 모든 키를 순회하는 &#39;for...in&#39; 반복문</h3>
<p><code>for...in</code> 반복문을 사용하면 객체의 모든 키(key)를 순회할 수 있다. for 반복문과는 완전히 다르다!</p>
<p>문법은 아래와 같다.</p>
<pre><code class="language-js">for (key in 객체) {
  // 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행합니다.
}</code></pre>
<p>객체의 모든 프로퍼티 키와 값을 출력하는 예제를 보자.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  age: 30,
  isAdmin: true
};

for (let key in user) {
  // 키
  alert( key );  // name, age, isAdmin
  // 키에 해당하는 값
  alert( user[key] ); // John, 30, true
}</code></pre>
<p>여기서 <code>key</code>는 단순한 변수명이다. 다른 변수명으로 바꿔도 된다.</p>
<h3 id="객체-정렬-방식">객체 정렬 방식</h3>
<p>객체와 객체 프로퍼티를 다루다 보면 &quot;프로퍼티엔 순서가 있을까?&quot;라는 의문이 생기기 마련이다. 특히 반복문은 프로퍼티를 추가한 순서대로 실행될지, 그리고 이 순서는 항상 동일할지 궁금해진다.</p>
<blockquote>
<p>결론은, 정수 프로퍼티(integer property)는 자동으로 정렬되고, 그 외의 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.</p>
</blockquote>
<ul>
<li>정수 프로퍼티 : 정수로 변환하거나 변환된 정수를 다시 문자열로 바꿔도 변형이 없는 문자열을 의미함</li>
</ul>
<p>키(key)가 정수인 경우는 오름차순으로 자동 정렬된다.</p>
<pre><code class="language-js">let codes = {
  &quot;49&quot;: &quot;독일&quot;,
  &quot;41&quot;: &quot;스위스&quot;,
  &quot;44&quot;: &quot;영국&quot;,
  &quot;1&quot;: &quot;미국&quot;
};

for (let code in codes) {
  alert(code); // 1, 41, 44, 49
}</code></pre>
<p>키(key)가 정수가 아닌 경우는 작성된 그대로 나열된다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  surname: &quot;Smith&quot;
};
user.age = 25; // 프로퍼티를 하나 추가합니다.

// 정수 프로퍼티가 아닌 프로퍼티는 추가된 순서대로 나열됩니다.
for (let prop in user) {
  alert( prop ); // name, surname, age
}</code></pre>
<h2 id="🌝-참조에-의한-객체-복사">🌝 참조에 의한 객체 복사</h2>
<h3 id="객체와-원시-타입의-근본적인-차이">객체와 원시 타입의 근본적인 차이</h3>
<ul>
<li>객체 : <code>참조에 의해(by reference)</code> 저장되고 복사된다.</li>
<li>원시 타입 : <code>값 그대로</code> 저장, 할당되고 복사된다.</li>
</ul>
<p>원시타입 예제를 보자.</p>
<pre><code class="language-js">let message = &quot;Hello!&quot;;
let phrase = message;</code></pre>
<p>이렇게 하면 message, phrase 변수에 각각 문자열 <code>Hello!</code>가 저장된다.</p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/c2b8eded-e5e2-4c7b-84bc-ada7e37a1b8d/image.png" alt=""></p>
<p>반면 객체는, 객체가 그대로 저장되는 것이 아니라 객체가 저장되어 있는 <strong>메모리 주소</strong>인 <strong>객체에 대한 참조 값</strong>이 저장된다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/f9b0f5e3-53b1-4491-a434-a587ec84a63b/image.png" alt=""></p>
<p>객체는 메모리 내 어딘가에 저장되고, 변수 user엔 객체를 <strong>참조</strong>할 수 있는 값이 저장된다.</p>
<h3 id="객체-복사하기">객체 복사하기</h3>
<p>위의 내용에 따라, 객체가 할당된 변수를 복사할 때, 객체의 <strong>참조 값</strong>이 복사되는 것이지 객체 자체가 복사되는 것이 아니다. </p>
<pre><code class="language-js">let user = { name: &quot;John&quot; };

let admin = user; // 참조값을 복사함</code></pre>
<p>그림을 보면 이해가 쉽다.</p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/0240c19f-51a9-47bf-b9e7-270dafd26728/image.png" alt=""></p>
<p>변수는 2개이지만 각 변수에는 <strong>동일 객체에 대한 참조 값</strong>이 저장된다.</p>
<p>아래의 예시도 보자.</p>
<pre><code class="language-js">let user = { name: &#39;John&#39; };

let admin = user;

admin.name = &#39;Pete&#39;; // &#39;admin&#39; 참조 값에 의해 변경됨

alert(user.name); // &#39;Pete&#39;가 출력됨. &#39;user&#39; 참조 값을 이용해 변경사항을 확인함</code></pre>
<p>객체를 서랍장에 비유하면 변수는 서랍장을 열 수 있는 열쇠라고 할 수 있다. 서랍장은 하나, 서랍장을 열 수 있는 열쇠는 두 개인데, 그중 admin 열쇠를 사용해 서랍장을 열어 정돈한 후, user 열쇠로 서랍장을 열면 내용이 정돈되어 있는 것을 확인할 수 있다.</p>
<ul>
<li>참조에 의한 비교에 대한 내용을 알고 싶다면 문서 참고</li>
</ul>
<h3 id="객체-복사-병합과-objectassign">객체 복사, 병합과 Object.assign</h3>
<p>앞에서 한 것과 달리 객체를 <strong>복제</strong>하고 싶다면 어떻게 해야 할까? 즉, 기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면 말이다. </p>
<p>방법은 있는데 자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵다. 사실 객체를 복제해야 할 일은 거의 없다. 참조에 의한 복사로 해결 가능한 일이 대다수이다.</p>
<p>정말 복제가 필요한 상황이라면 2가지 방법을 사용하면 된다.</p>
<ol>
<li>새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티 복사하기</li>
</ol>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  age: 30
};

let clone = {}; // 새로운 빈 객체

// 빈 객체에 user 프로퍼티 전부를 복사해 넣습니다.
for (let key in user) {
  clone[key] = user[key];
}

// 이제 clone은 완전히 독립적인 복제본이 되었습니다.
clone.name = &quot;Pete&quot;; // clone의 데이터를 변경합니다.

alert( user.name ); // 기존 객체에는 여전히 John이 있습니다.</code></pre>
<ol start="2">
<li><code>Object.assign</code> 사용하기</li>
</ol>
<p>문법을 보자.</p>
<pre><code class="language-js">Object.assign(dest, [src1, src2, src3...])</code></pre>
<ul>
<li>첫 번째 인수 dest는 목표로 하는 객체이다.</li>
<li>이어지는 인수 src1, ..., srcN는 dest에 복사하고자 하는 객체이다. ...은 필요에 따라 얼마든지 많은 객체를 인수로 사용할 수 있다는 것을 나타낸다.</li>
<li>객체 src1, ..., srcN의 프로퍼티를 dest에 복사한다. dest를 제외한 인수(객체)의 프로퍼티 전부가 첫 번째 인수(객체)로 복사된다.</li>
<li>마지막으로 dest를 반환한다.</li>
</ul>
<p><code>assign</code> 메서드를 사용해 여러 객체를 하나로 병합하는 예시를 살펴보자.</p>
<pre><code class="language-js">let user = { name: &quot;John&quot; };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// permissions1과 permissions2의 프로퍼티를 user로 복사합니다.
Object.assign(user, permissions1, permissions2);

// now user = { name: &quot;John&quot;, canView: true, canEdit: true }</code></pre>
<p>목표 객체(user)에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워 진다.</p>
<pre><code class="language-js">let user = { name: &quot;John&quot; };

Object.assign(user, { name: &quot;Pete&quot; });

alert(user.name); // user = { name: &quot;Pete&quot; }</code></pre>
<p>Object.assign을 사용하면 반복문 없이도 간단하게 객체를 복사할 수 있다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  age: 30
};

let clone = Object.assign({}, user);</code></pre>
<p>예시를 실행하면 user에 있는 모든 프로퍼티가 빈 배열에 복사되고 변수에 할당된다.</p>
<h3 id="중첩-객체-복사">중첩 객체 복사</h3>
<p>아래의 경우에는 어떻게 해야할까?</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  sizes: { //중첩 객체
    height: 182,
    width: 50
  }
};

alert( user.sizes.height ); // 182</code></pre>
<p><code>clone.sizes = user.sizes</code>로 프로퍼티를 복사하는 것만으론 객체를 복제할 수 없다. <code>user.sizes</code>는 객체이기 때문에 참조 값이 복사되기 때문이다. <code>clone.sizes = user.sizes</code>로 프로퍼티를 복사하면 clone과 user는 같은 sizes를 공유하게 된다.</p>
<p>이 문제를 해결하려면 user[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 한다. 이런 방식을 <code>깊은 복사(deep cloning)</code>라고 한다. </p>
<p>자바스크립트 라이브러리 lodash의 메서드인 <code>_.cloneDeep(obj)</code>을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수 있다. </p>
<h2 id="🌝-가비지-컬렉션">🌝 가비지 컬렉션</h2>
<h3 id="가비지-컬렉션이란">가비지 컬렉션이란?</h3>
<p>자바스크립트는 눈에 보이지 않는 곳에서 메모리 관리를 수행한다.</p>
<p>원시값, 객체, 함수 등 우리가 만드는 모든 것은 메모리를 차지하는데, 더는 쓸모 없어지게 된 것들은 찾아내 삭제해야 한다. 자바스크립트 엔진이 필요 없는 것을 찾아내 삭제하는 것이 <code>가비지 컬렉션</code>이다.</p>
<h3 id="가비지-컬렉션-기준">가비지 컬렉션 기준</h3>
<p>자바스크립트는 도달 가능성(reachability) 이라는 개념을 사용해 메모리 관리를 수행한다.</p>
<p>가비지 컬렉터는 모든 객체를 모니터링하고, 도달할 수 없는 객체는 삭제한다. 도달 가능한 값은 메모리에서 삭제되지 않는다.</p>
<ol>
<li>태생부터 도달 가능한 값 <code>루트(root)</code> : 명백한 이유 없이는 삭제되지 않는다.</li>
</ol>
<ul>
<li>현재 함수의 지역 변수와 매개변수</li>
<li>중첩 함수의 체인에 있는 함수에서 사용되는 변수와 매개변수</li>
<li>전역 변수</li>
<li>기타 등등</li>
</ul>
<ol start="2">
<li>루트가 참조하는 값이나 체이닝으로 루트에서 참조할 수 있는 값 : 도달 가능한 값</li>
</ol>
<h3 id="그림과-예시로-이해하기">그림과 예시로 이해하기</h3>
<ol>
<li><pre><code class="language-js">let user = {
name: &quot;John&quot;
};</code></pre>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/9524bda9-2d0f-4df1-8d92-3f2ad59b18d1/image.png" alt=""></p>
<p><code>user</code> 값을 다른 값으로 덮어쓰면 참조(화살표)가 사라진다.</p>
<pre><code class="language-js">user = null;</code></pre>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/2c0ca176-56b2-418c-8dca-601e3ad00763/image.png" alt=""></p>
<ol start="2">
<li><pre><code class="language-js">// user엔 객체 참조 값이 저장됩니다.
let user = {
name: &quot;John&quot;
};
</code></pre>
</li>
</ol>
<p>let admin = user;</p>
<pre><code>![](https://velog.velcdn.com/images/cse_pebb/post/24893914-8e40-412e-b923-e9e932a08976/image.png)

이번에도 `user`의 값을 다른 값으로 덮어써 보자.
```js
user = null;</code></pre><p>1번 예시와 달리 전역 변수 admin을 통하면 여전히 객체 John에 접근할 수 있기 때문에 John은 메모리에서 삭제되지 않는다.</p>
<ol start="3">
<li><pre><code class="language-js">function marry(man, woman) {
woman.husband = man;
man.wife = woman;

return {
 father: man,
 mother: woman
}
}
</code></pre>
</li>
</ol>
<p>let family = marry({
  name: &quot;John&quot;
}, {
  name: &quot;Ann&quot;
});</p>
<pre><code>![](https://velog.velcdn.com/images/cse_pebb/post/a0492af2-0484-4173-8803-c9dd9b163ed6/image.png)

참조 2개를 지워보자.
```js
delete family.father;
delete family.mother.husband;</code></pre><p><img src="https://velog.velcdn.com/images/cse_pebb/post/2b780d3c-47d8-4302-bf8d-1be209688c89/image.png" alt=""></p>
<p>외부로 나가는 참조는 도달 가능한 상태에 영향을 주지 않는다. 외부에서 들어오는 참조만이 도달 가능한 상태에 영향을 준다. 그 결과 아래와 같이 된다.
<img src="https://velog.velcdn.com/images/cse_pebb/post/c6abcb6b-d2c3-429c-a94c-6bce2cca9469/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/1fb4de64-69c2-4a87-824a-15309fa06496/image.png" alt=""></p>
<blockquote>
<p>결론은, 객체들이 연결되어 섬 같은 구조를 만드는데, 이 섬에 도달할 방법이 없는 경우, 섬을 구성하는 객체 전부가 메모리에서 삭제된다.</p>
</blockquote>
<h3 id="내부-알고리즘">내부 알고리즘</h3>
<ul>
<li>가비지 컬렉션 기본 알고리즘 : <code>mark-and-sweep</code></li>
</ul>
<ol>
<li>가비지 컬렉터는 루트(root) 정보를 수집하고 이를 ‘mark(기억)’ 한다.</li>
<li>루트가 참조하고 있는 모든 객체를 방문하고 이것들을 ‘mark’ 한다.</li>
<li>mark 된 모든 객체에 방문하고 그 객체들이 참조하는 객체도 mark 한다. 한번 방문한 객체는 전부 mark 하기 때문에 같은 객체를 다시 방문하는 일은 없다.</li>
<li>루트에서 도달 가능한 모든 객체를 방문할 때까지 위 과정을 반복한다.</li>
<li>mark 되지 않은 모든 객체를 메모리에서 삭제한다.</li>
</ol>
<h4 id="최적화-기법">최적화 기법</h4>
<p>자바스크립트 엔진은 실행에 영향을 미치지 않으면서 가비지 컬렉션을 더 빠르게 하는 다양한 최적화 기법을 적용한다.</p>
<p>자세한 내용은 문서 참조!</p>
<h2 id="🌝-메서드와-this">🌝 메서드와 this</h2>
<h3 id="메서드-만들기">메서드 만들기</h3>
<p>객체의 프로퍼티에 함수를 할당해 객체에게 행동할 수 있는 능력을 부여해줄 수 있다. 그렇게 객체 프로퍼티에 할당된 함수를 <code>메서드(method)</code>라고 한다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  age: 30
};

user.sayHi = function() {
  alert(&quot;안녕하세요!&quot;);
};

user.sayHi(); // 안녕하세요!</code></pre>
<p>이미 정의된 함수를 이용해서 메서드로 만들어 줄 수도 있다.</p>
<pre><code class="language-js">let user = {
  // ...
};

// 함수 선언
function sayHi() {
  alert(&quot;안녕하세요!&quot;);
};

// 선언된 함수를 메서드로 등록
user.sayHi = sayHi;

user.sayHi(); // 안녕하세요!</code></pre>
<h3 id="메서드-단축-구문">메서드 단축 구문</h3>
<pre><code class="language-js">// 아래 두 객체는 동일하게 동작합니다.

user = {
  sayHi: function() {
    alert(&quot;Hello&quot;);
  }
};

// 단축 구문을 사용하니 더 깔끔해 보이네요.
user = {
  sayHi() { // &quot;sayHi: function()&quot;과 동일합니다.
    alert(&quot;Hello&quot;);
  }
};</code></pre>
<p>사실 일반적인 방법과 단축 구문을 사용한 방법이 완전히 동일하진 않고 미묘한 차이가 있는데, 우선은 중요하지 않으므로 넘어가자. </p>
<h3 id="메서드와-this">메서드와 this</h3>
<p>메서드 내부에서 this 키워드를 사용하면 <strong>현재 객체</strong>에 접근할 수 있다. <code>this</code>는 메서드를 호출할 때 사용된 객체를 나타낸다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  age: 30,

  sayHi() {
    // &#39;this&#39;는 &#39;현재 객체&#39;를 나타냅니다.
    alert(this.name);
  }

};

user.sayHi(); // John</code></pre>
<p>user.sayHi()가 실행되는 동안에 <code>this</code>는 <code>user</code>를 나타낸다.</p>
<p>자세한 내용은 문서를 참고하자.</p>
<h3 id="js의-자유로운-this">JS의 자유로운 this</h3>
<p>자바스크립트의 <code>this</code>는 다른 프로그래밍 언어의 <code>this</code>와 달리 모든 함수에 <code>this</code>를 사용할 수 있다. </p>
<p>아래와 같이 작성해도 에러가 발생하지 않는다.</p>
<pre><code class="language-js">function sayHi() {
  alert( this.name );
}</code></pre>
<p>this 값은 런타임에 결정된다. 즉, <strong>컨텍스트에 따라 달라진다.</strong></p>
<p>동일한 함수라도 다른 객체에서 호출했다면 &#39;this’가 참조하는 값이 달라진다.</p>
<pre><code class="language-js">let user = { name: &quot;John&quot; };
let admin = { name: &quot;Admin&quot; };

function sayHi() {
  alert( this.name );
}

// 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;

// &#39;this&#39;는 &#39;점(.) 앞의&#39; 객체를 참조하기 때문에
// this 값이 달라짐
user.f(); // John  (this == user)
admin.f(); // Admin  (this == admin)

admin[&#39;f&#39;](); // Admin (점과 대괄호는 동일하게 동작함)</code></pre>
<h3 id="객체-없이-호출하고-this-값-확인하기">객체 없이 호출하고 this 값 확인하기</h3>
<pre><code class="language-js">function sayHi() {
  alert(this);
}

sayHi(); // undefined</code></pre>
<p>엄격모드에서는 객체가 없으므로 <code>this</code>에 <code>undefined</code>가 할당된다. (런타임에서 할당될 객체가 없기 때문) 그리고 <code>this.name</code>으로 <code>name</code>에 접근하려고 하면 에러가 발생한다.</p>
<p>❗<strong>헷갈리지 말자!</strong> <strong>객체</strong>가 없을 경우에 해당되는 얘기다. <strong>프로퍼티</strong>가 아니라 !!
예시를 보자.</p>
<pre><code class="language-js">// 클래스와 모듈을 사용하지 않아 엄격모드가 자동으로 적용되지 않기 때문에 직접 적용함
&quot;use strict&quot;; 

let imObject = {
  callThisObejct() {
    alert(this);
  },
  generateProperty() {
    this.a = &quot;나는 this와 함께 생성된 a야.&quot;;
    alert(this.a);
  },
};

//1
imObject.callThisObejct(); // 결과 : [object Object]
//2
imObject.generateProperty(); // 결과 : 나는 this와 함께 생성된 a야.
</code></pre>
<p>여기서 <code>imObject</code>라는 <strong>객체는 존재한다</strong>. 따라서 1번 결과에서 확인할 수 있듯 <code>this</code>에 <code>undefined</code>가 할당되지 않는다. 
2번의 경우 <strong><code>a</code>라는 프로퍼티는 존재하지 않는다. 하지만 이것은 위에서 말한 내용과 전혀 관계가 없다.</strong> <code>this</code>는 <code>a</code>라는 프로퍼티를 자동으로 생성하고, 정상적으로 값도 출력한다. </p>
<p>다시 한번 헷갈리지 말자. <strong>객체가 존재하지 않을 경우</strong>에 <code>this</code>에 <code>undefined</code>가 할당되는 것이다.</p>
<pre><code class="language-js">function func() {
  alert(this);
}

func(); // 결과 : undefined</code></pre>
<p><del>음? 근데 함수도 객체아닌가 이게 뭔소리지........???????엥??? 함수가 존재한다는 건 객체가 존재한단 뜻인데....... 그 객체가 그 객체가 아닌가? 어쩌라는거임?</del> 
👉 아무래도 프로퍼티가 존재하는.. 고러한 전형적인(?) 객체를 의미하는듯.</p>
<p>정리해보자면,</p>
<ul>
<li>함수를 선언할 때 <code>this</code>를 사용할 수 있다. 다만 함수가 호출되기 전까지 <code>this</code>엔 값이 할당되지 않는다. 즉, <strong>함수가 호출되는 순간에 <code>this</code>에 값이 할당된다.</strong></li>
<li>함수를 복사해 객체 간 전달할 수 있다.</li>
<li>함수를 객체 프로퍼티에 저장해 <code>객체명.method()</code>와 같이 메서드 형태로 호출하면 <code>this</code>는 그때 해당 <code>객체명에 해당되는 객체</code>를 참조한다.</li>
</ul>
<h2 id="🌝-new-연산자와-생성자-함수">🌝 new 연산자와 생성자 함수</h2>
<p><code>new</code> 연산자와 <code>생성자 함수</code>를 사용하면 유사한 객체 여러 개를 쉽게 만들 수 있다. </p>
<p><del>생성자 함수는 처음 나오는 개념이다.. 함수 파트 글 찾아보지마...</del></p>
<h3 id="생성자-함수">생성자 함수</h3>
<p><code>생성자 함수</code>와 일반 함수에 기술적인 차이는 없지만, <code>생성자 함수는</code> 2가지의 컨벤션이 있다.</p>
<ol>
<li>함수 이름의 첫 글자는 대문자로!</li>
<li>반드시 <code>new</code> 연산자를 붙여 실행!</li>
</ol>
<p>예시를 보자.</p>
<pre><code class="language-js">function User(name) {
  this.name = name;
  this.isAdmin = false;
}

let user = new User(&quot;보라&quot;);

alert(user.name); // 보라
alert(user.isAdmin); // false</code></pre>
<p><code>new User(...)</code>를 써서 함수를 실행할 때 어떤 알고리즘이 동작하는지 알아보자.</p>
<ol>
<li>User() 함수 안에 빈 객체를 만들어 <code>this</code>에 할당한다. </li>
<li>User() 함수 본문을 실행한다. <code>this</code>에 새롭게 할당된 프로퍼티를 추가하여 <code>this</code>를 수정한다.</li>
<li><code>this</code>를 반환한다.</li>
</ol>
<p>User() 함수 안에서 일어나는 일을 아래의 예시를 통해 보자.</p>
<pre><code class="language-js">function User(name) {
  // this = {};  1. 빈 객체가 암시적으로 만들어짐

  // 2. 새로운 프로퍼티를 this에 추가함
  this.name = name;
  this.isAdmin = false;

  // return this;  3. this가 암시적으로 반환됨
}</code></pre>
<p>왜 생성자 함수를 사용하면 객체를 쉽게 만들 수 있다는 것일까? 
아래의 예시를 통해 알아보자.</p>
<ol>
<li>생성자 함수로 객체 생성<pre><code class="language-js">let user = new User(&quot;보라&quot;);</code></pre>
</li>
<li>객체 리터럴 문법으로 객체 생성 <pre><code class="language-js">let user = {
name: &quot;보라&quot;,
isAdmin: false
}</code></pre>
</li>
</ol>
<p><code>new User(&quot;보라&quot;)</code>이외에도 <code>new User(&quot;호진&quot;)</code>, <code>new User(&quot;지민&quot;)</code> 등을 이용하면 손쉽게 사용자 객체를 만들 수 있다. 객체 리터럴 문법으로 일일이 객체를 만드는 방법보다 훨씬 간단하고 읽기 쉽게 객체를 만들 수 있다.</p>
<blockquote>
<p>생성자의 의의는 바로 여기에 있다. <strong>재사용할 수 있는 객체 생성 코드를 구현하는 것</strong>이다.</p>
</blockquote>
<h3 id="익명-생성자-함수">익명 생성자 함수</h3>
<p>재사용할 필요가 없는데 복잡한 객체를 만들어야 할 때, 코드를 익명 생성자 함수로 감싸주는 방식을 사용할 수 있다.</p>
<pre><code class="language-js">let user = new function() {
  this.name = &quot;John&quot;;
  this.isAdmin = false;

  // 사용자 객체를 만들기 위한 여러 코드.
  // 지역 변수, 복잡한 로직, 구문 등의
  // 다양한 코드가 여기에 들어갑니다.
};</code></pre>
<p>위 생성자 함수는 익명 함수이기 때문에 어디에도 저장되지 않는다. 처음 만들 때부터 단 한 번만 호출할 목적으로 만들었기 때문에 재사용이 불가능하다. </p>
<blockquote>
<p>이렇게 익명 생성자 함수를 이용하면 재사용은 막으면서 코드를 캡슐화 할 수 있다.</p>
</blockquote>
<h3 id="newtarget과-생성자-함수">new.target과 생성자 함수</h3>
<p><code>new.target</code> 프로퍼티를 사용하면 <strong>함수가 <code>new</code>와 함께 호출되었는지 아닌지</strong>를 알 수 있다.</p>
<p><code>new</code>와 함께 호출하지 않고 일반적인 방법으로 함수를 호출하면 <code>new.target</code>은 <code>undefined</code>를 반환하고, <code>new</code>과 함께 호출한 경우에는 함수 자체를 반환해준다.</p>
<pre><code class="language-js">function User() {
  alert(new.target);
}

// &#39;new&#39; 없이 호출함
User(); // undefined

// &#39;new&#39;를 붙여 호출함
new User(); // function User { ... }</code></pre>
<blockquote>
<p><code>new.target</code> 문법은 자주 쓰이지 않는다. 자세한 내용은 문서를 참고하자.</p>
</blockquote>
<h3 id="생성자와-return문">생성자와 return문</h3>
<p>생성자 함수에는 보통 <code>return</code>문이 없다. 반환해야 할 것들은 모두 <code>this</code>에 저장되고, <code>this</code>는 자동으로 반환도기 때문에 반환문을 명시적으로 써 줄 필요가 없다.</p>
<p>그러나 만약 <code>return</code>문이 있다면, 아래의 규칙이 적용된다.</p>
<ol>
<li>객체를 <code>return</code>한다면 <code>this</code>가 반환되는 대신 해당 객체가 반환된다.</li>
<li>원시형을 <code>return</code>하거나 <code>return</code> 예약어만 쓰고 아무것도 반환하지 않는다면 <code>return</code>문이 무시된다.</li>
</ol>
<p>1번 규칙이 적용되는 예시</p>
<pre><code class="language-js">function BigUser() {

  this.name = &quot;원숭이&quot;;

  return { name: &quot;고릴라&quot; };  // &lt;-- this가 아닌 새로운 객체를 반환함
}

alert( new BigUser().name );  // 고릴라</code></pre>
<p>2번 규칙이 적용되는 예시</p>
<pre><code class="language-js">function SmallUser() {

  this.name = &quot;원숭이&quot;;

  return; // &lt;-- this를 반환함
}

alert( new SmallUser().name );  // 원숭이</code></pre>
<blockquote>
<p>사실 <code>return</code>문이 있는 생성자 함수는 거의 없다. 특이 케이스이기 때문에 넘어가도 좋다.</p>
</blockquote>
<h3 id="생성자-내-메서드">생성자 내 메서드</h3>
<p>생성자 함수를 사용하면 매개변수를 이용해 객체 내부를 자유롭게 구성할 수 있다. <code>this</code>에 프로퍼티를 더해주는 것 말고도, 메서드를 더해주는 것도 가능하다. </p>
<p>예시를 보자.</p>
<pre><code class="language-js">function User(name) {
  this.name = name;

  this.sayHi = function() {
    alert( &quot;제 이름은 &quot; + this.name + &quot;입니다.&quot; );
  };
}

let bora = new User(&quot;이보라&quot;);
bora.sayHi(); // 제 이름은 이보라입니다. 
</code></pre>
<p>맨 아래 두 줄의 코드는 아래의 코드와 동일하게 동작한다.</p>
<pre><code class="language-js">bora = {
   name: &quot;이보라&quot;,
   sayHi: function() { ... }
}</code></pre>
<h2 id="🌝-옵셔널-체이닝-">🌝 옵셔널 체이닝 &#39;?.&#39;</h2>
<blockquote>
<p>옵셔널 체이닝(optional chaining) <code>?.</code>을 사용하면 프로퍼티가 없는 중첩 객체를 에러 없이 안전하게 접근할 수 있다.</p>
</blockquote>
<h3 id="옵셔널-체이닝이-필요한-이유">옵셔널 체이닝이 필요한 이유</h3>
<ol>
<li>사용자가 여러 명 있는데 그중 몇 명은 주소 정보를 가지고 있지 않다고 가정해보자. 이럴 때 <code>user.address.street</code>를 사용해 주소 정보에 접근하면 에러가 발생할 수 있다. 이렇게 에러가 발생하지 않아도 되는 상황에서 발생하는 에러를 막기 위해 옵셔널 체이닝이 필요하다. <pre><code class="language-js">let user = {}; // 주소 정보가 없는 사용자
</code></pre>
</li>
</ol>
<p>alert(user.address.street); // TypeError: Cannot read property &#39;street&#39; of undefined</p>
<pre><code>
2. 또 다른 사례론 브라우저에서 동작하는 코드를 개발할 때 발생할 수 있는 문제가 있다. 자바스크립트를 사용해 페이지에 존재하지 않는 요소에 접근해 요소의 정보를 가져오려 하면 문제가 발생하는데, 이런 에러를 막기 위해 옵셔널 체이닝이 필요하다.

```js
// querySelector(...) 호출 결과가 null인 경우 에러 발생
let html = document.querySelector(&#39;.my-element&#39;).innerHTML;</code></pre><h3 id="옵셔널-체이닝의-반환값">옵셔널 체이닝의 반환값</h3>
<blockquote>
<p><code>?.</code>은 <code>?.</code><strong>앞</strong>의 평가 대상이 <code>undefined</code>나 <code>null</code>이면 평가를 멈추고 <code>undefined</code>를 반환한다.</p>
</blockquote>
<p>예시를 보자.</p>
<pre><code class="language-js">let user = {}; // 주소 정보가 없는 사용자

alert( user?.address?.street ); // undefined, 에러가 발생하지 않습니다.</code></pre>
<p><code>user?.address</code>로 주소를 읽으면 아래와 같이 user 객체가 존재하지 않더라도 에러가 발생하지 않는다.</p>
<pre><code class="language-js">let user = null;

alert( user?.address ); // undefined
alert( user?.address.street ); // undefined</code></pre>
<p>위 예시를 통해 우리는 ?.은 ?. ‘앞’ 평가 대상에만 동작되고, 확장은 되지 않는다는 사실을 알 수 있다.</p>
<p>참고로 위 예시에서 사용된 <code>user?.</code>는 <code>user</code>가 <code>null</code>이나 <code>undefined</code>인 경우만 처리할 수 있다. <code>user</code>가 <code>null</code>이나 <code>undefined</code>가 아니고 실제 값이 존재하는 경우엔 반드시 <code>user.address</code> 프로퍼티는 있어야 합니다. 그렇지 않으면 <code>user?.address.street</code>의 두 번째 점 연산자에서 에러가 발생한다.</p>
<h3 id="옵셔널-체이닝을-사용할-때-주의점">옵셔널 체이닝을 사용할 때 주의점</h3>
<ol>
<li>옵셔널 체이닝을 남용하지 말 것!</li>
</ol>
<p><code>?.</code>는 <strong>존재하지 않아도 괜찮은 대상에만</strong> 사용해야 한다.</p>
<p>사용자 주소를 다루는 위 예시에서 논리상 <code>user</code>는 반드시 있어야 하는데 <code>address</code>는 <strong>필수값이 아니다</strong>. 그러니 옵셔널 체이닝 <code>user.address?.street</code>를 사용하는 것이 바람직합니다.</p>
<p><strong>실수로 인해</strong> <code>user</code>에 값을 할당하지 않았다면 바로 알아낼 수 있도록 해야 한다(즉 옵셔널 체이닝을 쓰면 안된다). 그렇지 않으면 에러를 조기에 발견하지 못하고 디버깅이 어려워진다.</p>
<ol start="2">
<li><code>?.</code>앞의 변수는 꼭 선언되어 있어야 한다.</li>
</ol>
<p>변수 <code>user</code>가 선언되어있지 않으면 <code>user?.anything</code> 평가시 에러가 발생한다.</p>
<pre><code class="language-js">// ReferenceError: user is not defined
user?.address;</code></pre>
<p>이렇게 옵셔널 체이닝은 선언이 완료된 변수를 대상으로만 동작한다.</p>
<h3 id="단락-평가">단락 평가</h3>
<p><code>?.</code>는 왼쪽 평가대상에 값이 없으면(<code>null</code>이나 <code>undefined</code>이면) 즉시 평가를 멈춘다. 참고로 이런 평가 방법을 <code>단락 평가(short-circuit)</code>라고 부른다.</p>
<pre><code class="language-js">let user = null;
let x = 0;

user?.sayHi(x++); // 아무 일도 일어나지 않습니다.

alert(x); // 0, x는 증가하지 않습니다.</code></pre>
<h3 id="와-">?.()와 ?.[]</h3>
<p><code>?.</code>은 연산자가 아니다. <code>?.</code>은 함수나 대괄호와 함께 동작하는 특별한 <code>문법 구조체(syntax construct)</code>이다.</p>
<p>함수 관련 예시와 함께 존재 여부가 확실치 않은 함수를 호출할 때 <code>?.()</code>를 어떻게 쓸 수 있는지 알아보자.</p>
<pre><code class="language-js">let user1 = {
  admin() {
    alert(&quot;관리자 계정입니다.&quot;);
  }
}

let user2 = {};

user1.admin?.(); // 관리자 계정입니다.
user2.admin?.();</code></pre>
<p>두 상황 모두에서 user 객체는 존재하기 때문에 admin 프로퍼티는 <code>.</code>만 사용해 접근했다. </p>
<p>그리고 난 후 <code>?.()</code>를 사용해 admin의 존재 여부를 확인했다. user1엔 admin이 정의되어 있기 때문에 메서드가 제대로 호출되는 반면, user2엔 admin이 정의되어 있지 않았음에도 불구하고 메서드를 호출하면 에러 없이 그냥 평가가 멈추는 것을 확인할 수 있다.</p>
<p>한편, <code>?.[]</code>를 사용할 수도 있다. 예시를 보자.</p>
<pre><code class="language-js">let user1 = {
  firstName: &quot;Violet&quot;
};

let user2 = null; // user2는 권한이 없는 사용자라고 가정해봅시다.

let key = &quot;firstName&quot;;

alert( user1?.[key] ); // Violet
alert( user2?.[key] ); // undefined

alert( user1?.[key]?.something?.not?.existing); // undefined</code></pre>
<h3 id="과-delete">?.과 delete</h3>
<p><code>?.</code>은 <code>delete</code>와 조합해 사용할 수도 있다.</p>
<pre><code class="language-js">delete user?.name; // user가 존재하면 user.name을 삭제합니다.</code></pre>
<h3 id="과-할당-연산자">?.과 할당 연산자</h3>
<p><code>?.</code>은 할당 연산자 왼쪽에서 사용할 수 없다.</p>
<pre><code class="language-js">// user가 존재할 경우 user.name에 값을 쓰려는 의도로 아래와 같이 코드를 작성해 보았습니다.

user?.name = &quot;Violet&quot;; // SyntaxError: Invalid left-hand side in assignment
// 에러가 발생하는 이유는 undefined = &quot;Violet&quot;이 되기 때문입니다.</code></pre>
<h3 id="요약">요약</h3>
<p>옵셔널 체이닝 문법 <code>?.은</code> 세 가지 형태로 사용할 수 있다.</p>
<ol>
<li><code>obj?.prop</code> : <code>obj</code>가 존재하면 <code>obj.prop</code>을 반환하고, 그렇지 않으면 <code>undefined</code>를 반환함</li>
<li><code>obj?.[prop]</code> : <code>obj</code>가 존재하면 <code>obj[prop]</code>을 반환하고, 그렇지 않으면 <code>undefined</code>를 반환함</li>
<li><code>obj?.method()</code> : <code>obj</code>가 존재하면 <code>obj.method()</code>를 호출하고, 그렇지 않으면 <code>undefined</code>를 반환함</li>
</ol>
<p><code>?.</code>은 <code>?.</code>의 왼쪽 평가대상이 <strong>없어도 괜찮은 경우에만 선택적으로</strong> 사용해야 한다. 꼭 있어야 하는 값인데 없는 경우에 <code>?.</code>을 사용하면 <strong>프로그래밍 에러를 쉽게 찾을 수 없으므로</strong> 이런 상황을 만들지 말도록 하자.</p>
<h2 id="🌝-심볼형">🌝 심볼형</h2>
<p>자바스크립트는 객체 프로퍼티 키로 오직 문자형과 심볼형만을 허용한다.</p>
<p>지금까지는 프로퍼티 키가 문자형인 경우만 살펴봤다. 이번에는 프로퍼티 키로 심볼값을 사용해 보면서, 심볼형 키를 사용할 때의 이점에 대해 살펴보자.</p>
<h3 id="심볼">심볼</h3>
<blockquote>
<p><code>심볼(symbol)</code>은 원시형 데이터로, 유일한 식별자(unique identifier)를 만들고 싶을 때 사용한다. <code>Symbol()</code>을 사용하면 심볼값을 만들 수 있다.</p>
</blockquote>
<pre><code class="language-js">// id는 새로운 심볼이 됩니다.
let id = Symbol();</code></pre>
<p>심볼을 만들 때 <code>심볼 이름</code>이라 불리는 &#39;설명&#39;을 선택적으로 추가할 수 있다. 심볼 이름은 디버깅 시 아주 유용하다.</p>
<p>설명이 같아도 심볼은 유일한 식별자이기 때문에, 동일 연산자(==)로 비교 시 false가 반환된다. 즉 이름이 같더라도 값이 항상 다른 것이다.</p>
<pre><code class="language-js">let id1 = Symbol(&quot;id&quot;);
let id2 = Symbol(&quot;id&quot;);

alert(id1 == id2); // false</code></pre>
<p><code>symbol.description</code> 프로퍼티를 이용하면 설명을 보여줄 수 있다.</p>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);
alert(id.description); // id</code></pre>
<h3 id="심볼은-문자형으로-자동-형-변환되지-않는다">심볼은 문자형으로 자동 형 변환되지 않는다</h3>
<p>심볼형 값은 다른 자료형으로 암시적 형 변환(자동 형 변환)되지 않는다. 문자열과 심볼은 근본이 다르기 때문에 우연히라도 서로의 타입으로 변환돼선 안된다.</p>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);
alert(id); // TypeError: Cannot convert a Symbol value to a string</code></pre>
<p>심볼을 반드시 출력해줘야 하는 상황이라면 아래와 같이 <code>.toString()</code> 메서드를 명시적으로 호출해주면 된다.</p>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);
alert(id.toString()); // Symbol(id)가 얼럿 창에 출력됨</code></pre>
<h3 id="숨김hidden-프로퍼티">&#39;숨김(hidden)&#39; 프로퍼티</h3>
<p>심볼을 이용하면 ‘숨김(hidden)’ 프로퍼티를 만들 수 있다. 숨김 프로퍼티는 외부 코드에서 접근이 불가능하고 값도 덮어쓸 수 없는 프로퍼티이다.</p>
<ol>
<li>third party 코드에서 가지고 온 <code>user</code>라는 객체를 를 이용해 어떤 작업을 해야 하는 상황이라고 가정해보자.<pre><code class="language-js">let user = { // 서드파티 코드에서 가져온 객체
name: &quot;John&quot;
};
</code></pre>
</li>
</ol>
<p>let id = Symbol(&quot;id&quot;);</p>
<p>user[id] = 1;</p>
<p>alert( user[id] ); // 심볼을 키로 사용해 데이터에 접근할 수 있습니다.</p>
<pre><code>
왜 문자형 프로퍼티가 아니라 심볼형 프로퍼티를 사용했을까?

`user`는 third party 코드에서 가지고 온 객체이므로 함부로 새로운 프로퍼티를 추가할 수 없다. 그런데 심볼은 third party 코드에서 접근할 수 없기 때문에, 심볼을 사용하면 third party 코드가 모르게 `user`에 프로퍼티를 추가할 수 있다(식별자 부여).


2. 이 외에도 각각 `user`를 다르게 식별해야 하는 상황에도 심볼을 이용할 수 있다. `user`의 원천인 third party 코드, 현재 작성 중인 스크립트, 제3의 스크립트(자바스크립트 라이브러리 등)가 각자 서로의 코드도 모른 채 `user`를 식별해야 하는 상황이 발생했다고 해보자.
제3의 스크립트에선 아래와 같이 Symbol(&quot;id&quot;)을 이용해 전용 식별자를 만들어 사용할 수 있다.
```js
// ...
let id = Symbol(&quot;id&quot;);

user[id] = &quot;제3 스크립트 id 값&quot;;</code></pre><p>심볼은 유일성이 보장되므로 우리가 만든 식별자와 제3의 스크립트에서 만든 식별자가 충돌하지 않는다. 이름이 같더라도 충돌하지 않는다.</p>
<p>그럼 심볼 대신 문자형을 사용했다면 어떻게 될까? 충돌이 발생할 수 있다.</p>
<pre><code class="language-js">let user = { name: &quot;John&quot; };

// 문자열 &quot;id&quot;를 사용해 식별자를 만들었습니다.
user.id = &quot;스크립트 id 값&quot;;

// 만약 제3의 스크립트가 우리 스크립트와 동일하게 문자열 &quot;id&quot;를 이용해 식별자를 만들었다면...

user.id = &quot;제3 스크립트 id 값&quot;
// 의도치 않게 값이 덮어 쓰여서 우리가 만든 식별자는 무의미해집니다.</code></pre>
<h3 id="객체-리터럴-안의-심볼">객체 리터럴 안의 심볼</h3>
<p>객체 리터럴 {...}을 사용해 객체를 만들고 심볼형 프로퍼티를 넣어줄 경우, 대괄호를 사용해 심볼형 키를 만들어야 한다.</p>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);

let user = {
  name: &quot;John&quot;,
  [id]: 123 // &quot;id&quot;: 123은 안됨
};</code></pre>
<h3 id="forin에서-배제되는-심볼형">for...in에서 배제되는 심볼형</h3>
<blockquote>
<p>키가 심볼인 프로퍼티는 <code>for..in</code> 반복문에서 배제된다.</p>
</blockquote>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);
let user = {
  name: &quot;John&quot;,
  age: 30,
  [id]: 123
};

for (let key in user) alert(key); // name과 age만 출력되고, 심볼은 출력되지 않습니다.

// 심볼로 직접 접근하면 잘 작동합니다.
alert( &quot;직접 접근한 값: &quot; + user[id] );</code></pre>
<p><code>Object.keys(user)</code>에서도 키가 심볼인 프로퍼티는 배제됩니다. <code>심볼형 프로퍼티 숨기기(hiding symbolic property)</code>라 불리는 이런 원칙 덕분에 외부 스크립트나 라이브러리는 심볼형 키를 가진 프로퍼티에 접근하지 못한다.</p>
<p>그런데 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign">Object.assign</a>은 키가 심볼인 프로퍼티를 배제하지 않고 객체 내 모든 프로퍼티를 복사한다.</p>
<pre><code class="language-js">let id = Symbol(&quot;id&quot;);
let user = {
  [id]: 123
};

let clone = Object.assign({}, user);

alert( clone[id] ); // 123</code></pre>
<p>객체를 복사하거나 병합할 때, 대개 id 같은 심볼을 포함한 프로퍼티 전부를 사용하고 싶어 할 것이라는 생각에서 설계되었다.</p>
<h3 id="전역-심볼">전역 심볼</h3>
<p>심볼은 이름이 같더라도 값이 항상 다르다(모두 별개로 취급된다). 그런데 이름이 같을 때 값도 같길 원한다면, 즉 이름이 같은 심볼이 같은 개체를 가리키길 원한다면, <code>전역 심볼 레지스트리(global symbol registry)</code>를 사용해야 한다. </p>
<blockquote>
<p>전역 심볼 레지스트리 안에 심볼을 만들고 해당 심볼에 접근하면, 이름이 같은 경우 항상 동일한 심볼을 반환해준다. </p>
</blockquote>
<p>레지스트리 안에 있는 심볼을 읽거나, 새로운 심볼을 생성하려면 <code>Symbol.for(key)</code>를 사용하면 된다. 이 메서드를 호출하면 이름이 <code>key</code>인 심볼을 반환한다. 조건에 맞는 심볼이 레지스트리 안에 없으면 새로운 심볼 <code>Symbol(key)</code>을 만들고 레지스트리 안에 저장한다.</p>
<pre><code class="language-js">// 전역 레지스트리에서 심볼을 읽습니다.
let id = Symbol.for(&quot;id&quot;); // 심볼이 존재하지 않으면 새로운 심볼을 만듭니다.

// 동일한 이름을 이용해 심볼을 다시 읽습니다(좀 더 멀리 떨어진 코드에서도 가능합니다).
let idAgain = Symbol.for(&quot;id&quot;);

// 두 심볼은 같습니다.
alert( id === idAgain ); // true</code></pre>
<blockquote>
<p>전역 심볼 레지스트리 안에 있는 심볼은 <code>전역 심볼</code>이라고 불린다. 애플리케이션에서 광범위하게 사용해야 하는 심볼이라면 전역 심볼을 사용하자!</p>
</blockquote>
<p>전역 심볼을 찾을 때 사용되는 <code>Symbol.for(key)</code>에 반대되는 메서드도 있다. <code>Symbol.keyFor(sym)</code>를 사용하면 <strong>이름</strong>을 얻을 수 있다.</p>
<pre><code class="language-js">// 이름을 이용해 심볼을 찾음
let sym = Symbol.for(&quot;name&quot;);
let sym2 = Symbol.for(&quot;id&quot;);

// 심볼을 이용해 이름을 얻음
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id</code></pre>
<p><code>Symbol.keyFor</code>는 전역 심볼 레지스트리를 뒤져서 해당 심볼의 이름을 얻어낸다. <strong>검색 범위가 전역 심볼 레지스트리</strong>이기 때문에 전역 심볼이 아닌 심볼에는 사용할 수 <strong>없다</strong>. 전역 심볼이 아닌 인자가 넘어오면 <code>Symbol.keyFor</code>는 <code>undefined</code>를 반환한다.</p>
<p>전역 심볼이 아닌 모든 심볼은 <code>description</code> 프로퍼티가 있다. 일반 심볼에서 이름을 얻고 싶으면 <code>description</code> 프로퍼티를 사용하면 된다.</p>
<pre><code class="language-js">let globalSymbol = Symbol.for(&quot;name&quot;);
let localSymbol = Symbol(&quot;name&quot;);

alert( Symbol.keyFor(globalSymbol) ); // name, 전역 심볼
alert( Symbol.keyFor(localSymbol) ); // undefined, 전역 심볼이 아님

alert( localSymbol.description ); // name</code></pre>
<h2 id="🌝-객체를-원시형으로-변환하기">🌝 객체를 원시형으로 변환하기</h2>
<p>형 변환 챕터에선 객체의 형 변환은 다루지 않았습니다. 메서드와 심볼에 대한 지식을 갖추었으니 본격적으로 객체의 형 변환에 대해 알아보자.</p>
<ol>
<li><p>객체에 대한 논리평가 
객체는 논리 평가 시 예외없이 항상 <code>true</code>를 반환합니다. 따라서 객체는 숫자형이나 문자형으로만 형 변환이 일어난다고 생각하면 된다.</p>
</li>
<li><p>숫자형으로의 형 변환
객체끼리 빼는 연산을 할 때나 수학 관련 함수를 적용할 때 일어난다.</p>
</li>
<li><p>문자형으로의 형 변환 
문자형으로의 형 변환은 대개 <code>alert(obj)</code>같이 객체를 출력하려고 할 때 일어난다.</p>
</li>
</ol>
<h3 id="toprimitive">ToPrimitive</h3>
<p>객체 형 변환은 세 종류로 구분되는데, <code>hint</code>라 불리는 값이 구분 기준이된다. <code>hint</code>는 <strong>목표로 하는 자료형</strong> 정도로 이해하면 된다.</p>
<ol>
<li><code>string</code>
<code>alert</code> 함수같이 문자열을 기대하0는 연산을 수행할 때는(객체-문자형 변환), <code>hint</code>가 <code>string</code>이 된다.<pre><code class="language-js">// 객체를 출력하려고 함
alert(obj);
</code></pre>
</li>
</ol>
<p>// 객체를 프로퍼티 키로 사용하고 있음
anotherObj[obj] = 123;</p>
<pre><code>
2. `number`
수학 연산을 적용하려 할 때(객체-숫자형 변환), `hint`는 `number`가 된다.
```js
// 명시적 형 변환
let num = Number(obj);

// (이항 덧셈 연산을 제외한) 수학 연산
let n = +obj; // 단항 덧셈 연산
let delta = date1 - date2;

// 크고 작음 비교하기
let greater = user1 &gt; user2;</code></pre><ol start="3">
<li><code>default</code>
아주 드물게 발생하지만 연산자가 기대하는 자료형이 ‘확실치 않을 때’ <code>hint</code>는 <code>default</code>가 된다.</li>
</ol>
<p>이항 덧셈 연산자 <code>+</code>는 피연산자의 자료형에 따라 문자열을 합치는 연산을 할 수도 있고 숫자를 더해주는 연산을 할 수도 있다. 따라서 <code>+</code>의 인수가 객체일 때는 <code>hint</code>가 <code>default</code>가 된다.</p>
<p>동등 연산자 <code>==</code>를 사용해 객체-문자형, 객체-숫자형, 객체-심볼형끼리 비교할 때도, 객체를 어떤 자료형으로 바꿔야 할지 확신이 안 서므로 <code>hint</code>는 <code>default</code>가 된다.</p>
<pre><code class="language-js">// 이항 덧셈 연산은 hint로 `default`를 사용합니다.
let total = obj1 + obj2;

// obj == number 연산은 hint로 `default`를 사용합니다.
if (user == 1) { ... };</code></pre>
<p>크고 작음을 비교할 때 쓰이는 연산자 <code>&lt;</code>, <code>&gt;</code> 역시 피연산자에 문자형과 숫자형 둘 다를 허용하는데, 이 연산자들은 <code>hint</code>를 <code>number</code>로 고정하여 <code>hint</code>가 <code>default</code>가 되는 일이 없다. 이는 하위 호환성 때문에 정해진 규칙이다.</p>
<p>하지만 실제 일을 할 때는 이런 사항을 모두 외울 필요는 없고, <code>Date</code> 객체를 제외한 모든 내장 객체는 <code>hint</code>가 &quot;<code>default</code>인 경우와 <code>number</code>인 경우를 동일하게 처리한다. 우리도 커스텀 객체를 만들 땐 이런 규칙을 따르면 된다.</p>
<h3 id="boolean-hint">&quot;boolean&quot; hint?</h3>
<p>‘boolean’ hint는 존재하지 않는다. 모든 객체는 그냥 <code>true</code>로 평가된다. </p>
<h3 id="자바스크립트의-형-변환-알고리즘에-따른-세가지-메서드">자바스크립트의 형 변환 알고리즘에 따른 세가지 메서드</h3>
<ol>
<li><p>객체에 <code>obj[Symbol.toPrimitive](hint)</code>메서드가 있는지 찾고, 있다면 메서드를 호출한다. <code>Symbol.toPrimitive</code>는 시스템 심볼로, 심볼형 키로 사용된다.</p>
</li>
<li><p>1에 해당하지 않고 hint가 <code>string</code>이라면, <code>obj.toString()</code>이나 <code>obj.valueOf()</code>를 호출합니다(존재하는 메서드만 실행됨).</p>
</li>
<li><p>1과 2에 해당하지 않고, hint가 <code>number</code>나 <code>default</code>라면
<code>obj.valueOf()</code>나 <code>obj.toString()</code>을 호출한다(존재하는 메서드만 실행됨).</p>
</li>
</ol>
<h3 id="symboltoprimitive">Symbol.toPrimitive</h3>
<p>첫 번째 메서드부터 살펴보자. 자바스크립트엔 <code>Symbol.toPrimitive</code>라는 내장 심볼이 존재하는데, 이 심볼은 아래와 같이 목표로 하는 자료형(hint)을 명명하는 데 사용된다.</p>
<pre><code class="language-js">obj[Symbol.toPrimitive] = function(hint) {
  // 반드시 원시값을 반환해야 합니다.
  // hint는 &quot;string&quot;, &quot;number&quot;, &quot;default&quot; 중 하나가 될 수 있습니다.
};</code></pre>
<p>실제 예시를 살펴보자.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  money: 1000,

  [Symbol.toPrimitive](hint) {
    alert(`hint: ${hint}`);
    return hint == &quot;string&quot; ? `{name: &quot;${this.name}&quot;}` : this.money;
  }
};

// 데모:
alert(user); // hint: string -&gt; {name: &quot;John&quot;}
alert(+user); // hint: number -&gt; 1000
alert(user + 500); // hint: default -&gt; 1500</code></pre>
<p>이렇게 메서드를 구현해 놓으면 <code>user</code>는 hint에 따라 문자열로 변환되기도 하고 숫자로 변환되기도 한다. <code>user[Symbol.toPrimitive]</code>를 사용하면 메서드 하나로 모든 종류의 형 변환을 다룰 수 있다. </p>
<h3 id="tostring과-valueof">toString과 ValueOf</h3>
<p><code>toString</code>과 <code>ValueOF</code> 메서드를 이용하면 &#39;구식’이긴 하지만 형 변환을 직접 구현할 수 있다.</p>
<p>객체에 <code>Symbol.toPrimitive</code>가 없으면 자바스크립트는 아래 규칙에 따라 <code>toString</code>이나 <code>valueOf</code>를 호출한다. </p>
<ul>
<li>hint가 &#39;string’인 경우: <code>toString</code> -&gt; <code>valueOf</code> 순. <code>toString</code>이 있다면 <code>toString</code>을 호출, <code>toString</code>이 없다면 <code>valueOf</code>를 호출한다.</li>
<li>그 외: valueOf -&gt; toString 순</li>
</ul>
<p>이 메서드들은 반드시 원시값을 반환해야한다. <code>toString</code>이나 <code>valueOf</code>가 객체를 반환하면 그 결과는 무시된다. <code>toString</code>이나 <code>valueOf</code>가 객체를 반환해도 에러가 발생하지는 않는다. 반면에 <code>Symbol.toPrimitive</code>는 무조건 원시자료를 반환해야 한다. 그렇지 않으면 에러가 발생한다.</p>
<p>일반 객체는 기본적으로 toString과 valueOf에 적용되는 다음 규칙을 따른다.</p>
<ul>
<li><code>toString</code>은 문자열 <code>&quot;[object Object]&quot;</code>을 반환한다.</li>
<li><code>valueOf</code>는 객체 자신을 반환한다.</li>
</ul>
<pre><code class="language-js">let user = {name: &quot;John&quot;};

alert(user); // [object Object]
alert(user.valueOf() === user); // true</code></pre>
<p><code>Symbol.toPrimitive</code>를 사용한 위쪽 예시와 동일하게 동작하는 예시를 보자.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,
  money: 1000,

  // hint가 &quot;string&quot;인 경우
  toString() {
    return `{name: &quot;${this.name}&quot;}`;
  },

  // hint가 &quot;number&quot;나 &quot;default&quot;인 경우
  valueOf() {
    return this.money;
  }

};

alert(user); // toString -&gt; {name: &quot;John&quot;}
alert(+user); // valueOf -&gt; 1000
alert(user + 500); // valueOf -&gt; 1500</code></pre>
<p>객체에 <code>Symbol.toPrimitive</code>와 <code>valueOf</code>가 없으면, <code>toString</code>이 모든 형 변환을 처리한다.</p>
<pre><code class="language-js">let user = {
  name: &quot;John&quot;,

  toString() {
    return this.name;
  }
};

alert(user); // toString -&gt; John
alert(user + 500); // toString -&gt; John500</code></pre>
<p>3개 메서드의 반환 타입에 대해 자세한 내용은 공식 문서를 참고하자.</p>
<h3 id="추가-형-변환">추가 형 변환</h3>
<p>객체가 피연산자일 때는 다음과 같은 단계를 거쳐 형 변환이 일어난다.</p>
<ol>
<li>객체는 원시형으로 변환된다.</li>
<li>변환 후 원시값이 원하는 형이 아닌 경우엔 또다시 형 변환이 일어난다.</li>
</ol>
<pre><code class="language-js">let obj = {
  // 다른 메서드가 없으면 toString에서 모든 형 변환을 처리합니다.
  toString() {
    return &quot;2&quot;;
  }
};

alert(obj * 2); // 4, 객체가 문자열 &quot;2&quot;로 바뀌고, 곱셈 연산 과정에서 문자열 &quot;2&quot;는 숫자 2로 변경됩니다.</code></pre>
<ol>
<li>obj * 2에선 객체가 원시형으로 변화되므로 toString에의해 obj는 문자열 &quot;2&quot;가 됩니다.</li>
<li>곱셈 연산은 문자열은 숫자형으로 변환시키므로 &quot;2&quot; * 2는 2 * 2가 됩니다.</li>
</ol>
<p>그런데 이항 덧셈 연산은 위와 같은 상황에서 문자열을 연결한다.</p>
<pre><code class="language-js">let obj = {
  toString() {
    return &quot;2&quot;;
  }
};

alert(obj + 2); // 22(&quot;2&quot; + 2), 문자열이 반환되기 때문에 문자열끼리의 병합이 일어났습니다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공 자바스크립트 17-24강]]></title>
            <link>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-17-24%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-17-24%EA%B0%95</guid>
            <pubDate>Wed, 22 Nov 2023 13:47:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>윤인성 님의 <a href="https://www.youtube.com/watch?v=pXuyfvJPENA&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl">혼공 자바스크립트</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🍏-기본-자료형과-복합-자료형">🍏 기본 자료형과 복합 자료형</h2>
<ul>
<li>기본 자료형 : 숫자, 문자열, 불</li>
<li>복합 자료형 : 배열, 함수, 객체</li>
</ul>
<p>복합 자료형은 기본 자료형보다 훨씬 크다.</p>
<h3 id="기본-자료형">기본 자료형</h3>
<p>스택(stack)에 저장한다.</p>
<ul>
<li>스택 : 상자들이 쌓여있는 구조 같은 것. 스택스택 쌓는 공간. 잘 쌓는 공간</li>
</ul>
<p>변수/상수를 만든다는 것은, 스택에 있는 상자에 이름을 붙여준다는 의미이다.
ex) a=10은, 스택 상자에 10을 넣고 그 상자의 이름을 a라고 붙여준다는 의미이다.</p>
<p>기본 자료형은 직접 스택에 저장이 된다.</p>
<h3 id="복합-자료형">복합 자료형</h3>
<p>힙(heap)에 저장한다.</p>
<ul>
<li>힙 : 힙힙 던져서 쌓는 공간. 대충 큰 것들을 던져서 쌓는 공간</li>
</ul>
<p>복합 자료형은 그 자료를 가리키는 주소가 스택에 저장이 되고, 복합 자료형의 본체는 힙에 저장된다. 힙에 저장된 자료의 주소가 스택에 저장이 되는 것이다. 즉, 스택이 저장한 값은 힙에 저장된 자료의 주소를 가리키게 된다.</p>
<h2 id="🍏-파괴적-처리와-비파괴적-처리">🍏 파괴적 처리와 비파괴적 처리</h2>
<p>처리 후에 </p>
<ul>
<li>원본이 변경되었다 : 파괴적 처리</li>
<li>원본이 변경되지 않았다 : 비파괴적 처리</li>
</ul>
<h2 id="🍏-const의-제한">🍏 const의 제한</h2>
<p><code>const</code>는 스택에 있는 값을 변경할 때만 오류가 발생한다. </p>
<p>힙에 있는 레퍼런스된 복합 자료형을 조작하는 것에는 문제가 없다! </p>
<pre><code class="language-js">const a = 1;
a = 2; //오류 발생. 스택에 a의 값이 저장되고 그 a를 변경하려하므로.</code></pre>
<pre><code class="language-js">const a = [1, 2];
a.push(3); //문제 없음. 스택에는 a의 주소가, 실제 배열 값은 힙에 저장되어 있으므로.</code></pre>
<p>강의 내용 매우 좋음. 꼭 <a href="https://www.youtube.com/watch?v=9tbjjZb65ng&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl&amp;index=22">다시 보기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공 자바스크립트 11-16강]]></title>
            <link>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-11-16%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-11-16%EA%B0%95</guid>
            <pubDate>Tue, 21 Nov 2023 13:38:26 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>윤인성 님의 <a href="https://www.youtube.com/watch?v=pXuyfvJPENA&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl">혼공 자바스크립트</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🐙-상수">🐙 상수</h2>
<p>JS는 대부분 상수로 선언해주고, 값이 변할 때만 변수로 사용해준다. </p>
<p>→ 헐.. 이게 맞나?</p>
<h2 id="🐙-lvalue와-rvalue">🐙 lvalue와 rvalue</h2>
<pre><code class="language-js">let a = 10;</code></pre>
<p>a : <code>lvalue</code>, left value → 넣는 놈
b : <code>rvalue</code>, right value → 꺼내는 놈, 값</p>
<p>ex)</p>
<pre><code class="language-js">let a = 10; // a는 넣는 놈, 10은 값
let b = a; // b는 넣는 놈, a는 꺼내는 놈</code></pre>
<h2 id="🐙-undefined-자료형">🐙 undefined 자료형</h2>
<ol>
<li><p>상수와 변수로 선언하지 않은 식별자</p>
<pre><code class="language-js">typeof(a); //undefined</code></pre>
</li>
<li><p>값이 없는 변수</p>
<pre><code class="language-js">let b;
typeof(b); //undefined</code></pre>
</li>
</ol>
<h2 id="🐙-날짜와-시간-구하기">🐙 날짜와 시간 구하기</h2>
<pre><code class="language-js">const date = new Date();
date.getFullYear(); // 올해 연도 출력
date.getMonth(); // 현재 달 출력. 0~11로 출력. 즉 11월이 10월로 출력됨
date.getDate(); // 현재 월 출력. 1~31로 출력. 21일이 21일이다.
date.getHours(); // 현재 시간 출력. 0~23으로 출력</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공 자바스크립트 5-10강]]></title>
            <link>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-6-10%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-6-10%EA%B0%95</guid>
            <pubDate>Mon, 20 Nov 2023 05:24:04 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>윤인성 님의 <a href="https://www.youtube.com/watch?v=pXuyfvJPENA&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl">혼공 자바스크립트</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="💟-문자열-내에서-따옴표를-사용하고-싶은-경우">💟 문자열 내에서 따옴표를 사용하고 싶은 경우</h2>
<p><strong>1. 작은 따옴표를 사용하고 싶다면</strong></p>
<pre><code class="language-js">&quot;This is &#39;string&#39;&quot;</code></pre>
<ul>
<li>문자열을 큰 따옴표로 감싸주면 된다.</li>
</ul>
<p>*<em>2. 큰 따옴표를 사용하고 싶다면
*</em></p>
<pre><code class="language-js">&#39;This is &quot;string&quot;&#39;</code></pre>
<p>문자열을 작은 따옴표로 감싸주면 된다.</p>
<p>*<em>3. 내부, 외부 둘다 같은 따옴표를 쓰고 싶다면
*</em></p>
<pre><code class="language-js">&#39;This is \&#39;string\&#39;&#39;
&quot;This is \&quot;string\&quot;&quot;</code></pre>
<p>내부 따옴표 앞에 escape 기호 \를 사용해준다.</p>
<h3 id="escape-기호-">escape 기호 \</h3>
<blockquote>
<p>문자 그대로의 의미가 아니라 다른 의미로써 코드 실행기에게 무언가를 전달할 때 사용한다.</p>
</blockquote>
<ul>
<li>\n : 줄바꿈</li>
<li>\t : tab 문자</li>
<li>\ : \ 자체</li>
</ul>
<h2 id="💟-문자열에-적용할-수-있는-처리">💟 문자열에 적용할 수 있는 처리</h2>
<ol>
<li><p>문자열 연결 연산 : 문자열 + 문자열</p>
<pre><code class="language-js">&#39;안녕&#39; + &#39;하세요&#39; //&quot;안녕하세요&quot; </code></pre>
</li>
<li><p>문자 선택 연산 : 문자열[인덱스] → 문자 하나</p>
<pre><code class="language-js">&quot;안녕하세요&quot;[0] //&quot;안&quot;
&quot;안녕하세요&quot;[1] //&quot;녕&quot;</code></pre>
</li>
<li><p>문자열의 길이 : 문자열.length → 문자 개수</p>
<pre><code class="language-js">&quot;안녕하세요&quot;.length //5</code></pre>
<h2 id="💟-부등식과-논리-연산자">💟 부등식과 논리 연산자</h2>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/194cecd1-f733-433b-b2b9-cd47ee87775b/image.png" alt=""></p>
</li>
</ol>
<p>위와 같은 부등식을 JS로 표현하고자 할 때,</p>
<p><code>-3 &lt;= x &lt;= 2</code>와 같이 쓰면 안된다. </p>
<p>올바르게 쓰려면 논리 연산자를 이용해야 한다.</p>
<p><code>-3 &lt;= x &amp;&amp; x &lt;= 2</code></p>
<h3 id="드모르간-법칙">드모르간 법칙</h3>
<pre><code class="language-js">// 첫 번째 줄과 두 번째 줄은 동일 
!(12 &lt;= x &amp;&amp; x &lt;= 13)
12 &gt; x || x &gt; 13</code></pre>
<h2 id="💟-typeof">💟 typeof</h2>
<blockquote>
<p>자료형을 <strong>문자형</strong>으로 출력해줌</p>
</blockquote>
<pre><code class="language-js">typeof(typeof(1)) // string. 
//typeof(1)의 결과는 &quot;number&quot;이고 &quot;number&quot;는 문자열이기 때문</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[모던 JS 튜토리얼 Part 1. 2강 자바스크립트 기본]]></title>
            <link>https://velog.io/@cse_pebb/%EB%AA%A8%EB%8D%98-JS-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-Part-1.-2%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%EB%AA%A8%EB%8D%98-JS-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-Part-1.-2%EA%B0%95</guid>
            <pubDate>Sat, 18 Nov 2023 16:49:11 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://ko.javascript.info/">모던 JS 튜토리얼</a> Part 1. 코어 자바스크립트 문서를 읽고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🐑-코드-구조">🐑 코드 구조</h2>
<h3 id="세미콜론">세미콜론</h3>
<p>JS는 <strong>대부분의 경우</strong> 줄 바꿈이 있다면 세미콜론(semicolon)을 생략할 수 있다. </p>
<ul>
<li>생략 가능한 경우<pre><code class="language-javascript">alert(&#39;Hello&#39;)
alert(&#39;World&#39;)</code></pre>
</li>
</ul>
<p>하지만, 항상 그런 것은 아니다.</p>
<ul>
<li>생략 불가능한 경우</li>
</ul>
<pre><code class="language-javascript">alert(3 +
1
+ 2);</code></pre>
<pre><code class="language-javascript">alert(&quot;에러가 발생합니다.&quot;)

[1, 2].forEach(alert)</code></pre>
<blockquote>
<p>결론은, 줄 바꿈으로 문을 나눴더라도 statement 사이엔 세미콜론을 넣는 것이 좋다는 것이다.</p>
</blockquote>
<h3 id="에디터에서의-주석-단축키">에디터에서의 주석 단축키</h3>
<blockquote>
<ul>
<li>한 줄 주석 처리 : Ctrl+/</li>
</ul>
</blockquote>
<ul>
<li>여러 줄 주석 처리 : Ctrl+Shift+/</li>
</ul>
<p>cf) 중첩 주석은 지원하지 않는다. 쓸 경우 에러가 발생한다.</p>
<pre><code class="language-javascript">/*
  /* 중첩 주석 ?!? */
*/
alert( &#39;World&#39; );</code></pre>
<h2 id="🐑-엄격-모드strict-mode">🐑 엄격 모드(strict mode)</h2>
<h3 id="엄격-모드strict-mode란">엄격 모드(strict mode)란?</h3>
<p>자바스크립트가 발전함에 따라 새로운 기능이 추가되고 기존 기능 중 일부가 변경되었다. 이로 인한 하위 호환성 문제 때문에, 변경사항 대부분이 기본적으로 활성화되지 않도록 되어있다. </p>
<p>대신 <code>use strict</code>라는 특별한 지시자를 사용해 엄격 모드(strict mode)를 설정하면, 이 변경사항이 활성화된다.</p>
<h3 id="use-strict">use strict</h3>
<p><code>use strict</code>는 대부분 스크립트 최상단에 위치시킨다. <code>use strict</code> 위에는 주석만 위치할 수 있고, 그 외의 것들은 엄격모드가 적용되지 않는다.</p>
<pre><code class="language-javascript">alert(&quot;some code&quot;);
// 하단에 위치한 &quot;use strict&quot;는 스크립트 상단에 위치하지 않으므로 무시됩니다.

&quot;use strict&quot;;

// 엄격 모드가 활성화되지 않습니다.</code></pre>
<h3 id="모던-자바스크립트에서의-use-strict">모던 자바스크립트에서의 use strict</h3>
<p>모던 자바스크립트에는 &#39;클래스’와 &#39;모듈’이라는 것이 있는데, 이 둘을 사용하면 <code>use strict</code>가 자동으로 적용된다. 따라서 스크립트에 <code>use strict</code>를 붙일 필요가 없다. </p>
<blockquote>
<p>결론은, 코드를 클래스와 모듈을 사용해 구성한다면 <code>use strict</code>를 생략해도 된다.</p>
</blockquote>
<h2 id="🐑-변수와-상수">🐑 변수와 상수</h2>
<h3 id="변수">변수</h3>
<p>자바스크립트에선 <code>let</code> 키워드를 사용해 변수를 생성한다.</p>
<pre><code class="language-javascript">let message;</code></pre>
<p>한 줄에 여러 변수를 선언하는 것도 가능하다.</p>
<pre><code class="language-javascript">let user = &#39;John&#39;, age = 25, message = &#39;Hello&#39;;</code></pre>
<p>하지만 가독성을 위해 <strong>한 줄에는 하나의 변수</strong>를 작성한다.</p>
<pre><code class="language-javascript">let user = &#39;John&#39;;
let age = 25;
let message = &#39;Hello&#39;;</code></pre>
<p>cf) <code>var</code> 키워드
만들어진 지 오래된 스크립트에서 <code>let</code> 대신 <code>var</code>가 작성되어있는 경우가 있다. <code>var</code>는 <code>let</code>과 거의 동일하게 동작하지만, <code>var</code>는 ‘오래된’ 방식이다.</p>
<h3 id="변수-이름-컨벤션">변수 이름 컨벤션</h3>
<p>자바스크립트에서는 카멜 표기법(camelCase)을 흔히 사용한다. 
ex) myVeryLongName</p>
<h3 id="상수">상수</h3>
<p>변화하지 않는 변수를 선언할 때는 <code>const</code>를 사용한다. </p>
<pre><code class="language-javascript">const myBirthday = &#39;18.04.1982&#39;;</code></pre>
<p>상수를 사용하는 이유는 변숫값이 절대 변경되지 않을 것이라 확신하면, <strong>값이 변경되는 것을 방지</strong>하면서 <strong>다른 개발자들에게 이 변수는 상수라는 것을 알리기</strong> 위해서이다. </p>
<h3 id="대문자-상수">대문자 상수</h3>
<p>&#39;상수’는 변수의 값이 절대 변하지 않음을 의미한다. 이 상수를 두 종류로 나눌 수 있다.</p>
<ol>
<li><p>코드가 실행되기 전에 이미 그 값을 알고 있는 상수. 즉  ‘하드 코딩한’ 값. 실행 전에 이미 값을 알고 있고, 코드에서 직접 그 값을 쓰는 경우 
ex) 색상코드 #FFFFFF</p>
</li>
<li><p>런타임 과정에서 계산되지만 최초 할당 이후 값이 변하지 않는 상수</p>
</li>
</ol>
<p>1번의 경우에 <strong>대문자 상수</strong>를 작성한다.</p>
<p>비교 예제)</p>
<pre><code class="language-javascript">const BIRTHDAY = &#39;18.04.1982&#39;; // 1번 

const age = someCode(birthday); // 2번
</code></pre>
<p>birthday는 이미 알고 있고, 정해져있다. 반면, age는 런타임에 평가된다. 올해의 나이와 내년의 나이는 다르다. 따라서 age는 대문자 상수에 적합하지 않다.</p>
<h2 id="🐑-자료형">🐑 자료형</h2>
<p>자바스크립트에는 여덟 가지 기본 자료형이 있으나, 변수는 어떤 순간에 문자열일 수 있고 다른 순간엔 숫자가 될 수도 있다. </p>
<pre><code class="language-javascript">// 에러 발생하지 않음
let message = &quot;hello&quot;;
message = 123456;</code></pre>
<p>이처럼 자료의 타입은 있지만 변수에 저장되는 값의 타입은 언제든지 바꿀 수 있는 언어를 <code>동적 타입(dynamically typed) 언어</code>라고 부른다.</p>
<h3 id="숫자형--특수-숫자값">숫자형 : 특수 숫자값</h3>
<p>숫자형엔 일반적인 숫자 외에 <code>Infinity</code>, <code>-Infinity</code>, <code>NaN</code>같은 &#39;특수 숫자 값(special numeric value)이 있다. </p>
<ol>
<li>Infinity : 무한대(∞)를 나타낸다. <pre><code class="language-javascript">alert( 1 / 0 ); // 무한대
</code></pre>
</li>
</ol>
<p>alert( Infinity ); // 무한대</p>
<pre><code>
2. NaN : 계산 중에 에러가 발생했다는 것을 나타내주는 값. 부정확하거나 정의되지 않은 수학 연산을 사용하면 계산 중에 에러가 발생하는데, 이때 NaN이 반환된다. 
```javascript 
alert( &quot;숫자가 아님&quot; / 2 ); // NaN, 문자열을 숫자로 나누면 오류가 발생

alert( &quot;숫자가 아님&quot; / 2 + 5 ); // NaN</code></pre><h3 id="bigint">BigInt</h3>
<p>자바스크립트에선 (2^53-1)보다 크거나 -(2^53-1) 보다 작은 정수는 &#39;숫자형’을 사용해 나타낼 수 없다. </p>
<p>대신 <code>BigInt</code>형을 사용한다. 이는 길이에 상관없이 정수를 나타낼 수 있으며, 정수 리터럴 끝에 n을 붙이면 만들 수 있다.</p>
<pre><code class="language-javascript">const bigInt = 1234567890123456789012345678901234567890n;</code></pre>
<p>사실 대부분의 상황에서 <code>BigInt</code>형을 쓸 일은 없지만, 암호 관련 작업같이 아주 큰 숫자가 필요한 상황이거나 아주 높은 정밀도로 작업을 해야 할 때는 필요하다.</p>
<h3 id="문자형">문자형</h3>
<pre><code class="language-javascript">let str = &quot;Hello&quot;; //큰따옴표
let str2 = &#39;Single quotes are ok too&#39;; //작은 따옴표
let phrase = `can embed another ${str}`; //백틱</code></pre>
<p>${…} 안에는 name 같은 변수나 1 + 2 같은 수학 관련 표현식을 넣을 수도 있다.</p>
<pre><code class="language-javascript">alert( &quot;the result is ${1 + 2}&quot; ); 
</code></pre>
<p>cf) JS에는 char형이 따로 없다.</p>
<h3 id="null-값">null 값</h3>
<p>어느 자료형에도 속하지 않는 값. null 값은 오로지 null 값만 포함하는 별도의 자료형을 만든다.</p>
<pre><code class="language-javascript">let age = null;</code></pre>
<p>자바스크립트의 null은 자바스크립트 이외 언어의 null과 성격이 다르다.</p>
<ul>
<li>다른 언어에서의 null : &#39;존재하지 않는 객체에 대한 참조’, &#39;널 포인터(null pointer)&#39;</li>
<li>자바스크립트에서의 null : ‘존재하지 않는(nothing)’ 값, ‘비어 있는(empty)’ 값, ‘알 수 없는(unknown)’ 값을 나타내는 데 사용</li>
</ul>
<h3 id="undefined-값">undefined 값</h3>
<p>undefined 값도 null 값처럼 자신만의 자료형을 형성한다. undefined는 &#39;값이 할당되지 않은 상태’를 나타낼 때 사용한다.</p>
<p>변수는 선언했지만, 값을 할당하지 않았다면 해당 변수에 undefined가 자동으로 할당된다.</p>
<pre><code class="language-javascript">let age;

alert(age); // &#39;undefined&#39;가 출력됩니다.</code></pre>
<p>null vs. undefined)</p>
<ul>
<li>null : 변수가 ‘비어있거나’ ‘알 수 없는’ <strong>상태</strong>라는 걸 나타낼 때 사용</li>
<li>undefined : 값이 할당되지 않은 변수의 초기값에 사용</li>
</ul>
<h3 id="객체와-심볼">객체와 심볼</h3>
<p>다른 자료형은 문자열이든 숫자든 한 가지만 표현할 수 있기 때문에 원시(primitive) 자료형이라고 부르지만, 객체는 데이터 컬렉션이나 복잡한 개체(entity)를 표현할 수 있다. </p>
<p>심볼(symbol)형은 객체의 고유한 식별자(unique identifier)를 만들 때 사용된다. </p>
<h3 id="typeof-연산자">typeof 연산자</h3>
<p>두 가지 형태의 문법</p>
<ul>
<li>연산자: typeof x</li>
<li>함수: typeof(x)</li>
</ul>
<p>헷갈리는 예외</p>
<pre><code class="language-javascript">typeof null // &quot;object&quot;  

typeof alert // &quot;function&quot;  </code></pre>
<ol>
<li>null은 별도의 고유한 자료형을 가지는 특수 값으로 객체가 아니지만, 하위 호환성을 유지하기 위해 이런 오류를 수정하지 않고 남겨둔 상황이다. 언어 자체의 오류! null이 객체가 아니다!</li>
<li>typeof는 피연산자가 함수면 &quot;function&quot;을 반환한다. 그러므로 typeof alert는 &quot;function&quot;을 출력해준다. <strong>그런데 &#39;함수’형은 따로 없고, 함수는 객체형에 속한다.</strong> 이런 동작 방식이 형식적으론 잘못되긴 했지만, 아주 오래전에 만들어진 규칙이었기 때문에 하위 호환성 유지를 위해 남겨진 상태이다. 실무에선 이런 특징이 매우 유용하게 사용되기도 한다.</li>
</ol>
<h2 id="🐑-alert-prompt-confirm을-이용한-상호작용">🐑 alert, prompt, confirm을 이용한 상호작용</h2>
<p>브라우저 환경에서 사용되는 최소한의 사용자 인터페이스 기능인 alert, prompt, confirm에 대해 알아보자.</p>
<h3 id="alert">alert</h3>
<p>사용자가 ‘확인(OK)’ 버튼을 누를 때까지 메시지를 보여주는 창이 계속 떠있게 된다.</p>
<pre><code class="language-javascript">alert(&quot;Hello&quot;);</code></pre>
<p>alert은 undefined 값을 반환한다. (아무것도 반환하지 않는다.)</p>
<p>cf) 모달(modal)창
메시지가 있는 작은 창. 사용자는 모달 창이 떠있는 동안 모달 창 바깥에 있는 버튼을 누르는 등 페이지의 나머지 부분과 상호 작용이 불가능하다.</p>
<h3 id="prompt">prompt</h3>
<pre><code class="language-javascript">result = prompt(title, [default]);</code></pre>
<p>메세지(title)와 사용자 input field, 확인(OK) 및 취소(Cancel) 버튼이 있는 모달 창이 뜬다. default 값을 넣어주면 기본 input 값이 field에 세팅되어있다.</p>
<p>사용자는 input field에 원하는 값을 입력하고 확인을 누르거나, 취솧 혹은 Esc를 누를 수 있다.</p>
<p>prompt 함수는 사용자가 input field에 기재한 <strong>문자열을 반환</strong>한다. 사용자가 입력을 취소한 경우는 null이 반환된다.</p>
<p>cf) 인수를 감싸는 대괄호 [...]의 의미
default를 감싸는 대괄호는 이 매개변수가 필수가 아닌 선택값이라는 것을 의미한다.</p>
<p>ex)</p>
<pre><code class="language-javascript">let age = prompt(&#39;나이를 입력해주세요.&#39;, 100);

alert(`당신의 나이는 ${age}살 입니다.`); </code></pre>
<h3 id="confirm">confirm</h3>
<pre><code class="language-js">result = confirm(question);</code></pre>
<p>매개변수로 받은 question(질문)과 확인 및 취소 버튼이 있는 모달 창을 보여준다.</p>
<p>사용자가 확인 버튼을 누르면 <strong>true</strong>, 그 외의 경우는 <strong>false를 반환</strong>한다.</p>
<p>ex)</p>
<pre><code class="language-js">let isBoss = confirm(&quot;당신이 주인인가요?&quot;);

alert( isBoss ); // 확인 버튼을 눌렀다면 true가, 취소 버튼을 눌렀다면 false가 나온다.</code></pre>
<h2 id="🐑-형-변환">🐑 형 변환</h2>
<h3 id="문자형으로-변환">문자형으로 변환</h3>
<ol>
<li><p>alert 함수
alert메서드는 매개변수로 문자형을 받지만, 만약 다른 형의 값을 전달받으면 그 값이 문자형으로 자동 변환된다.</p>
</li>
<li><p>String 함수
String(value) 함수는 value를 문자형으로 명시해서 변환해준다.</p>
<pre><code class="language-js">let value = true;
alert(typeof value); // boolean
</code></pre>
</li>
</ol>
<p>value = String(value); // 문자열 &quot;true&quot;로 변환됨
alert(typeof value); // string</p>
<pre><code>false는 문자열 &quot;false&quot;로, null은 문자열 &quot;null&quot;로 변환된다.

### 숫자형으로 변환
1. 숫자형이 아닌 값에 연산을 취하기
숫자형이 아닌 값들에 연산을 취하면 해당 값들은 자동으로 숫자형으로 변환된다.
```js
alert( &quot;6&quot; / &quot;2&quot; ); // 3, 문자열이 숫자형으로 자동변환된 후 연산이 수행된다</code></pre><ol start="2">
<li>Number 함수
Number(value) 함수는 value를 숫자형으로 명시해서 변환해준다.</li>
</ol>
<pre><code class="language-js">let str = &quot;123&quot;;
alert(typeof str); // string

let num = Number(str); // 문자열 &quot;123&quot;이 숫자 123으로 변환됩니다.
alert(typeof num); // number</code></pre>
<p>❗한편, 숫자 이외의 글자가 들어가 있는 문자열을 숫자형으로 변환하려고 하면, 그 결과는 NaN이 된다. </p>
<ul>
<li>NaN 값의 자료형은 숫자형이고, 그 값이 NaN인 것이다!<pre><code class="language-js">let age = Number(&quot;임의의 문자열 123&quot;);
alert(age); // NaN</code></pre>
그 외 숫자형으로 변환 시 적용되는 규칙
<img src="https://velog.velcdn.com/images/cse_pebb/post/326cd496-e019-4075-ad6a-60c7f8a5f219/image.png" alt=""></li>
</ul>
<pre><code class="language-js">alert( Number(&quot;   123   &quot;) ); // 123
alert( Number(&quot;123z&quot;) );      // NaN 
alert( Number(true) );        // 1
alert( Number(false) );       // 0</code></pre>
<h3 id="boolean형으로-변환">Boolean형으로 변환</h3>
<p>Boolean(value) 함수는 value를 Boolean형으로 바꿔준다.</p>
<pre><code class="language-js">alert( Boolean(1) ); // true
alert( Boolean(0) ); // false

alert( Boolean(&quot;hello&quot;) ); // true
alert( Boolean(&quot;&quot;) ); // false</code></pre>
<ul>
<li>false : 숫자 0, 빈 문자열, null, undefined, NaN
(falsy한 값들)
(그 외의 값은 true로 변환)</li>
</ul>
<p>❗문자열 &quot;0&quot;은 true이다.</p>
<pre><code class="language-js">alert( Boolean(&quot;0&quot;) ); // true
alert( Boolean(&quot; &quot;) ); // 공백이 있는 문자열도 비어있지 않은 문자열이기 때문에 true! 숫자형이랑 헷갈리지 말 것</code></pre>
<p>여기서 발표 + 퀴즈내자 !!!!!!!!!!!</p>
<h2 id="🐑-기본-연산자와-수학">🐑 기본 연산자와 수학</h2>
<h3 id="거듭제곱-연산자-">거듭제곱 연산자 **</h3>
<pre><code class="language-js">alert( 2 ** 2 ); // 4  (2 * 2)
alert( 2 ** 3 ); // 8  (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)</code></pre>
<h3 id="이항연산자-로-연결하는-문자열과-숫자">이항연산자 +로 연결하는 문자열과 숫자</h3>
<ol>
<li><p>문자열 + 문자열 : 문자열이 단순히 연결된다.</p>
<pre><code class="language-js">let s = &quot;my&quot; + &quot;string&quot;;
alert(s); // mystring</code></pre>
</li>
<li><p>문자열 + 숫자 / 숫자 + 문자열 : <strong>숫자가 문자열로</strong> 변환된다.</p>
<pre><code class="language-js">alert( &#39;1&#39; + 2 ); // &quot;12&quot;
alert( 2 + &#39;1&#39; ); // &quot;21&quot;</code></pre>
</li>
</ol>
<ul>
<li>3개일 때도 마찬가지. 피연산자 중 어느 하나라도 문자열이면, 나머지가 다 문자열로 변환된다.</li>
</ul>
<h3 id="그-외-연산자로-연결하는-문자열과-숫자">그 외 연산자로 연결하는 문자열과 숫자</h3>
<p>+를 제외한 나머지 연산자로 연결되는 피연산자는 숫자로 변환된다.</p>
<pre><code class="language-js">alert( 6 - &#39;2&#39; ); // 4, &#39;2&#39;를 숫자로 바꾼 후 연산 진행
alert( &#39;6&#39; / &#39;2&#39; ); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행</code></pre>
<h3 id="단항연산자-의-숫자형으로의-변환">단항연산자 +의 숫자형으로의 변환</h3>
<p>단항연산자가 숫자형이 아닌 다른 자료형 앞에 붙으면, 해당 피연산자는 <strong>숫자형으로 변환</strong>된다. 즉 Number 함수와 동일한 역할을 하게 된다.</p>
<pre><code class="language-js">alert( +true ); // 1
alert( +&quot;&quot; );   // 0</code></pre>
<pre><code class="language-js">let apples = &quot;2&quot;;
let oranges = &quot;3&quot;;

// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화합니다.
alert( +apples + +oranges ); // 5</code></pre>
<p>여기서 알 수 있는 사실 : 단항연산자가 이항연산자보다 우선순위가 높다!</p>
<p>여기도 발표준비<del>~</del></p>
<h3 id="-연산자의-복잡한-표현식">= 연산자의 복잡한 표현식</h3>
<pre><code class="language-js">let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

alert( a ); // 3
alert( c ); // 0</code></pre>
<p>동작 원리 이해용으로 작성된 코드. 직접 코드를 작성할 땐 이런 방식을 사용하지 말 것. 가독성이 떨어진다!</p>
<h3 id="증가-감소-연산자의-전위형과-후위형">증가, 감소 연산자의 전위형과 후위형</h3>
<ul>
<li>전위형 : ++counter. 증가·감소 후의 새로운 값을 반환한다. 값을 증가시키고 난 후, 증가한 값을 바로 사용하려면 전위형 증가 연산자를 사용하면 된다.</li>
<li>후위형 : counter++. 증가·감소 전의 기존 값을 반환한다. 값을 증가시키지만, 증가 전의 기존값을 사용하려면 후위형 증가 연산자를 사용하면 된다.</li>
</ul>
<p>비교 예시)</p>
<pre><code class="language-js">let counter = 1;
let a = ++counter; // (*)
alert(a); // 2

let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(a); // 1</code></pre>
<p>반환 값을 사용하지 않는 경우라면, 전위형과 후위형엔 차이가 없다.</p>
<h3 id="쉼표-연산자-">쉼표 연산자 ,</h3>
<p>쉼표 연산자(comma operator) ,는 좀처럼 보기 힘들고, 특이한 연산자 중 하나이다. 코드를 짧게 쓰려는 의도로 가끔 사용된다.</p>
<p>쉼표 연산자 ,는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해준다. 이때 표현식 각각이 모두 평가되지만, <strong>마지막 표현식의 평가 결과만 반환</strong>되는 점에 유의해야 한다.</p>
<pre><code class="language-js">let a = (1 + 2, 3 + 4);

alert( a ); // 7 (3 + 4의 결과)</code></pre>
<p>이렇게 마지막 표현식을 제외한 모든 것을 버리는 연산자는 어디서 사용되는 걸까? 여러 동작을 하나의 줄에서 처리하려는 복잡한 구조에서 이를 사용합니다.</p>
<pre><code>// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a &lt; 10; a++) {
 ...
}</code></pre><blockquote>
<p>쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다. 하지만 쉼표 연산자는 코드 가독성에 도움이 되지 않는다. 따라서 곰곰이 생각해 본 후, 진짜 필요한 경우에만 사용하기를 추천한다.</p>
</blockquote>
<h2 id="🐑-비교-연산자">🐑 비교 연산자</h2>
<h3 id="문자열-비교">문자열 비교</h3>
<p>문자열은 왼쪽부터 <strong>사전순</strong>으로 문자열을 비교한다.
문자열의 길이가 다를 경우 긴 문자열이 더 크다고 결론낸다.</p>
<pre><code class="language-js">alert(&#39;Z&#39; &gt; &#39;A&#39;); //true
alert(&#39;Glow&#39; &gt; &#39;Glee&#39;); //true
alert(&#39;Bee&#39; &gt; &#39;Be&#39;); //true
alert(&#39;2&#39; &gt; &#39;12&#39;); //true</code></pre>
<h3 id="다른-형을-가진-값들에-대한-비교-연산">다른 형을 가진 값들에 대한 비교 연산</h3>
<p>비교하려는 값의 <strong>자료형이 다르면</strong> JS는 이 값들을 <strong>숫자형</strong>으로 바꾼다.</p>
<pre><code class="language-js">alert(&#39;2&#39; &gt; 1); //true. 2 &gt; 1 → true
alert(&#39;01&#39; == 1); //true. 1 == 1 → true
alert(true == 1); //true
alert(false == 0); //true
alert(&#39;&#39; == false); //true </code></pre>
<h3 id="일치-연산자">일치 연산자</h3>
<p>비교하려는 값의 자료형이 다르더라도 형 변환 없이 값을 비교한다. 즉 자료형의 동등 여부까지 검사하는 것이다. JS에서는 이것을 대부분 사용한다.</p>
<pre><code class="language-js">alert(false === 0); //false</code></pre>
<h3 id="null-값이-피연산자일-때">null 값이 피연산자일 때</h3>
<blockquote>
<p>피연산자가 null일 때 비교 연산자는 형 변환을 하고, 동등 연산자는 형 변환을 하지 않는다.</p>
</blockquote>
<pre><code class="language-js">alert(null &gt; 0); // false. 0 &gt; 0은 false
alert(null == 0); //false. null이 0으로 바뀌지 않음.
alert(null &gt;= 0); //true. 0 &gt;= 0은 true</code></pre>
<h3 id="undefined-값이-피연산자일-때">undefined 값이 피연산자일 때</h3>
<blockquote>
<p>피연산자가 undefined일 때, 비교 연산자와 동등 연산자 모두 항상 false를 반환한다.</p>
</blockquote>
<pre><code class="language-js">alert(undefined &gt; 0); // false
alert(undefined &lt; 0); //false
alert(undefined == 0); //false</code></pre>
<h3 id="null과-undefined가-피연산자일-때-동등-연산자">null과 undefined가 피연산자일 때 동등 연산자</h3>
<blockquote>
<p>null과 undefined는 동등 연산자를 취하면 서로 같다. 다른 자료형과는 배타적이다. 둘만 동등하다.</p>
</blockquote>
<h2 id="🐑-if와-를-사용한-조건-처리">🐑 if와 &#39;?&#39;를 사용한 조건 처리</h2>
<h3 id="조건부-연산자-">조건부 연산자 &#39;?&#39;</h3>
<p>조건부 연산자는 물음표?로 표시한다. 피연산자가 세 개이기 때문에 조건부 연산자를 &#39;삼항(ternary) 연산자’라고 부르는 사람도 있다. JS에서 피연산자를 3개나 받는 연산자는 조건부 연산자가 유일하다.</p>
<pre><code class="language-js">let result = condition ? value1 : value2;</code></pre>
<p>condition이 truthy라면 value1이, 그렇지 않으면 value 2가 result에 반환된다.</p>
<p>ex)</p>
<pre><code class="language-js">let accessAllowed = (age &gt; 18) ? true : false;</code></pre>
<p>age &gt; 18 조건을 만족하면 accessAllowed에 true가, 만족하지 않으면 false가 반환된다.</p>
<h3 id="다중-">다중 &#39;?&#39;</h3>
<p>물음표 연산자?를 여러 개 연결하면 복수의 조건을 처리할 수 있다.</p>
<pre><code class="language-js">let age = prompt(&#39;나이를 입력해주세요.&#39;, 18);

let message = (age &lt; 3) ? &#39;아기야 안녕?&#39; :
  (age &lt; 18) ? &#39;안녕!&#39; :
  (age &lt; 100) ? &#39;환영합니다!&#39; :
  &#39;나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!&#39;;

alert( message );</code></pre>
<blockquote>
<p>물음표 연산자?는 조건에 따라 반환 값을 달리하려는 목적으로 만들어졌다. 이런 목적에 부합하는 곳에 물음표를 사용해야 한다. 여러 분기를 만들어 처리할 때는 if를 사용하는 것이 좋다.</p>
</blockquote>
<h2 id="🐑-논리-연산자">🐑 논리 연산자</h2>
<h3 id="첫-번째-truthy를-찾는-or-연산자-">첫 번째 truthy를 찾는 OR 연산자 &#39;||&#39;</h3>
<p>JS에서만 제공하는 논리연산자 OR의 추가 기능에 대해 알아보자.</p>
<pre><code class="language-js">result = value1 || value2 || value3;</code></pre>
<p>OR 연산자가 여러 개인 경우, OR 연산자 ||는 다음 순서에 따라 연산을 수행한다.</p>
<ol>
<li>가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 확인한다.</li>
<li>각 피연산자를 불린형으로 변환합니다. 변환 후 그 값이 true이면 연산을 멈추고 해당 피연산자의 <strong>변환 전 원래 값을 반환</strong>한다.</li>
<li>피연산자 모두를 평가한 경우(모든 피연산자가 false로 평가되는 경우)엔 마지막 피연산자를 반환한다.</li>
</ol>
<p>반환 값이 <strong>형 변환을 하지 않은 원래 값</strong>이라는 것이 중요하다.</p>
<pre><code class="language-js">alert( 1 || 0 ); // 1 (1은 truthy임)

alert( null || 1 ); // 1 (1은 truthy임)
alert( null || 0 || 1 ); // 1 (1은 truthy임)

alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을 반환함)</code></pre>
<p>cf) 구체적인 활용 방안은 문서 2.11 참고</p>
<h3 id="첫-번째-falsy를-찾는-and-연산자-">첫 번째 falsy를 찾는 AND 연산자 &#39;&amp;&amp;&#39;</h3>
<pre><code class="language-js">result = value1 &amp;&amp; value2 &amp;&amp; value3;</code></pre>
<p>AND 연산자 &amp;&amp;는 아래와 같은 순서로 동작한다.</p>
<ol>
<li>가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 확인한다.</li>
<li>각 피연산자는 불린형으로 변환됩니다. 변환 후 값이 false이면 평가를 멈추고 해당 피연산자의 <strong>변환 전 원래 값을 반환</strong>합니다.</li>
<li>피연산자 모두가 평가되는 경우(모든 피연산자가 true로 평가되는 경우)엔 마지막 피연산자가 반환된다.<pre><code class="language-js">// 첫 번째 피연산자가 truthy이면,
// AND는 두 번째 피연산자를 반환합니다.
alert( 1 &amp;&amp; 0 ); // 0
alert( 1 &amp;&amp; 5 ); // 5
</code></pre>
</li>
</ol>
<p>// 첫 번째 피연산자가 falsy이면,
// AND는 첫 번째 피연산자를 반환하고, 두 번째 피연산자는 무시합니다.
alert( null &amp;&amp; 5 ); // null
alert( 0 &amp;&amp; &quot;아무거나 와도 상관없습니다.&quot; ); // 0</p>
<pre><code>
```js
alert( 1 &amp;&amp; 2 &amp;&amp; null &amp;&amp; 3 ); // null
alert( 1 &amp;&amp; 2 &amp;&amp; 3 ); // 마지막 값, 3</code></pre><h3 id="not을-2개-연달아-사용하면">NOT(!)을 2개 연달아 사용하면?</h3>
<p>NOT을 두 개 연달아 사용(!!)하면 값을 Boolean형으로 변환할 수 있다.</p>
<pre><code class="language-js">alert(!!&quot;non-empty string&quot;); //true
alert(!!null); //false</code></pre>
<h2 id="🐑-nullish-병합-연산자-">🐑 nullish 병합 연산자 &#39;??&#39;</h2>
<p><code>a ?? b</code></p>
<ul>
<li>a가 null도 아니고 undefined도 아니면 a, 그 외의 경우는 b</li>
</ul>
<p>아래의 코드와 동일한 기능을 한다.</p>
<pre><code class="language-js">x = (a !== null &amp;&amp; a !== undefined) ? a : b;</code></pre>
<p>nullish 병합 연산자 ??를 사용하면 값이 정해진 변수를 간편하게 찾아낼 수 있다.</p>
<pre><code class="language-js">let firstName = null;
let lastName = null;
let nickName = &quot;바이올렛&quot;;

// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? &quot;익명의 사용자&quot;); // 바이올렛</code></pre>
<h3 id="와-의-차이">&#39;??&#39;와 &#39;||&#39;의 차이</h3>
<p>둘은 매우 비슷해보이지만 중요한 차이점이 있다.</p>
<ul>
<li>||는 첫 번째 truthy 값을 반환한다.</li>
<li>??는 첫 번째 정의된(defined) 값을 반환한다.</li>
</ul>
<pre><code class="language-js">let height = 0;

alert(height || 100); // 100
alert(height ?? 100); // 0</code></pre>
<h2 id="🐑-while과-for-반복문">🐑 while과 for 반복문</h2>
<h3 id="와-break-continue">&#39;?&#39;와 break, continue</h3>
<blockquote>
<p>&#39;?&#39; 오른쪽엔 <code>break</code>나 <code>continue</code>가 올 수 없다.</p>
</blockquote>
<pre><code class="language-js">if (i &gt; 5) {
  alert(i);
} else {
  continue;
}</code></pre>
<p>이 코드를 삼항 연산자로 나타낸다고 해보자.</p>
<pre><code class="language-js">(i &gt; 5) ? alert(i) : continue; // 여기에 continue를 사용하면 안 됩니다.</code></pre>
<p>이 코드는 에러를 발생시킨다.</p>
<h3 id="breakcontinue와-레이블">break/continue와 레이블</h3>
<p>평범한 break 지시자를 사용하면 안쪽에 있는 반복문만 빠져나올 수 있다. 그러나 중첩 반복문을 포함한 반복문 두 개 모두를 빠져나와야 한다면, 이럴 때 레이블을 사용할 수 있다.</p>
<p>레이블(label) 은 반복문 앞에 콜론과 함께 쓰이는 식별자이다.</p>
<pre><code class="language-js">labelName: for (...) {
  ...
}</code></pre>
<p>반복문 안에서 break &lt;labelName&gt;문을 사용하면 레이블에 해당하는 반복문을 빠져나올 수 있다.</p>
<pre><code class="language-js">outer: for (let i = 0; i &lt; 3; i++) {

  for (let j = 0; j &lt; 3; j++) {

    let input = prompt(`(${i},${j})의 값`, &#39;&#39;);

    // 사용자가 아무것도 입력하지 않거나 Cancel 버튼을 누르면 두 반복문 모두를 빠져나옵니다.
    if (!input) break outer; // (*)

    // 입력받은 값을 가지고 무언가를 함
  }
}
alert(&#39;완료!&#39;);</code></pre>
<p>위 예시에서 break outer는 outer라는 레이블이 붙은 반복문을 찾고, 해당 반복문을 빠져나오게 해준다. 따라서 제어 흐름이 (*)에서 alert(&#39;완료!&#39;)로 바로 바뀐다.</p>
<p>continue 지시자를 레이블과 함께 사용하는 것도 가능하다. 레이블이 붙은 반복문의 다음 이터레이션이 실행된다.</p>
<h2 id="🐑-함수">🐑 함수</h2>
<h3 id="함수의-선언과-사용">함수의 선언과 사용</h3>
<pre><code class="language-js">function showMessage() {
  alert( &#39;안녕하세요!&#39; );
}

showMessage();
showMessage();</code></pre>
<h3 id="매개변수와-인수">매개변수와 인수</h3>
<ul>
<li>매개변수 : 함수 선언문 괄호에 있는 변수. 선언 시 쓰이는 용어이다.</li>
<li>인수 : 함수를 호출 할 때 매개벼수에 전달되는 값. 호출 시 쓰이는 용어이다.</li>
</ul>
<pre><code class="language-js">function showMessage(from, text) { //  from, text : 매개변수
  alert(from + &#39;: &#39; + text);
}

showMessage(&#39;Ann&#39;, &#39;Hello!&#39;); // Ann, Hello : 인수</code></pre>
<h3 id="기본값">기본값</h3>
<p>함수 호출 시 매개변수에 인수를 전달하지 않으면 그 값은 <code>undefined</code>가 된다. </p>
<pre><code class="language-js">function showMessage(from, text) {
  alert(from + &#39;: &#39; + text);
}

showMessage(&quot;Ann&quot;);</code></pre>
<p>이렇게 코드를 작성해도 에러가 발생하지 않고, 매개변수 text에 undefined가 할당될 뿐이다. 따라서 에러없이 &quot;Ann: undefined&quot;가 출력된다.</p>
<p>매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면 함수를 선언할 때 =를 사용해 &#39;기본값(default value)&#39;을 설정해주면 된다.</p>
<pre><code class="language-js">function showMessage(from, text = &quot;no text given&quot;) {
  alert( from + &quot;: &quot; + text );
}

showMessage(&quot;Ann&quot;); // Ann: no text given</code></pre>
<p>기본값에 함수 표현식도 넣어줄 수 있다.</p>
<pre><code class="language-js">function showMessage(from, text = anotherFunction()) {
  // anotherFunction()은 text값이 없을 때만 호출됨
  // anotherFunction()의 반환 값이 text의 값이 됨
}</code></pre>
<p>cf) 매개변수에 기본값을 설정하는 다양한 방법은 2.15 문서 참고</p>
<h3 id="return">return</h3>
<p>return문이 없거나, return 지시자만 있는 함수는 <code>undefined</code>를 반환한다.</p>
<h3 id="함수-이름-짓기">함수 이름 짓기</h3>
<p>함수는 어떤 <strong>동작</strong>을 수행하기 위한 코드를 모아놓은 것이므로, 함수 이름은 대개 동사이다. </p>
<p>그리고 함수는 동작 하나만 담당해야 한다. 함수는 간결하고 한 가지 기능만 수행할 수 있게 만들어야 한다. </p>
<h2 id="🐑-함수-표현식">🐑 함수 표현식</h2>
<p>함수 선언 방식 외에 함수 표현식(Function Expression) 을 사용해서 함수를 만들 수 있다. </p>
<pre><code class="language-js">let sayHi = function() {
  alert( &quot;Hello&quot; );
};</code></pre>
<p>함수를 생성하고 변수에 값을 할당하는 것처럼 함수가 변수에 할당되었다. 즉 함수를 만들고 그 함수를 변수 <code>sayHi</code>에 할당한 것이다.</p>
<p>함수는 값이기 때문에 alert를 이용하여 함수 코드를 출력할 수도 있다.</p>
<pre><code class="language-js">function sayHi() {
  alert( &quot;Hello&quot; );
}

alert( sayHi ); // 함수 코드 전체가 보임!</code></pre>
<p>변수를 복사해 다른 변수에 할당하는 것처럼 함수를 복사해 다른 변수에 할당할 수도 있다.</p>
<pre><code class="language-js">function sayHi() {   // (1) 함수 생성
  alert( &quot;Hello&quot; );
}

let func = sayHi;    // (2) 함수 복사

func(); // Hello     // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello    //     본래 함수도 정상적으로 실행됩니다.</code></pre>
<h3 id="콜백-함수">콜백 함수</h3>
<pre><code class="language-js">function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( &quot;동의하셨습니다.&quot; );
}

function showCancel() {
  alert( &quot;취소 버튼을 누르셨습니다.&quot; );
}

// 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨
ask(&quot;동의하십니까?&quot;, showOk, showCancel);</code></pre>
<p>함수 ask의 인수, showOk와 showCancel은 콜백 함수 또는 콜백이라고 불린다.</p>
<p>함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 그 함수를 <strong>나중에 호출(called back)</strong>하는 것이 콜백 함수의 개념이다. 위 예시에선 사용자가 &quot;yes&quot;라고 대답한 경우 showOk가 콜백이 되고, &quot;no&quot;라고 대답한 경우 showCancel가 콜백이 된다.</p>
<p>아래와 같이 함수 표현식을 사용하면 코드 길이가 짧아진다.</p>
<pre><code class="language-js">function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  &quot;동의하십니까?&quot;,
  function() { alert(&quot;동의하셨습니다.&quot;); },
  function() { alert(&quot;취소 버튼을 누르셨습니다.&quot;); }
);</code></pre>
<h3 id="함수-표현식-vs-함수-선언문">함수 표현식 vs. 함수 선언문</h3>
<p><strong>1. 문법에서 차이가 있다</strong></p>
<pre><code class="language-js">// 함수 선언문
function sum(a, b) {
  return a + b;
}</code></pre>
<pre><code class="language-js">// 함수 표현식
let sum = function(a, b) {
  return a + b;
};</code></pre>
<p><strong>2. JS 엔진이 함수를 언제 생성하는지가 다르다</strong></p>
<ul>
<li><p><strong>함수 표현식</strong>은 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다. 따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있다.</p>
</li>
<li><p>위 예시에서, 스크립트가 실행되고 실행 흐름이 let sum = function…의 우측(함수 표현식)에 도달 했을때 함수가 생성된다. 이때 이후부터 해당 함수를 사용(할당, 호출 등)할 수 있다. </p>
</li>
<li><p>하지만 <strong>함수 선언문</strong>은 함수 선언문이 정의되기 전에도 호출할 수 있다.</p>
</li>
<li><p>따라서 전역 함수 선언문은 스크립트 어디에 있느냐에 상관없이 어디에서든 사용할 수 있다.</p>
</li>
</ul>
<p>예시를 살펴보자.</p>
<pre><code class="language-js">//함수 선언문
sayHi(&quot;John&quot;); // Hello, John

function sayHi(name) {
  alert( `Hello, ${name}` );
}</code></pre>
<pre><code class="language-js">//함수 표현식
sayHi(&quot;John&quot;); // error!

let sayHi = function(name) {  // (*) 마술은 일어나지 않습니다.
  alert( `Hello, ${name}` );
};</code></pre>
<p><strong>3. scope가 다르다</strong></p>
<pre><code class="language-js">// 함수 선언문

let age = prompt(&quot;나이를 알려주세요.&quot;, 18);

// 조건에 따라 함수를 선언함
if (age &lt; 18) {

  function welcome() {
    alert(&quot;안녕!&quot;);
  }

} else {

  function welcome() {
    alert(&quot;안녕하세요!&quot;);
  }

}

// 함수를 나중에 호출합니다.
welcome(); // Error: welcome is not defined</code></pre>
<p>함수 선언문은 함수가 선언된 코드 블록 안에서만 유효하기 때문에 이런 에러가 발생한다.</p>
<pre><code class="language-js">let age = prompt(&quot;나이를 알려주세요.&quot;, 18);

let welcome;

if (age &lt; 18) {

  welcome = function() {
    alert(&quot;안녕!&quot;);
  };

} else {

  welcome = function() {
    alert(&quot;안녕하세요!&quot;);
  };

}

welcome(); // 제대로 동작합니다.</code></pre>
<p>함수 표현식을 사용하면 에러가 발생하지 않는다. if문 밖에 선언한 변수 welcome에 함수 표현식으로 만든 함수를 할당하면 되기 때문이다.</p>
<p>그럼 어떤 것을 사용하는게 좋을까?</p>
<blockquote>
<p>함수 선언문을 이용해 함수를 선언하는 걸 먼저 고려하는 게 좋다. 함수 선언문으로 함수를 정의하면, 함수가 선언되기 전에 호출할 수 있어서 코드 구성을 좀 더 자유롭게 할 수 있고, 가독성도 좋아지기 때문이다. 그러나 어떤 이유로 함수 선언 방식이 적합하지 않거나, (위 예제와 같이) 조건에 따라 함수를 선언해야 한다면 함수 표현식을 사용해야 한다.</p>
</blockquote>
<h2 id="🐑-화살표-함수-기본">🐑 화살표 함수 기본</h2>
<p>함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법이 있다. 바로 화살표 함수(arrow function)를 사용하는 것이다.</p>
<pre><code class="language-js">let func = (arg1, arg2, ...argN) =&gt; expression</code></pre>
<p>이 함수는 아래 함수와 동일하다.</p>
<pre><code class="language-js">let func = function(arg1, arg2, ...argN) {
  return expression;
};</code></pre>
<p>좀 더 구체적인 예시를 보자.</p>
<pre><code class="language-js">let sum = (a, b) =&gt; a + b;

/* 위 화살표 함수는 아래 함수의 축약 버전입니다.

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3
</code></pre>
<ul>
<li>인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략할 수 있다.</li>
</ul>
<pre><code class="language-js">let double = n =&gt; n * 2;
// let double = function(n) { return n * 2 }과 거의 동일합니다.

alert( double(3) ); // 6</code></pre>
<ul>
<li>인수가 하나도 없을 땐 괄호를 비워놓으면 된다. 다만, 이 때 괄호는 생략할 수 없다.</li>
</ul>
<pre><code class="language-js">let sayHi = () =&gt; alert(&quot;안녕하세요!&quot;);

sayHi();</code></pre>
<p>화살표 함수는 함수 표현식과 같은 방법으로 사용할 수 있다. 아래 예시와 같이 함수를 동적으로 만들 수 있다.</p>
<pre><code class="language-js">let age = prompt(&quot;나이를 알려주세요.&quot;, 18);

let welcome = (age &lt; 18) ?
  () =&gt; alert(&#39;안녕&#39;) :
  () =&gt; alert(&quot;안녕하세요!&quot;);

welcome();</code></pre>
<h3 id="본문이-여러-줄인-화살표-함수">본문이 여러 줄인 화살표 함수</h3>
<pre><code class="language-js">let sum = (a, b) =&gt; {  // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
  let result = a + b;
  return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};

alert( sum(1, 2) ); // 3</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공 자바스크립트 0-4강]]></title>
            <link>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-0-4%EA%B0%95</link>
            <guid>https://velog.io/@cse_pebb/%ED%98%BC%EA%B3%B5-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-0-4%EA%B0%95</guid>
            <pubDate>Tue, 14 Nov 2023 13:30:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>윤인성 님의 <a href="https://www.youtube.com/watch?v=pXuyfvJPENA&amp;list=PLBXuLgInP-5kxpAKy2DNXoebCse2grHjl">혼공 자바스크립트</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🐤-개발-환경">🐤 개발 환경</h2>
<p><code>텍스트 에디터</code> : 코드 작성
ex) VSC</p>
<p><code>코드 실행기</code> : 웹 브라우저
ex) 크롬</p>
<h2 id="🐤-aboutblank">🐤 about:blank</h2>
<p>주소창에 <code>about:blank</code>를 입력하면 아무 것도 없는 페이지에 접속할 수 있다.</p>
<h2 id="🐤-자바스크립트-코드를-실행하는-방법-2가지">🐤 자바스크립트 코드를 실행하는 방법 2가지</h2>
<ol>
<li>브라우저 개발자 도구 이용</li>
<li>파일 만들어서 실행</li>
</ol>
<p>프로그램은 기본적으로 2번 방법을 사용하고, 예외로 간단하게 테스트 해야하는 상황에서는 1번 방법을 사용한다.</p>
<p>1번의 경우 콘솔에서는 한 문장씩 코드를 입력하면서 브라우저와 대화하는 형태로 코드를 작성한다. 즉 브라우저가 코드를 곧바로 읽고, 실행(평가)하고, 출력하는 것을 반복한다.
이를 <strong>interactive하게 코드를 작성한다</strong> 또는 <strong>REPL(Read Eval Print Loop)</strong> 이라고 한다.</p>
<h2 id="🐤-에러의-종류">🐤 에러의 종류</h2>
<h3 id="reference-error">Reference Error</h3>
<p>단어 오탈자가 발생하면 뜬다.</p>
<p>ex) alert 대신 alrt 작성</p>
<pre><code>Uncaught ReferenceError: alrt is not defined</code></pre><h3 id="syntax-error">Syntax Error</h3>
<p>일반적으로 기호에서 오탈자가 발생하면 뜬다.</p>
<p>ex) alert&quot;&quot;)</p>
<pre><code>Uncaught SyntaxError: Unexpected string</code></pre><h2 id="🐤-vsc">🐤 VSC</h2>
<h3 id="들여쓰기">들여쓰기</h3>
<ul>
<li>여러 줄 들여쓰기 : Shift 누른 채로 여러 줄 선택 + Tab 키 누르기</li>
<li>들여쓰기 삭제 : Shift + Tab</li>
</ul>
<h3 id="vsc-단축키">VSC 단축키</h3>
<p><img src="https://velog.velcdn.com/images/cse_pebb/post/e4d3bf71-b46d-4c01-808b-4cdd6d986189/image.png" alt=""></p>
<ul>
<li>멀티 커서 : Alt + 마우스 클릭 / Ctrl + Alt + 방향키 </li>
</ul>
<h2 id="🐤-자바스크립트-코딩-스타일">🐤 자바스크립트 코딩 스타일</h2>
<p>코딩 스타일 = 코딩 컨벤션
<a href="https://standardjs.com/rules-kokr.html">https://standardjs.com/rules-kokr.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 바닐라 JS로 크롬 앱 만들기 #5]]></title>
            <link>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-5</link>
            <guid>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-5</guid>
            <pubDate>Wed, 07 Sep 2022 15:19:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>노마드 코더의 <a href="https://nomadcoders.co/javascript-for-beginners/lobby">바닐라 JS로 크롬 앱 만들기</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🦖-js에서-제공하는-interval-기능">🦖 JS에서 제공하는 interval 기능</h2>
<h3 id="interval이란">interval이란?</h3>
<blockquote>
<p><strong>매번</strong> 일어나야 하는 무언가를 의미. 예를 들어 &#39;매 2초&#39;라고 하면 이것이 interval이 된다. </p>
</blockquote>
<h3 id="setinterval">setInterval</h3>
<blockquote>
<p>setInterval(실행하려는함수, 호출되는함수의시간간격)</p>
</blockquote>
<p>시간 단위는 ms이므로 5초마다 호출하고 싶다면 5000이라고 적어주어야 함</p>
<p><code>예시</code></p>
<pre><code class="language-javascript">function sayHello() {
  console.log(&quot;Hello&quot;);
}

setInterval(sayHello, 5000);
</code></pre>
<p>바로 실행되지 않고 5초 후 첫 시작이 되고, 그 이후 5초마다 <strong>계속</strong> 콘솔 창에 Hello가 출력된다.</p>
<h3 id="settimeout">setTimeout</h3>
<blockquote>
<p>setTimeout(실행하려는함수, 호출되는함수의시간간격)</p>
</blockquote>
<p><code>예시</code></p>
<pre><code class="language-javascript">function sayHello() {
  console.log(&quot;Hello&quot;);
}

setTimeout(sayHello, 5000);

</code></pre>
<p>setInterval과 동일하게 바로 실행되지 않고 5초 후 첫 시작이 된다.
하지만 차이점은 그 이후에는 더이상 실행되지 않는다는 것이다. 즉 콘솔 창에 Hello가 처음 한번만 출력된다.</p>
<h2 id="🦖-date-객체">🦖 Date 객체</h2>
<pre><code class="language-javascript">const date = new Date() //오늘 날짜와 요일, 현재 시간 정보 저장

date.getDate() // 며칠
date.getDay() // 무슨 요일(0은 일요일)
date.getFullYear() // 몇년도
date.getHours() // 몇시
date.getMinutes() // 몇분
date.getSeconds() // 몇초</code></pre>
<h2 id="🦖-padstart-함수">🦖 padStart 함수</h2>
<blockquote>
<p>string에 쓸 수 있는 함수로, string의 길이에 따라 앞에 문자를 추가해주는 함수이다.</p>
</blockquote>
<pre><code class="language-javascript">&quot;1&quot;.padStart(2,&quot;0&quot;) // 문자열의 길이가 2가 안될 경우, 해당 길이가 될 때까지 앞에 0을 붙여준다. </code></pre>
<p>결과는 &quot;01&quot;이 된다.</p>
<h2 id="🦖-string-함수">🦖 String() 함수</h2>
<blockquote>
<p>다른 자료형을 문자열로 바꿔주는 함수</p>
</blockquote>
<pre><code class="language-javascript">String(new Date().getHours())
// getHours는 현재 시간인 숫자를 반환하는데, 이를 String으로 변환해주면 문자열로 변환된다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 바닐라 JS로 크롬 앱 만들기 #4]]></title>
            <link>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94</link>
            <guid>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94</guid>
            <pubDate>Mon, 05 Sep 2022 23:25:09 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>노마드 코더의 <a href="https://nomadcoders.co/javascript-for-beginners/lobby">바닐라 JS로 크롬 앱 만들기</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🦖-string-길이-구하기">🦖 string 길이 구하기</h2>
<pre><code class="language-javascript">const username = &quot;hello&quot;
console.log(username.length);</code></pre>
<p><code>출력</code> : 5</p>
<h2 id="🦖-input-태그의-특징">🦖 input 태그의 특징</h2>
<p>input의 attirubte로 required, maxlength를 지정해줄 수 있다.
단, 이러한 input의 유효성 검사는 input 태그가 form 태그로 감싸져 있을 때만 가능하다.</p>
<pre><code class="language-html">&lt;form&gt;
  &lt;input required maxlength=&quot;15&quot; type=&quot;text&quot; /&gt;
&lt;/form&gt;</code></pre>
<h2 id="🦖-form-태그의-submit">🦖 form 태그의 submit</h2>
<p>아래의 경우에는 굳이 버튼에 click 이벤트를 주지 않아도 <strong>자동으로 submit이 된다</strong>.</p>
<blockquote>
<p>기억하자 - submit은 엔터를 누르거나 버튼을 클릭할 때 발생한다.</p>
</blockquote>
<h3 id="enter-버튼이나-input-안에-있는-button을-누를-경우">enter 버튼이나 input 안에 있는 button을 누를 경우</h3>
<pre><code class="language-html">&lt;form&gt;
  &lt;input type=&quot;text&quot; placeholder=&quot;입력하세요&quot;/&gt;
  &lt;button&gt;로그인&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<h3 id="enter-버튼이나-type이-submit인-input--엔터를-누를-경우">enter 버튼이나 type이 submit인 input / 엔터를 누를 경우</h3>
<pre><code class="language-html">&lt;form&gt;
  &lt;input type=&quot;text&quot; placeholder=&quot;입력하세요&quot;/&gt;
  &lt;input type=&quot;submit&quot; value=&quot;로그인&quot;/&gt;
&lt;/form&gt;</code></pre>
<h2 id="🦖-event의-기본동작-막아주기">🦖 event의 기본동작 막아주기</h2>
<h3 id="form-태그의-submit">form 태그의 submit</h3>
<p>위에서 봤듯 form 태그의 submit은 자동으로 submit이 되는데, 그 때 자동으로 페이지가 새로고침이 되면서(기본동작) 입력한 value 값도 우리가 받기 전에 사라진다. </p>
<p>이를 해결하기 위해서는** submit 이벤트**에 대한 함수를 만들어주어야 하고, 해당 함수에서 새로고침을 막아주는 코드를 적어주어야 입력한 value를 우리가 받아낼 수 있다.</p>
<p><code>HTML</code></p>
<pre><code class="language-html">&lt;form id=&quot;login-form&quot;&gt;
  &lt;input type=&quot;text&quot; placeholder=&quot;입력하세요&quot;/&gt;
  &lt;input type=&quot;submit&quot; value=&quot;로그인&quot;/&gt;
&lt;/form&gt;</code></pre>
<p><code>Javascript</code></p>
<pre><code class="language-javascript">const loginForm = document.querySelector(&quot;#login-form&quot;);
const loginInput = document.querySelector(&quot;#login-form input&quot;);

function onLoginSubmit(event) { //argument에 submit 이벤트에 대한 정보가 저장됨
  event.preventDefault(); //event의 기본동작을 막아주는 코드
  console.log(loginInput.value); //콘솔창에 사용자가 input란에 입력한 값이 뜬다.
}

loginForm.addEventListener(&quot;submit&quot;, onLoginSubmit); //submit event</code></pre>
<p>모든 EventListener function의 첫 번째 arugment에는 항상 지금 막 벌어진 일들에 대한 정보를 담은 object가 들어간다. JS가 그 정보를 제공하기 때문에, 우리는 그냥 arguement라는 공간만 주면 된다. 우리가 argument만 작성해주면 JS가 방금 일어난 event(여기서는 submit)에 대한 정보를 argument에 채워넣어준다. argument명은 아무거나 와도 되지만 보통은 event라고 작성한다. 
console.log(event)를 작성해주면 object에 담긴 정보들을 확인할 수 있다. </p>
<p><strong>preventDefault()</strong>
어떤 event의 기본행동도 발생되지 않는 것. 즉, 어떤 function에 대해 브라우저가 기본적으로 수행하는 동작을 막아주는 것. 여기서는 submit 이벤트의 기본동작인 브라우저의 페이지 새로고침을 막아주는 것이다. </p>
<h3 id="a-태그의-link">a 태그의 link</h3>
<p>link의 기본 동작은 클릭 시 다른 페이지로 이동하는 것이다. 이걸 막아보자!
<code>HTML</code></p>
<pre><code class="language-html">&lt;a href=&quot;https://nomadcoders.co&quot;&gt;링크&lt;/a&gt;</code></pre>
<p><code>Javascript</code></p>
<pre><code class="language-javascript">const link = document.querySelector(&quot;a&quot;);

function handleLinkClick(event) {
  event.preventDefault();
}

link.addEventListener(&quot;click&quot;, handleLinkClick);
</code></pre>
<p>이제 link를 클릭해도 해당 페이지로 이동하는 기본동작이 작동되지 않는다!</p>
<h3 id="참고-함수-뒤에-를-작성하는-경우와-작성하지-않는-경우">참고) 함수 뒤에 ()를 작성하는 경우와 작성하지 않는 경우</h3>
<blockquote>
<p>함수 뒤에 ()를 작성한 코드는 바로 해당 함수를 실행시키겠다는 의미</p>
</blockquote>
<p><strong>브라우저가 이 코드를 보는 순간 함수를 바로 실행시킨다</strong>. 그래서 EventListener를 할 때 함수 뒤에 ()를 안 붙이는 것이다. 바로 실행시키는게 아니라 이벤트가 발생했을 때만 실행시키려고 하는 거니까! addEventListener에 안에 있는 함수는 우리가 직접 실행하는게 아니라는 것을 명심하자! 내가 아니라 브라우저가 해주는 것이고, 브라우저는 실행시켜줄 뿐만 아니라 event에 대한 정보도 제공해준다! 우리가 argument로 자리만 마련해주면, 그 정보를 argument에 공짜로 넣어준다!</p>
<h2 id="🦖-css---visibilityhidden과-displaynone의-차이점">🦖 CSS - visibility:hidden과 display:none의 차이점</h2>
<h3 id="visibility-hidden">visibility: hidden;</h3>
<blockquote>
<p>공간은 그대로 두고, 눈에만 안 보인다.</p>
</blockquote>
<h3 id="display-none">display: none;</h3>
<blockquote>
<p>잡아둔 공간까지도 모두 사라진다.</p>
</blockquote>
<h2 id="🦖-변수명-convention-string만-포함된-변수">🦖 변수명 convention) string만 포함된 변수</h2>
<blockquote>
<p>일반적으로 string만 포함된 변수는 대문자로 표기한다.</p>
</blockquote>
<pre><code class="language-javascript">const HIDDEN_CLASSNAME = &quot;hidden&quot;;</code></pre>
<h2 id="🦖-string과-변수-조합하는-방법-2가지">🦖 string과 변수 조합하는 방법 2가지</h2>
<h3 id="단순히-와-로-연결">단순히 &quot;&quot;와 +로 연결</h3>
<pre><code class="language-javascript">const username = loginInput.value; //input에서 사용자 입력값을 받아와 변수에 저장한다고 가정
console.log(&quot;Hello &quot; + username); //honi를 입력하면 콘솔에 &quot;Hello honi&quot; 출력</code></pre>
<h3 id="와-변수값을-의미하는--이용하기-추천">`와 변수값을 의미하는 $ 이용하기 (추천!)</h3>
<pre><code class="language-javascript">const username = loginInput.value;
console.log(`Hello ${username}`); // 위의 코드와 동일하게 동작</code></pre>
<p>반드시 `로 감싸야하고, ${변수명} 으로 작성하면 JS가 알아서 변수에 저장된 값으로 바꿔준다. </p>
<h2 id="🦖-localstorage-api">🦖 localStorage API</h2>
<blockquote>
<p>우리가 브라우저에 뭔가를 저장할 수 있게 해준다.</p>
</blockquote>
<p>예를 들어 유튜브에서 볼륨을 조절하고 새로고침하면, 유튜브가 그 볼륨값을 기억하는 등 뭔가를 기억할 수 있도록 해주는 것이다. </p>
<p>local storage에 뭐가 들어있는지 보고 싶으면 개발자 도구 - Application - local storage를 찾으면 된다. </p>
<p>localStorage에는 다양한 메소드들이 있다.</p>
<h3 id="setitem">setItem</h3>
<blockquote>
<p>local storage에 정보를 저장할 수 있다.</p>
</blockquote>
<pre><code class="language-javascript">localStorage.setItem(&quot;username&quot;, &quot;nico&quot;) // (key값, value값)</code></pre>
<h3 id="getitem">getItem</h3>
<blockquote>
<p>local storage에 저장된 정보를 불러올 수 있다.</p>
</blockquote>
<pre><code class="language-javascript">localStorage.getItem(&quot;username&quot;) // key값에 해당하는 value를 가져온다</code></pre>
<p>만약 없는 key값으로 getItem을 한다면, null이 반환된다!</p>
<h3 id="removeitem">removeItem</h3>
<blockquote>
<p>local storage에 저장된 정보를 지울 수 있다.</p>
</blockquote>
<pre><code class="language-javascript">localStorage.removeItem(&quot;username&quot;) // key값에 해당하는 값을 지운다.</code></pre>
<hr>
<blockquote>
<p>여기부터는 과제하면서 내가 삽질한 이야기..</p>
</blockquote>
<h2 id="🦖-input으로-입력받은-값의-자료형">🦖 input으로 입력받은 값의 자료형</h2>
<p>input에 사용자가 입력한 값은 <strong>문자열로 취급한다</strong>... 심지어 input type이 number여도....................... 숫자만 입력해도 숫자로 이루어진 문자열로 본다..........</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 바닐라 JS로 크롬 앱 만들기 #3]]></title>
            <link>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</link>
            <guid>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</guid>
            <pubDate>Fri, 05 Aug 2022 18:54:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>노마드 코더의 <a href="https://nomadcoders.co/javascript-for-beginners/lobby">바닐라 JS로 크롬 앱 만들기</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🦖-html과-javascript">🦖 HTML과 Javascript</h2>
<p><code>Javascript</code>를 사용하는 이유는 <code>HTML</code>과 상호작용하기 위해서이다. 
<code>JS</code>를 통해 <code>HTML</code>의 element들을 변경하고, 읽을 수 있다.</p>
<p><code>Javascript</code>는 <code>HTML</code>에 이미 연결되어 있기 때문에 별다른 연결을 해줄 필요가 없다.</p>
<h2 id="🦖-브라우저의-핵심-object인-document">🦖 브라우저의 핵심 object인 document</h2>
<p>document는 브라우저에 이미 존재하는 object로 <code>HTML</code>을 가리킨다. <code>HTML</code> 파일을 보여준다. 이 document가 <code>Javascript</code>가 <code>HTML</code> 파일을 가져오도록 해주는 시작점이다.</p>
<p>console창에 document.title이라고 치면 <code>HTML</code>의 title에 접근하여 해당 title의 content를 보여준다.</p>
<p>title은 document의 properties(속성)으로, 속성은 변경이 가능하기 때문에 <code>HTML</code> 파일을 직접 수정하지 않아도 console 창에서 수정할 수 있다. 즉 <code>JS</code>로 <code>HTML</code> 요소에 접근하여 수정이 가능하다는 것이다.
document.title = &quot;수정할 제목&quot; 
과 같이 작성해주면 된다.</p>
<hr>
<p>그렇다면 어떻게 <code>Javascript</code>가 <code>HTML</code>의 특정한 element를 가져오고 접근할 수 있을까?</p>
<h2 id="🦖-getelementbyid">🦖 getElementByID()</h2>
<p>원하는 요소의 ID로 접근하여 해당 요소를 가져온다.</p>
<pre><code class="language-javascript">document.getElementByID(&quot;타켓 태그의 id&quot;);</code></pre>
<h2 id="🦖-element를-찾은-후-html-바꾸기">🦖 element를 찾은 후 HTML 바꾸기</h2>
<p>getElementByID와 같이 element를 찾은 후, <code>HTML</code>을 <code>JS</code>에서 원하는대로 접근하거나 바꿀 수 있다.</p>
<pre><code class="language-javascript">// HTML에서 h1 태그를 찾고자 하고, 해당 태그의 id가 abc라고 가정하자.
const element = document.getElementById(&quot;abc&quot;);

element.innerText = &quot;Got you!&quot;; // innerText는 h1의 contents를 의미

console.log(element.id); // console창에 abc가 출력된다.
console.log(element.className); // h1 태그에 class 부여는 안했으므로 console 창에는 아무것도 출력되지 않는다.</code></pre>
<h2 id="🦖-html의-요소태그를-가져오는-다양한-방법">🦖 HTML의 요소(태그)를 가져오는 다양한 방법</h2>
<h3 id="getelementbyid">getElementByID()</h3>
<p>위에서 설명했듯 getElementById는 id로 접근하여 가져오는 것</p>
<h3 id="getelementsbyclassname">getElementsByClassName()</h3>
<p>class name으로 접근하여 가져오는 것. 하지만 해당 class name을 가진 모든 태그들을 가져와서 하나의 배열에 저장하기 때문에 많은 element를 한번에 가지고 와야하는 경우에 사용한다.</p>
<pre><code class="language-javascript">const hellos = document.getElementByClassName(&quot;hello&quot;);
// class name이 hello인 모든 element들을 가져온다.</code></pre>
<h3 id="getelementsbytagname">getElementsByTagName()</h3>
<p>태그명으로 접근하여 가져오는 것. ByClassName과 마찬가지로 해당 태그명을 가진 모든 tag들을 한꺼번에 array로 가져온다.</p>
<pre><code class="language-javascript">const title = document.getElementsByTagName(&quot;태그명&quot;);</code></pre>
<h3 id="queryselector">querySelector()</h3>
<p>querySelector는 element를 CSS 방식으로 검색할 수 있다. CSS selector를 사용하여 검색할 수 있다는 것이다. 예를 들면 동일한 class명을 지니고 있는 여러 요소(태그)들 중에 특정 태그명을 가진 태그만 가져올 수 있다.</p>
<p>가장 많이 사용한다. querySelector는 ByClassName이나 ByTagName과 달리 단 하나의 element를 return 해주기 때문이다. 만약에 조건에 맞는 해당 태그가 여러개라면 첫 번째 것만 가져온다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;.hello h1&quot;); // hello 클래스의 h1 태그를 가져온다

const title = document.querySelector(&quot;#hello&quot;); // id가 hello인 태그를 가져온다.
// const title = document.getElementsById(&quot;hello&quot;); 와 동일하다.

const title = document.querySelector(&quot;#hello h1&quot;); // id가 hello인 h1 태그를 가져온다.
// getElementsByID에서는 이와 같이 해줄 수 없다.

const title = document.querySelector(&quot;div.hello:first-child h1&quot;);
// div 태그 중 class명이 hello이고 first-child인 h1 태그를 가져온다.</code></pre>
<p>만약 다 가지고오고 싶다면 querySelectorAll()을 사용하면 된다. 이것은 ByClassName과 ByTagName과 동일하게 한꺼번에 array로 가져온다.</p>
<h2 id="🦖-queryselector로-html-style-바꾸기">🦖 querySelector로 HTML style 바꾸기</h2>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);
title.style.color = &quot;blue&quot;; // color라는 property(속성)을 변경해준 것</code></pre>
<hr>
<h2 id="🦖-event">🦖 Event</h2>
<p>click을 하거나, 마우스를 올리거나, 입력을 끝내거나, enter를 누르는 등이 event이다.</p>
<p><code>Javascript</code>는 이 모든 event들을 listen 할 수 있다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);
title.addEventListener(이벤트명); 
</code></pre>
<p>eventListener는 말 그대로 event를 listen 하는 것이다.</p>
<h3 id="click-event">click event</h3>
<p>element를 클릭하면 event가 발생한다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleTitleClick() { // 이벤트 발생시 특정 일을 해주는 함수
  console.log(&quot;title was clicked!&quot;);
}
title.addEventListener(&quot;click&quot;, handleTitleClick); 
// 이벤트 발생시 실행할 함수를 두 번째 인수로 전달</code></pre>
<p>다른 예시</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleTitleClick() { // 이벤트 발생시 특정 일을 해주는 함수
  title.style.color = &quot;blue&quot;;
}
title.addEventListener(&quot;click&quot;, handleTitleClick);</code></pre>
<h3 id="mouseenter">mouseenter</h3>
<p>마우스가 element 위에 올라가면 이벤트가 발생한다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleMouseEnter() {
  console.log(&quot;The mouse is here!&quot;);
}
title.addEventListener(&quot;mouseenter&quot;, handleMouseEnter);</code></pre>
<h3 id="mouseleave">mouseleave</h3>
<p>마우스가 element 위에 올라갔다 떠나면 이벤트가 발생한다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleMouseEnter() {
  title.innerText = &quot;Mouse is here!&quot;// innerText는 h1 태그의 contents를 의미
}

function handleMouseLeave() {
  title.innerText = &quot;Mouse is gone!&quot;;
}
title.addEventListener(&quot;mouseenter&quot;, handleMouseEnter);
title.addEventListener(&quot;mouseleave&quot;, handleMouseLeave);</code></pre>
<h3 id="resize">resize</h3>
<p>window에서 사용할 경우, window 창의 크기를 조정하면 발생하는 event</p>
<pre><code class="language-javascript">function handleWindowResize() {
  document.body.style.backgroundColor = &quot;tomato&quot;;
}

window.addEventListener(&quot;resize&quot;, handleWindowResize); // window는 전체 창을 의미함. </code></pre>
<p>그런데 document의 body, head, title 이런 것들은 중요하기 때문에 기본적으로 존재하지만, 나머지 element들은 querySelector나 getElementById 등으로 찾아와야 한다.</p>
<h3 id="copy">copy</h3>
<p>사용자가 복사를 할 경우 발생하는 이벤트</p>
<pre><code class="language-javascript">function handleWindowCopy() {
  alert(&quot;Copier!&quot;);
}

window.addEventListener(&quot;copy&quot;, handleWindowCopy); // window는 전체 창을 의미함. 
</code></pre>
<h3 id="onlineoffline">online/offline</h3>
<p>와이파이 연결이 되었을 경우/끊길 경우 발생하는 event</p>
<pre><code class="language-javascript">function handleWindowOffline() {
  alert(&quot;SOS no WIFI&quot;);
}

function handleWindowOnline() {
  alert(&quot;ALL GOOD&quot;);
}
window.addEventListener(&quot;offline&quot;, handleWindowOffline);
window.addEventListener(&quot;online&quot;, handleWindowOnline);</code></pre>
<h2 id="🦖-event를-listen하는-또다른-방법">🦖 event를 listen하는 또다른 방법</h2>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleTitleClick() { 
  console.log(&quot;title was clicked!&quot;);
}

function handleMouseEnter() {
  title.innerText = &quot;Mouse is here!&quot;// innerText는 h1 태그의 contents를 의미
}

function handleMouseLeave() {
  title.innerText = &quot;Mouse is gone!&quot;;
}

title.addEventListener(&quot;click&quot;, handleTitleClick); 
title.addEventListener(&quot;mouseenter&quot;, handleMouseEnter);
title.addEventListener(&quot;mouseleave&quot;, handleMouseLeave);
</code></pre>
<p>이 코드는 위에서 해왔던 방법인데, 또다른 방법이 있다.</p>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);

function handleTitleClick() { 
  console.log(&quot;title was clicked!&quot;);
}

function handleMouseEnter() {
  title.innerText = &quot;Mouse is here!&quot;// innerText는 h1 태그의 contents를 의미
}

function handleMouseLeave() {
  title.innerText = &quot;Mouse is gone!&quot;;
}

title.onclick = handleTitleClick;
title.onmouseenter = handleMouseEnter;
title.onmouseleave = handleMouseLeave;
</code></pre>
<p>하지만 addEventListener를 사용하는 것이 더 좋다. 왜냐하면 나중에 .removeEventListener를 통해 event listener를 제거할 수 있기 때문이다.</p>
<h2 id="🦖-listen하고-싶은-event-찾기-팁">🦖 listen하고 싶은 event 찾기 팁</h2>
<h3 id="1-구글링">1. 구글링</h3>
<p>구글에 <strong>찾고 싶은element이름 html element mdn</strong> 검색하기!
ex) h1 html element mdn </p>
<p>mdn 문서 중에 <strong>Web APIs</strong> 라는 문장이 포함된 페이지를 들어간다.
<code>Javascript</code> 관점의 HTML Heading Element를 여기에서 확인할 수 있다.</p>
<h3 id="2-콘솔창에-element-출력">2. 콘솔창에 element 출력</h3>
<pre><code class="language-javascript">const title = document.querySelector(&quot;div.hello:first-child h1&quot;);
console.dir(title);</code></pre>
<p>console.dir은 element의 properties들을 출력해준다. properties들 중 이름 앞에 on이 붙어있다면 그것이 바로 event listener이다. 실제 코드 작성 시에는 on을 빼고 작성하면 된다.</p>
<hr>
<h2 id="🦖-예시---클릭할-때마다-blue-tomato로-색-변환되는-event">🦖 예시 - 클릭할 때마다 blue-&gt;tomato로 색 변환되는 event</h2>
<pre><code class="language-javascript">const a = document.querySelector(&quot;h1&quot;);

function handleClick() {
  const currentColor = a.style.color;
  let newColor;
  if (currentColor == &quot;blue&quot;) {
    newColor = &quot;tomato&quot;;
  } else {
    newColor = &quot;blue&quot;;
  }
  a.style.color = newColor;
}
a.addEventListener(&quot;click&quot;, handleClick);</code></pre>
<h2 id="🦖-getter와-setter">🦖 getter와 setter</h2>
<p>h1.style.color와 같이 h1의 color을 얻을 수 있는 것 등은 getter이고,
h1.style.color = &quot;blue&quot;; 와 같이 color를 변경해주는 것 등은 setter이다.</p>
<hr>
<h2 id="🦖-총정리">🦖 총정리</h2>
<blockquote>
<ol>
<li>element를 찾아라</li>
<li>event를 listen해라 </li>
<li>그 event에 반응하라 (무언가를 보여주거나, 감추거나, 색을 바꾸는 등) </li>
</ol>
</blockquote>
<hr>
<h2 id="🦖-javascript에서-변경하는-style">🦖 Javascript에서 변경하는 style</h2>
<p>위에서는 <code>JS</code>로 style을 변경했지만 사실은 <code>CSS</code>가 하는 것이 좋다. 
style 작업에 적합한 도구는 <code>CSS</code>이고, animation에 적합한 도구는 <code>Javascript</code>이다.</p>
<h2 id="🦖-html-파일에-css-import-하기">🦖 HTML 파일에 CSS import 하기</h2>
<p>head 안에서 title 태그를 작성하기 전에 아래와 같은 코드를 작성해주면 된다.</p>
<pre><code class="language-HTML">&lt;link rel=&quot;stylesheet&quot; href=&quot;CSS파일명.css&quot; /&gt;</code></pre>
<h2 id="🦖-위에서-했던-예시에서-style을-css에서-해주자">🦖 위에서 했던 예시에서 style을 CSS에서 해주자</h2>
<p><code>CSS</code></p>
<pre><code class="language-css">body {
  background-color: beige;
}

h1 {
  color: cornflowerblue;
}

.active { // active는 내가 작성한 클래스명임
  color: tomato;
}

</code></pre>
<p><code>JS</code></p>
<pre><code class="language-javascript">const h1 = document.querySelector(&quot;h1&quot;);

function handleClick() {
  const activeClass = &quot;active&quot;;
  if (h1.className === activeClass) {
    h1.className = &quot;&quot;;
  } else {
    h1.className = activeClass;
  }
}
h1.addEventListener(&quot;click&quot;, handleClick);</code></pre>
<p>하지만 이 코드의 문제점은 만약 기존에 다른 class명을 가지고 있었고 그 class명에 해당하는 CSS가 적용이 되어있었다면 className을 바꿈과 동시에 해당 CSS는 의미가 없어져버린다.</p>
<p>아래와 같은 경우이다.</p>
<p><code>html</code></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot; /&gt;
    &lt;title&gt;Document&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1 class=&quot;sexy-font&quot;&gt;Hello!&lt;/h1&gt; // h1에 기존의 class가 있음
    &lt;script src=&quot;app.js&quot;&gt;&lt;/script&gt; 
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p><code>CSS</code></p>
<pre><code class="language-css">body {
  background-color: beige;
}

h1 {
  color: cornflowerblue;
}

.active {
  color: tomato;
}

.sexy-font { // 이 부분 확인
  font-family: &quot;Courier New&quot;, Courier, monospace;
}
</code></pre>
<p>그렇기 때문에 className보다는 classList를 사용하는 것이 좋다.</p>
<p>classList는 우리가 class들의 목록으로 작업할 수 있도록 허용해준다.
아래와 같이 사용하면 된다.</p>
<pre><code class="language-javascript">const h1 = document.querySelector(&quot;h1&quot;);

function handleClick() {
  const activeClass = &quot;active&quot;;
  if (h1.classList.contains(activeClass)) { //classList가 active class를 포함하고 있는지 확인
    h1.classList.remove(activeClass);
  } else {
    h1.classList.add(activeClass);
  }
}
h1.addEventListener(&quot;click&quot;, handleClick);</code></pre>
<p>그런데 이 코드를 더욱 간단하게 할 수 있다.
위와 같은 일은 자주 발생하는 일이기 때문에 이것을 해결해줄 function이 개발되어 있다.
바로 toogle이다.</p>
<p>toogle 함수는 class name이 존재하는지 확인을 해준다. 만약 class name이 존재할 경우 해당 class name을 제거하고, 존재하지 않는다면 class name을 추가한다.</p>
<p>toogle 함수를 적용한 코드는 아래와 같다.</p>
<pre><code class="language-javascript">const h1 = document.querySelector(&quot;h1&quot;);

function handleClick() {
  h1.classList.toggle(&quot;active&quot;);
}
h1.addEventListener(&quot;click&quot;, handleClick);
</code></pre>
<p>toogle은 껐다 켰다 해주는 스위치같은 것이라고 생각하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 바닐라 JS로 크롬 앱 만들기 #2]]></title>
            <link>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BCJS</link>
            <guid>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BCJS</guid>
            <pubDate>Mon, 01 Aug 2022 14:56:01 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>노마드 코더의 <a href="https://nomadcoders.co/javascript-for-beginners/lobby">바닐라 JS로 크롬 앱 만들기</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🦖-브라우저에-내장되어있는-자바스크립트">🦖 브라우저에 내장되어있는 자바스크립트</h2>
<p>자바스크립트를 바로 다루고 싶다면 브라우저의 검사(insepct)의 console을 사용하면 된다. 자바스크립트는 브라우저에 이미 설치되어있기 때문에 그냥 console에서 사용하면 된다.</p>
<p>자바스크립트는 항상 브라우저에 상주하며 내가 어떤 코드를 입력하기를 기다리고 있다.</p>
<p>그러나 콘솔에서는 한줄만 작성할 수 있고 긴 프로그램 작성에는 유용하지 않기 때문에 자바스크립트 파일을 만드는 것이다. </p>
<h2 id="🦖-브라우저와-css-javascript">🦖 브라우저와 CSS, Javascript</h2>
<p><code>CSS</code>와 <code>JS</code> 파일 만들고 코드를 작성한 후 해당 파일을 브라우저에서 열면, 브라우저는 해당 코드를 실행하지 않고 그냥 작성한 코드를 보여주기만 해서 우리가 원하는 결과가 나오지 않는다. 이들은 파일을 연다고 실행되지 않는다. </p>
<p>이것은 <code>HTML</code>이 접착제 역할을 함으로써 해결할 수 있다. 즉 <code>CSS</code>와 <code>JS</code>는 <code>HTML</code> 없이는 우리가 원하는대로 동작될 수 없다는 것이다.</p>
<p>브라우저는 <strong><code>HTML</code>을 열어서 실행하고</strong>, <code>HTML</code> 파일이 <strong><code>CSS</code>와 <code>JS</code>를 가져오는 것</strong>이다.</p>
<h2 id="🦖-javascript-파일을-html에서-가져오기">🦖 Javascript 파일을 HTML에서 가져오기</h2>
<p>일반적으로, 자바스크립트 파일은 맨 위에서 가져오지 않고 주로 끝에서 한다.</p>
<p><code>HTML</code> body 태그의 끝에서 아래와 같이 적으면 된다.</p>
<pre><code class="language-html">&lt;body&gt;
  &lt;script src=&quot;파일명.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;</code></pre>
<h2 id="🦖-브라우저의-검사insect에서-html-css-js-확인하기">🦖 브라우저의 검사(insect)에서 HTMl, CSS, JS 확인하기</h2>
<p><code>HTML</code>은 Elements의 왼쪽 창에서, <code>CSS</code>는 오른쪽 창에서 확인할 수 있다.
<code>JS</code>는 Console 창에서 확인할 수 있다.</p>
<h2 id="🦖-콘솔에게-메세지를-보내는-js-코드">🦖 콘솔에게 메세지를 보내는 JS 코드</h2>
<pre><code class="language-javascript">console.log(545454);</code></pre>
<p>콘솔창은 545454를 출력한다. 즉 콘솔에 log 또는 print를 하는 것이다.</p>
<h2 id="🦖-변수-선언">🦖 변수 선언</h2>
<p><code>JS</code>에서는 변수 선언을 위해 const(상수), let을 사용한다.</p>
<pre><code class="language-javascript">const a = 5;
let b = 6;

console.log(a+2);
console.log(b*2);</code></pre>
<p>const는 값이 바뀔 수 없다. 즉 값을 절대 업데이트 할 수 없다.
반면 let은 값이 바뀔 수 있다. </p>
<p>둘중 더 디폴트로 사용하는 것은 const고 변수를 업데이트 해야하는 경우에만 let을 사용함</p>
<p>과거에는 const, let은 존재하지 않았고 var가 있었는데 var는 어떠한 규칙도 가지고 있기 않다. 그렇기 때문에 이것은 상수에 대한 보호가 안 되어서 잘 사용하지 않는다. var은 절대 쓰지 말 것!</p>
<h2 id="🦖-자바스크립트-변수명-컨벤션">🦖 자바스크립트 변수명 컨벤션</h2>
<p>카멜케이스로 작성한다.</p>
<pre><code class="language-Javascript">const veryLongVariableName = 0;</code></pre>
<p>추가) 파이썬에서는 스네이크케이스로 작성한다. </p>
<pre><code class="language-python">very_long_variable_name = 0</code></pre>
<h2 id="🦖-문자열-작성">🦖 문자열 작성</h2>
<p>자바스크립트 문자열 작성시 큰따옴표나 작은 따옴표 무엇을 쓰든 상관없다.</p>
<h2 id="🦖-boolean-데이터-타입">🦖 boolean 데이터 타입</h2>
<p>true, false로 나뉘어져있음.</p>
<pre><code class="language-javascript">const amIFat = true;</code></pre>
<p>참고) python은 true 대신 True, false 대신 False이다.</p>
<h2 id="🦖-null-데이터-타입">🦖 null 데이터 타입</h2>
<p>아무것도 없음을 의미. 그 변수에 아무것도 없음을 의미한다. </p>
<pre><code class="language-javascript">const amIFat = null;</code></pre>
<p>주의! false랑 헷갈리지 말 것. false는 false라는 값이 존재하는 것임.</p>
<p>null은 절대 자연적으로 발생하지 않는다. null은 우리가 변수 안에 어떤 것이 없다는 것을 확실하게 해주기 위해 사용하는 것이다. 자바스크립트에게 여기에는 값이 &quot;없다&quot;는 것을 알려주는 것이다.  </p>
<p>참고) python은 null 대신 None이다.</p>
<h2 id="🦖-undefined-데이터-타입">🦖 undefined 데이터 타입</h2>
<p>우리는 보통 variable을 만들면 값을 주지만, 만약 변수에 값을 주지 않고 콘솔 창에 출력하면 undefined라고 출력이 된다. 정의되어 있지 않다는 것이다.</p>
<pre><code class="language-javascript">let something;
console.log(someting);</code></pre>
<h2 id="🦖-null-vs-undefined">🦖 null vs. undefined</h2>
<p>undefined는 변수가 존재하는데, 값이 주어지지 않은 것이고
null은 변수가 존재하고, 값이 주어졌는데 그 값이 &quot;비어있음&quot;인 것이다.</p>
<h2 id="🦖-배열array">🦖 배열(array)</h2>
<p>데이터로 이루어진 리스트.
꼭 요소들의 데이터 타입이 동일하지 않아도 됨.</p>
<pre><code class="language-javascript">const daysOfWeek = [&quot;mon&quot;, &quot;tue&quot;, &quot;wed&quot;, &quot;thu&quot;, &quot;fri&quot;, &quot;sat&quot;];
const nonsense = [1, 2, &quot;hello&quot;, false, null, true, undefined];

console.log(daysOfWeek, nonsense);

// 값에 접근하기
console.log(daysOfWeek[2]);

// 값 추가하기
daysOfWeek.push(&quot;sun&quot;);</code></pre>
<p>만약 인덱스 범위를 넘어선 인덱스 값을 출력하면 undefined라고 나온다.</p>
<h2 id="🦖-객체objects">🦖 객체(Objects)</h2>
<pre><code class="language-javascript">// 객체 생성
const player = {
  name: &quot;nico&quot;,
  points: 10,
  fat: true,

}

// 객체 통으로 출력
console.log(player);

// 특정 속성값 출력
console.log(player.name);
console.log(player[&quot;name&quot;]); //동일

// 속성값 업데이트
player.fat = false;

// 속성값 추가
player.lastName = &quot;potato&quot;;
</code></pre>
<p>player가 object이고, player object 안의 name, points, fat이 property이다.</p>
<p>object 안에서는 = 대신에 : 를 사용한다.
그리고 하나의 property를 작성하고 다른 property를 작성하기 위해서는 ,(콤마)를 쓴다.</p>
<p>object의 property에 접근하기 위해서는 object명.property명 을 쓰면 된다.
이를 통해 console.log 또한 console이라는 object의 log라는 property를 사용하고 있음을 알 수 있다.</p>
<p>속성값을 업데이트하는 코드에서, 의문이 생길 수 있다. player 객체는 const이고 const는 수정할 수 없다고 했는데 어떻게 업데이트가 가능한 것일까?
사실 우리가 하는 것은 객체의 &quot;속성값&quot;을 업데이트하는 것이지 객체 자체를 업데이트하는 것은 아니기 때문에 오류가 생기지 않는다.
아래와 같이 객체 자체를 수정할 때는 오류가 발생한다.</p>
<pre><code class="language-javascript">player = false;</code></pre>
<p>const는 원래 object 타입이었는데 boolean으로 바꾸려고 하는 경우이다.</p>
<h2 id="🦖-리스트배열-vs-객체">🦖 리스트(배열) vs. 객체</h2>
<p>리스트는 모든 값이 같은 의미를 가진다. 만약 내가 한 주의 요일 리스트를 가진다면 그 리스트에 있는 모든 값들이 요일이라는 의미를 지닌다.</p>
<p>하지만 object(객체)에서는 객체 이름만으로는 무엇인지 알 수 없는 property들도 있다. 그래서 player.name, player.points, player.fat과 같이 속성이름으로 접근하는 것이다. </p>
<h2 id="🦖-함수function">🦖 함수(function)</h2>
<p>함수의 목적은 여러가지 일을 같은 코드로 하기 위해 사용한다.</p>
<pre><code class="language-javascript">function 함수명(변수명1, 변수명2, ...) {
  return 반환값;
}

const 함수반환값받을변수명 = 함수명(인수명1, 인수명2, ...);
</code></pre>
<p>함수가 받는 변수의 자료형 써줄 필요 없이 그냥 변수명만 써주면 됨.</p>
<p>만약 함수가 받는 변수는 1개로 해뒀는데 인수를 여러개 보낸다면 첫 번째 인수만 함수가 받는다.</p>
<p>함수가 받는 변수명은 함수 안에서만 사용 가능하다. 함수 밖에서 사용하면 정의되지 않은 변수명으로 인식된다.</p>
<hr>
<h2 id="🦖-object-안에-함수-넣기">🦖 Object 안에 함수 넣기</h2>
<pre><code class="language-javascript">const player = {
  name: &quot;nico&quot;,
  sayHello: function (otherPersonsName) {
    console.log(&quot;hello &quot; + otherPersonsName + &quot; nice to meet you&quot;);
  },
};

console.log(player.name);
player.sayHello(&quot;lynn&quot;);
</code></pre>
<h2 id="🦖-nan-자료형">🦖 NaN 자료형</h2>
<p>Not a Number</p>
<h2 id="🦖-prompt-함수">🦖 prompt 함수</h2>
<p>사용자에게 창을 띄울 수 있게 해주는 함수이다.
prompt는 2개의 argument(인자)를 받는데 하나는 string형인 message(문자), 다른 하나는 default이다.</p>
<p>사용자에게 message를 보여주고 값을 넣으라고 말해준다.</p>
<p>하지만 prompt는 사용자가 값을 입력할 때까지 <code>javascript</code> 코드를 일시정지 시킨다. 
또한 message가 별로 안 예쁘고 CSS를 적용시킬 수 없기 때문에 잘 사용하지 않는다.</p>
<p>사용자가 입력한 message를 반환해준다.</p>
<h2 id="🦖-변수의-자료형을-알려주는-코드">🦖 변수의 자료형을 알려주는 코드</h2>
<pre><code class="language-javascript">const age = 15;
console.log(typeof age);</code></pre>
<h2 id="🦖-string을-number로-바꿔주는-함수-parseint">🦖 string을 number로 바꿔주는 함수 parseInt</h2>
<pre><code class="language-javascript">const str = &quot;15&quot;;
console.log(typeof parseInt(str)); // string이 아닌 number가 출력된다.</code></pre>
<p>parseInt는 &quot;123&quot;과 같은 숫자로 된 문자열만 숫자로 바꿔줄 수 있다. 그래서 만약 &quot;hello&quot; 같은 문자로 된 문자열을 처리하면 결과값으로 NaN(Not a Number)을 반환한다.</p>
<h2 id="🦖-nan인지-아닌지-확인하는-함수-isnan">🦖 NaN인지 아닌지 확인하는 함수 isNaN</h2>
<p>boolean(true/false)을 return하여 number인지 아닌지 알려준다.</p>
<pre><code class="language-javascript">const age = parseInt(prompt(&quot;How old are you?&quot;));
console.log(isNaN(age));</code></pre>
<h2 id="🦖-연산자-와-">🦖 연산자 ===와 !==</h2>
<p>==은 값이 같은지 비교하는 연산자이고, ===은 값과 유형까지도 비교하는 연산자이다.
주로 ===을 사용하는 것을 추천한다.</p>
<p>not도 마찬가지이다. !=은 값만 비교, !==은 값과 유형까지도 비교한다.</p>
<h2 id="🦖-조건문">🦖 조건문</h2>
<pre><code class="language-javascript">if(조건) {
  //조건문이 true일 경우 이 코드블록 실행
} else {
  //조건문이 false일 경우 이 코드블록 실행
}</code></pre>
<pre><code class="language-javascript">if(조건1) {
  // 조건1이 true일 경우 이 코드블록 실행
} else if(조건2) {
  // 조건1이 false이고 조건2가 true일 경우 이 코드블록 실행
}</code></pre>
<p>if에 들어가는 조건(condition)은 boolean으로 판별 가능해야 한다.</p>
<p>예를 들어보자.</p>
<pre><code class="language-javascript">const age = parseInt(prompt(&quot;How old are you?&quot;));

if (isNaN(age) || age &lt; 0) {
  console.log(&quot;Please write a real positive number&quot;);
} else if (age &lt; 18) {
  console.log(&quot;You are too young.&quot;);
} else if (age &lt;= 50) {
  console.log(&quot;You can drink&quot;);
} else if (age &lt;= 80) {
  console.log(&quot;You should exercise&quot;);
} else {
  console.log(&quot;You can do whatever you want.&quot;);
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 바닐라 JS로 크롬 앱 만들기 #1]]></title>
            <link>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</link>
            <guid>https://velog.io/@cse_pebb/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EB%B0%94%EB%8B%90%EB%9D%BC-JS%EB%A1%9C-%ED%81%AC%EB%A1%AC-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</guid>
            <pubDate>Mon, 01 Aug 2022 07:08:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>노마드 코더의 <a href="https://nomadcoders.co/javascript-for-beginners/lobby">바닐라 JS로 크롬 앱 만들기</a> 강의를 듣고 내용을 정리합니다.</p>
</blockquote>
<hr>
<h2 id="🦖-프로그래밍-언어-자바-스크립트">🦖 프로그래밍 언어 자바 스크립트</h2>
<p>프론트엔드에서는 자바스크립트가 쓸 수 있는 유일한 프로그래밍 언어이기 때문에 다른 프로그래밍 언어들은 필요가 없다.</p>
<p>기억하자! <strong>자바스크립트가 프론트엔드에 쓸 수 있는 유일한 프로그래밍 언어</strong>이다! 그래서 프론트엔드 개발자는 다른 선택지가 없다. 다르게 생각하면 프론트엔드에서는 언어를 자바 스크립트 하나만 배우면 된다는 것이다.</p>
<p>자바스크립트는 세계 모든 컴퓨터에서 사용할 수 있다. 자바스크립트는 모든 브라우저에 내장되어있기 때문이다. 그래서 따로 자바 스크립트를 설치해줄 필요가 없다.</p>
<h2 id="🦖-프레임워크">🦖 프레임워크</h2>
<p>자바스크립트 기술을 좀 더 다듬어서 더 깊에 배우고 싶으면 프레임워크를 공부하면 된다.</p>
<p>프레임워크는 내가 하려는 일을 도와주는 도우미같은 것이다.</p>
<p>그 중 하나가 바로 리액트 네이티브이다. 리액트 네이티브는 자바스크립트 만으로 안드로이드와 iOS 앱을 만들 수 있게 해준다. </p>
<p>그 다음으로는 일렉트론이 있다. 일렉트론은 <code>HTML</code>, <code>CSS</code>, <code>JS</code>로 데스크탑 앱을 만들 수 있게 해준다. </p>
<h2 id="🦖-자바스크립트의-다양한-용도">🦖 자바스크립트의 다양한 용도</h2>
<h3 id="백엔드">백엔드</h3>
<p>전에는 불가능했지만 이제는 자바스크립트로 백엔드도 가능하다. </p>
<p>프론트엔드와 백엔드 모두 자바스크립트로 만들 수 있는 것이다.</p>
<h3 id="3d">3D</h3>
<p>자바스크립트 3D로 무언가를 하기에 아주 완벽한 프로그래밍 언어이다. </p>
<p>예를 들어 실시간 채팅방을 만들고 싶다면 자바스크립트가 딱이다. </p>
<h3 id="머신러닝">머신러닝</h3>
<p><code>ml5.js</code>를 쓰면 머신러닝 모델을 생성하는 웹사이트를 구축해서 그 모델을 훈련시킬 수도 있다. </p>
<h2 id="🦖-replit">🦖 replit</h2>
<p><a href="https://replit.com/">replit</a>은 브라우저에서 무엇이든 코딩을 가능하게 해준다. 현존하는 대부분의 언어들로 프로그래밍 할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[C++] vector의 값 지우기 
- remove() 함수 vs. vector의 erase() 함수]]></title>
            <link>https://velog.io/@cse_pebb/C-remove-%ED%95%A8%EC%88%98-vs.-vector%EC%9D%98-erase-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@cse_pebb/C-remove-%ED%95%A8%EC%88%98-vs.-vector%EC%9D%98-erase-%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 03 Apr 2022 16:36:13 GMT</pubDate>
            <description><![CDATA[<h2 id="💻-remove-함수와-erase-함수-비교하기">💻 remove() 함수와 erase() 함수 비교하기</h2>
<h3 id="✏️-선언해주어야-하는-헤더">✏️ 선언해주어야 하는 헤더</h3>
<p><code>remove</code> 함수는 <code>algorithm</code> 헤더를 선언해주어야 한다.</p>
<p><code>erase</code> 함수는 <code>vector</code>의 함수들 중 하나이기 때문에, <code>vector</code> 헤더를 선언해주어야 한다.</p>
<h3 id="✏️-기본-형태">✏️ 기본 형태</h3>
<h4 id="remove-함수의-기본-형태">remove 함수의 기본 형태</h4>
<pre><code class="language-cpp">remove(first, last, 삭제하려는 값); // 범위는 [first,last)</code></pre>
<p><code>remove</code> 함수는 특정 범위를 탐색하여 그 범위에 있는 특정 값을 삭제할 수 있다.</p>
<h4 id="erase-함수의-기본-형태">erase 함수의 기본 형태</h4>
<pre><code class="language-cpp">// vector의 이름이 v라고 가정

// 1
v.erase(first, last); // 범위는 [first,last)

// 2
v.erase(삭제하려는 값의 위치);
</code></pre>
<p><code>erase</code> 함수는 특정 범위에 속하는 모든 값들을 삭제하거나(해당 범위에서의 특정 값은 삭제 불가능), 특정 값의 위치를 보내면 해당 값을 삭제할 수 있다</p>
<h4 id="두-함수의-공통점">두 함수의 공통점</h4>
<p>둘 다 <code>first</code>와 <code>last</code>에 포함되는 범위가 <code>[first, last)</code>이다. <strong><code>last</code>는 범위에 포함되지 않는다</strong>는 것을 기억하자!</p>
<p>그리고 두 함수 모두 <strong>맨 끝 범위</strong>에 위치한 값은 <strong>삭제할 수 없다</strong>!
ex) 1 2 3 4 5 가 있을 때, 범위가 1<del>5라면 5는 삭제할 수 없다. 만약 범위가 1</del>3까지라면 3은 삭제할 수 없다.</p>
<h4 id="두-함수의-차이점">두 함수의 차이점</h4>
<p><code>remove</code> 함수는 아예 <strong>특정 값</strong>을 인자로 보내어 해당 값을 삭제할 수 있고, 이 때 특정 범위를 탐색하여 <strong>삭제하려는 값을 찾아내어</strong> 삭제할 수 있다.</p>
<p>반면 <code>erase</code> 함수의 경우 특정 값을 삭제하려면 <strong>해당 값의 위치</strong>를 인자로 보내야 삭제할 수 있고, 범위 내에서 특정 값을 찾아내는 것은 불가능하다. 범위가 주어지면 <strong>그 범위의 모든 값들을 삭제하는 것만</strong> 가능하다. </p>
<h3 id="✏️-두-함수의-반환값">✏️ 두 함수의 반환값</h3>
<h4 id="remove-함수의-반환값">remove 함수의 반환값</h4>
<p><code>remove</code> 함수는 <strong>주어진 범위</strong>( [first, last) - last는 미포함 ) 중에서 <strong>삭제되지 않은 가장 마지막 값</strong>의 <strong>새로운 위치에서 바로 뒤</strong>에 있는 위치의 <code>iterator</code>를 반환해준다. </p>
<p>예를 들어 1 2 3 2 2 4 라는 <code>vector</code>의 전체 범위 중에서 2를 <code>remove</code>하면 1 3 4 ... 가 되는데, 1 3 4 ... 에서 4 바로 뒤 위치의 <code>iterator</code>를 반환해준다는 것이다.</p>
<p>또 예를 들어 1 2 2 3 4 5 라는 <code>vector</code>의 범위를 2 2 3 이라고 하고 2를 <code>remove</code>하면 1 3 4 5 ... 가 되는데(실제로는 아니다. 이에 대한 내용은 뒤에 나오는 각 함수의 특징에 대한 설명에 나와있다), <strong>범위 내에서</strong> 삭제되지 않은 마지막 값인 3의 바로 뒤 위치 <code>iterator</code>를 반환해준다는 것이다. </p>
<h4 id="earse-함수의-반환값">earse 함수의 반환값</h4>
<p><code>erase</code> 함수는 범위와 상관없이 <strong>마지막으로 지워진 값</strong>의 위치에서 <strong>바로 뒤에 있던 값</strong>의 새로운 위치의 <code>iterator</code>를 반환해준다.  </p>
<p>예를 들어 1 2 3 4 5 6 7 이라는 <code>vector</code>의 범위를 2 3 4라고 하고 <code>erase</code>하면 2 3 4가 모두 지워지고 1 5 6 7 ... 이 된다(실제로는 아니다. 이에 대한 내용은 뒤에 나오는 각 함수의 특징에 대한 설명에 나와있다). 이 때 기존의 <code>vector</code>에서 가장 마지막에 지워진 4 바로 뒤에 있던 값이 5이므로, 1 5 6 7 ... 에 있는 새로운 5의 위치 <code>iterator</code>를 반환해준다는 것이다.</p>
<h4 id="두-함수의-차이점-1">두 함수의 차이점</h4>
<p>결국 <code>erase</code> 함수보다는, 삭제하고 남은 값들 중 가장 마지막 값의 바로 뒤를 가리키게 되는 <strong><code>remove</code> 함수의 <code>return</code> 값이 더 쓸모있고 의미있어 보인다</strong>.  </p>
<h3 id="✏️-각-함수의-특징">✏️ 각 함수의 특징</h3>
<h4 id="remove-함수의-특징">remove 함수의 특징</h4>
<p><code>remove</code> 함수를 통해 <code>vector</code>의 특정 값을 삭제한다고 할 때, 해당 값이 삭제가 되어 그만큼 <code>vector</code>의 사이즈가 줄어드는 것이 아니라, <strong>삭제된 값이 다른 값으로 대체</strong>된다. 이 때 대체되어 들어가는 값은 <strong>주어진 범위에서 가장 뒤쪽에 있는 값(들)</strong>이 들어간다.</p>
<p>❗ 주의할 점은 그렇다고 해서 <strong>삭제된 값이 있던 위치</strong>에 그대로 대체되는 값이 들어가는 것이 아니라, <strong>인자로 주었던 범위의 맨 뒤에 들어가게 된다</strong>. </p>
<p>예를 들어 <code>vector</code>에 1 2 3 4 5 가 들어있고 전체 범위에서 2를 삭제한다고 할 때, 2가 1개 삭제되므로 1 3 4 5 뒤에 5(가장 뒤쪽에 있는 값 1개)만 들어가는 것이다. 즉 1 3 4 5 5 가 된다.
또 <code>vector</code>에 1 2 2 2 3 4 가 들어있고 전체 범위에서 2를 삭제한다고 할 때, 2가 3개 삭제되므로 1 3 4 뒤에 2 3 4(가장 뒤쪽에 있는 값 3개)가 들어가는 것이다. 즉 1 3 4 2 3 4 가 된다.
또한 <code>vector</code>에 1 2 2 3 4 가 들어있고 범위가 2 2 3 일 때 2를 삭제하면, 2가 2개 삭제되므로 1 3 4 가 되고 범위의 맨 뒤는 3이었으므로 3의 뒤에 대체값이 붙는다. 이 때 대체값은 주어진 범위에서 가장 뒤쪽에 있는 값 2개이므로 2 3 이 된다. 결국 1 3 4 에서 3 뒤에 2 3 이 붙게 되어 1 3 2 3 4 가 된다.</p>
<p><code>vector</code>의 특성상 값이 삭제되면 그 <strong>삭제된 공간 만큼 앞으로 당겨진다</strong>. 그러나 앞에서 말했듯 삭제된 값은 다른 값으로 대체되기 때문에, <strong><code>vector</code>의 <code>size</code>나 <code>capacity</code>는 줄어들지 않고 그대로</strong>이다.</p>
<p>예시로 확인해보자.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt; 
#include &lt;vector&gt;
#include &lt;algorithm&gt;

using namespace std;

int main() {
    vector&lt;int&gt; v;
    // v에 값 0~4 값 넣어주기 
    for (int i=0; i&lt;5; i++) {
        v.push_back(i);
    }

    // 삭제 전 vector 값들, size, capacity 출력 
    cout &lt;&lt; &quot;삭제 전 vector 값들 : &quot;;
    for (int i=0; i&lt;5; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;확인을 위해 뒤의 값들 추가로 출력 : &quot;;
    for (int i=5; i&lt;10; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;size : &quot; &lt;&lt; v.size() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;capacity : &quot; &lt;&lt; v.capacity() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;============\n&quot;;

    // 삭제 : 0~4(처음부터 끝) 값 중 1 없애기 
    remove(v.begin(), v.end(), 1);

    // 삭제 후 vector 값들, size, capacity 출력 
    cout &lt;&lt; &quot;삭제 후 vector 값들 : &quot;;
    for (int i=0; i&lt;5; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;확인을 위해 뒤의 값들 추가로 출력 : &quot;;
    for (int i=5; i&lt;10; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;size : &quot; &lt;&lt; v.size() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;capacity : &quot; &lt;&lt; v.capacity() &lt;&lt; &quot;\n&quot;;

    return 0;
}</code></pre>
<p><img src="https://media.vlpt.us/images/cse_pebb/post/5905f6dd-4f69-4deb-bc5b-8a4b5c6bf30f/image.png" alt=""> 결과를 보면 1이 정상적으로 삭제되고 앞으로 한칸 당겨졌지만 표시한 흰색 네모의 위치, 즉 범위의 맨 끝 위치에 대체값이 들어갔음을 확인할 수 있다. 그에 따라 <code>size</code>와 <code>capacity</code>도 변함이 없음도 확인할 수 있다.</p>
<h4 id="erase-함수의-특징">erase 함수의 특징</h4>
<p><code>erase</code> 함수를 통해 <code>vector</code>의 특정 값을 삭제한다고 할 때, 해당 값이 삭제가 되고 <strong>그만큼 <code>vector</code>의 <code>size</code>가 줄어든다</strong>. </p>
<p>해당 값이 지워지면 <code>container</code>가 모든 요소를 새 위치로 재배치한다. 그렇기 때문에 <code>size</code>는 줄어도, <code>capacity</code>는 줄어들지 않는다.</p>
<p>예시로 확인해보자.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt; 
#include &lt;vector&gt;

using namespace std;

int main() {
    vector&lt;int&gt; v;
    // v에 값 0~4 값 넣어주기 
    for (int i=0; i&lt;5; i++) {
        v.push_back(i);
    }

    // 삭제 전 vector 값들, size, capacity 출력 
    cout &lt;&lt; &quot;삭제 전 vector 값들 : &quot;;
    for (int i=0; i&lt;5; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;확인을 위해 뒤의 값들 추가로 출력 : &quot;;
    for (int i=5; i&lt;10; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;size : &quot; &lt;&lt; v.size() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;capacity : &quot; &lt;&lt; v.capacity() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;============\n&quot;;

    // 0~4(처음부터 끝) 값 중 1 없애기 
    v.erase(v.begin()+1,v.begin()+2); 
    // 범위 설명 : 1번 인덱스 ~ 2번 인덱스 전 -&gt; 즉 1번 인덱스 값 하나만 해당 

    // 삭제 후 vector 값들, size, capacity 출력 
    cout &lt;&lt; &quot;삭제 후 vector 값들 : &quot;;
    for (int i=0; i&lt;4; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;확인을 위해 뒤의 값들 추가로 출력 : &quot;;
    for (int i=4; i&lt;9; i++) {
        cout &lt;&lt; v[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; &quot;\n&quot;;    
    cout &lt;&lt; &quot;size : &quot; &lt;&lt; v.size() &lt;&lt; &quot;\n&quot;;
    cout &lt;&lt; &quot;capacity : &quot; &lt;&lt; v.capacity() &lt;&lt; &quot;\n&quot;;

    return 0;
}</code></pre>
<p><img src="https://media.vlpt.us/images/cse_pebb/post/aded2ab7-ab20-4a97-bd49-86db17acd169/image.png" alt=""></p>
<p>결과를 보면 1이 정상적으로 삭제되고 앞으로 한칸 당겨졌으며, <code>size</code> 또한 삭제된 만큼 줄었음을 확인할 수 있다. 
다만 표시한 흰색 밑줄을 보면, 값이 재할당되어 있다. 그에 따라 <code>capacity</code>는 변함이 없음을 확인할 수 있다.</p>
<h4 id="두-함수-비교">두 함수 비교</h4>
<p>두 함수 모두 값을 삭제하면 <strong>삭제한 공간만큼 앞으로 당겨지고</strong>, 값을 삭제를 해도 <strong><code>capacity</code>는 유지</strong>된다는 것이 공통점이다.</p>
<p>그러나 <code>remove</code> 함수는 <strong><code>size</code> 또한 그대로</strong>인 반면, <code>erase</code> 함수는 <strong><code>size</code>가 삭제된 값의 개수만큼 줄어든다</strong>.</p>
<h3 id="✏️-각-함수의-주요-장단점-정리">✏️ 각 함수의 주요 장/단점 정리</h3>
<p><code>remove</code> 함수는 값을 삭제해도 <code>size</code>가 줄어들지 않는다는 단점이 있다. 
하지만 <code>return</code> 값이 남은 값들 중 마지막 값의 바로 뒤를 가리킨다는 장점이 있다.</p>
<p><code>erase</code> 함수는 <code>return</code> 값이 의미가 없다는 단점이 있다. 
하지만 함수의 값을 삭제하면 <code>size</code>가 줄어든다는 장점이 있다. </p>
<hr>
<h2 id="💻-remove-함수와-erase-함수를-함께-사용하여-vector의-값-쉽게-지우기">💻 remove() 함수와 erase() 함수를 함께 사용하여 vector의 값 쉽게 지우기</h2>
<p>앞서 말한 <code>remove</code> 함수와 <code>erase</code> 함수의 단점을 보완하려면, <strong>두 함수의 장점만을 취해서 함께 사용</strong>해주면 된다. </p>
<p>우선 코드를 보자.</p>
<pre><code class="language-cpp">// vector의 이름이 v라고 가정

v.erase(remove(first, last, 삭제하려는 값),last);</code></pre>
<p>이 코드를 보면, <code>remove</code> 함수를 먼저 수행하고 그 결과를 <code>erase</code> 함수의 시작범위로 사용하고 있음을 알 수 있다. 즉, <strong><code>remove</code> 함수의 <code>return</code> 값이 <code>erase</code> 함수의 시작범위가 되는 것</strong>이다.</p>
<p>그런데 <code>remove</code> 함수의 <code>return</code> 값은 삭제되지 않은 가장 마지막 값의 새로운 위치에서 바로 뒤에 있는 위치의 <code>iterator</code>를 반환해주기 때문에, 결국 범위 내에서 삭제하고 싶지 않은 값들은 냅두고, 그 값들의 바로 뒤부터가 <code>erase</code> 함수의 시작 범위가 된다. </p>
<p>삭제하고 싶지 않은 값들을 <code>erase</code> 해버리면 안되므로 그 뒤부터 <code>erase</code> 하도록 <code>remove</code>의 <code>return</code> 값을 <code>erase</code> 함수의 시작 범위에 넣어준 것이고, 이것이 바로 <strong><code>remove</code> 함수의 장점을 이용한 것</strong>이다. </p>
<p>그러나 <code>remove</code> 함수에서 삭제하고 싶지 않은 값들 바로 뒤에, 삭제한 값의 <strong>대체값</strong>들이 생긴다. 이 대체값들로 인해 <code>remove</code> 함수가 <code>size</code>가 줄지 않는다는 단점이 생긴 것이다. 이 쓸모없는 대체값들을 없애주면서 <code>size</code> 또한 그만큼 줄여주어야 한다. </p>
<p>그것을 해주는 것이 바로 <code>erase</code> 함수이다. <code>erase</code> 함수가 삭제하고 싶지 않은 값들의 바로 뒤부터, 즉 대체값들의 시작 범위부터 시작하여 대체값들의 끝 범위까지 <strong>값을 삭제해주고 <code>size</code> 또한 줄여준다</strong>. 이것이 바로 <strong><code>erase</code> 함수의 장점</strong>을 이용한 것이다.</p>
<hr>
<h2 id="💻-결론">💻 결론</h2>
<p><code>vector</code>의 특정 범위를 지정하여 해당 범위에 있는 특정 값을 지우고 싶을 때는 아래의 코드를 작성하면 된다. </p>
<pre><code class="language-cpp">// vector의 이름이 v라고 가정

v.erase(remove(first, last, 삭제하려는 값),last);</code></pre>
<p>만약 범위를 <code>vector</code>의 전체로 설정하고 싶다면, 아래와 같이 작성하면 된다.</p>
<pre><code class="language-cpp">// vector의 이름이 v라고 가정

v.erase(remove(v.begin(), v.end(), 삭제하려는 값),v.end());</code></pre>
<hr>
<h2 id="💻-참고-링크">💻 참고 링크</h2>
<p>C++ 공식 문서 - <a href="http://www.cplusplus.com/reference/algorithm/remove/?kw=remove">remove</a>, <a href="http://www.cplusplus.com/reference/vector/vector/erase/">erase</a>
<a href="https://openmynotepad.tistory.com/80">참고 블로그</a></p>
]]></description>
        </item>
    </channel>
</rss>