<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>devcdd.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 29 Jan 2024 05:59:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>devcdd.log</title>
            <url>https://velog.velcdn.com/images/dev_cdd/profile/aa381d7c-3f16-4571-bc09-046fe7d630e0/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. devcdd.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_cdd" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React.FC 자체를 props로 넘기는 방법]]></title>
            <link>https://velog.io/@dev_cdd/React.FC-%EC%9E%90%EC%B2%B4%EB%A5%BC-props%EB%A1%9C-%EB%84%98%EA%B8%B0%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dev_cdd/React.FC-%EC%9E%90%EC%B2%B4%EB%A5%BC-props%EB%A1%9C-%EB%84%98%EA%B8%B0%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 29 Jan 2024 05:59:45 GMT</pubDate>
            <description><![CDATA[<h2 id="고민을-하게-된-계기">고민을 하게 된 계기</h2>
<h3 id="서론">서론</h3>
<p>본격적으로 회사에서 프론트 개발을 한지 4개월 차가 넘어가는데, 아직도 <code>React.js</code>에 대한 구조적 고민은 계속해서 하게 되는 것 같다. 이번에 제목과 같은 고민을 하게 된 이유는 아이콘을 렌더링하는 컴포넌트에서 동적으로 아이콘을 받아 넣고 싶은 상황이었는데, 아이콘을 <code>React.FC</code>와 같은 형태로 관리하다보니 <code>props</code>에 꽤나 부담을 주는 것은 아닐까라는 생각이 들었다.</p>
<pre><code class="language-ts">const Section = (props: SectionProps) =&gt; {
  return (
    &lt;Link
      className={cn(props.className || &quot;&quot;, &quot;h-full&quot;)}
      href={props.redirectURL}
    &gt;
      &lt;div className={&quot;flex flex-col justify-center items-center gap-8 &quot;}&gt;
        {/* 여기에 아이콘을 넣고 싶음 */}
        &lt;div className={cn(&quot;h-full flex justify-center items-center&quot;)}&gt;
          {props.message}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/Link&gt;
  );
};</code></pre>
<h3 id="how-do-you-think-gpt">How Do you think, GPT?</h3>
<blockquote>
</blockquote>
<p>리액트에서 컴포넌트 자체를 props로 전달하는 것은 특별한 경우에 사용될 수 있습니다. 이는 일반적으로 고급 사용 사례 중 하나이며, 주의를 기울여야 합니다. 일반적으로 컴포넌트는 데이터(props)를 통해 정보를 전달받고, 해당 데이터를 기반으로 렌더링을 수행합니다. 그러나 때로는 컴포넌트 자체를 다른 컴포넌트에게 전달하고, 해당 컴포넌트를 그 자체로 사용하거나 조작하는 경우가 있을 수 있습니다. 예를 들어, 고차 컴포넌트(Higher-Order Component)나 래더 함수(Render Prop)를 사용하여 특정 로직이나 상태를 재사용하고 싶을 때, 컴포넌트 자체를 props로 전달할 수 있습니다.</p>
<p>여기서 주의점은 <code>props</code>로 받아온 컴포넌트를 실사용하는 상황에서는 특정 로직이나 상태를 재사용하기 어렵다는 것을 의미하는 듯하다. 내가 걱정했던 부분은 무거운 컴포넌트를 <code>props</code>로 넘겨주었을 때의 문제였는데, 예상 밖의 답이 나왔다.</p>
<h3 id="props에-대한-생각의-변화">props에 대한 생각의 변화</h3>
<h4 id="🥚-props를-잘-활용하면-모든-컴포넌트가-이어질-수-있다-그러므로-사용법을-익히자">🥚 props를 잘 활용하면 모든 컴포넌트가 이어질 수 있다. 그러므로 사용법을 익히자.</h4>
<p>리액트를 처음 배웠을 때 <code>props</code>라는 개념이 되게 신기했다. 서로 다른 파일 간에 <code>props</code>를 활용하여 데이터를 전달할 수 있다는 사실을 알게 된 이후부터는 그 어떤 웹사이트도 만들 수 있을 것 같았다. 바닐라로 개발할 때 겪었던 답답한 점이 해결되기도 했고 말이다.</p>
<h4 id="🐣-상태관리-라이브러리를-사용하면-props를-안써도-된다고-props-drilling을-방지할-수-있다고">🐣 상태관리 라이브러리를 사용하면 props를 안써도 된다고? props drilling을 방지할 수 있다고?</h4>
<p>리액트를 좀 더 사용해보면서 느꼈던 문제점은 <code>props</code>를 타고, 타고 들어가는 경우가 많아 계속해서 선언을 해줘야 한다는 점이었다. 그리고 중간의 특정 컴포넌트가 해당 데이터를 사용하지 않는 경우가 있다고 하더라도 계속해서 다음 <code>props</code>로 넘겨줘야 하는 경우도 있었다. 그때 알게되었던 <code>Redux, Recoil</code> 등의 상태 변화 라이브러리들은 이러한 고민에서 해방시켜주었고, 딱 원하는 컴포넌트에서 아름다운 사용을 도와주었다. 이 당시에 <code>props</code>로 관리하기 귀찮은 데이터들은 모두 상태관리 라이브러리로 뺐던 것 같다.</p>
<p>하지만 이 생각은 오래가지 못했다. 상태가 너무 많아지니 오히려 상태선언 코드들이 무지하게 많아지고, 코드를 작성하는 상황에서 이게 어느 스코프 상에서 존재하는 상태인지도 한눈에 알아보기가 힘들었다. 더구나 전역으로 값을 관리한다는 말은 전역 변수를 사용하는 것과 동일한데, 그렇기에 크기가 큰 데이터를 전역에다가 올려두는 것이 좋은 방법일 것 같진 않았다. 그래서 이 시점에서는 <code>props</code>와 <code>state</code>를 적절히 묶는 방법을 여러번 고민했었다.</p>
<h4 id="🐥-atomic-design을-사용하고-있으니-효율적인-props의-사용법에-대해-고민해보자">🐥 Atomic Design을 사용하고 있으니, 효율적인 props의 사용법에 대해 고민해보자.</h4>
<p>사이드 프로젝트를 하면서 디자인 패턴을 적용하고 싶은 욕심이 생겼다. 제일 눈에 들어온 게 <code>Atomic</code>이고, 재사용성을 위해 <code>props</code>를 제법 많이 사용하게 되었다. 여기서 느꼈던 문제점은 렌더링 방식 자체를 분기처리 하는 것이 힘들다는 것이었다. 개발 잘하는 친구들에게 물어보니 애초에 분기처리를 해서 특정 컴포넌트를 렌더한다는 것 자체가 애초에 잘못된 추상화이고, <code>animal</code>이라는 클래스에 개가 짖는 방식, 닭이 우는 방식 등이 다 담겨져있는 것 같다는 말을 하더라 🥲.</p>
<pre><code class="language-ts">{props.type === &quot;artists&quot; &amp;&amp; (
          &lt;ArtistPostModal
            open={postModalStatus}
            setOpen={setPostModalStatus}
          /&gt;
        )}
        {props.type === &quot;albums&quot; &amp;&amp; (
          &lt;AlbumPostModal open={postModalStatus} setOpen={setPostModalStatus} /&gt;
        )}</code></pre>
<p>이때 좀 추상화에 개념에 대해 흥미가 생기기 시작했다. 코드를 보면서 설명하는 것이 좋을 것 같은데, 현재 구조에 대해서 간단하게 설명하자면 <strong>아티스트, 앨범</strong>을 관리하는 컴포넌트를 하나로 통합해서 관리하고자 했다. 그래서 상위에서 type을 던져주고, 받는 입장에서는 타입을 보고 다른 <code>Modal</code>을 렌더하도록 말이다. 하지만 이렇게 코드를 짜게 된다면 계속해서 통합 컴포넌트의 크기만 커질 것이고, <strong>아티스트</strong> 파트를 수정하다가 <strong>앨범</strong> 파트 쪽에 문제가 생길 확률도 높아보였다.</p>
<p>이전에는 이런식으로 하위 컴포넌트 입장에서 렌더링을 했다면 지금은 방식을 바꿔 상위 컴포넌트를 활용하기로 했다.</p>
<pre><code class="language-ts">const handleModifyModalOpen = (artist: ArtistImageGridType) =&gt; {
    setDetailId(artist.id);

    if (artist.artistType === &quot;SOLO&quot;) {
      setArtistModifyModalOpen(true);
      return;
    }
    if (artist.artistType === &quot;GROUP&quot;) {
      setGroupModifyModalOpen(true);
      return;
    }
  };

  return (
    &lt;&gt;
      &lt;Management&lt;ArtistImageGridType&gt;
        label={&quot;아티스트&quot;}
        type={&quot;artists&quot;}
        handlePostModalOpen={handlePostModalOpen}
        handleModifyModalOpen={handleModifyModalOpen}
        fetch={getArtist}
        search={searchArtist}
        // detail={getArtistDetail}
      /&gt;
      &lt;ArtistPostModal open={postModalOpen} setOpen={setPostModalOpen} /&gt;
      &lt;ArtistModifyModal
        id={detailId}
        open={artistModifyModalOpen}
        setOpen={setArtistModifyModalOpen}
      /&gt;
      &lt;GroupModifyModal
        id={detailId}
        open={groupModifyModalOpen}
        setOpen={setGroupModifyModalOpen}
      /&gt;
    &lt;/&gt;
  );</code></pre>
<p>이렇게 해주니 <code>Management</code> 컴포넌트의 무게가 가벼워졌고, 재사용성도 높아진 것을 확인할 수 있었다. 모달과 관련된 로직들은 상위에 묶여있으니 하위 컴포넌트에서는 깔끔하게 <code>props</code>로 받아온 <code>setModalOpen</code> 함수만 호출해주면 되는 것이다. 이 타이밍에서 문뜩 고민이 하나 들었는데, &#39;컴포넌트 자체를 하위로 넘겨줄 수 있으면 하위 컴포넌트에서 <code>id</code> 값을 관리하고 편하게 모달을 오픈할 수 있지 않을까?&#39; 라는 생각이 들었다.</p>
<p>사실 이 경우는 <strong>아티스트</strong>와 <strong>그룹</strong> 간의 모달 개수와 형식이 너무 달라서 적용하기 힘들었던 개념이긴 한데, 새롭게 이것이 필요한 상황이 생겨났다. 그리고 이 경우가 바로 처음에 봤던 이 코드이다.</p>
<pre><code class="language-ts">const Section = (props: SectionProps) =&gt; {
  return (
    &lt;Link
      className={cn(props.className || &quot;&quot;, &quot;h-full&quot;)}
      href={props.redirectURL}
    &gt;
      &lt;div className={&quot;flex flex-col justify-center items-center gap-8 &quot;}&gt;
        {/* 여기에 아이콘을 넣고 싶음 */}
        &lt;div className={cn(&quot;h-full flex justify-center items-center&quot;)}&gt;
          {props.message}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/Link&gt;
  );
};</code></pre>
<p>단순히 머릿 속에서 떠오르는 해결책들이 몇가지 있었는데, 아래 코드와 같다.</p>
<pre><code class="language-ts">// 상위 컴포넌트 호출 방식
&lt;하위컴포넌트 icon={&lt;아이콘컴포넌트 /&gt;} /&gt;

// 하위 컴포넌트 수신 방식
interface 하위컴포넌트props {
  ...
  icon: React.FC // Node, ComponentType 등이 들어갈수도 있을 것 같음
}</code></pre>
<p>위와 같은 방식으로 하면 아이콘 컴포넌트의 <code>props</code>를 상위 컴포넌트에서 선언해야 하기 때문에 개인적인 불편함이 있었다. 그래서 두 번째 방법은 <code>props</code>로 받는 아이콘의 타입을 <code>React.FC</code>로 사용하고, <code>icon={아이콘컴포넌트}</code>와 같은 방식으로 사용하는 것이었다. <code>&lt;&gt;</code>을 상위에서 사용하느냐, 하위에서 사용하느냐의 차이인 것 같은데, 상위에서 사용한다면 하위에서는 <code>{props.icon}</code> 이렇게만 적어줘도 되고, 상위에서 사용하지 않을 땐 <code>&lt;props.icon className=&quot;...&quot; /&gt;</code> 이런 식으로 사용해줘야 한다.</p>
<pre><code class="language-ts">// 상위 컴포넌트 렌더 파트

&lt;Section
![](https://velog.velcdn.com/images/dev_cdd/post/ae96161d-9fd5-4588-93c6-bd337ed8b294/image.png)
        icon={UsersIcon}
        className={&quot;w-[50%]&quot;}
        message={&quot;아티스트 관리&quot;}
        redirectURL={&quot;/admin/artist&quot;}
      /&gt;

// 하위 컴포넌트 렌더 파트

import Link from &quot;next/link&quot;;
import { cn } from &quot;@/lib/utils&quot;;
import React, { ComponentType } from &quot;react&quot;;

interface SectionProps {
  className?: string;
  icon: React.FC&lt;{ className: string }&gt;;
  message: string;
  redirectURL: string;
}

const Section = (props: SectionProps) =&gt; {
  return (
    &lt;Link
      className={cn(props.className || &quot;&quot;, &quot;h-full&quot;)}
      href={props.redirectURL}
    &gt;
      {/*{props.icon &amp;&amp; &lt;props.icon className={&quot;text-hipzip-white&quot;} /&gt;}*/}
      &lt;div className={&quot;flex flex-col justify-center items-center gap-8 &quot;}&gt;
        &lt;props.icon
          className={
            &quot;text-hipzip-white h-64 w-64 hover:scale-110 transition-transform&quot;
          }
        /&gt;
        &lt;div className={cn(&quot;h-full flex justify-center items-center&quot;)}&gt;
          {props.message}
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/Link&gt;
  );
};

export default Section;</code></pre>
<p>이렇게 완성시킨 코드고, <code>props</code>로 태그 없이 넘긴다고 하면 참조값과 같은 형식으로 넘어갈 것이기 때문에 막 &quot;무거운 컴포넌트를 어떻게 하위로 내려줄수가 있어? 너 정말 나쁘다 😭&quot; 와 같이 생각할 필요는 없는 것이다. 사실 타입과 렌더링 관련해서 오류가 많이 났어서 고치는데 어려움을 조금 겪었었고, 위의 글을 참고한다면 쉽게 <code>props</code>를 넘겨 사용해줄 수 있을 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 개발자로의 첫 출발]]></title>
            <link>https://velog.io/@dev_cdd/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C%EC%9D%98-%EC%B2%AB-%EC%B6%9C%EB%B0%9C</link>
            <guid>https://velog.io/@dev_cdd/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A1%9C%EC%9D%98-%EC%B2%AB-%EC%B6%9C%EB%B0%9C</guid>
            <pubDate>Tue, 19 Dec 2023 09:07:34 GMT</pubDate>
            <description><![CDATA[<p>올해 2월 달부터 부트캠프를 들어가게 되면서 <code>html</code>의 <code>h1</code> 태그부터 배웠던 기억이 생생하다. 우리 부트캠프는 진도를 정말 빠르게 나갔는데, 사실 비전공자 기준으로는 거의 불가능에 가까울만한 커리큘럼인 것 같다. 5월 직전까지 <code>Vanilla.js</code>만 다루다가 이후부터 <code>React.js</code>를 처음 제대로 시도하게 되고 6월에는 <code>React</code>로 이뤄진 프로젝트에서 팀장을 맡아 열심히 개발을 진행했었다. 사실 이때 즈음 들었던 생각은 상상했던 무언가를 그럴싸하게 만들 수 있는 정도는 된다고 생각했었고, 부트캠프에서 수상도 해서 자만한 상태였다. 그렇게 부트캠프를 끝내고 2-3개월 정도 하염없이 쉬다가 이력서를 적기 시작했다. 가만 보면 그때 개발을 거의 3개월 쉬고 갑자기 취준이라니, 무슨 배짱이었나 싶다. 당연하게도 취업의 길은 쉽지 않았다.</p>
<p>리액트만 할 수 있어도 취업이 가능하다고 얘기했던 세상은 생각보다 쉽게 취업의 길을 내어주지 않았고, 지원했던 대부분의 결과는 서류탈락이었다. 진지하게 진로에 대한 고민도 시작했던 것 같다. 결과가 좋지 않으니 내 자신에 대한 의구심이 생겼고, 차라리 다른 길로 전향할까 생각도 했었다. 개발팀장으로 일하고 있는 친구에게 이력서를 보여주니 좋지 않은 답변을 들었고, 개발자의 길은 멀고도 험하구나 느꼈다. 하긴, 제대로 된 프로젝트도 없고, 그 당시 취업자들이 주변에서도 슬슬 늘어나게 되면서 마음이 급해졌던 것 같다. 그렇게 모든 것을 포기하고 눈을 돌리려는 순간 한 곳에서 면접 제의가 들어왔고, 다행히도 바로 합격하게 되어 지금은 프론트엔드 개발자로 자리 잡게 되었다.</p>
<p>난 첫 출근까지 개발 관련 공부를 아무것도 안했다, 정말 나태의 극치였다. 내 머릿 속에 들어있던 건 간단한 <code>git</code> 사용법 정도에 <code>html, css, javascript, react</code> 이 정도였다. 그렇게 들어온 지 얼마 안되서 환경 세팅을 하게 되었고, 다행히도 몇 년 째 맥을 써오고 있었던 상황이라 적응하는데 오랜 시간이 걸리지는 않았다. 다만 배포 환경이나 <code>ssh</code> 같은 건 거의 경험이 없었어서 ‘우와’ 하면서 따라했었다. 확실히 현업의 다른점은 몇 시간 동안 주구장창 의자에 앉아 강제로 코드만 들여다보고 있어야 되는데, 여기서 오는 실력 향상 폭이 엄청났던 것 같다. 솔직히 처음에는 일을 별로 안주셔서 그냥 자체적으로 사이드 프로젝트를 진행했고, 공부해보고 싶었던 여러 기술들을 2개월 동안 열심히 공부했다.</p>
<p><code>tailwind, nextJs 14, next-pwa, nginx, pm2, typescript, docker, aws, supabase</code> 등 그저 멀게만 느껴졌던 기술들이 이제는 평소에 사용하는 기술들이 되고, 개발에 흥미를 못느껴 20분을 못버티던 내가 이제는 코드에 대한 생각들로 머리가 복잡하다. 그치만 이 기술들은 회사에서 배운 게 아닌 그냥 개인적으로 사이드 프로젝트를 진행하며 얻게 된 지식이다. 부질 없는 생각일수도 있지만 딱 1년만이라도 더 빠르게 흥미를 느껴 부트캠프를 일찍 시작했거나 제대로 된 멘토를 만났었으면 어땠을까 생각이 들기도 한다. 아직도 배우고 연습해야 할 것들이 많지만, 향상 속도는 자신있게 얘기할 수 있을 정도다. 올해 시작부터 중순까지 정말 미치도록 우울했었는데, 마무리는 찬란한 것 같아 다행이다. 아, 참고로 사이드 프로젝트는 <a href="https://hip-zip.kro.kr">여기</a>로 들어가면 사용해 볼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[useState, re-rendering]]></title>
            <link>https://velog.io/@dev_cdd/useState</link>
            <guid>https://velog.io/@dev_cdd/useState</guid>
            <pubDate>Sun, 07 May 2023 15:49:25 GMT</pubDate>
            <description><![CDATA[<h1 id="usestate">useState</h1>
<p><code>State</code>는 영단어 사전에 찾아보면 <code>상태</code>라는 의미를 가지고 있는데, 리액트에서도 비슷한 의미를 가지고 있다. <code>useState</code>라는 것은 상태를 관리한다는 목적으로 사용되는데, 이를 위해서는 리액트의 기본적인 구조부터 다시 살펴볼 필요가 있다.</p>
<h2 id="re-rendering">Re-Rendering</h2>
<pre><code class="language-js">const componentExample = () =&gt; {
  const name = &quot;디디&quot;;
  return &lt;div&gt;{name}&lt;/div&gt;;
};</code></pre>
<p>지난 번의 글에서 위와 같은 함수형 컴포넌트를 구성했었다. 그러나 만약 저기서 <code>{name}</code>에 들어갈 값이 바꾸어야 한다면 어떤 식으로 바뀌게 될까? 당연히 바뀐 값을 넣어 다시 컴포넌트를 랜더링 해주는 식으로 진행하여야 한다. 순수 자바스크립트로 구현했다고 한다면 값을 바꾼 뒤 파싱해서 값을 바꾸거나 페이지 전체를 <code>reload</code> 했겠지만, 리액트는 딱 그 컴포넌트만 <code>re-render</code> 해줄 수 있다. 거기다 값이 바뀌었을 때를 자동으로 인식한다는 점도 리액트의 강점이라고 할 수 있다. 이러한 방식으로 <strong>상태관리</strong>를 진행한다고 보면 될 것 같고, 이를 위해 <code>useState</code>를 사용한다.</p>
<h2 id="usestate-왜-쓰는거야-아직-이해가-안돼-">useState 왜 쓰는거야? 아직 이해가 안돼 !</h2>
<p>버튼을 누르면 카운터가 올라가는 컴포넌트를 만든다고 가정하고, 대충 컴포넌트를 작성해보자.</p>
<pre><code class="language-js">const Counter = () =&gt; {
  let count = 0;

  return (
    &lt;div&gt;
      &lt;button
        onClick={() =&gt; {
          count += 1;
          console.log(count);
        }}
      &gt;
        click
      &lt;/button&gt;
      &lt;h2&gt;{count}&lt;/h2&gt;
    &lt;/div&gt;
  );
};

export default Counter;</code></pre>
<p>이렇게 코드를 작성하는 것이 일반적이겠지만, 바뀐 <code>&lt;h2&gt;count&lt;/h2&gt;</code>의 값이 반영되지 않는다. 그치만 콘솔에는 제대로 된 값들이 찍힌다. 이는 컴포넌트가 랜더링 되지 않아 바뀐 값이 적용되지 않는 경우다. 이를 해결하기 위해 <code>useState</code>를 사용해보자.</p>
<h2 id="usestate-사용-방법">useState 사용 방법</h2>
<p>아무런 세팅도 되어있지 않은 상태에서는 곧바로 상태관리를 진행할수가 없다. <code>CRA</code>로 프로젝트를 구성해보면 <code>import React from &#39;react&#39;</code>와 같이 상단에 <code>import</code>가 되어있는 모습을 볼 수 있을 텐데, 이를 다음과 같은 코드로 수정해주자.</p>
<pre><code class="language-js">import React, { useState } from &quot;react&quot;;</code></pre>
<p>앞으로 사용할 여러 기능들도 저 중괄호 안에 들어갈 예정이니 바로 시도해보는 것이 좋을 것 같다. 무튼 저런식으로 선언을 해준다면 사용할 준비는 끝났고, 바로 실행에 옮기면 된다.</p>
<h3 id="선언부">선언부</h3>
<p>리랜더링의 원인은 <code>count</code>의 값이 바뀌기 때문이다. 그러면 <code>count</code>를 <code>state</code>로 선언해주면 된다. 코드는 다음과 같이 작성한다.</p>
<pre><code class="language-js">const [count, setCount] = useState(0); // 네이밍은 보통 이런 식으로 한다, &#39;국룰&#39;이라고 이해하면 좋을 것 같다.</code></pre>
<h3 id="set-함수의-사용">Set 함수의 사용</h3>
<p><code>count</code>는 알겠는데, <code>setCount</code>는 도대체 왜 등장한걸까? 객체지향에서 주로 쓰이는 <code>getter, setter</code>를 알면 수월할 것 같다. 객체지향에서는 값을 직접적으로 수정하지 않고 <code>set</code> 함수를 활용하는데, 리액트도 비슷하게 사용한다. 다행히도 <code>get</code> 함수는 쓰지 않고 그냥 <code>count</code>만 적어주면 현재의 <code>count</code> 값을 가져올 수 있다. 저렇게 선언을 해준다면 <code>button</code>의 <code>onClick</code> 이벤트에 들어갈 함수도 교체를 해줘야 한다. 값을 직접적으로 바꾸지 않기 위해 <code>setCount</code>를 사용해보자.</p>
<pre><code class="language-html">&lt;button
  onClick={() =&gt; {
    setCount(count + 1);
  }}
&gt;&lt;/button&gt;</code></pre>
<p>코드를 해석해보자면 클릭 이벤트가 발생했을 때 <code>set</code> 함수를 활용하여 <code>count</code>에 1을 더한 값을 다시 <code>count</code>에 넣어주는 구조이다. 이 부분만 수정해주면 코드는 정상적으로 작동하는데, 완성된 코드를 보자.</p>
<h2 id="최종-코드">최종 코드</h2>
<pre><code class="language-js">import React, { useState } from &quot;react&quot;;

const Counter = () =&gt; {
  const [count, setCount] = useState(0);

  return (
    &lt;div&gt;
      &lt;button
        onClick={() =&gt; {
          setCount(count + 1);
        }}
      &gt;
        click
      &lt;/button&gt;
      &lt;h2&gt;{count}&lt;/h2&gt;
    &lt;/div&gt;
  );
};

export default Counter;</code></pre>
<p>크롬의 확장 프로그램에서 <code>React Developer Tools</code>를 설치하고 <code>Highlight updates when components render.</code>을 체크해주면 실시간으로 <code>Re-Rendering</code> 되는 내 컴포넌트를 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dev_cdd/post/b9940e6e-f4e1-42f1-b28f-1b393aa5de8a/image.gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Components]]></title>
            <link>https://velog.io/@dev_cdd/Components</link>
            <guid>https://velog.io/@dev_cdd/Components</guid>
            <pubDate>Sun, 07 May 2023 13:53:13 GMT</pubDate>
            <description><![CDATA[<h1 id="about-components">About Components</h1>
<pre><code class="language-js">// App.jsx

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

export default App;</code></pre>
<p><code>ReactJS</code>의 코드 구성은 다음과 같다. 리액트를 아예 모르는 상태에서 보면 <code>App</code>이라는 함수가 <code>HTML</code>을 반환하는 형식이다. 저렇게 구성된 <code>App</code>은 기본적으로 생성된 <code>index.js</code> 파일에서 모듈 형태로 불러와지고, 다음과 같이 사용된다.</p>
<pre><code class="language-js">// index.js

const root = ReactDOM.createRoot(document.getElementById(&quot;root&quot;));

root.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;
);</code></pre>
<p><code>create-react-app</code>을 통해 프로젝트를 실행하여 브라우저의 <code>DOM</code> 구성을 보면 항상 최상단 태그의 <code>id</code> 값이 <code>root</code>인 것을 알 수 있다. 최상단 태그의 바로 밑에 <code>&lt;App /&gt;</code>을 붙이는 형태로 코드를 작성하면 <code>App</code>에 있는 내용을 프로젝트에 붙일 수 있는 것이다. 어떻게 보면 당연한건데, 익숙하지 않은 부분이 있다. 바로 태그 이름이다, <code>&lt;Gallery /&gt;</code>와 같은 태그는 실제로 <code>HTML</code> 문법이 아닐텐데 어떻게 사용할 수 있는걸까?</p>
<h2 id="리액트는-사용자-정의-태그를-만드는-기술이고-이것을-컴포넌트라고-한다">리액트는 사용자 정의 태그를 만드는 기술이고, 이것을 컴포넌트라고 한다.</h2>
<p>이고잉 코치님의 수업 진행 방식 중 하나는 본인이 멘트 하나를 알려주면 수강생들에게 따라하라고 지시하는 형태이다. 실제로 저렇게 이야기를 하셨고, 수많은 수강생들이 위의 말을 열심히 따라서 외쳤다. 그래서 저게 무슨 말이냐면 그냥 소스코드로 설명하는 것이 편할 것 같다.</p>
<pre><code class="language-js">&lt;div&gt;
  &lt;h1&gt;안녕하세요, 저는 디디입니다 !&lt;/h1&gt;
  &lt;Profile /&gt; // component 1
  &lt;PortFolio /&gt; // component 2
&lt;/div&gt;</code></pre>
<p>실제로 존재하지 않는 <code>Profile, PortFolio</code> 태그는 내가 직접 만든 태그이다. 그러면 저 코드를 보고 이러한 의문이 들 것이다.</p>
<h3 id="에-그러면-태그-안의-내용물은-어디다가-적는거지-저런-태그는-어떤식으로-생겼는지-어떻게-인식하는거야">에..? 그러면 태그 안의 내용물은 어디다가 적는거지? 저런 태그는 어떤식으로 생겼는지 어떻게 인식하는거야?</h3>
<p>물론 태그에 대한 내용도 정의해야 하는데, 흔히 클래스형 컴포넌트와 함수형 컴포넌트가 존재한다. 요즘은 함수형 컴포넌트만 사용하는 경우가 많아 함수형으로만 설명을 진행하는데, 클래스 컴포넌트에 관해서 궁금하다면 이전에 리액트 찍먹할 때 정리해놨던 <a href="https://senscalibur.tistory.com/14">내 포스트</a>를 참고하면 될 것 같다. 무튼 간에 함수형 컴포넌트를 만드는 과정은 다음과 같다.</p>
<pre><code class="language-js">// Profile.jsx

const Profile = (props) =&gt; {
  return (
    &lt;&gt;
      &lt;h2&gt;{props.name}의 Skills&lt;/h1&gt;
      &lt;ul&gt;
        &lt;li&gt;CSS&lt;/li&gt;
        &lt;li&gt;JavaScript&lt;/li&gt;
        &lt;li&gt;ReactJS&lt;/li&gt;
      &lt;/ul&gt;
    &lt;/&gt;
  );
};

export default Profile;</code></pre>
<p><code>arrow function</code>을 굳이 사용하지 않아도 사용이 가능하긴 한데, 가독성을 위해서는 쓰는 것을 추천한다. 의미적으로 보면 <code>Profile</code>이라는 함수를 만들고, 저러한 태그들을 반환하는 것이다. 그냥 저렇게 적어놓은 상태로 다른 곳에 <code>import Profile from &#39;./Profile.jsx&#39;</code>로 가져온다면 바로 <code>&lt;Profile /&gt;</code>와 같이 사용할 수 있다. 당연히 이러한 방식으로 컴포넌트들끼리의 합성도 가능하고, 분해해서 따로 파일을 관리하는 것도 가능하다. 나중에 상태 관리로 들어가면 알게 되겠지만, 불필요한 랜더링을 방지하기 위해 컴포넌트를 어느정도 세분화 하는것도 중요하다.</p>
<h3 id="잠시만-profile이-인자로-받는-props는-또-뭐야">잠시만.. <code>Profile</code>이 인자로 받는 <code>props</code>는 또 뭐야?</h3>
<p>라는 의문을 제기할 정도라면 어느정도의 눈썰미가 있다는 것이다 ! 이전에 자바스크립트나 객체 지향 언어를 공부했다면 생성자를 통해 초기값이나 필요한 값 등을 할당했던 경험이 있었을 것이다. 비슷한 느낌으로 사용된다, 정말 간단한 예제 코드를 만들어봤다.</p>
<pre><code class="language-js">// Profile Component 사용 부분

  &lt;Profile name = &#39;디디&#39;&gt;

// Profile Component 선언 부분

// 방법 1
const Profile = (props) =&gt; {
  return (
    &lt;&gt;
      &lt;h2&gt;{props.name}의 Skills&lt;/h1&gt; // 디디의 Skills
      ...
    &lt;/&gt;
  );
};

//방법 2

const Profile = ({name}) =&gt; {
  return (
    &lt;&gt;
      &lt;h2&gt;{name}의 Skills&lt;/h1&gt; // 디디의 Skills
      ...
    &lt;/&gt;
  );
};
</code></pre>
<p><code>props</code>를 활용하여 통째로 값들을 가져오고, <code>props.name, props.age</code>처럼 내부 값들을 하나씩 빼서 쓰거나 <code>({name, age, ...})</code>와 같이 가져와서 곧바로(방법 2 참고) <code>{name}</code>처럼 사용하는 방법도 있다. 취향 따라 알아서 작성하면 되겠지만, 개인적으로 방법 2와 같이 구조분해를 해서 사용하는 것이 가독성에서 우월하다는 느낌을 받는다.</p>
<p>그리고 변수, 함수 등을 <code>tag</code> 내에서 사용하는 경우 무조건 중괄호 <code>{ ... }</code>을 사용한다. 사실 이건 이벤트 쪽 내용을 작성하면서 추가적인 설명을 할 것 같은데 미리 알아두는 것이 좋을 것 같아 추가로 적어놓는다.</p>
<h3 id="하나-더-아무것도-없는-태그-가-있는데-저건-꼭-필요한거야">하나 더, 아무것도 없는 태그 <code>&lt;&gt;&lt;/&gt;</code>가 있는데, 저건 꼭 필요한거야?</h3>
<pre><code class="language-js">return (
  &lt;div&gt;&lt;/div&gt;
  &lt;div&gt;&lt;/div&gt;
) // Bad

return (
  &lt;&gt;
    &lt;div&gt;&lt;/div&gt;
    &lt;div&gt;&lt;/div&gt;
  &lt;&gt;
) // Good</code></pre>
<p>리액트의 컴포넌트가 리턴하는 태그는 <strong>무조건</strong> 하나의 최상위 태그로만 구성되어야 한다. 트리로 치면 <code>depth</code> 같은 느낌인데, 같은 깊이의 최상단 태그들이 여럿 존재하게 된다면 에러가 뜨게 된다. 그래서 이러한 경우 그냥 아무 의미가 없는 <code>&lt;&gt;&lt;/&gt;</code>를 상단, 하단에 붙여주면 되고, 그러고 싶지 않다면 전체 태그를 <code>&lt;div&gt;</code> 태그로 감싸주면 된다. 만약 최상위 태그가 하나만 존재한다면 굳이 수정하지 않고 그대로 진행하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSR VS SSR]]></title>
            <link>https://velog.io/@dev_cdd/ReactJS</link>
            <guid>https://velog.io/@dev_cdd/ReactJS</guid>
            <pubDate>Tue, 02 May 2023 17:05:27 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>짧았지만 길었던 1차 프로젝트를 뒤로 하고 다시 강의가 재개되었다. 순수 자바스크립트로 프로젝트를 진행하면서 여러가지 불편한 사항이 많았는데, 예를 들면 헤더와 NAV Bar와 같이 중복되는 레이아웃에 대한 처리가 힘들기도 했고, <code>Parsing</code> 기반의 데이터 처리가 익숙치 않았던 경우도 있었다. 물론 순수 자바스크립트만으로도 가능하긴 하다.</p>
<pre><code class="language-js">returnHeader = () =&gt; { return &lt;nav class = &#39;navbar&#39;&gt;`Hello World, {name}`&lt;/nav&gt;}</code></pre>
<p>하지만 이렇게 되는 경우 매 페이지마다 다시 랜더링이 되는 구조이고, 템플릿 엔진을 쓰지 않았던 터라 모든 페이지 이동을 <code>href</code>와 같은 형태로 구성해야 했다. 페이지 이동을 최소화 하고자 <code>css</code>의 <code>display</code> 옵션을 건드리거나 부분적으로 <code>return</code> 함수를 사용하기도 했는데, 파일 관리가 제대로 되지 않아 구현이 힘들기도 했고 상태 관리도 쉽지 않았다. 사실 좀 더 깊게 <code>Vanilla JS</code>를 팠다면 더 많은 불편함을 느꼈을지도 모른다, 코드의 가독성 같은 측면이나 외부 라이브러리의 정보량 등등. 아직까지는 핑계라고 해도 될 정도의 얕은 수준이긴 하지만, 리액트 강의부터는 <a href="https://www.youtube.com/@coohde">이고잉</a>님이 실시간 강의를 진행하셔서 더욱 설렜던 느낌이 있기도 했다.</p>
<h1 id="csr-vs-ssr">CSR VS SSR</h1>
<p>프로젝트 이전까지는 <code>CSR: Client Side Rendering</code>와 <code>SSR: Server Side Rendering</code>의 차이를 제대로 체감하지 못했었다. <code>CSR</code>은 <code>Client</code>가 직접 랜더링을 수행하는 것이고, <code>SSR</code>은 서버가 대신 랜더링을 수행하는 것이다. 웹페이지마다 가지고 있는 데이터에 대한 양도 다르고, 쓰이는 용도도 다르기 때문에 현재 웹페이지들을 보면 두 가지의 랜더링 방식 모두 쉽게 찾을 수 있다. 당장 글을 적고 있는 이 <a href="https://velog.io">벨로그</a> 같은 사이트는 <code>CSR</code> 기반으로 만들어졌고, <a href="https://naver.com">네이버</a> 같이 규모가 큰 사이트는 <code>SSR</code>을 많이 쓴다. 아무래도 데이터의 양이 방대해지거나 표시해야 할 요소들이 많다면 <code>SSR</code> 형식을 많이 쓰게 되는 것 같다. 클라이언트로부터 요청을 받게 되면 서버 측에서 해당 템플릿을 로드해주는 방식인데, 큰 규모에서 클라이언트가 이것들을 다 진행하기에는 무리가 있을 것이다. 그래서 요즘은 다시 <code>SSR</code>로 추세가 바뀌고 있다고 하고, <code>nextJS</code>를 배워야 할 때라는 말이 나오기도 한다.</p>
<p><code>CSR</code>은 다소 규모가 적거나 한번에 표시해야 할 데이터가 한정적인 상황에서 주로 쓰게 되는데, <code>SPA: Single Page Application</code>의 형태로 구성하게 된다. 초기 로딩 속도는 <code>SSR</code>보다 느리다, 클라이언트에서 랜더링을 진행하기 때문에 무거운 느낌도 있다. 장점이라고 한다면 <code>interactive</code> 하다고 해야 할까? 보통 로직을 수행하거나 특정 작업을 수행할 때 <code>reload</code>가 발생하게 되는데, <code>CSR</code> 같은 경우 이러한 과정 없이 계속해서 브라우저가 동작하도록 한다.</p>
<p align="center">
  <img src="https://velog.velcdn.com/images/dev_cdd/post/f01f59cd-66f0-4e17-ac55-266a59bff576/image.png" width="60%">
</p>

<p>그래서 이 캡쳐본을 보면 각 탭마다 아이콘이 있는 것을 볼 수 있는데, 특정 로직을 수행하거나 페이지가 바뀌었을 때 저 아이콘이 빙글빙글 돌아가는 모양으로 바뀌면서 <code>reload</code>가 일어나면 <code>SSR</code>이라고 유추할수도 있다, <code>CSR</code>이면 해당과정 없이 그대로 있을 것이다. 벨로그는 표시할 데이터가 제법 있는 것 같은데, 왜 <code>CSR</code>로도 빠른 퍼포먼스가 가능한지가 궁금해 찾아보니 <code>graphQL</code>이라는 것을 사용하더라. 자세한 로직은 모르겠지만, 특정 요소들에 대한 캐시가 쌓이면 로드 없이도 빠르게 랜더링을 진행할 수 있는 느낌이라고 한다.</p>
<h1 id="create-react-app">create-react-app</h1>
<p>친구한테 물어보니 이건 고전적인 방법이고, 요즘에는 <code>Vite</code> 같은 것을 이용한다고 하는데 배우는 입장에서는 고전적인 것만큼 좋은게 없는 것 같다. <code>jQuery</code> 몰라도 웬만한 로직 다 구현할 수 있고, <code>react</code> 넘어가는 순간 중요도가 떨어지게 된다고 하더라. 무튼 간에 <code>nodeJS</code>가 설치되어 있다는 가정 하에 다음과 같은 명령어를 입력하면 <code>react</code>의 기본적인 프로젝트  파일을 구성할 수 있다.</p>
<pre><code class="language-bash">npx create-react-app directoryName --template typescript
npx create-react-app directoryName
npx create-react-app .</code></pre>
<p>1번 명령어는 타입스크립트 템플릿 형식으로 <code>directoryName</code>이라는 프로젝트 폴더를 만드는 것이고, 두 번째는 JS 템플릿, 세 번째는 그냥 현 디렉토리에 만드는 형식이다. 현 강의는 타입스크립트 기반으로 강의가 진행되는 중이라 타입스크립트 템플릿도 일단 넣어봤다. 해당 명령어를 실행하게 되면 약간의 시간이 지난 후, 기본적인 <code>structure</code>가 완성되는데, 다음과 같다.</p>
<p align="center">

  <img src="https://velog.velcdn.com/images/dev_cdd/post/87636969-db03-47b6-8633-a251d55f5b6d/image.png" width = "35%">

</p>

<p>기본적으로 <code>package.json</code> 세팅도 다 잘되어 있어서 저 상태에서 <code>npm start</code> 명령어만 입력해주면 바로 샘플 리액트 페이지를 만나볼 수 있다. 이제 개발을 위한 모든 준비가 끝났으니, 다음 글부터는 <code>Component</code>부터 시작해서 <code>State, Hooks</code> 등 다양하게 작성할 예정이다. 드디어 좀 선진적이고 컴퓨터공학스러운(?) 기술을 사용하게 되어 기분이 매우 좋은 상태이다. 얼마나 갈지는 모르겠지만, 더 열심히 해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[포트 찾아 죽이기]]></title>
            <link>https://velog.io/@dev_cdd/%ED%8F%AC%ED%8A%B8-%EC%B0%BE%EC%95%84-%EC%A3%BD%EC%9D%B4%EA%B8%B0</link>
            <guid>https://velog.io/@dev_cdd/%ED%8F%AC%ED%8A%B8-%EC%B0%BE%EC%95%84-%EC%A3%BD%EC%9D%B4%EA%B8%B0</guid>
            <pubDate>Mon, 01 May 2023 12:28:10 GMT</pubDate>
            <description><![CDATA[<h2 id="how-to-kill-server">How to Kill Server?</h2>
<pre><code class="language-bash">$ lsof -i :3000</code></pre>
<p><code>:</code> 뒤에 오는 번호는 포트 번호이다. 포트의 중복사용으로 인해 오류가 떴다면 해당 명령어를 터미널에 입력해주고 <code>PID</code> 값을 확인해주자.</p>
<pre><code class="language-bash">$ kill -9 PID</code></pre>
<p>그리고 해당되는 <code>PID</code> 값을 <code>kill -9</code> 다음에 넣어주면 된다. 강제로 끄게 될 경우가 자주 발생하는데, 명령어가 잘 기억이 안나서 여기에 적어놓게 되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[엘리스 SW 트랙 1차 프로젝트 회고록]]></title>
            <link>https://velog.io/@dev_cdd/%EC%97%98%EB%A6%AC%EC%8A%A4-SW-%ED%8A%B8%EB%9E%99-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@dev_cdd/%EC%97%98%EB%A6%AC%EC%8A%A4-SW-%ED%8A%B8%EB%9E%99-1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Fri, 28 Apr 2023 18:24:19 GMT</pubDate>
            <description><![CDATA[<h1 id="프로젝트-introduction">프로젝트 Introduction</h1>
<p>엘리스 트랙은 <code>HTML -&gt; CSS -&gt; JavaScript: 기초문법 -&gt; TypeScript: 맛보기 -&gt; express.js</code> 순으로 커리큘럼이 진행되고, 이후에 1차 프로젝트를 진행한다. 사실 지금까지의 이 과정을 단 <strong>1개월 반</strong>만에 배웠다고 생각하니 말도 안되는 난이도인 것 같기는 하다. 엘리스에 지원하는 비전공자들 같은 경우 기존에 개발을 많이 진행해 본 경험이 있는 사람들도 있지만, 아무런 베이스도 없는 상태로 임하는 사람들도 많아서 <code>레이서: 수강생</code> 마다의 차이가 엄청나다. 무튼 그렇게 진행되는 프로젝트라 사실 완성도에서 부족할 수 밖에 없는 것이 현실인 것 같다.</p>
<h2 id="stack">Stack</h2>
<p>앞서 말한대로 <code>순수 자바스크립트</code> 만을 이용하여 코드를 작성하게 되는데, 백엔드는 <code>express.js</code>를 사용해서, 프론트엔드도 레이아웃에 <code>JavaScript</code>를 입혀서 코드를 작성하게 된다. 백엔드 같은 경우 추가적으로 <code>passport</code>나 <code>bodyParser</code> 같은 모듈들을 사용하기도 하는데, 워낙 기본적인 모듈이라 스택이라고 보기는 어려울 것 같고, <code>express.js + mongoDB</code>를 활용한 프로젝트라고 생각하면 된다.</p>
<h2 id="주제">주제</h2>
<p>지난번까지는 스켈레톤 코드가 주어졌다고 하는데, 이번에는 아쉽게도 그런 게 없었다. 단순히 주제가 <code>쇼핑몰</code>로 정해졌고, 엘리스 측에서 기능 구현에 관한 요구사항을 준다. 이러한 필수적인 기능들을 먼저 일주일 동안 구현한 후, 2주차 때는 추가적인 기능구현을 진행하는 방식이다. 사실 일주일 만에 다 하기 힘든 양의 기능 구현이기는 하지만, 노력을 갈아 넣으면 가능은 할 정도의 난이도인 것 같다.</p>
<h2 id="전반적인-후기">전반적인 후기</h2>
<p>프로젝트 진행 전 포지션 수요조사를 진행한다. 난 당연히 프론트엔드 쪽 비율이 압도적으로 많을 것 같았는데, 생각보다 백엔드 포지션들이 꽤나 있었다. 다행히라고 생각했지만, 예상치 못한 탈주 인원들도 꽤나 있어 생각보다 적은 팀원들로 프로젝트를 진행하게 되었다. 그렇게 팀원은 프론트 3, 백엔드 2로 구성되었다.</p>
<p>초반에 레이아웃을 짜는 데 애를 먹었다. 피그마를 사용하려 했으나, 시간이 없다는 압박감에 정말 간단한 레이아웃을 그리고 곧바로 코드를 작성하기 시작했다. 이론만으로 배웠던 <code>CSS</code>를 실제로 적용하는 것은 그렇게 쉬운 일이 아니었다. <code>Grid, FlexBox</code> 같은 속성들이 내가 원하는대로 배치되지 않았고, 그래서 <code>BootStrap</code>의 도움을 받아 기본적인 레이아웃만 구성한 채로 기능 구현에 들어갔다. 다행히도 코딩 경험이 있어서 그런지 기능 구현에서는 큰 어려움이 없었는데, 문제는 다른 팀원들이었다.</p>
<h3 id="강제-풀스택">강제 풀스택(?)</h3>
<p>각자 맡은 파트가 있었지만, 원하는 만큼의 진행속도가 나오지 않아 답답한 느낌이 있었다. 학부 시절 때와는 전혀 다른 페이스였고, 첫 플로우에서 시간 지연이 심해지는 바람에 뒤의 <code>Front - Back</code> 연동 작업이 매우 늦어져버렸다. 지적하기에는 눈치가 보이고, 다들 노력도 열심히 하고 있는 것 같아 재촉도 안하고 일단 기다렸는데 사실 이 부분이 굉장히 후회되는 부분이다. 로그인 같은 경우 <code>Chat GPT</code>를 사용하면 사실 1시간도 안되서 구현할 수 있을만큼 쉬운 부분이었는데, 여기부터 막히는 바람에 다음 플로우가 전혀 진행이 되지 못했다.</p>
<p>개인적으로 프로젝트에 대한 욕심이 있어서 레이아웃 부분에 신경을 쓰고 싶었는데, 코드 이슈가 너무 많아 해결에 초점을 맞춘 상태로 프로젝트를 진행했다. 이미 어느정도 작성 되어버린 코드를 다 지우고 새롭게 만들기도 눈치 보여서 계속해서 기다리며 이슈가 발생하면 해결해주는 쪽으로 진행하게 되었다. 그렇게 프론트엔드, 백엔드의 이슈를 모두 처리하게 되면서 프로젝트에 대한 개괄적 이해가 쌓이게 되었다는 장점이 있기는 했다.</p>
<h3 id="배포-관련">배포 관련</h3>
<p>배포가 많이 늦었기는 했지만 다행히도 원할하게 진행되었다. 사실 그렇게 큰 의미가 있지는 않겠지만, 나름 맥을 오래 써오기도 했고 유닉스 사용 경험이 있어서 배포에 어려움을 겪지는 않았다. 그렇게 <code>IP</code>를 할당 받아 프로젝트를 개발 경험이 있는 친구들에게 공유했고, 친구들은 신나게 이슈들을 불러주었다. 사실 이슈를 찾아준다는 것은 정말 고마운 일이지만 당장 육안으로 보기에도 부족함이 많은 사이트였어서 대부분 예상이 가는 이슈들이 많았다.</p>
<h3 id="로그인-무한-이슈">로그인 무한 이슈</h3>
<p>프로젝트의 처음부터 끝까지 로그인이 발목을 잡았는데, 막판에 그냥 라우터 파일을 많이 고쳤다. 간단한 예외처리도 잘 안되어있는 부분들이 많아 서버가 정말 자주 꺼졌다. 처음에 되게 당황해서 급하게 소스를 핫픽스 했는데, 친구들이 또 다른 오류를 찾아줘서 빠르게 문제를 해결했다. 10분이면 해결할 수 있는 오류들이 많았는데, 이 부분에 대해서는 팀원들에 대한 아쉬움이 컸다. 결국 모든 에러처리를 완료하여 현재는 로그인으로 인해 서버가 꺼지는 일은 없는 상태이다.</p>
<h3 id="git-관련-이슈">GIT 관련 이슈</h3>
<p>깃 사용 경험이 있는 사용자들이 많이 없다보니 애를 많이 먹었다. 브랜치를 만들어 소스를 공유해도 <code>clone</code>을 잘못하여 <code>conflict</code>가 발생하는 경우가 많았고, 대놓고 이야기를 하기에는 팀원들에게 상처가 될 것 같아 <code>아, 뭔가 깃이 꼬인 것 같습니다, 에어드롭으로 파일 주십시오</code> 라고 이야기를 했다. 부산에서 프로젝트를 위해 성수까지 왔는데, 이 부분에 대해서는 나름 잘 한 일이라고 생각하고 있다.</p>
<h3 id="최종-결과물">최종 결과물</h3>
<p>코치님과의 상의 끝에 레이아웃에 힘을 조금 더 싣기로 마음 먹고, 관련 라이브러리를 좀 찾아봤다. 친구에게서 <code>tailWind, chaKra</code> 이 둘을 추천 받았는데, 편하게 <code>CDN</code>으로도 사용할 수 있는 <code>tailWind</code>을 활용하여 <code>UI</code> 개선하기로 했다. 다행히도 이 부분은 레이아웃을 잘 짜는 팀원이 있어서 빠르게 진행될 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/dev_cdd/post/92b5d2d0-9687-4adb-b33c-3f65be393c72/image.png" alt=""></p>
<p><code>Pinterest</code> 와 같은 갤러리 형태로 메인페이지 <code>UI</code>를 만들게 되었고, 카테고리 별로 분류하여 진행하니 꽤나 괜찮은 모양새가 나오기는 했다. 상품 관련 <code>API</code>나 레이아웃 같은 경우 특별한 이슈가 있지는 않았어서 다행히었다.</p>
<h2 id="소감">소감</h2>
<p><code>SSR</code>로 진행을 하려다 템플릿 엔진을 사용하기에 사전지식이 부족했어서 <code>HTML</code> 파일을 <code>href</code> 하는 방식으로 진행했는데, 페이지마다 적용되어야 할 부분들이 아직 많이 적용이 안 된 상태이다. 이후에 <code>render</code> 방식들을 배우면서 어떻게 하면 효율적으로 공통된 컴포넌트를 렌더링 할 수 있는지에 대한 추가적인 학습이 필요할 것 같다.</p>
<p>그리고 사실 백엔드 연동에 너무 신경을 많이 써서 개인적으로 진행할 수 있었던 부분까지 못하기도 했는데, 이 부분은 내 잘못이 맞는 것 같다. 어느정도의 밸런스 있는 진행을 추구했어야 했는데 너무 이슈 해결에 혼을 쏟았다. 다음에는 진행할 부분 다 진행해놓고, 문제가 있으면 문제되는 파일을 받아 통째로 작업하는 방식으로 진행해야 할 것 같다.</p>
<p>리액트를 진행하기 전에 이번 프로젝트를 하면서 여러 이슈들을 접했기 때문에 개인 프로젝트도 어느정도 구현할 수 있을 것 같다는 자신감이 생겼다. 그래서 시간이 좀 된다면 순수 자바스크립트만을 이용한 웹페이지를 하나 만들 것 같은데, 다음주에 바로 리액트 강의가 들어가서 진행할 수 있을지 잘 모르겠긴 하다. 그래도 하는 데까지 해봐야지.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PS Study 3rd Week]]></title>
            <link>https://velog.io/@dev_cdd/PS-Study-3rd-Week</link>
            <guid>https://velog.io/@dev_cdd/PS-Study-3rd-Week</guid>
            <pubDate>Fri, 07 Apr 2023 07:01:21 GMT</pubDate>
            <description><![CDATA[<h1 id="타겟넘버"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43165">타겟넘버</a></h1>
<h2 id="문제-요약">문제 요약</h2>
<p>정수들이 들어가있는 배열 <code>numbers</code>와 목표 결과값인 <code>target</code>을 인자로 받는다. 모든 값을 더하거나 빼서 결과값이 <code>target</code>이 나온다면 카운팅을 하고, 해당 값을 <code>return</code>하면 되는 문제다.</p>
<h2 id="io">IO</h2>
<table>
<thead>
<tr>
<th align="center">Numbers</th>
<th align="center">Target</th>
<th align="center">Return</th>
</tr>
</thead>
<tbody><tr>
<td align="center">[1, 1, 1, 1, 1]</td>
<td align="center">3</td>
<td align="center">5</td>
</tr>
<tr>
<td align="center">[4, 1, 2, 1]</td>
<td align="center">4</td>
<td align="center">2</td>
</tr>
</tbody></table>
<h2 id="제한사항">제한사항</h2>
<ul>
<li>주어지는 숫자의 개수는 2개 이상 20개 이하입니다.</li>
<li>각 숫자는 1 이상 50 이하인 자연수입니다.</li>
<li>타겟 넘버는 1 이상 1000 이하인 자연수입니다.</li>
</ul>
<h2 id="풀이">풀이</h2>
<pre><code class="language-js">function solution(numbers, target) {
  let answer = 0;

  const stack = [{ index: 0, sum: 0 }];

  while (stack.length) {
    const { index, sum } = stack.pop();

    if (index === numbers.length) {
      if (sum === target) answer++;
      continue;
    }

    stack.push({ index: index + 1, sum: sum + numbers[index] });
    stack.push({ index: index + 1, sum: sum - numbers[index] });
  }

  return answer;
}

console.log(solution([4, 1, 2, 1], 4));</code></pre>
<p><code>DFS</code> 방식을 사용했는데, <code>Python</code>을 사용하다 와서 그런지 다른 풀이를 참고하면서 풀었다. <code>stack</code>에는 <code>index, sum</code> 값이 들어가있고, 스택이 빌 때까지 탐색을 시작한다. 카운팅이 수행되는 조건은 <code>index</code>가 <code>numbers</code> 배열의 길이만큼 늘어나고, 합산이 <code>target</code>과 일치할 때이다. <code>index</code>는 말 그대로 인덱스의 의미도 가지고 있지만, 무조건 순차적인 탐색이라 카운팅의 의미를 갖기도 한다.</p>
<p><code>push</code> 구문을 보면 더하는 케이스와 빼는 케이스가 있는데, <code>index</code>는 다음 <code>index</code>로 넘어가게 되면서 <code>+1</code>이 되고, <code>sum</code>은 기존 값에 <code>numbers</code> 배열의 해당 인덱스 값을 더하거나 빼는 과정을 수행하게 된다. 나머지 문제들에 비해 상대적으로 쉬웠던 문제였던 것 같다.</p>
<h1 id="여행경로"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43164">여행경로</a></h1>
<h2 id="문제-요약-1">문제 요약</h2>
<p><code>tickets</code> 배열을 받아오는데, 배열의 형태가 <code>[[&#39;KOR&#39;, &#39;JPN&#39;], [&#39;JPN&#39;, &#39;USA&#39;], ...]</code>와 같은 형식으로 주어져있다. 인덱스의 첫 번째 값과 두 번째 값은 각 출발지와 도착지를 의미하며, 모든 항공권을 이용하여 여행경로를 짜야 한다.</p>
<h2 id="io-1">IO</h2>
<table>
<thead>
<tr>
<th align="center">Tickets</th>
<th align="center">Return</th>
</tr>
</thead>
<tbody><tr>
<td align="center">[[&quot;ICN&quot;, &quot;JFK&quot;], [&quot;HND&quot;, &quot;IAD&quot;], [&quot;JFK&quot;, &quot;HND&quot;]]</td>
<td align="center">[&quot;ICN&quot;, &quot;JFK&quot;, &quot;HND&quot;, &quot;IAD&quot;]</td>
</tr>
<tr>
<td align="center">[[&quot;ICN&quot;, &quot;SFO&quot;], [&quot;ICN&quot;, &quot;ATL&quot;], [&quot;SFO&quot;, &quot;ATL&quot;], [&quot;ATL&quot;, &quot;ICN&quot;], [&quot;ATL&quot;,&quot;SFO&quot;]]</td>
<td align="center">[&quot;ICN&quot;, &quot;ATL&quot;, &quot;ICN&quot;, &quot;SFO&quot;, &quot;ATL&quot;, &quot;SFO&quot;]</td>
</tr>
</tbody></table>
<h2 id="제한사항-1">제한사항</h2>
<ul>
<li>모든 공항은 알파벳 대문자 3글자로 이루어집니다.</li>
<li>주어진 공항 수는 3개 이상 10,000개 이하입니다.</li>
<li>tickets의 각 행 [a, b]는 a 공항에서 b 공항으로 가는 항공권이 있다는 의미입니다.</li>
<li>주어진 항공권은 모두 사용해야 합니다.</li>
<li>만일 가능한 경로가 2개 이상일 경우 알파벳 순서가 앞서는 경로를 return 합니다.</li>
<li>모든 도시를 방문할 수 없는 경우는 주어지지 않습니다.</li>
</ul>
<h2 id="풀이-1">풀이</h2>
<pre><code class="language-js">function solution(tickets) {
  let routes = [];

  DFS = (extra, current, route) =&gt; {
    if (extra.length === 0) {
      routes.push(route);
    } else {
      extra.forEach(([from, to], index) =&gt; {
        if (current === from) {
          const newExtra = extra.slice();
          newExtra.splice(index, 1);
          DFS(newExtra, to, route.concat(to));
        }
      });
    }
  };

  DFS(tickets, &quot;ICN&quot;, [&quot;ICN&quot;]);
  return routes.sort()[0];
}</code></pre>
<p><code>BFS</code>로 풀고 싶었는데, 생각대로 잘 안되었던 것도 있고 문제 자체가 좀 어려워서 외부 풀이를 참고해서 풀었다. 전반적인 <code>DFS</code> 구조를 보면 인자값으로 <code>extra, current, route</code>가 들어가는 것을 볼 수 있다. 처음에 선언하는 <code>routes</code>는 최종적인 경로라고 생각하면 되고, 인자로 들어가는 <code>route</code>는 중간에 경로를 기억할 수 있는 <code>tmp_route</code> 정도로 이해하면 될 것 같다.</p>
<p><code>DFS</code> 함수가 실행되면 <code>extra</code> 값이 비어있는지 확인한다. 초기값은 티켓 전체가 그대로 들어가므로 바로 <code>else</code>문으로 들어가는데, <code>extra</code>에 <code>forEach</code> 루프를 돌려 각 인덱스 내의 출발지와 도착지에 대한 연산을 시작한다. 현위치 <code>current</code>에는 초기값 <code>&quot;ICN&quot;</code>이 들어가기 때문에 첫 루프에는 출발지가 <code>ICN</code>인 경우를 서칭하게 될 것이다. 조건을 충족하면 임시로 쓸 변수 <code>newExtra</code>에 <code>extra</code> 배열을 얕은 복사해주고 <strong><em>복사하는 이유는 단순 대입 연산자를 이용하여 넣어버리면 기존 배열값이 바뀌기 때문이다.</em></strong></p>
<p>그렇게 가져온 <code>newExtra</code>에서 조건을 충족하는 <code>index</code>를 빼줌으로써 다음 서칭에는 포함되지 않도록 만들어준다. 그리고 재귀적으로 동작하도록 <code>DFS</code>를 호출하는데, 여기서 <code>newExtra: extra, to: current, route.concat(to)</code>라는 의미를 담고 있다. 첫 루프에는 <code>route</code>에 <code>ICN</code> 밖에 안들어있었는데 그 다음 목적지, 예를 들면 <code>&quot;JFK&quot;</code>가 들어가게 되는 것이다.</p>
<p>그렇게 나온 <code>routes</code>를 제한사항 5번을 참고하여 정렬해야 하는데, <code>sort()</code>를 활용하여 정렬을 수행하고 그렇게 정렬된 <code>routes</code> 배열의 첫 번째 인덱스 값을 가져오기 위해 <code>[0]</code>을 사용했다.</p>
<h1 id="네트워크"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43162">네트워크</a></h1>
<h2 id="문제-요약-2">문제 요약</h2>
<p>지난 번에 풀었던 백준의 <strong><a href="https://www.acmicpc.net/problem/2606">바이러스</a></strong> 와 유사한 문제이다. 인자값으로 <code>n, computers</code>를 받는데 <code>n</code>은 컴퓨터의 개수, <code>computers</code>는 연결 상태가 담긴 배열이다. 뭐, 예를 들어 컴퓨터가 4대라고 한다면 <code>[[0: 1번 컴퓨터와의 연결 여부, 0: 2번 컴퓨터와의 연결 여부, 0: 3번 컴퓨터와의 연결 여부, 0: 4번 컴퓨터와의 연결 여부], [...], [...], [...]</code> 와 같은 형태로 되는 것이다. 각 인덱스는 컴퓨터의 번호를 의미한다고 보면 되고, 그렇게 해서 컴퓨터들은 각각의 연결로 하나의 네트워크를 이루게 될 것이다. 그렇게 구성된 네트워크의 개수를 알아내면 되는 문제다.</p>
<h2 id="io-2">IO</h2>
<table>
<thead>
<tr>
<th align="center">n</th>
<th align="center">computers</th>
<th align="center">return</th>
</tr>
</thead>
<tbody><tr>
<td align="center">3</td>
<td align="center">[[1, 1, 0], [1, 1, 0], [0, 0, 1]]</td>
<td align="center">2</td>
</tr>
<tr>
<td align="center">3</td>
<td align="center">[[1, 1, 0], [1, 1, 1], [0, 1, 1]]</td>
<td align="center">1</td>
</tr>
</tbody></table>
<h2 id="풀이-2">풀이</h2>
<pre><code class="language-js">function solution(n, computers) {
  var answer = 0;
  const visited = Array(n).fill(false);

  DFS = (index, visited, computers) =&gt; {
    visited[index] = true;
    for (let i = 0; i &lt; computers.length; i++) {
      if (computers[index][i] === 1 &amp;&amp; !visited[i]) DFS(i, visited, computers);
    }
  };

  for (let i = 0; i &lt; n; i++) {
    if (!visited[i]) {
      DFS(i, visited, computers);
      answer++;
    }
  }
  return answer;
}

console.log(
  solution(3, [
    [1, 1, 0],
    [1, 1, 0],
    [0, 0, 1],
  ])
); // local 확인용 콘솔</code></pre>
<p><code>DFS</code>로 풀었는데 먼저 <code>visited</code> 배열은 각 컴퓨터의 방문 상태를 기록하기 위해 선언했다. 개수를 맞추기 위해 <code>Array(n).fill(false)</code>로 선언했고, <code>[false, false, ... , false]</code> 이런식으로 될 것이다. 이렇게 초기값은 다 <code>false</code>로 선언이 되었기 때문에 루프를 돌려서 첫 <code>index</code>부터 <code>DFS</code> 탐색을 시작한다. <code>DFS</code> 함수를 분석해보자.</p>
<p>우선 방문을 기록하기 위해 <code>visited</code> 배열의 해당 인덱스의 값을 <code>true</code>로 수정해준다. 그리고 반복문을 돌려 그 해당 인덱스와의 연결이 되어있는 경우를 찾는다. 이것이 <code>computers[index][i]</code>를 의미하고, 방문 여부도 <code>!visited[i]</code>를 통해 확인해준다. 그렇게 방문하지 않고 연결되어 있는 케이스를 찾아내면 재귀적으로 <code>DFS</code>를 호출한다. 그렇게 다 돌면 하나의 네트워크를 다 탐색했으므로 <code>answer</code>의 값을 1 증가시킨 후, 다음 네트워크를 찾게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[What is TypeScript?]]></title>
            <link>https://velog.io/@dev_cdd/About-TypeScript</link>
            <guid>https://velog.io/@dev_cdd/About-TypeScript</guid>
            <pubDate>Mon, 03 Apr 2023 04:47:56 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript"><strong>TypeScript</strong></h1>
<p>타입스크립트는 기존의 자바스크립트에서 문제가 되었던 타입을 제대로 표기해주는 식으로 사용할 수 있다. <code>Type</code> 표기의 종류는 다음과 같다.</p>
<h3 id="기본-자료형"><strong>기본 자료형</strong></h3>
<ul>
<li><code>string</code></li>
<li><code>boolean</code></li>
<li><code>number</code></li>
<li><code>null: 값이 의도적으로 비어 있는 상태</code></li>
<li><code>undefined: 아무 값이 할당되지 않은 상태</code></li>
<li><code>symbol: ES6에서 추가된 문법</code></li>
</ul>
<p>다른 언어를 많이 접하다보니 이러한 타입에 대해서 익숙하긴 하다. 임의의 코드를 만들어 예시를 들어보겠다.</p>
<pre><code class="language-js">// js
function f1(val) {
  result = 1;
  return result + val;
}

console.log(f1(&quot;1&quot;)); // 결과값: 11
console.log(f1(1)); // 결과값: 2</code></pre>
<p>다음과 같은 코드를 작성하게 되면 들어가는 <code>value</code>의 자료형에 따라 결과값을 다른 형태로 배출하게 되는 모습을 볼 수 있다. 의도적으로 이렇게 만들수도 있지만, 정확한 디버깅이나 가독성 및 유지보수를 위해서는 타입을 지정하는 형식으로 사용한다.</p>
<pre><code class="language-ts">// ts
function f1(val: number): number {
  result = 1;
  return result + val;
}

console.log(f1(&quot;1&quot;)); // 결과값: error
console.log(f1(1)); // 결과값: 2</code></pre>
<p>위와 같은 방법으로 작성하게 되면 나타날 수 있는 오류를 방지할 수 있다는 장점이 있다. 추가적으로 메모리에 값을 주소로 저장하고, 출력 시 메모리 주소와 일치하는 값을 출력하는 참조 자료형과 개발자의 편의를 위해 추가로 제공하는 자료형들 또한 더 있다.</p>
<h3 id="참조-자료형">참조 자료형</h3>
<ul>
<li><code>object</code></li>
<li><code>array</code></li>
<li><code>function</code></li>
</ul>
<h3 id="추가-제공-자료형">추가 제공 자료형</h3>
<ul>
<li><code>tuple: 길이와 각 요소의 타입이 정해진 배열을 저장하는 타입</code></li>
<li><code>enum: 특정 값의 집합을 저장하는 타입</code></li>
<li><code>any, void, never</code></li>
</ul>
<pre><code class="language-ts">let arr: [string, number] = [&quot;Hi&quot;, 6];

enum Car {
  BUS = 1,
  TAXI = 2,
  SUBWAY = 3,
}

let bus: Car = Car.BUS; // 인덱스 번호로도 접근 가능
let subway: string = Car[3];</code></pre>
<h2 id="utility-types">Utility Types</h2>
<p>사실 이 개념을 많이 안써봐서 직관적으로 어떻게 써야겠다라는 감이 안오기는 하지만, 우선 각 타입이 어떠한 것을 의미하는지는 알아두면 좋을 것 같아서 이에 관해서 정리해두고 나중에 시도해보려고 한다.</p>
<ul>
<li><code>Partial&lt;T&gt;</code><ul>
<li>프로퍼티를 선택적으로 만드는 타입을 구성</li>
<li>주어진 타입의 모든 하위 타입 집합을 나타내는 타입을 반환</li>
<li>T에 <code>interface</code>가 들어가면 인터페이스 내의 값을 선택적으로 사용할 수 있음</li>
</ul>
</li>
<li><code>Readonly&lt;T&gt;</code><ul>
<li>프로퍼티를 읽기 전용으로 설정한 타입</li>
</ul>
</li>
<li><code>Record&lt;T&gt;</code><ul>
<li>프로퍼티의 집합 K로 타입을 구성</li>
<li>타입의 프로퍼티들을 다른 타입에 매핑시키는 데 사용</li>
</ul>
</li>
<li><code>Pick&lt;T, K&gt;</code><ul>
<li>프로퍼티 K의 집합을 선택해 타입을 구성한다.</li>
</ul>
</li>
<li><code>Omit&lt;T, K&gt;</code><ul>
<li>모든 프로퍼티를 선택한 다음 K를 제거한 타입을 구성한다.</li>
</ul>
</li>
<li><code>Exclude&lt;T, U&gt;</code><ul>
<li>T에서 U에 할당할 수 있는 모든 속성을 제외한 타입을 구성</li>
</ul>
</li>
<li><code>Extract&lt;T, U&gt;</code><ul>
<li>T에서 U에 할당 할 수 있는 모든 속성을 추출하여 타입을 구성한다.</li>
</ul>
</li>
<li><code>NonNullable&lt;T&gt;</code><ul>
<li>null과 undefined를 제외한 타입</li>
</ul>
</li>
<li><code>Parameters&lt;T&gt;</code><ul>
<li>함수 타입 T의 매개변수 타입들의 튜플 타입을 구성한다.</li>
</ul>
</li>
<li><code>ConstructorParameters&lt;T&gt;</code><ul>
<li>생성자 함수 타입의 모든 매개변수 타입을 추출</li>
<li>모든 매개변수 타입을 가지는 튜플 타입을 생성한다</li>
</ul>
</li>
<li><code>ReturnType&lt;T&gt;</code><ul>
<li>함수 T의 반환 타입으로 구성된 타입을 생성</li>
</ul>
</li>
<li><code>Required&lt;T&gt;</code><ul>
<li>T의 모든 프로퍼티가 필수로 설정된 타입을 구성</li>
</ul>
</li>
</ul>
<pre><code class="language-ts">// 실사용 예제

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit&lt;Todo, &quot;description&quot;&gt;;
type TodoPreview = Pick&lt;Todo, &quot;title&quot;&gt;;

const todo: TodoPreview = {
  title: &quot;Go to the market&quot;,
  completed: false,
};

const todo: TodoPreview = {
  title: &quot;Wash face&quot;,
};</code></pre>
<h2 id="typescript의-함수-사용"><strong>TypeScript의 함수 사용</strong></h2>
<p>자바스크립트와 타입스크립트의 함수는 일급 객체이다. 일급 객체의 조건은 다음과 같다.</p>
<ul>
<li>다른 함수에 매개변수로 제공할 수 있다.</li>
<li>함수에서 반환 가능하다.</li>
<li>변수에 할당 가능하다.</li>
</ul>
<p>타입스크립트 함수 작성 시 반환 타입을 추론하도록 하는 것을 권장하고, 함수의 매개 변수와 인수의 타입이 호환 가능하게 작성하여야 하며, 인수의 타입을 잘못 전달하면 에러가 발생하도록 해야 한다.</p>
<pre><code class="language-ts">// 선택적 매개변수
function f1(val1: number, val2?: number): number {
  if (val2) return val1 + val2;
  else return val1;
}

f1(2, 3); // 5
f1(2); // 2</code></pre>
<p>위와 같은 형식으로 사용한다면 두 번째 인자를 받든 안받든 간에 그에 따른 결과를 출력할 수 있다.</p>
<h2 id="oop---객체-지향-프로그래밍">OOP - 객체 지향 프로그래밍</h2>
<p>정보처리기사를 준비하면서 봐왔던 객체 지향 프로그래밍에 대한 개념과 거의 유사했다. 객체들은 서로 메세지를 주고 받을 수 있으며, 데이터를 처리할 수 있다는 특징을 가진다.</p>
<h3 id="클래스의-요소">클래스의 요소</h3>
<ul>
<li>멤버</li>
<li>필드</li>
<li>생성자</li>
<li>메소드</li>
</ul>
<p><code>public, private</code>와 같은 키워드들로 명시적 타입 표시가 가능하다.</p>
<h3 id="상속"><strong>상속</strong></h3>
<ul>
<li>OOP는 상속을 이용하여 존재하는 클래스를 확장해 새로운 클래스를 생성할 수 있다.</li>
<li><code>extends</code> 키워드를 활용하여 상위클래스에서 하위클래스로 확장할 수 있다.</li>
</ul>
<h3 id="protected-접근-제어자"><strong>protected 접근 제어자</strong></h3>
<ul>
<li>멤버가 포함된 클래스와 그 하위 클래스 외부에서의 접근을 막는다.</li>
<li><code>Person</code>에서 파생된 <code>Employee</code>의 인스턴스 메소드에서는 <code>name</code>을 사용할 수 있다.</li>
<li>상속 관계에서만 쓸 수 있는 느낌</li>
</ul>
<h3 id="getters--setters"><strong>getters &amp; setters</strong></h3>
<ul>
<li>비공개로 설정하려는 속성은 <code>private</code>로 설정하고, 속성값을 읽고 수정하는 <code>getter/setter</code> 함수를 사용한다.</li>
</ul>
<h3 id="readonly"><strong>readonly</strong></h3>
<ul>
<li>읽기만 가능한 속성을 선언하기 위해 사용한다.</li>
</ul>
<h3 id="static"><strong>static</strong></h3>
<ul>
<li>전역 멤버를 선언할 때 사용</li>
<li>전역멤버: 객체마다 할당되지 않고 클래스의 모든 객체가 공유하는 멤버</li>
</ul>
<pre><code class="language-ts">class Something {
  static origin = { a: 0, b: 0 };
  add(): number {
    return Something.origin.a + Something.origin.b;
  }
}

const some = new Something();
Something.origin = { a: 1, b: 1 };
console.log(some.add()); // 2</code></pre>
<h3 id="추상-클래스"><strong>추상 클래스</strong></h3>
<ul>
<li>추상 클래스는 다른 클래스들이 파생될 수 있는 기초 클래스이다</li>
<li>직접 인스턴스화 할 수 없다</li>
<li><code>abstract</code> 키워드는 추상 클래스나 추상 메소드를 정의하는 데 사용된다</li>
<li>추상 메소드는 클래스에는 구현되어 있지 않고, 파생된 클래스에서 구현해야 한다</li>
</ul>
<pre><code class="language-ts">abstract class Animal {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  abstract makeSound(): void;
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  makeSound(): void {
    console.log(`${this.name} 멍멍!!`);
  }
}

const dog = new Dog(&quot;개&quot;);
dog.makeSound(); // 개 멍멍!!</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트의 동기, 비동기]]></title>
            <link>https://velog.io/@dev_cdd/Node.JS%EC%9D%98-%EC%A3%BC%EC%9A%94-%ED%8A%B9%EC%A7%95</link>
            <guid>https://velog.io/@dev_cdd/Node.JS%EC%9D%98-%EC%A3%BC%EC%9A%94-%ED%8A%B9%EC%A7%95</guid>
            <pubDate>Tue, 28 Mar 2023 18:13:38 GMT</pubDate>
            <description><![CDATA[<h1 id="nodejs-feature"><strong>Node.JS Feature</strong></h1>
<p><code>JavaScript</code>를 공부한 지 어느덧 4주 정도가 지났는데, 가장 핵심적인 부분인 동기 처리와 비동기 처리에 관해 정리를 할 필요가 있어 글로써 적게 되었다. 자바스크립트 개발은 주로 <code>Node.js</code>로 이루어지기 때문에 이에 대한 특징을 잘 알아야 한다. 싱글스레드, 비동기, 이벤트 기반 같은 특징이 있는데, 이는 다 연결된 개념으로 이어지기 때문에 이들을 중심으로 설명해보려고 한다.</p>
<h2 id="싱글스레드-방식"><strong>싱글스레드 방식</strong></h2>
<p>스레드는 명령을 실행하는 단위를 의미한다. 흔히 일을 하는 사람이라고도 표현할 수 있는데, 한 개의 스레드는 한 번에 한가지 동작 밖에 수행을 하지 못한다. 장점이라면 프로세스 단위에서 <code>DeadLock</code>에 대한 걱정을 하지 않아도 되고, 경쟁 상태도 신경 쓸 필요가 없지만 작업 처리 효율이 떨어진다는 단점이 있긴 한다. 대규모 프로젝트 같은 경우 백엔드를 <code>spring</code> 쪽으로 선호하는 이유도 자바는 멀티스레드 방식이기 때문이다. 이를 위해 <code>Node.js</code>에서는 비동기 동작으로 스레드 기반의 작업을 최소화한다.</p>
<h2 id="동기-방식"><strong>동기 방식</strong></h2>
<p>비동기와 대비되는 동기적(Synchronous) 방식부터 설명하자면 기본적으로 우리가 알고 있는 코드의 흐름이라고 보면 된다. 한 줄의 코드가 실행된 후에 그 다음 작업이 수행되는 절차적인 방식이다. 흐름에 있어서 헷갈릴 걱정이 없긴 하지만 가끔 앞선 작업이 오래 걸릴 경우 다음 작업이 그만큼 늦춰지게 되어 효율성을 잃게 되는 경우가 있다. 간단한 예를 들어보자.</p>
<pre><code class="language-js">for (let i = 0; i &lt; 1000; i++) console.log(&quot;First&quot;);
for (let i = 0; i &lt; 1000; i++) console.log(&quot;Second&quot;);
for (let i = 0; i &lt; 1000; i++) console.log(&quot;Third&quot;);</code></pre>
<h3 id="블로킹"><strong>블로킹</strong></h3>
<p>동기적 방식으로 실행된다고 하면 <code>First</code>가 1000번 루프를 돌 때까지 <code>Second</code>는 기다려야 하고, <code>Third</code>는 최종적으로 2000번의 루프를 기다려야 한다. 그 다음에 또 작업이 존재한다고 하면 골치 아파질 것이다. <code>블로킹</code>은 하나의 작업을 마치고 나서 다음 작업을 시작하는 순차적인 실행 방식이다. 자바스크립트에서는 이를 위해 <code>await</code>과 같은 방법을 사용한다.</p>
<h2 id="비동기-방식"><strong>비동기 방식</strong></h2>
<p>반면 비동기 방식은 특정 코드를 큐에 넣어놓고, 이후의 코드부터 실행하는 방식으로 진행된다. 만약 이전의 코드에서 도출된 결과값이 필요 없다면 이를 활용하여 훨씬 효율적인 코드를 구성할 수 있다.</p>
<pre><code class="language-js">function wait() {
  setTimeout(() =&gt; {
    console.log(&quot;비동기&quot;);
  }, 3000);
}

function Hello() {
  console.log(&quot;Hello&quot;);
}

wait();
Hello();

/* Console Output
Hello
비동기 */</code></pre>
<p>가장 대표적인 쓰임이 <code>setTimeout()</code> 함수이다. 두 번째 인자에 있는 <code>ms</code>만큼 기다렸다가 첫 번째 인자에 있는 함수를 실행한다. 동기적인 방식으로 진행된다면 <code>wait()</code> 함수가 실행되고 5초 후에 <code>Hello</code>가 출력되어야 하는데, <code>setTimeout()</code>은 비동기적인 방식으로 진행되기 때문에 <code>Hello()</code>부터 실행이 된다.</p>
<h3 id="논블로킹"><strong>논블로킹</strong></h3>
<p>논블로킹은 하나의 작업을 실행시키고, 그 작업이 마치지 않아도 다음 작업을 실행하는 방식이다. 작업을 실행시켜 놓기만 하는 느낌인데, 이렇게 구현하면 다음 작업의 지연을 걱정할 필요가 없다. 보통 결과값을 바로 리턴 받지 못하고, 콜백이나 그 외 다른 방식으로 받는 경우가 많다. 기술적으로는 사실 싱글스레드 만으로 불가능한데, 이는 나중에 설명하는 것으로 미뤄두겠다.</p>
<p><code>setTimeout</code>은 그렇다 치고, 그냥 일반적인 코드를 비동기 방식으로 변환할수는 없을까? 이에 대한 방법은 크게 세 가지 방법을 이용할 수 있다. 바로 <code>callback</code>, <code>promise</code>, <code>async/await</code>이다.</p>
<h3 id="callback"><strong>Callback</strong></h3>
<p>콜백함수라는 말이 처음에는 잘 와닿지가 않았다. 인터넷에 예시를 찾아봐도 이해하기 힘든 말들로 가득하고 말이다. 그래서 알기 쉽게 설명하자면, 콜백함수는 특정 함수가 존재할 때 인자로 넘기는 함수의 형태로 존재한다, 외형적으로 봤을 때는 그렇다.</p>
<pre><code class="language-js">function someFunction(callback) {
  console.log(&quot;not callback&quot;);
  callback();
}

someFunction(() =&gt; {
  console.log(&quot;callback&quot;);
});</code></pre>
<p>이와 같은 방법을 응용하면 <code>someFunction</code>에서 어떠한 데이터를 로드한다고 쳤을 때, 그 결과를 처리하기 위해 <code>callback</code> 함수를 비동기적으로 사용할 수 있다. 하지만 <code>callback</code> 함수를 무분별하게 사용한다면 콜백 지옥에 빠져버리게 될수도 있다. 성능을 떠나서 코드의 가독성과 유지보수 모두 헤치는 요인이 될 수 있기에 새로운 <code>Promise</code>라는 기술이 도입되었다.</p>
<h3 id="promise"><strong>Promise</strong></h3>
<p><code>Promise</code>는 비동기 작업을 표현하는 자바스크립트의 객체인데, 비동기 작업의 <code>진행(then, catch ..), 성공(resolve), 실패(reject)</code> 상태를 표현할 수 있다. 구현 방법은 객체이기 때문에 생성자가 존재하는데, 인자로 <code>resolve</code>와 <code>reject</code>를 받는다. 각각은 성공과 실패를 의미하고, 보통 조건문을 통해 <code>resolve</code>를 실행할지, <code>reject</code>를 실행할지를 결정한다. 예시 코드로 보는게 이해가 쉬울 것이다.</p>
<pre><code class="language-js">let promise = new Promise((resolve, reject) =&gt; {
  if (value &gt; 30) {
    return reject(&quot;실패&quot;);
  }
  resolve(value);
});</code></pre>
<p>이를 직접 사용하는 방식은 다음과 같다.</p>
<pre><code class="language-js">promise
  .then((data) =&gt; {
    console.log(data);
  })
  .then((data) =&gt; {
    console.log(data++);
  })
  .catch((e) =&gt; {
    console.log(e);
  })
  .finally(() =&gt; {
    console.log(&quot;종료&quot;);
  });</code></pre>
<p><code>then</code>을 계속해서 메서드 체이닝 시켜주는 방식으로 비동기 동작을 실행시킬 수 있다. 앞의 <code>then</code>이 끝나야 뒤의 <code>then</code>이 실행되고, 작업 실패 시 <code>reject</code>로 넘어가 이를 <code>catch</code>로 사용한다. <code>resolve - then</code>, <code>reject - catch</code>로 이어져있다고 생각하면 된다. 마지막으로 <code>finally</code>는 말 그대로 최종적인 의미를 담고 있는데, 위의 실행 결과가 어떻든 최종적으로 수행할 작업을 의미한다. 진행이 <code>then</code>, <code>catch</code> 둘 중 어느것이 되었든 간에 종료를 출력하는 코드는 실행된다는 말이다.</p>
<pre><code class="language-js">Promise.all([promise1, promise2, promise3])
  .then((data) =&gt; {
    console.log(&quot;All clear: &quot;, data);
  })
  .catch((err) =&gt; {
    console.log(&quot;Something Failed: &quot;, err);
  });</code></pre>
<p>다음과 같이 <code>Promise</code> 배열을 받아 모두 성공시에만 <code>then</code>을 실행시키는 방식으로도 구현할 수 있는데, 여기서 사용되는 것이 <code>Promise.all</code>이다. 하나라도 실패할 경우 에러를 출력하기 위해서, 무조건 모든 과정이 성공적으로 실행시켜야 하는 경우에 사용한다. 사실 오래된 코드의 콜백함수를 <code>Promise</code>로 변환하는 과정을 현업에서 많이 거친다고 한다. 하지만 이것보다 더 쉽게 사용할 수 있는 방법인 <code>async/await</code> 함수가 있다.</p>
<h3 id="asyncawait"><strong>async/await</strong></h3>
<p><code>Promise</code>를 활용한 방법인데, <code>await</code> 키워드를 이용한다. 단순히 함수 앞에 <code>async</code>를 써주는 것 만으로도 사용할 수 있고, <code>async</code>로 선언된 함수는 반드시 <code>Promise</code>를 리턴하여야 한다.</p>
<pre><code class="language-js">async function asyncFunc() {
  let data = await fetchData();
  let user = await fetchUser(data);
  return user;
}

fetchData = () =&gt; {
  return new Promise((res, rej) =&gt; {
    if (fetch(&#39;http://sample ...&#39;)) res();
    else rej();
  });
};

function fetchUser ...</code></pre>
<p>대충 이런식으로 작성해봤는데, 가장 주목해야 할 것은 맨 처음의 <code>async function</code>이다. <code>user</code>에서 <code>data</code>를 쓰기 때문에 <code>data</code>의 작업이 다 끝날때까지 기다려야 한다. <code>Promise</code> 같은 경우 <code>then</code>을 사용했지만 <code>async function</code>에서는 단순히 앞에 <code>await</code> 키워드를 붙여주는 것만으로도 끝난다. 가독성의 끝판왕이라고 볼 수 있고, 코드를 작성하기도 편하기 때문에 유지보수 측면에서 정말 좋다. 에러가 발생하는 경우, <code>async function</code>에서는 <code>try, catch</code>를 사용하면 된다.</p>
<pre><code class="language-js">async function asyncFunc() {
  try {
    let data = await fetchData();
    return fetchAnotherData(data);
  } catch (err) {
    console.log(err);
  }
}</code></pre>
<h2 id="event-loop"><strong>Event Loop</strong></h2>
<p>아까 싱글스레드의 비동기에 대해 간략하게 설명하고 넘어갔는데, 좀 더 자세하게 설명하기 위해서는 <code>Event Loop</code> 개념이 들어간다. <code>이전 코드의 마무리를 짓지 않고 다음 코드에 들어갔을 때, 그 코드는 어떻게 될까? 멀티 스레드면 관리 못하는거 아냐?</code> 와 같은 질문의 대답을 해줄 수 있는 개념이다.</p>
<h3 id="task-queue-microtask-queue-call-stack"><strong><a href="https://www.jsv9000.app/">Task Queue, Microtask Queue, Call Stack</a></strong></h3>
<p>위의 사이트에 들어가서 직접 코드를 실행시켜보면 어떠한 방식으로 진행되는지 알 수 있다. 그래도 좀 더 자세히 설명하기 위해 위의 사이트 내 존재하는 소스코드를 가져와봤다.</p>
<pre><code class="language-js">function logA() {
  console.log(&quot;A&quot;);
}
function logB() {
  console.log(&quot;B&quot;);
}
function logC() {
  console.log(&quot;C&quot;);
}
function logD() {
  console.log(&quot;D&quot;);
}

// 실행
logA();
setTimeout(logB, 0);
Promise.resolve().then(logC);
logD();</code></pre>
<p><code>A -&gt; B -&gt; C -&gt; D</code> 순서대로 적혀있는 만큼 순서대로 출력하면 좋겠지만, 비동기적인 방식 두 가지가 섞여 있기 때문에 예상과는 다르게 진행된다. 우선 맨 처음으로 <code>logA</code> 함수가 <code>Call Stack</code>에 올라갈 것이다, 그리고 <code>A</code>라는 값이 출력된다. 그 다음에는 <code>setTimeout</code>에 있는 <code>logB</code>가 실행될 차례인데, 지연시간이 0초임에도 불구하고 <code>logB</code>의 실행은 <code>Task Queue</code>로 가게 된다. 다음으로 <code>Promise</code> 내부에 있는 <code>logC</code> 함수가 실행되게 되는데 <code>Promise</code> 같은 경우 <code>Microtask Queue</code>로 간다. 이 두 가지 큐에 있는 작업들은 <code>Call Stack</code>이 모두 비워진 후에야 비로소 실행되게 된다. 아직 <code>Call Stack</code>에 들어갈 <code>logD</code>가 남았으므로 <code>D</code>가 출력되고 나면 <code>Microtask Queue</code>부터 순차적으로 <code>Call Stack</code>에 쌓이기 시작하고, 실행된다. 그래서 <code>A -&gt; D -&gt; C -&gt; B</code> 순으로 실행된다.</p>
<p><code>Task Queue</code>는 대기 중인 작업들의 처리를 담당하는 큐이다. <code>setInterval</code>, <code>setTimeout</code>과 같은 비동기 함수나 콜백함수에서 사용하는 큐이기도 하다. <code>Microtask Queue</code>는 <code>Task Queue</code>보다 우선순위가 높은 작업들의 처리를 담당하는데 <code>Promise</code>와 같은 비동기 함수들이 이 큐에 들어가게 된다. 일반적으로 <code>Task Queue = Message Queue</code>라고 부르기도 하고, <code>Microtask Queue = Job Queue</code>라고 부르기도 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PS Study 1st Week]]></title>
            <link>https://velog.io/@dev_cdd/PS-Study-1st-Week</link>
            <guid>https://velog.io/@dev_cdd/PS-Study-1st-Week</guid>
            <pubDate>Wed, 22 Mar 2023 16:57:36 GMT</pubDate>
            <description><![CDATA[<h1 id="algorithm-study">Algorithm Study</h1>
<p>어쩌다보니 부트캠프 내에서 스터디장을 맡게 되었다. 스터디를 만들게 된 이유는 소마 코테에서 좌절을 맛보기도 했고, 알고리즘에 대한 이해가 너무 부족해서 정말 단순한 문제들도 못풀 때도 많기 때문이었다. 교수님이 실제 코딩이 아닌 이론으로만 가르쳐줘서 코딩으로는 해 볼 생각을 안하고 있었는데, 4학년이 끝나서야 코테 공부를 시작하다니 기분이 처참해졌다. <del>컴공을 졸업해놓고 실버 문제 따위에서 해매고 있다니,</del> 이러한 부끄러운 모습을 개선하기 위해 스터디를 시작했고, 시작하자마자 좌절이었다.</p>
<h2 id="python-to-js">Python to JS</h2>
<p>사실 이때까지 <code>python</code>으로만 알고리즘 문제를 풀다보니 입출력을 받거나 배열을 구현하는 데 있어 아무런 어려움이 없었기에 문제를 몰랐다. 이번 스터디원들이 모두 <code>js</code>를 사용하여 알고리즘 스터디를 진행하길 원하기도 했고, 인터넷에 찾아보니 가끔 <code>js</code>로만 코테를 보는 곳도 있다고 해서 &#39;나도 이 참에 JS로 문제나 풀어볼까?&#39; 싶어서 반강제로(?) 팀원들의 언어를 <code>JS</code>로 고정시켰다. 나름 여러 언어들을 해왔으니 구현은 쉽겠다 싶었다, 알고리즘은 문제 해결력이 중요한거니 언어가 뭐가 문제인가 싶기도 했다. 그렇게 문제가 선정되었고, 꽤 쉬워보이는 문제들이었기에 자신감 있게 풀이에 들어갔으나 생각보다 어떻게 구현해야 할 지 감이 잡히지 않았다.</p>
<p>&#39;파이썬으로는 이렇게 했는데, 이거 <code>JS</code>로는 어떻게 풀지?&#39; 라는 생각이 자꾸 반복되면서 어쩔 수 없이 인터넷을 뒤져야 했다. 양심 상 풀이를 뒤지기는 그렇고 모르는 함수에 대해서 서칭을 했는데, 하면 할수록 끝이 없어서 결국 문제들을 다 풀지 못했다. 그래서 조만간 <code>map()</code> 함수와 같은 <code>array</code> 계열 함수에 대해 좀 공부를 하면서 이 곳에 포스팅을 해야겠다는 생각이 들었다.</p>
<p>아, 그리고 <code>readline</code> 모듈에 대해 학습하려고 했으나 뒤늦게 시작한 탓에 시간이 많이 모자라서 백준 문제를 풀지 못했다. 다음주 내로 재빨리 학습해서 주어진 모든 문제를 풀 수 있도록 해봐야겠다.</p>
<h2 id="ps">PS</h2>
<h3 id="완주하지-못한-선수"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42576">완주하지 못한 선수</a></h3>
<pre><code class="language-js">function solution(participant, completion) {
    participant.sort();
    completion.sort();

    for(var i = 0; i &lt; participant.length; i++) {
        if(participant[i] != completion[i]){
            return participant[i];
        }
    }
}</code></pre>
<p>이 문제는 간단했는데, 시간 초과 에러 때문에 약간의 애를 먹었다. 2단 루프문을 통해 처음에 결과를 구현했었는데, 테스트 케이스 시간 초과가 떠서 코드를 수정했다. 이름들이 <code>participant, completion</code>으로 주어지기에 미리 오름차순으로 배열해놓고 양 쪽 <code>index</code> 내의 값을 비교해가며 다른 결과가 나오면 곧바로 리턴하는 방식이다.</p>
<h3 id="카펫"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42842">카펫</a></h3>
<pre><code class="language-js">function solution(brown, yellow) {
  const answer = [];
  const carpet_size = brown + yellow; // 넓이

  for (let height = 3; height &lt;= carpet_size / height; height++) {
    var width = Math.floor(carpet_size / height);
    if ((height - 2) * (width - 2) === yellow) {
      return [width, height];
    }
  }
}</code></pre>
<p>이 문제를 해결하기 위해서는 격자무늬 구조에 대한 이해가 필요하다. 격자무늬 내의 모든 값을 더하면 넓이가 나오는 구조이고 그렇기에 처음부터 넓이의 값은 주어져있다. 이를 <code>carpet_size</code>로 선언해줬고, 여기에 최소 높이인 3부터 순차적으로 나눠져가며 제일 바깥 테두리 부분을 제외한 넓이가 노란색과 일치하는지에 대한 조건, <code>if ((height - 2) * (width - 2) === yellow)</code>으로 코드를 완성시켰다. </p>
<h3 id="신고-결과-받기"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/92334">신고 결과 받기</a></h3>
<pre><code class="language-js">function solution(id_list, report, k) {
  const answer = new Array(id_list.length);
  answer.fill(0);
  const report_list = {};

  id_list.map((user) =&gt; {
    report_list[user] = [];
  });

  report.map((user) =&gt; {
    const [user_id, report_id] = user.split(&quot; &quot;);
    if (!report_list[report_id].includes(user_id)) {
      report_list[report_id].push(user_id);
    }
  });

  for (const key in report_list) {
    if (report_list[key].length &gt;= k) {
      report_list[key].map((user) =&gt; {
        answer[id_list.indexOf(user)] += 1;
      });
    }
  }
  return answer;
}</code></pre>
<p>사실 이 문제를 풀 때가 제일 난감했는데, 머릿 속에 떠오른 구현을 어떻게 처리할지 고민이 많았다. 그렇게 수차례 시도하다가 결과값이 이상하게 나와서 <a href="https://velog.io/@dnjsdud2257/%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0-JavaScript">타인의 문제풀이</a>를 참고했다. <code>answer</code>에 0을 채워 <code>[0, 0, 0, 0]</code>과 같은 형태로 만들어주고, 마지막에 처리 결과를 담아주는 식으로 구현했다. <code>id_list</code>에서 <code>map()</code> 함수를 이용하여 <code>user</code>, 즉 <code>key</code> 값을 설정해주고 <code>value</code>는 빈 배열 형태로 구성한다. <code>report</code>에서 <code>map</code> 함수는 인자로 받아온 <code>report</code> 배열에서 신고를 <strong>한</strong> 사람과 <strong>당한</strong> 사람을 따로 저장하고, <code>if (!report_list[report_id].includes(user_id)</code>를 통해 중복 확인을 해준다. 중복이 아닐 경우 <code>report_list</code>의 <code>report_id</code>에 해당되는 키 값에 <code>user_id</code>라는 <code>value</code> 값을 <code>push</code> 해준다. 마지막 루프문은 <code>value</code>의 길이를 세 몇 명의 사람에게 신고를 당했는지 확인해주는 방식이다.</p>
<h3 id="바이러스"><a href="https://www.acmicpc.net/problem/2606">바이러스</a></h3>
<pre><code class="language-python">import sys
from collections import deque


def BFS(V):
    queue = deque([V])
    visited_BFS[V] = 1
    count = 0
    while queue:
        V = queue.popleft()
        for i in range(computerCount):
            if linkedList[V][i] == 1 and visited_BFS[i] == 0:
                queue.append(i)
                visited_BFS[i] = 1
                count += 1
    print(count)


computerCount = int(input())
link = int(input())
linkedList = [[0 for _ in range(computerCount)]
              for _ in range(computerCount)]
visited_BFS = [0] * (computerCount)

for i in range(link):
    x, y = map(int, sys.stdin.readline().split())
    linkedList[x-1][y-1] = linkedList[y-1][x-1] = 1

BFS(0)</code></pre>
<p><code>computerCount</code>로 컴퓨터의 개수를 입력받고, <code>linkedList</code> 배열을 이용하여 각 인덱스마다 <code>[0, 0, 0, 0 ...]</code>의 형식으로 채워준다. 이렇게 하는 이유는 이어지는 경우를 체크하기 위해서이다. 방문 확인을 위한 <code>visited_BFS</code> 배열도 만들어주고, 반복문으로 이어지는 점들을 입력 받아 <code>linkedList</code> 배열의 해당 인덱스에 1로 표시해준다.</p>
<pre><code class="language-python"># 1번 컴퓨터가 2, 4번 컴퓨터에 연결 되어 있는 linkedList 구조
[[0, 1, 0, 1, 0 ...], ...]</code></pre>
<p>그리고 나서 깊이 우선 탐색으로 들어가는 데 초기 인자를 0으로 넘겨준 이유는 1번부터 탐색을 시작하기에 그렇게 넘겨줬다. <code>queue</code>를 만들어 준 후에 <code>[0] : 1번 컴퓨터</code>의 <code>visited</code> 값을 1로 바꿔주고, <code>queue</code>가 끝날 때까지 반복하여 순회한다. <code>for loop</code> 안에 있는 조건문을 보면 <code>queue</code>에서 <code>popleft</code>된 값과 이어진 부분을 검사하는 조건과 방문 여부를 확인할 수 있는 조건 이렇게 총 2개로 이뤄져있다. 그렇게 선정된 <code>i</code>는 <code>queue</code>에 <code>append</code>되고, 탐색 카운팅이 올라가는 구조로 되어있다.</p>
<p>사실 비슷한 류의 <code>BFS, DFS</code>를 몇 문제 풀어봤지만 <code>JS</code>로 시도하다가 실패했다. <code>JS</code>에 대해 더 열심히 공부해봐야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[this in JavaScript]]></title>
            <link>https://velog.io/@dev_cdd/this-in-JavaScript</link>
            <guid>https://velog.io/@dev_cdd/this-in-JavaScript</guid>
            <pubDate>Thu, 16 Mar 2023 18:23:09 GMT</pubDate>
            <description><![CDATA[<h1 id="intro">Intro</h1>
<p>객체 지향 언어를 다뤄보았다면 한 번 즈음은 들어봤을 만한 단어 <code>this</code>, 주로 클래스 내에서 자기 자신을 가리키기 위해 사용하는 방식으로 알고 있었다. 그런데 JS에서는 종종 다른 느낌을 받아서, 이번에 공부를 통해 알게된 <code>this</code> 연산자의 사용에 대한 여러가지 케이스들을 작성해보려고 한다.</p>
<h2 id="기존에-알고--있던-일반적인-this">기존에 알고  있던 일반적인 this</h2>
<pre><code class="language-js">class Person {
  height;
  weight;
  constructor(h, w) {
    this.height = h; // 객체 자기 자신을 가리킬 때 쓰이는 this
    this.weight = w;
  };
}

const p1 = new Person();</code></pre>
<p>기존에 알고 있던 가장 보편적인 <code>this</code>의 쓰임이다. <code>class</code>의 목적 중에 캡슐화, 은닉화 정도를 위해 다른 언어들에서는 내부 변수를 <code>private</code> 선언하며 <code>get(), set()</code> 함수를 정의해 외부 스코프에서도 클래스의 내부 변수에 접근하는 방법이 있다. 여기서 메서드 하나를 만들어보자.</p>
<pre><code class="language-js">class Person {
  ... // height, weight, constructor
  heightAverageDifference(average) {
    return this.height - average
  }
}</code></pre>
<p>클래스 속성의 <code>height</code> 값에 평균치를 뺀 편차를 반환하는 함수이다. <code>this</code>는 <code>Person</code>으로 만들어진 하나의 객체를 가리키기 때문에 내부 선언된 <code>height, weight</code> 값에 접근할 수 있다는 특성이 있다. 여기까지가 기존에 알던것이고, 이 다음부터 나오는 것은 모르고 있었던 <code>JS</code> 내의 <code>this</code> 사용 예시이다.</p>
<h2 id="함수-스코프에서의-this">함수 스코프에서의 this</h2>
<h3 id="일반-함수에서의-this">일반 함수에서의 this</h3>
<pre><code class="language-js">function returnBMI (h, w) {
  let height;
  this.height = h;
  return w / height ** 2;
}

returnBMI(1.7, 70)// Error</code></pre>
<p>육안으로 봤을 때는 정상적으로 작동할 것 같지만 이 코드는 그럴수가 없다. 여기서 사용되는 <code>this</code>는 당연히 함수 본인 <code>returnBMI()</code>를 가리킬 것 같지만, 실제로는 다른 곳을 가리키고 있다. 함수 내 사용되는 <code>this</code>는 함수를 호출한 곳을 가리키는데, 인터넷을 서칭하다보니 함수에서 실행된 컨텍스트 내(<code>object, class 어디에도 바인딩 되지 않은 케이스</code>의 <code>this</code>는 거의 무조건적으로 <code>global scope</code>을 가리킨다고 한다.</p>
<h3 id="nodejs-vs-browser-console">nodeJS VS Browser Console</h3>
<pre><code class="language-js">function thisIsGlobal () { console.log(this); }
thisIsGlobal();</code></pre>
<p>임의의 함수를 만든 후, 실행을 해보면 다음과 같은 결과가 나온다.</p>
<pre><code class="language-js">&lt;ref *1&gt; Object [global] {
  global: [Circular *1],
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  structuredClone: [Getter/Setter],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  atob: [Getter/Setter],
  btoa: [Getter/Setter],
  performance: [Getter/Setter],
  fetch: [AsyncFunction: fetch],
  crypto: [Getter]
} // nodeJS 환경에서 실행 시

Window {0: Window, window: Window, self: Window, document: document, name: &#39;&#39;, location: Location, …} // 브라우저 개발자 도구의 console에서 실행시</code></pre>
<p>둘 다 <code>global</code>을 가리킬텐데 왜 결과가 다르게 나오는지에 대한 의문이 들 수 있다. 바로 설명하자면 <code>nodeJS</code>에서는 다음과 같이 전역 스코프가 구성되어 있고, 브라우저 같은 경우 <code>Window</code>가 전역 객체를 의미하기 때문에 <code>Window</code>를 출력한다. 실행 컨텍스트의 <code>call stack</code> 구조를 보면 초기 상태에서 <code>this</code>가 <code>Window</code>를 가리키고 있는 이유이기도 하다. 브라우저 콘솔에 다음과 같은 코드를 쳐보면 알 수 있다.</p>
<pre><code class="language-js">$ var a = 10;
$ let b = 20;
$ console.log(window.a); // 10
$ console.log(window.b); // Error</code></pre>
<p><code>Window</code>가 전역 객체이기 때문에 <code>console.log(window.b)</code>도 정상 작동해야 할 것 같지만, 관련해서 정보를 찾아보니까 <code>Window</code> 객체 내부에 보이지 않는 개념적인 블록 스코프가 존재한다고 한다. <code>let</code>과 <code>const</code>는 블록 스코프 내에서만 유효하므로 <code>window</code>에서 접근을 할수가 없는 것이다. 사실 실사용이 자주 될 것 같지 않은 개념이기는 한데, <code>this</code>가 전역 스코프를 가리킨다는 내용은 분명 중요하다.</p>
<h2 id="class와-object-내에서의-this">Class와 Object 내에서의 this</h2>
<pre><code class="language-js">const personObject = {
  function thisFunction () {
    console.log(this); // personObject 객체
  },
  thisArrowFunction = () =&gt; {
    console.log(this); // globalScope
  }
}

class personClass {
  function thisFunction () {
    console.log(this);
  }; // personClass 객체
  thisArrowFunction = () =&gt; {
    console.log(this);
  }; // personClass 객체
}</code></pre>
<p>헷갈릴수도 있는 코드이기도 한데, 출력 값은 주석을 참고하면 될 것 같다. 오브젝트 내에서의 <code>this</code> 같은 경우 일반 함수에서 쓰였을 때는 스코프체인으로 묶여있는 <code>Object</code>를 가리킨다. 화살표 함수 같은 경우 그렇지 않고, 전역 스코프를 가리키는데 자신이 생성된 환경을 가리키기 때문이다. 이것에 대해서 좀 더 잘 이해하기 위해서는 <code>Lexical Enviroment / Scope</code>에 관련해서 찾아보면 될 것이다. 반면 <code>class</code>는 모든 <code>this</code>가 객체 자신을 가리키는데, 정확히 어떤 스코프 차이가 있는지는 잘 모르겠지만 뭐 그렇다. 여러 번 코드를 작성해보면 <code>this</code>가 어디를 가리키고 있는지에 대한 감이 올 것이다.</p>
<h3 id="class-object-내의-메서드-내의-메서드가-가리키는-this">Class, Object 내의 메서드 내의 메서드가 가리키는 this</h3>
<pre><code class="language-js">class personClass {
  function f1() {
    function f2() { console.log(this); }
  }
}</code></pre>
<p>다음과 같이 되어 있는 코드에서 &quot;<code>this</code>는 당연히 personClass를 가리키겠지&quot; 라고 생각했다면 오답이다. 함수를 실행시켜보면 <code>this</code>는 전역을 가리키는 것을 알 수 있는데, 함수 컨텍스트에서 쓰인 <code>this</code>는 무조건 전역을 가리킨다. <code>this</code>의 시점이 함수 실행이면  사실 상 전역을 가리킨다고 보면 된다. 그렇다면 메서드 내의 함수에서 <code>this</code>가 전역을 가리키게 만드려고 하면 어떻게 해야 할까? 바로 화살표 함수를 쓰면 된다.</p>
<h3 id="화살표-함수의-this-vs-일반-함수의-this">화살표 함수의 this VS 일반 함수의 this</h3>
<pre><code class="language-js">class personClass {
  function f1() {
    function f2() { console.log(this); } // 전역
  }
  function f3() {
    f4 = () =&gt; { console.log(this); } // personClass 객체
  }
}</code></pre>
<p>기본적으로 <code>f1()</code>이나 <code>f3()</code>에서 <code>this</code>를 사용한다면 모두 동일하게 <code>personClass</code>를 가리키지만 그 안의 <code>f2()</code>와 <code>f4()</code>에서 쓰이는 <code>this</code>는 각기 다른 곳을 가리킨다. <code>arrow function</code>을 사용하면 함수에서의 실행 컨텍스트 개념이 아니라 <code>personClass</code>와 바인딩 되어 있는 느낌이라 그대로 <code>this</code>를 사용하여 내부 값에도 접근 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[How to use Git?]]></title>
            <link>https://velog.io/@dev_cdd/How-to-use-Git</link>
            <guid>https://velog.io/@dev_cdd/How-to-use-Git</guid>
            <pubDate>Tue, 14 Mar 2023 16:52:09 GMT</pubDate>
            <description><![CDATA[<h1 id="lets-use-git-">Let&#39;s Use Git !!</h1>
<p>이전에 만들었던 프로젝트의 소스를 깃에 업로드 했던 적이 몇 번 있다. 사실 몇 번 사용해 본 적이 있음에도 협업에는 단 한 번도 사용해보지 않아 이번 기회를 통해 관련 명령어들을 정리하며 방법을 정리해 볼 생각이다. 그리고 남이 &#39;Git 어떻게 써요?&#39;라고 물어볼 때마다 이 링크를 전해줄 예정이다.</p>
<h2 id="-create-repository-">** Create Repository **</h2>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/4ff17785-6faf-42d2-9287-3206d134c215/image.png' width = 100% heigh = 50% />

<p>상단의 <code>New</code> 버튼을 누르면 레포지토리를 생성할 수 있다. 여러가지 설정 창들이 뜨겠지만 <code>README</code> 옵션 정도만 체크해주고 넘어가면 될 것 같다. 해당 옵션이 활성화 되면 <code>README.md</code> 파일이 만들어지는데, 마크다운 문법을 통해 해당 레포지토리를 설명하는 글을 포스트 형식으로 작성할 수 있다. 지금 작성하고 있는 이 <code>velog post</code>도 마크다운 문법으로 작성되었다.</p>
<h3 id="-git-cloneyour-site-">** git clone(your site) **</h3>
<p><img src="https://velog.velcdn.com/images/dev_cdd/post/b17b0226-8d03-4f85-821e-328e89521765/image.png" alt=""></p>
<p>레포지토리를 만들었으면 다음과 같은 창이 뜨게 된다. 이 레포지토리에 있는 데이터들을 깔끔하게 가져오고 싶다면 <code>git clone</code>을 쓰면 되는데, 맥이라면 터미널을 쓰고 윈도우라면 파워쉘을 사용하는 것이 명령어 환경에 친숙해지는 데에 도움이 된다. 앞으로의 설명도 <code>console</code>에서의 명령어들로 구성되니 정말 아무것도 모르는 상태라면 <code>git</code>부터 설치해야 한다. 윈도우는 알아서 하고, 맥은 <a href="https://brew.sh/">brew</a>에서 <code>brew install git</code> 명령어를 사용해서 깃을 설치하면 된다. 그 이후로 <code>git clone { 본인 레포지토리 링크 ... }</code> 형식으로 사용하여 주면 된다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/3e1acf10-a25f-46c7-b880-2b3f160e3b09/image.png' width = 70%>
</p>


<p>다음과 같이 제대로 레포지토리를 <code>clone</code> 해온 모습을 볼 수 있다. <code>ls</code> 명령어를 통해 <code>README.md</code> 파일을 확인했다.</p>
<h1 id="how-to-upload">How to Upload?</h1>
<h2 id="clone-이후-commit"><strong>clone 이후 commit</strong></h2>
<p>사실 저런 식으로 가져오게 된다면 그냥 다음과 같은 형식으로도 업로드 할 수 있다.!</p>
<pre><code class="language-bash">touch test.py
git add .
git commit -m &#39;commit message&#39;
git push</code></pre>
<p>하지만 이 글을 쓴 이유 자체가 협업을 위함이기에 <code>branch</code>를 만들어 로컬에서 <code>merge</code> 후 <code>push</code>를 써볼 생각이다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/2a20afda-a120-481a-97d2-0a5a7f18e926/image.png' width = 70%>
</p>

<h2 id="branch를-활용한-commit"><strong>branch를 활용한 commit</strong></h2>
<pre><code class="language-bash">git branch test-branch &amp;&amp; git checkout test-branch // test-branch를 만들고 main branch에서 test-branch로 이동
git add . // 수정된 파일들을 올려놓는 상태
git commit -m &#39;Initial commit&#39; // 해당 브랜치에 커밋
git checkout main // 다시 main으로 이동
git merge test-branch // main 브랜치에 test-branch를 병합
git push // 최종적인 업로드</code></pre>
<p>문제 없이 업로드 된 것을 볼 수 있다. 작은 기능 단위로 <code>branch</code>를 자주 쪼개주면서 기능 개발이 완료되면 <code>merge</code> 시키는 방식이 안정성에서도, 가시성에서도 우수하다고 한다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/93cf00ff-f397-4b87-a567-049d399d2ecf/image.png' width = 70%>
</p>

<p>다음은 다른 방식으로 파일을 가져온 경우인데 <code>git remote add origin</code> 방식을 사용한다.  현재 <code>git</code>에 업로드 된 레포지토리는 원격 저장소로써의 역할을 하고 거기에 <code>remote add origin</code>을 통해 <code>origin</code>이라는 이름을 붙여주는 느낌이다. 이 방법을 따르면 <code>push</code> 이후 가끔 다음과 같은 오류를 볼 수 있다.</p>
<pre><code>fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

To have this happen automatically for branches without a tracking
upstream, see &#39;push.autoSetupRemote&#39; in &#39;git help config&#39;.</code></pre><p>이럴 땐 겁 먹지 말고 그냥 <code>git push --set-upstream origin master</code>를 복붙 해주면 되고, 이후 <code>push</code> 명령의 결과값은 다음과 같다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/d8ed8f20-273a-4b09-bf65-ce0dc2463966/image.png' width = 70%>
</p>

<h3 id="pull-request">Pull Request</h3>
<p>아까와의 차이라고 하면 <code>git</code> 내에서 <code>pull request</code>를 받아야 한다는 것이다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/7ba2c4ea-6a42-4779-8024-ed2b8d375529/image.png' width = 70%>
</p>

<p>다음과 같이 <code>Compare &amp; pull request</code>가 뜨게 되는데 파일을 <code>merge</code> 할지 확인하는 <code>request</code> 느낌이다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/28bbdf1a-3fa4-49af-8259-d17b279aa05a/image.png' width = 70%>
</p>

<p>이것은 레포지토리의 해당 권한을 가진 사람이 볼 수 있는 창인데 코드 리뷰 및 설명 등을 적고 <code>Create pull request</code>를 누르면 <code>pull request</code>가 생성되며 <code>main branch</code>와의 병합 여부를 결정할 수 있는 창이 나온다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/ea28e2e3-d15c-4872-b0df-8ceef8887fda/image.png' width = 70%>
</p>

<p><code>merge</code> 이후 성공적으로 <code>index.html</code> 파일이 저장소에 저장된 모습을 볼 수 있다.</p>
<p>
<img src = 'https://velog.velcdn.com/images/dev_cdd/post/704f5c7c-d0bc-4c5a-b405-9fb40c1035d1/image.png' width = 70%>
</p>

]]></description>
        </item>
        <item>
            <title><![CDATA[Class, Iterator, Generator in JavaScript]]></title>
            <link>https://velog.io/@dev_cdd/Class-Iterator-Generator-in-JavaScript</link>
            <guid>https://velog.io/@dev_cdd/Class-Iterator-Generator-in-JavaScript</guid>
            <pubDate>Tue, 14 Mar 2023 08:18:46 GMT</pubDate>
            <description><![CDATA[<p>사실 JS를 새로 학습하기 시작하면서 생겼던 의문이 있다. <code>object</code> 의 형태가 <code>class</code>와 너무 유사해보여서 <code>class</code>라는 개념이 존재하는지에 대해서도 긴가민가 했다. 이에 대해서 적어보려고 한다.</p>
<h2 id="-class-vs-object-">** class VS object **</h2>
<pre><code class="language-js">const Person = {
  height: a,
  weight: b,
} // object

class Person {
  height;
  weight;
  #className = &#39;swTrack&#39;;
  constructor(height, weight) {
    this.height = height;
    this.weight = weight;
  } // 생성자
}

const personOne = new Person(174, 70);</code></pre>
<p>미래의 나를 위한 설명이기 때문에 자세한 설명은 생략하고, 간략하게 설명하자면 기존의 다른 객체 지향 언어들과 상당히 유사한 모습을 지녔다. 생성자도 존재하고, 그 이외의 클래스 내 변수들도 존재한다. 앞에 <code>#</code>을 붙이는 경우 <code>private</code>과 동일한 기능을 지니게 되며 스코프 외부에서 참조하는 것이 불가능하게 된다. <code>console.log(personOne.#className);</code>이 안먹힌다는 소리다.</p>
<pre><code class="language-js">class Element {
  #origin = &#39;Element&#39;;
  ...
}

class Input extends Element {
  constructor() {
    super(); // 부모의 속성을 상속받음
    this.name = &#39;Input&#39;; // 덮어쓰기
  }
}</code></pre>
<p>상속과 같은 개념도 물론 존재한다. 자식 생성자 부분의 <code>super()</code>는 부모의 데이터들을 상속받는 역할을 한다. 사실 <code>super()</code>을 사용하지 않으면 그냥 문법 오류가 떠버려서 필수적으로 써야하고, 그렇기 때문에 구조상 부모 클래스의 모든 값들을 상속 받을 수 밖에 없다. 일반적인 캡슐화를 위한 <code>private</code> 속성을 구현하기 위해서는 변수 앞에 <code>#</code>을 붙이면 된다. 그 예가 <code>Element</code> 클래스의 <code>#origin</code>이다. 심볼을 사용하는 방식도 존재하긴 하지만 문법적으로 <code>#</code>이 공식화 되었기 때문에 굳이 알아야 할 필요는 없을 것 같다.</p>
<h2 id="-이터레이터-iterator-">** 이터레이터 (Iterator) **</h2>
<pre><code class="language-js">function iter() {
  let num = 1;

  return {
    next: () =&gt; {
      const done = num &gt; 10; // num이 10보다 클 시 done = true
      const item = { done };
      if (!done) item.value = num++; // 10보다 작을시 num 값 1 증가

      return item;
    },
  };
}

const numEx = iter();
console.log(numEx.next());
console.log(numEx.next());
console.log(numEx.next());</code></pre>
<p>가장 기본적인 이터레이터 사용 예시이다. 동적인 특성을 지니고 있는데, 그렇기 때문에 메모리 관리 측면에서 유리하다는 장점을 가지고 있다. 이런 카운팅 예제에서 특히 많이 쓰이는 것 같고, 사용 시 <code>next()</code> 메서드를 호출하면 된다.</p>
<pre><code class="language-js">next() -&gt; { done: true | false, value : ? }</code></pre>
<p><code>next()</code> 자체의 사용 방식이다. 조건이 충족되어 <code>done</code> 값이 <code>true</code>가 된다면 그 이후에 아무리 함수를 호출하여도 계속해서 같은 값이 반복되어 나온다. 위의 예제를 봐도 이미 10보다 커져버렸으니 값을 증가시킬 필요가 없기 때문이다.</p>
<h3 id="이터러블-iterable-">*<em>이터러블 (Iterable) *</em></h3>
<pre><code class="language-js">const nums = [1, 2, 3, 4, 5];
const elements = document.querySelectorAll(&#39;div&#39;);

for (const num of nums) {
  console.log(num);
}

for (const element of elements) {
  console.log(element); // Node 0, 1, 2, 3 ...
}</code></pre>
<p>예제 코드를 보면 <code>elements</code>는 <code>querySelectorAll()</code>을 통해 다중 값들을 가져온 모습을 확인할 수 있다. 이 같은 경우 모든 값들이 배열 형태로 들어왔다는 착각을 할 수 있는데, 저런식으로 가져오게 된다면 <code>Node</code> 형태로 값을 가져오는 모습을 콘솔창으로 확인할 수 있다. <code>iterable</code>은 말 그대로 어떠한 집합이던 간에 <code>for .. of</code> 문법을 적용할 수만 있다면 <strong>이터러블(반복 가능)</strong>의 예가 될 수 있다는 것이다. </p>
<pre><code class="language-js">function iter() {
  let num = 1;

  const iterator = {
    next: () =&gt; {
      const done = num &gt; 5;
      const item = { done };

      if (!done) item.value = num++;
    },
  };

  return {
    [Symbol.iterator]() {
      return iterator;
    },
  };
}

for (const num of iter()) {
  console.log(num);
}</code></pre>
<p><code>[Symbol.iterator]</code>은 이터레이터 객체를 반환한다. <code>next()</code>와 저런식으로 나누어 작성할 수 있고, 기능은 사실 <code>iterator</code> 예제와 동일하다고 보면 된다.</p>
<pre><code class="language-js">class Nums {
  #num = 1;

  next() {
    if (this.#num &gt; 11) {
      return { done: true };
    }
    const value = this.#num;
    this.#num += 1;

    return {
      done: false,
      value,
    };
  }

  [Symbol.iterator]() {
    return this;
  }
}</code></pre>
<p>클래스 내의 <code>iterator</code> 사용도 비슷한 느낌이다. 저 문법을 외운다는 느낌보다는 원리에 대한 이해가 필요할 때마다 찾아서 보면 될 것 같다. 사실 이것보다 훨씬 쉬운 방식이 다음 내용에 나오기 때문이다.</p>
<h3 id="-제네레이터-generator-">** 제네레이터 (Generator) **</h3>
<p>앞의 모든 내용들은 이 제네레이터 개념을 이해하기 위한 빌드업이라고 생각하면 된다. 구현 방법은 간단하지만 원리는 <code>iterator</code>를 어느정도 이해할 수 있어야 한다. 예제 코드를 보자.</p>
<pre><code class="language-js">function* iter() {
  for (let i = 1; i &lt;= 10; i++) {
    yield i;
  }
}

for (const num of iter()) {
  console.log(num);
}</code></pre>
<p><code>function*, yield</code>라는 키워드가 익숙치 않을 수 있지만, 각각 반복 함수, 반환 value 값 정도인 것 같다. 그냥 메모리 관리가 필요하거나 저런 식의 카운팅 구현이 필요할 때마다 다시 이 곳을 찾아 방법을 확인하게 될 것 같다.</p>
<pre><code class="language-js">function* pick(items) {
  for (let i = 0; i &lt; items.length; i++) {
    for (let j = i + 1; j &lt; items.length; j++) {
      yield [items[i], items[j]];
    }
  }
}

const coms = [...pick([&quot;hello&quot;, &quot;world&quot;, &quot;good&quot;, &quot;day&quot;])];
console.log(coms);</code></pre>
<p>위의 예제는 목록들 중 몇개를 선정하여 팀을 짜는 <code>Combination</code> 기능 구현인데, 확실히 제네레이터는 코드 길이와 로직 구현에서 훨씬 짧고 간단하다는 특성이 있다.</p>
<pre><code class="language-js">function* pick(items, count) {
  yield* _pick([], count, 0);

  function* _pick(state, count, i) {
    for (; i &lt; items.length; i++) {
      const picked = [...state, items[i]];

      if (count === 1) {
        yield picked;
      } else {
        yield* _pick(picked, count - 1, i + 1);
      }
    }
  }
}

const samples = [1, 2, 3, 4, 5, 6, 7];

const coms = [...pick(samples, 5)];

console.log(coms);</code></pre>
<p>이 예제 코드를 이해할 정도면 <code>generator</code>에 대한 이해가 완벽하게 끝났다고 봐도 될 정도라고 한다. 서칭을 해보니 <code>yield*</code> 부분은 <code>iterator()</code>가 끝나는 시점 <code>done, true</code>가 되었을 때의 리턴값을 갖는다고 한다.</p>
<p>먼저 조합을 담을 그릇 <code>state</code>를 <code>[]</code>로 초기화 시킨 후에 <code>_pick</code> 함수를 실행시켜 조합을 만들게 된다. <code>count</code>의 값은 조합이 늘어날 때마다 1씩 감소되게 하고 <strong>i</strong> 값은 1씩 증가하면서 계속해서 <code>_pick</code> 함수를 재귀 호출하게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IndexedDB]]></title>
            <link>https://velog.io/@dev_cdd/IndexedDB</link>
            <guid>https://velog.io/@dev_cdd/IndexedDB</guid>
            <pubDate>Mon, 13 Mar 2023 11:06:05 GMT</pubDate>
            <description><![CDATA[<h1 id="web-storage">WEB Storage</h1>
<p>보통 웹페이지를 구성할 때 정보들을 <strong>기억</strong>해야 할 때가 분명 존재한다. 간단한 텍스트부터 용량이 꽤 되는 파일까지 다양한 요소들이 있다. 이를 위해 당연히 외부 DB를 사용할 것이라고 생각하겠지만 간단한 정보를 위해 외부 DB에 접근해서 값을 찾아오는 것은 성능적인 부분에서 꽤 손해가 큰 경우가 많다. 그럴 때 사용하는 것이 웹 브라우저 내의 <code>Storage</code> 기능인 <code>local storage, session storage</code> 기능이다.</p>
<h2 id="-local-storage-">** Local Storage **</h2>
<p>로컬 스토리지는 말 그대로 본인이 사용하고 있는 로컬 환경에 저장하는 방식이다. 세션을 종료하더라도 자료가 그대로 남고, 재활용에 용이하다는 장점이 있다. 크롬의 개발자 모드에서 <code>Application - Local Storage</code>로 들어가면 확인할 수 있고, 구현방식도 되게 간단하다.</p>
<pre><code class="language-js">localStorage.setItem(&#39;cdd&#39;, &#39;crazy&#39;);</code></pre>
<p>이런식으로 값을 <code>set</code> 해줌으로써 <code>local storage</code>에 값이 저장된다. 여기서 값을 다시 꺼내오려면 다음과 같이 진행하면 된다.</p>
<pre><code class="language-js">const cat = localStorage.getItem(&#39;myCat&#39;);</code></pre>
<p>메서드 종류는 다음과 같다.</p>
<pre><code>- setItem(key, value) – 키-값 쌍을 보관
- getItem(key) – 키에 해당하는 값을 받아옴
- removeItem(key) – 키와 해당 값을 삭제
- clear() – 모든 것을 삭제
- key(index) – 인덱스(index)에 해당하는 키를 받아옴
- length – 저장된 항목의 개수를 얻음</code></pre><p>하지만 이 방식은 브라우저마다 용량에 대한 제한이 있고, 그 제한이 15mb 정도라서 요즘의 고화질 이미지를 생각하면 1, 2장 정도로 끝나버리는 용량이다.</p>
<h2 id="session-storage"><strong>Session Storage</strong></h2>
<p>사실 세션 스토리지는 아직까지도 큰 필요성을 잘 못느끼고 있다. 탭을 닫으면 정보가 사라지고, 그렇기 때문에 이름에 <code>Session</code>이 들어가지 않을까 싶다. 메서드는 <code>local storage</code>와 동일하고, 생명주기 정도만 다르다고 인식하면 될 것 같다. 데이터가 갱신될 때는 <code>storage</code> 이벤트가 실행되는데, 종류는 다음과 같다고 한다.</p>
<pre><code>key – 변경된 데이터의 키 ( .clear()를 호출했다면 null )
oldValue – 이전 값 ( 키가 새롭게 추가되었다면 null )
newValue – 새로운 값 ( 키가 삭제되었다면 null )
url – 갱신이 일어난 문서의 url
storageArea – 갱신이 일어난 localStorage나 sessionStorage 객체</code></pre><h2 id="indexeddb"><strong>IndexedDB</strong></h2>
<p><code>DB</code>라는 이름이 붙은만큼 <code>transaction</code> 기능을 제공하는데, <code>local storage</code>나 <code>session storage</code>와 같이 <code>client</code> 입장에서 사용할 수 있는 <code>client storage</code> 형태로 사용하게 된다. 일반적인 DB와 다른 점이라면 <code>B-Tree</code> 구조를 형성하고 있고, <code>NoSQL</code> 즉 쿼리문을 사용할 수 없다. <code>Object Store : DB의 테이블 역할</code>와 <code>key, value</code> 형태로 데이터들이 저장이 되며, 이를 고려해서 코드를 작성해야 한다. 부트캠프에서 인스타그램 클론 코딩을 진행했었는데, 사진과 데이터를 저장할 수 있는 공간이 필요해서 사용하게 되었다.</p>
<h3 id="open-indexeddb">open IndexedDB</h3>
<pre><code class="language-js">const request = indexedDB.open(databaseName, version);</code></pre>
<p>데이터베이스 생성 방식은 다음과 같다. <code>indexedDB.open</code> 메서드에 인자값으로 데이터베이스의 이름과 버전이 들어간다. </p>
<pre><code class="language-js">shareBtn.addEventListener(&quot;click&quot;, function () {
  if (window.indexedDB) {
    const databaseName = &quot;instagram&quot;;
    const version = 1;
    const request = indexedDB.open(databaseName, version);
    const data = {
      content: document.querySelector(&quot;modal__write &gt; textarea&quot;).value,
      image: imageBase64,
    };
    request.onupgradeneeded = function () {
      request.result.createObjectStore(&quot;posts&quot;, { autoIncrement: true });
    };

    request.onsuccess = function () {
      const store = request.result
        .transaction(&quot;posts&quot;, &quot;readwrite&quot;)
        .objectStore(&quot;posts&quot;);

      store.add(data);
    };
  }
});</code></pre>
<p>위의 코드는 인스타그램 클론 코딩에서 <code>shareBtn</code>을 눌렀을 시에 대한 <code>Event Listener</code>인데, 전반적인 <code>indexedDB</code> 생성 구조를 살펴볼 수 있다. <code>window.indexedDB</code> 부분은 <code>indexedDB</code>의 오픈 여부를 확인하는 것이고, <code>databaseName</code>과 <code>version</code>을 직접 변수로 등록해서 바로 인자값으로 넣을 수 있게 만들었다. <code>data</code> 부분은 블록 스코프를 만들어서 내용(content)와 이미지(image) 형태로 저장할 수 있게 해두었고, <code>onupgradeneeded</code>에서는 키값을 자동으로 증가하게 해서 데이터들을 저장할 수 있게 해두었다. <code>const store</code> 부분은 <strong>request</strong>, 즉 indexedDB가 성공적으로 open 되었을 때 <code>transaction</code>을 생성하고 <strong>posts</strong>라는 이름의 <code>objectStore</code>을 생성한다. 마지막 <code>add()</code> 메서드는 data를 DB에 업로드하는 식이다.</p>
<p>종종 예외처리를 하지 않아 오류가 발생하는 경우가 있는데, 그런 경우 다음과 같은 코드를 작성해주면 해결할 수 있다.</p>
<pre><code class="language-js">request.onerror = (event) =&gt; {
  console.error(&quot;indexedDB error:&quot;, event.target.error);
}; // request 예외처리

else {
  console.error(&quot;indexedDB is not supported&quot;);
} // onsuccess 예외처리</code></pre>
<h3 id="indexeddb-값-가져오기">IndexedDB 값 가져오기</h3>
<p>그러면 이제 indexedDB에 업로드 된 모든 결과들을 화면에 출력해야 하는데, <code>getAll()</code> 메서드를 활용하면 된다.</p>
<pre><code class="language-js">store.add(data).onsuccess = function () {
              store.getAll().onsuccess = function (e) {
                const response = e.target.result;
                const mainPostsEl = document.querySelector(&#39;.main__posts&#39;);
                mainPostsEl.setAttribute(&#39;class&#39;, &#39;main__posts&#39;);
                document.querySelector(&#39;body&#39;).removeChild(modalEl);
                mainPostsEl.innerHTML = &#39;&#39;;
                for (let i = 0; i &lt; response.length; i++) {
                  const postListEl = document.createElement(&#39;img&#39;);
                  postListEl.setAttribute(&#39;src&#39;, response[i].image);

                  document
                    .querySelector(&#39;.main__posts&#39;)
                    .appendChild(postListEl);
                }
              };</code></pre>
<p><code>getAll()</code> 메서드를 이용하면 <code>e.target.result</code>을 통해 모든 값들을 가져올 수 있다. 그렇다고 바로 쓸 수 있는게 아니고, <code>for loop</code>와 <code>setAttribute</code>를 통해 각 데이터 타입의 객체들을 삽입해줘야 한다. <code>data</code>에는 위에서 <strong>content</strong>와 <strong>image</strong> 값을 가지고 있었으므로 결과 창에서 보일 필요가 있는 <strong>image</strong>만 <code>Attribute</code> 해준다. 그리고 해당되는 위치에 <code>appendChild()</code> 해주면서 화면에 출력하는 식이다. 다른 식의 출력 같은 경우에도 값을 가져오고 사용할 부분의 value 값을 가져와 <code>append()</code> 해줄 수 있다. 특정 값만 가져오고 싶다면 다음과 같은 방법을 사용할수도 있다.</p>
<pre><code class="language-js">db.transaction(&quot;customers&quot;).objectStore(&quot;customers&quot;).get(&quot;444-44-4444&quot;).onsuccess = function(event) {
  alert(&quot;Name for SSN 444-44-4444 is &quot; + event.target.result.name);
};</code></pre>
<p>정말 솔직히 얘기하자면 요즘은 하드웨어 성능이 워낙 좋아져서 외부 DB를 사용할 때도 그렇게 성능 저하가 느껴지지 않는다. 사용환경이 달라질 때 데이터가 유지되지 않는다는 단점도 있고, 정말 성능을 극대화 할 일이 아니라면 크게 사용할 일이 없을 것 같기는 하다. 다만 유저 개인의 데이터들을 출력하는 것이 주목적인 소프트웨어라면 다시 글을 참고하면서 <strong>indexedDB(<del>노후화된 DB</del>)</strong>를 설계해야 할 것 같다.</p>
<blockquote>
<p><strong>참고 링크</strong></p>
</blockquote>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage">https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage</a></li>
<li><a href="https://ko.javascript.info/localstorage">https://ko.javascript.info/localstorage</a></li>
<li><a href="https://elice.io">엘리스</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Event Listener]]></title>
            <link>https://velog.io/@dev_cdd/Event-Listener</link>
            <guid>https://velog.io/@dev_cdd/Event-Listener</guid>
            <pubDate>Sun, 12 Mar 2023 07:38:44 GMT</pubDate>
            <description><![CDATA[<h3 id="-old-eventhandling-">** Old EventHandling **</h3>
<p>나중에 <code>ReactJS</code> 에 관한 글을 작성하면서 <code>Handling Event</code> 에 대한 글을 한 번 더 적기는 하겠지만, 이번에 게시할 내용은 JS 내의 이벤트 핸들링 기능인 <code>eventListener</code> 에 관한 내용이다. Event는 말 그대로 어떠한 사건이 일어남을 의미하는데, 웹에서는 클릭과 같이 사용자로 인해 어떠한 행동이 트리거 되었을 때 특정 동작을 유도하는 식으로 사용된다. 사용자와 웹페이지 간의 상호작용을 만들어주는 기능이라고 보면 된다.</p>
<pre><code class="language-html">&lt;button onclick=&quot;this.innerHTML = &#39;클릭&#39;&quot;&gt;클릭 전&lt;/button&gt;</code></pre>
<p>간단한 예제코드로부터 먼저 알아보자면 <code>onclick : 사용자가 &#39;클릭&#39;했을 때</code> 이벤트가 발생한다면 현 <code>&lt;button&gt;</code> 의 <code>innerHTML</code>  값을 &#39;클릭&#39;으로 바꾼다는 의미를 가지고 있다. 하지만 위와 같은 방법은 이해하기는 좋은 코드지만 현재는 저런 방법을 많이 쓰지 않는다고 한다. 주로 로직 구현은 JS에서 이루어지기에 별개의 JS 파일에서 따로 <code>eventListener</code> 을 설정해주고, 트리거가 될 이벤트를 설정해주는 식으로 사용한다. 예제를 만들기 위해서 <code>HTML</code>에 <code>inline</code> 형태로 들어간 <code>onclick</code>은 잠시 빼주고, JS 코드를 작성해보자.</p>
<h2 id="-addeventlistener-">** addEventListener **</h2>
<pre><code class="language-html">&lt;!-- html --&gt;

&lt;!-- Button Elements --&gt;
&lt;button id = &#39;cdd-button&#39;&gt;클릭 전&lt;/button&gt;</code></pre>
<pre><code class="language-js">// index.js

// id 값을 활용하여 버튼을 찾는 querySelector
var cdd_button = document.querySelector(&quot;#cdd-button&quot;);

// 클릭시 이행 할 사용자 정의 함수
function click() {
  cdd_button.innerHTML = &quot;click complete&quot;;
}

// 화살표 함수를 통해 간소화, 괄호 내에서 즉시 함수 선언을 해줄 수 있음
cdd_button.addEventListener(&quot;click&quot;, () =&gt; {
  alert(&quot;click !&quot;);
});

// 사용자가 정의한 함수명을 안에 넣어주면 해당 이벤트 시 이행함
cdd_button.addEventListener(&quot;click&quot;, clickFunc);</code></pre>
<p><code>onclick</code> 보다는 위와 같이 <code>addEventListener</code>을 현업에서도 쓰는 경우가 더 많다고 한다. 기본적인 사용 방법은 <code>element.addEventListener(&#39;eventType&#39;, function)</code>와 같은 형태로 사용한다. 전역 스코프로 사용하기도 하고, 함수 스코프 내 특정 조건에 의해 리스너를 정의할수도 있다.</p>
<pre><code class="language-js">button = document.querySelector(&#39;#submit-button&#39;);

function printSomething(e) {
  e.preventDefault(); // 기존 고유한 태그 동작 종료
  button.innerHTML = &#39;clicked&#39;;
}

button.addEventListener(&#39;click&#39;, printtext);</code></pre>
<p><code>click</code> 이벤트 뿐만 아니라 <code>mouseover</code>이나 <code>mouseout</code> 등 찾아보면 다양한 이벤트에 함수를 정의하여 사용할 수 있다. 위의 코드에서 볼 수 있는 <code>preventDefault()</code>는 e의 동작을 정지시키는 메서드 역할을 하는데, 여기서 인자값으로 온 e는 <code>click event</code>를 의미하며, <code>e.target</code>과 같은 키워드를 통해 이벤트 대상이 되는 요소, 즉 버튼의 값을 활용하여 값을 직접적으로 수정하거나 업데이트 시킬 수 있다. 위에서 <code>preventDefault()</code>가 쓰인 이유는 버튼을 눌렀을 시 자동으로 페이지가 <code>reload() : 새로고침</code> 되는데, 이를 방지하기 위해 사용된다. 추가적으로 <code>stopPropagation()</code> 메서드를 활용하면 상위 요소로의 이벤트 전파까지 막을 수 있다.</p>
<h2 id="-queryselectorall-in-addeventlistener-">** querySelectorAll in addEventListener **</h2>
<pre><code class="language-js">element = document.querySelector(&#39;main div #header&#39;); // 단일 값
elements = document.querySelectorAll(&#39;#footer&#39;); // 복수 값</code></pre>
<p>특정 요소를 들고 오고 싶을 때 <code>getElementsById</code>와 같은 방법이 있지만 해당 방법은 가지고 오는 요소 태그의 종류에 따라 메서드명을 다르게 지정해줘야 한다는 번거로움이 있다. 그래서 보통은 <code>querySelector</code>나 <code>querySelectorAll</code>을 통해 직접적인 경로를 작성하여 요소를 편하게 가져오곤 하는데, 성능적인 부분에서는 다소 부족한 부분이 있다고 한다. 무튼 단일 객체를 가져올 때는 큰 문제가 되지 않지만 <code>querySelectorAll</code>을 통해 다중 객체를 가져오게 되면 <code>EventListener</code>를 작성하는데 약간의 문제가 생기게 된다. 한 가지 예를 들어보도록 하자.</p>
<pre><code class="language-js">elements = document.querySelectorAll(&#39;#footer&#39;); // 복수 값
elements.addEventListener(&#39;mouseout&#39;, () =&gt; { ... });</code></pre>
<p>대충 이렇게 적어놓으면 가져온 모든 객체들에 <code>EventListener</code>이 자동적으로 할당 될 것이라는 착각을 하곤 한다. 하지만 각 요소에 일일이 적용 시켜주는 것이 아니라면 제대로 기능이 작동하지 않는 문제점이 발생한다. 위의 코드도 마찬가지인 잘못된 예시이다. 그러면 이를 해결하기 위해서는 어떻게 해야 할까? 정답은 바로 <code>for loop</code>을 활용하여 각 요소들에 리스너를 넣어줘야 한다.</p>
<pre><code class="language-js">elements = document.querySelectorAll(&quot;#footer&quot;); // 복수 값

for (var i = 0; i &lt;= elements.length; i++) {
  elements[i].addEventListener(&quot;mouseout&quot;, () =&gt; { ... });
}</code></pre>
<p>이런식으로 말이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DOM, Nodes]]></title>
            <link>https://velog.io/@dev_cdd/JavaScript-DOM</link>
            <guid>https://velog.io/@dev_cdd/JavaScript-DOM</guid>
            <pubDate>Sat, 11 Mar 2023 17:31:11 GMT</pubDate>
            <description><![CDATA[<p>웹 개발을 하려면 <code>DOM : Document Object Model</code> 에 대한 이해가 필요하다. 사실 예전에 리액트 강의를 들으면서 <code>Virtual DOM</code> 에 대해서도 배운 적이 있지만 열심히 공부를 하지 않아 머릿 속에서 깔끔하게 잊혀졌다. 미래의 나는 이런 일이 일어나지 않도록 작은 개념이라도 꼼꼼히 체크하며 필기를 해나가는 습관을 가져야 할 것 같다.</p>
<h2 id="-dom--document-object-model">** DOM : Document Object Model**</h2>
<p>맞게 정의하는건지는 모르겠지만, DOM은 계층적 구조를 가지고 있는 노드 트리 형태로써 존재한다고 보면 된다. 종종 상속을 하기도 하고, 수평적인 관계를 이루기도 하고 다양하다. 이렇게 말로만 하면 너무 뻔한지라 간단한 소스코드와 함께 설명하자면,</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;index.css&quot; /&gt;
    &lt;title&gt;Document&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class=&quot;parent&quot;&gt;
      &lt;div class=&quot;child&quot;&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>정말 흔하게 볼 수 있는 HTML 코드이다. HTML은 태그를 감싸는 형태로써 모든 코드가 존재하는데, 태그와 태그 사이에 또 다른 태그 쌍이 존재하면 그것은 하위 태그가 상단 태그의 하위 노드 형태로써 존재한다고 보면 된다. 예를 들어 제일 상, 하단에 존재하는 HTML은 최상단 노드라고 볼 수 있고, 그 아래의 <code>&lt;head /&gt;</code> 와 <code>&lt;body /&gt;</code>는 바로 하단에 존재하는 형제 노드로 볼 수 있다. <code>&lt;head&gt;</code> 의 자식 노드는 <code>&lt;link /&gt;</code> 와 <code>&lt;title&gt;</code> 등이 될 수 있고, 그 아래는 뭐 설명 안해도 알 정도로 간단한 개념이다.</p>
<h3 id="-nodes-">** Nodes **</h3>
<pre><code class="language-js">var cdd_element = document.createElement(&quot;div&quot;); // div라는 요소 생성
var cdd_node = document.createTextNode(&quot;I am CDD&quot;); // I am CDD 라는 Text Node 생성
cdd_element.appendChild(cdd_node); // div라는 요소에 textnode를 자식으로 append</code></pre>
<p>주석으로 설명을 다 적어놓았지만 다시 설명하자면 <code>&lt;div&gt; ... &lt;/div&gt;</code> 의 사이는 자식이 들어갈 공간이다. 그 곳에 <code>textNode</code> 를 만들어 자식으로 append 시켜주면 또다른 자식노드가 형성이 되는 것이다. 이는 DOM을 노드 트리 형태로 봤을 때 div 노드에 cdd_node라는 하단 노드가 붙게 되는 형식으로 볼 수 있다.</p>
<pre><code class="language-js">var html = document.childNodes[1];
var head = html.childNodes[1];
var body = html.childNodes[2];</code></pre>
<p>대충 이런식으로 보면 된다. <code>element.childNodes</code> 는 해당 노드가 갖고 있는 자식 노드를 볼 수 있는 기능이고, 뒤에 붙는 인덱스 값은 해당 노드가 몇 번째인지에 대한 값이다.</p>
<pre><code class="language-js">cdd_node.firstChild.nodeValue = &#39;cdd&#39;;
cdd_node.lastChild.nodeValue = &#39;is crazy&#39;;</code></pre>
<p>이외에도 이렇게 자식 노드의 첫 번째, 마지막에 바로 접근하는 키워드도 있고, <code>nodeValue</code> 를 통해 노드 내의 값을 수정할수도 있다. 이 이상의 키워드는 별로 쓰지 않을 것 같아 여기서 글을 마친다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Property : Transition, Animation, Media Query, Flex box]]></title>
            <link>https://velog.io/@dev_cdd/%EC%9E%90%EC%A3%BC-%EC%93%B8-%EA%B2%83-%EA%B0%99%EC%9D%80-CSS-property-list</link>
            <guid>https://velog.io/@dev_cdd/%EC%9E%90%EC%A3%BC-%EC%93%B8-%EA%B2%83-%EA%B0%99%EC%9D%80-CSS-property-list</guid>
            <pubDate>Sat, 11 Mar 2023 15:57:58 GMT</pubDate>
            <description><![CDATA[<h2 id="css-property">CSS Property</h2>
<p>곧 있으면 프로젝트를 시작해야 하기도 하고, 부트캠프에서 HTML &amp; CSS는 되게 빨리 넘어가는 상황인지라 실사용을 몇 번 못해봤다. 물론 실습 시간에 부트캠프에서 제공해 준 스켈레톤 코드와 함께 어느정도 구현을 해봤기는 했지만 아직도 프로퍼티의 종류에 대해 좀 무지한 것 같기도 하고, 인터넷을 서칭하면서 개발을 진행하기엔 시간이 너무 많이 들어갈 것 같아 자주 쓸 것 같은 프로퍼티 정도를 정리해볼까 한다.</p>
<h3 id="transition--animation"><strong>Transition &amp; Animation</strong></h3>
<p> 처음에는 트랜지션과 애니메이션에 대한 개념이 혼동되었다. 어떻게 보면 둘 다 움직임을 표현하는 방식이고, 특정 속성값을 기준으로 변경을 눈에 보여준다는 점에서 &#39;에 .. 둘 중 하나만 쓰면 되는건가?&#39; 라는 생각이 들기도 했다. 그래서 이 부분은 소스를 보면서 생각하면 더 좋을 것 같다.</p>
<pre><code class="language-css">.Transition {
  transition: width 2s linear 1s;
  /*
    transition property : width
    transition duration : 2s
    transition timing-function : Linear
    transition delay : 1s
  */
}

Transition:hover {
  width: 300px;
}</code></pre>
<p>프로퍼티 속성을 하나하나 다 따로 지정할 수 있지만, 저렇게 간편하게 설정할수도 있다. 순서를 바꿔도 알아서 잘 인식했던 것 같은데, 어느정도의 인자값 종류에 대한 지식만 있으면 그냥 순서 상관 없이 적어도 제대로 작동되는 듯했다. 위의 코드를 보면 <code>hover : 마우스를 올려 놓는 이벤트</code> 같이 특정 이벤트에 트리거 되어 작동되는 방식이고, 이벤트 이후 단 한 번 실행된다는 특징이 있다.</p>
<pre><code class="language-css">.animation {
  width: 300px;
  height: 300px;
  background-color: yellow;
  animation-name: changeWidth;
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-delay: 1s;
  animation-iteration-count: 6;
  animation-direction: alternate; /* 원래 방향으로 되돌아옴 */
}

@keyframes changeWidth {
  from {
    width: 300px;
  }
  to {
    width: 600px;
  }
}</code></pre>
<p>Transition과 마찬가지로 시간의 흐름에 따라 특정 프로퍼티의 변화를 줄 때 사용하는데, 차이점이라고 한다면 특정 Trigger 없이 알아서 작동이 될수도 있는 특징이 있다. 소스 하단부를 보면 <code>keyframes</code> 라는 키워드가 보이는데, 사실 영상을 하는 사람 입장에서는 지겹도록 익숙한 단어일 것이다. 우리가 흔히 보는 화면 출력 기기 (모니터)는 초당 수십 장에서 수백 장의 프레임들을 뱉어내는데, 특정 프레임을 기준으로 애니메이션이 시작된다고 보면 된다. 첫 프레임은 <code>1s</code>라는 delay 직후이고, 1%에서 99%까지 각기 다른 동작을 넣을수도 있다. 아래의 표는 특징들을 나타낸 표이다.</p>
<table>
<thead>
<tr>
<th align="center">Transition</th>
<th align="center">Animation</th>
</tr>
</thead>
<tbody><tr>
<td align="center">- Can only move from initial to final state <br> - Can only run once <br> - Require a trigger to run (like mouse hover) <br> - Easier to use with Javascript <br> - Best for creating a simple change from one state to another</td>
<td align="center">- Can move from initial to final state, with intermediate steps in between <br> - Can loop infinitely thanks to animation-iteration-count property <br> - Can be triggered but can also run automatically <br> - Can run forwards, in reverse, or alternate directions <br> More difficult to use with JavaScript <br> - Best for creating a complex series of movements</td>
</tr>
</tbody></table>
<h3 id="-media-query-">** Media Query **</h3>
<p>미디어쿼리는 실제 웹사이트에서도 상당히 많이 쓰이는 기능이다. 주로 모바일 환경을 위해 설계된 경우가 많다고 하는데, 창을 줄일 때 모바일 환경에 맞춰 UI가 뒤바뀌는 그런 기능이 필요할 때 미디어쿼리를 사용한다. 사실 코드만 보면 바로 이해가 될만한 쉬운 구현이다.</p>
<pre><code class="language-css">@media (min-width: 320px) and (max-width: 800px) {
  .media {
    width: 100px;
    height: 100px;
    background-color: blue;
  }
}</code></pre>
<p>인자값으로 다른 값들이 들어가기도 하지만 주로 쓰이는 것들이 <code>min-width</code> 와 <code>max-width</code> 이다. 구현 목적 자체가 모바일 UI 최적화에 있기 때문에 다음과 같은 형식으로 사용하고, 저 코드 같은 경우 웹 페이지의 너비가 320에서 800 사이에 위치한다면 media 클래스를 다음과 같이 변경해준다는 의미를 가지고 있다. 지난 번에 소마 코테를 볼 때 화면이 특정 크기 이하로 작아지면 화면이 작다고 모든 화면이 다 가려지는 기능이 있었는데, 이도 역시 미디어쿼리를 이용했을 것이다. 추가적인 세팅값으로 미디어쿼리를 작성하고 싶다면 하단에 이어서 <code>@media ( ... ) { ... }</code> 과 같이 작성하면 된다.</p>
<h3 id="-flex-box-">** Flex Box **</h3>
<p>사실 무조건 배워야 했을 정도로 중요한 개념이라고 생각했는데, 부트캠프에서 강의자료로 넣어 주지 않아 개인적으로 공부했던 부분이다. 물론 어느정도 언급은 해주셨지만, 그래도 &#39;이건 좀 체계적으로 배워야 했지 않나?&#39;라는 아쉬움이 있는 부분이다. Flex Box는 컨테이너 속에 아이템들을 넣는 개념인데, 기본적인 설정은 <code>display: flex</code> 라는 코드에서 시작된다. 우리가 생각하는 block 개념은 inline과 달리 아이템이 추가 될 때마다 세로로 늘어나는 구조인데, flex-box 같은 경우 가로로 아이템들이 계속해서 배치된다. 어떻게 보면 <code>inline</code> 과 약간 비슷한 특성을 지니기도 한다.</p>
<pre><code class="language-css">.container {
  display: flex; /* flex-box 설정 */
  flex-direction: column; /* 컨텐츠 정렬 방식 : 행, 렬 등등 */
  flex-wrap: nowrap; /* 아이템들이 가로폭을 넘겼을 때의 줄바꿈 여부 */
  flex-flow: row, wrap; /* flex-direction, flex-wrap */
  justify-content: center; /* 수평(가로) 축 정렬 */
  align-items: center; /* 수직(세로) 축 정렬 */
}</code></pre>
<p>주로 쓰는 속성들은 다음과 같은데, 직접 실행해보면서 해야 더 이해하기 편한 것 같다. 필자는 <a href="https://flexboxfroggy.com/">flexbox froggy</a>에서 학습했는데, 더 직관적으로 나와있는 사이트가 있어서 <a href="https://studiomeal.com/archives/197">링크</a>를 추가한다. 그림으로 잘 나타나있어 이해하기 편하고, 토글 버튼을 통해 좀 더 직관적으로 바뀌는 모습을 볼 수 있어 좋은 것 같다. 다음에 기억이 나지 않는다면 <a href="https://studiomeal.com/archives/197">링크</a>를 참고할 예정이다.</p>
<h3 id="-참고-링크-">** 참고 링크 **</h3>
<ul>
<li><a href="https://blog.hubspot.com/website/css-transition-vs-animation">https://blog.hubspot.com/website/css-transition-vs-animation</a></li>
<li><a href="https://studiomeal.com/archives/197">https://studiomeal.com/archives/197</a></li>
<li><a href="https://flexboxfroggy.com">https://flexboxfroggy.com</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[🐰 엘리스 SW 엔지니어 트랙 합격 및 1주차 후기]]></title>
            <link>https://velog.io/@dev_cdd/%EC%97%98%EB%A6%AC%EC%8A%A4-SW-Engineer-Track-1st-Week</link>
            <guid>https://velog.io/@dev_cdd/%EC%97%98%EB%A6%AC%EC%8A%A4-SW-Engineer-Track-1st-Week</guid>
            <pubDate>Tue, 07 Mar 2023 03:18:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_cdd/post/62d4193f-6690-4b31-93e5-202b94c636b3/image.png" alt="">
기존 웹개발 공부를 독학으로 시작했다가 특정 지점에서 발목이 잡혀 혼자서 공부하기를 포기하고 정식 커리큘럼을 따라가는 것이 좋겠다고 느끼게 되어 부트캠프를 찾아보던 도중 <strong>생활코딩 이고잉 코치</strong>가 있는 부트캠프가 눈에 띄여 지원하게 되었고, 합격하여 수강하게 되었다.</p>
<p>수강금액은 수강신청 시 존재하지만, 결론적으로는 나라에서 다 지원해줘서 그냥 공짜라고 생각하면 된다. 다음 기수에 지원 할 사람들이 있을테고, 기록하는 것을 좋아하는 성격이라 주차마다 글을 조금씩 적어보려고 한다.</p>
<h1 id="합격까지의-과정">합격까지의 과정</h1>
<p>다른 후기들을 보면 정보들을 충분히 찾을 수 있어 정말 간단하게만 적고 넘어가려 한다. 기본적인 코스는 <code>서류 -&gt; 1차 코테 -&gt; 선발 인터뷰 -&gt; 최종 결과</code> 로 이루어진다. 소마나 우테코 같은 곳보다는 훨씬 간결한 선발 절차다.</p>
<p>아무래도 타깃의 기준을 높게 잡은 부트캠프는 아니다보니 코테 난이도가 매우 낮았고, 제일 어려운 난이도가 백준 실버4 정도 느낌이었다. 소마는 정말 열심히 해야 겨우 1솔 정도였는데 엘리스는 시간도 많이 남긴 채 모든 문제를 클리어했다. 다만 추가적으로 나오는 논리력 테스트가 있는데, NCS 형식의 처음 풀어보는 문제라 시간 계산을 못해서 거의 다 날렸다.
<img src="https://velog.velcdn.com/images/dev_cdd/post/502b0e75-4cc2-4241-9596-91773022c36a/image.png" alt=""></p>
<h2 id="최종-합격을-축하합니다-🎉">최종 합격을 축하합니다. 🎉</h2>
<p><code>디디님 안녕하세요, 디디님께서는 엘리스 SW 트랙 4기 레이서로 최종 선발되었습니다.</code></p>
<p>인터뷰에서는 그 동안의 경험, 지원 동기들을 물어봤고 솔직히 차근차근 얘기를 하고나니 다음과 같이 합격해있었다. 아, 참고로 본명으로 연락이 오는데 블로그 게시를 위해 이름을 다시 내 닉네임 <code>디디(CDD)</code>로 바꿨다.</p>
<h3 id="커리큘럼">커리큘럼</h3>
<p>자세한 사항에 대해서는 저작권 문제 등으로 인해 외부 유출이 불가능하다고 알고 있다. 그래서 간략하게 얘기하자면 전반적인 웹 개발 로드맵을 따라간다고 보면 된다. 첫 주차에서는 <code>HTML/CSS, Git</code>에 대해서 배우고 그 이후로 <code>JS -&gt; REST API -&gt; ReactJS</code> 순으로 배운다고 생각하면 된다.</p>
<p>사실 배우는 기간이 거의 4개월도 채 안되는 16주의 기간이라 이렇게 많은 양을 어떻게 배울지 막막할수가 있는데, 생각해보니 그냥 일과 자체를 부트캠프에 집어넣으면 하루 전체를 개발에 쏟을수가 있어서 열심히만 한다면 가능하리라 믿고 있다.</p>
<h3 id="기본-베이스">기본 베이스</h3>
<p>광고 자체를 비전공자 위주로 밀고 있어서 강의도 비전공자 위주로 진행하는 경향이 있다. 좋게 말하면 쉽게 배울 수 있지만, 한편으로는 강의 속도가 조금은 더디게 흘러가는 느낌이 있다. 전공자로써 정말 당연하게 생각하는 부분이 남들에게는 새롭고 어려운 부분인 경우가 많고, 코치 분들도 이러한 질문 하나, 하나에 정말 정성들여 답변을 해주시기 때문에 초심자 입장에서는 따뜻한 부트캠프라고 할 수 있을 것 같다.</p>
<p>다만 아직까지는 본격적인 커리큘럼에 들어가지 않았기 때문에 이 글 이후의 후기는 어떻게 달라질지 모른다. 사실 지금까지 배운 것들은 정말 간단한 로직 구현과 웹 디자인 정도가 끝이라 비교적 느슨하게 진행하는 것일수도 있다. 웹을 처음 공부하기 시작했을 때도 딱 이 시점을 넘어가기 시작하면서 따라가기가 벅찬 기억이 있었다. 사실 이게 웹 강의의 대표적인 특징이자 공통점일지도 모르겠다.</p>
<h3 id="엘리스-랩">엘리스 랩</h3>
<p>교육장이라고 해야되나? 엘리스는 프로그래밍 및 팀 프로젝트를 진행할 수 있는 장소를 제공해주는데, 여기 시설이 되게 좋다. 크게 라운지, 미팅룸, 프로그래밍 존으로 나뉘어져 있는데, <strong>모든 PC가 아이맥으로 구성</strong>되어 있다.</p>
<p>지역은 서울의 성수, 부산의 센텀으로 나뉘는데 운영시간의 차이가 있다. 아직 초기라 그런지는 잘 모르겠지만 부산랩에는 사람이 거의 없어 정말 쾌적하다. 그래도 개발 네트워크 형성을 위해 어느정도의 사람들은 좀 방문을 해줬으면 좋겠다는 바램이 있다.</p>
<h3 id="실시간-이론--실습-강의--이론-강의">실시간 이론 &amp; 실습 강의 &amp; 이론 강의</h3>
<p>호불호가 갈릴 만한 강의 방식이라고 생각하는데, 교육이 이루어지는 월요일과 금요일 사이에서 실시간 강의는 화, 목 단 이틀만 진행된다. 상호소통하며 배우기 위해 들어간 부트캠프에서 주에 3일 씩 강의 영상만으로 학습을 한다는 것이 개인적으로 좀 아쉽긴 했다. 그래도 디스코드가 있어 다른 레이서들과 소통하며 문제 해결을 할 수 있다.</p>
<p>실시간 강의는 이론 강의를 보충하는 느낌도 있고, 이론에서 빠진 요소들을 체크해서 추가적으로 알려준다. 사실 근데 이것보다 <strong>실시간 QnA</strong>가 가능하다는 점이 가장 좋은 것 같다. 물론 인터넷에 찾아보면 되는 정보들보다는 경험적인 질문들을 했을 때의 답변이 도움을 많이 주는 것 같았다.</p>
<h3 id="이후의-방향성">이후의 방향성</h3>
<p>본격적으로 학습을 하기 시작하면서 얻은 내용들을 재구성하여 이 곳 velog에 업로드 할 것 같고, 회고 등에 대한 내용은 주차마다 쓸 내용이 충분하다면 써 내려갈 예정이다.</p>
]]></description>
        </item>
    </channel>
</rss>