<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>foxrain_gg.log</title>
        <link>https://velog.io/</link>
        <description>컴퓨터공학과 학생입니다</description>
        <lastBuildDate>Mon, 06 Nov 2023 13:30:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>foxrain_gg.log</title>
            <url>https://images.velog.io/images/foxrain_gg/profile/b3f3700b-8036-44c0-bff4-ebbc41c83297/내꺼프로필.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. foxrain_gg.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/foxrain_gg" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 10월 마지막 프로젝트 중간 회고]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-10%EC%9B%94-%EB%A7%88%EC%A7%80%EB%A7%89-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%91%EA%B0%84-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-10%EC%9B%94-%EB%A7%88%EC%A7%80%EB%A7%89-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%A4%91%EA%B0%84-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 06 Nov 2023 13:30:24 GMT</pubDate>
            <description><![CDATA[<p>요즘 내가 개발자가 되기 위한 활동에서 가장 많은 시간을 투자하고 있는 것은 데브코스 최종 프로젝트인 것 같다.
이번 프로젝트에서는 백엔드와 프론트엔드가 함께 협업하여 하나의 서비스를 개발하기 위하 다같이 노력하고 있다.
개인적으로 처음 백엔드와 하는 협업이다보니 어려움을 겪는 부분과 서로의 소통에 문제가 생기는 부분도 있었지만 팀 중간 회고를 거친 지금까지는 마주치게 된 어려움을 팀원들과 잘 해결해나가고 있는 것 같다.</p>
<h1 id="주제-선정-과정">주제 선정 과정</h1>
<p>프로젝트 주제를 선정할 때 우리가 가장 신경썼던 부분은 3가지가 있었다.</p>
<blockquote>
<ol>
<li>적은 인원으로도 서비스의 원활한 이용이 가능한가?</li>
</ol>
</blockquote>
<p>기존에 팀 프로젝트를 진행하게 되면 가장 많이 하는 주제는 중개 플랫폼이나 SNS 관련 관련 주제를 많이 생각하게 된다. 당장 나도 이번 최종 프로젝트에서는 같은 취미를 가진 사람들이 모이는데 도움이 되는 모임 관련 SNS를 주제로 제출하였다. 하지만 이러한 서비스가 원활하게 이용이 가능하려면 많은 사람들의 이용이 필요하다.
이번 팀 프로젝트에서는 팀원들 모두 적은 이용자가 있어도 원활하게 모든 서비스 사용이 가능한 주제를 원했다.</p>
<blockquote>
<ol start="2">
<li>서비스 구현과 사용에 현실성이 있는가?</li>
</ol>
</blockquote>
<p>서비스를 구현하는데 우리의 개발 레벨에서 현실적으로 가능한지, 너무 어렵거나 불가능한건 아닌지를 생각하였다.
구현하기 어렵다고 생각하는 주제를 선택해 새로운 것들을 공부하며 프로젝트를 진행하는 것도 큰 의미가 있겠지만 비교적 짧은 시간안에 결과물을 완성해야하기에 서비스 구현 난이도도 중요한 요소라고 생각했다.</p>
<p>또한, 이용자가 정말 사용할만한 서비스인지도 중요하게 생각한 요소였다.
서비스를 만들었지만 막상 사용하기 불편해서 사용하지 않는 서비스라면 개발에 의미가 없다고 생각하였다.</p>
<p>팀 프로젝트 주제 선정 마지막 과정에서 이용자가 가지고 있는 옷 정보를 모두 등록해 세탁 방법과 날씨에 맞는 추천 의상, 자주 입는 옷과 입지 않는 옷을 알려주는 옷 관리 서비스와 이번 프로젝트 주제 두 가지를 고민하였다.
옷 관리 서비스는 이용자가 옷을 모두 수동으로 등록해야한다는 불편함이 있었고 이를 해결하기 위해 옷 태그를 카메라로 분석해서 등록 과정을 줄이자는 의견도 나왔지만 지금 팀의 지식으로는 개발에 현실성이 없다고 생각되었다. 또한, 입은 옷을 사용자가 계속해서 체크해야한다는 불편함에 서비스 이용이 현실성이 없다고 생각하여 다른 선택지를 고르게 되었다.</p>
<blockquote>
<ol start="3">
<li>구현을 통해 배울 요소들이 있는가?</li>
</ol>
</blockquote>
<p>난이도를 적절히 가져가면서 구현 과정에서 새로운 지식을 얻을 수 있는도 중요한 주제 선정 요소였다.
프론트엔드와 백엔드 모두가 단순 반복 작업이나 이전에 만들어둔 프로젝트 코드를 복붙하는 개발을 벗어나 윈윈할 수 있는 주제를 원했다.</p>
<h1 id="프로젝트-주제">프로젝트 주제</h1>
<p>그래서 이번 프로젝트에 우리 팀이 선택한 주제는 <a href="https://www.notion.so/prgrms/b748bded0601486bac4d76a0b4f9a70d">위치 기반 다이어리 작성에 중점을 둔 커플 애플리케이션</a>이다.
2명의 사용자만 있으면 모든 서비스를 사용이 가능하고, 두 명을 하나의 그룹으로 묶어 관리하는 과정과 현재 위치를 기반으로 한 다이어리 구현에서 백엔드와 프론트엔드 모두 새로운 경험을 할 것이라고 생각하였다.
기존 커플 앱의 장점과 단점들을 확인해 커플 앱에서 부족했던 부분을 채워 실제 사용해볼만한 서비스를 기획하고자 노력하였다.</p>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/38bd6c08-efbd-4751-81eb-6b59e7f1a3c4/image.png" alt=""></p>
<p>프론트엔드 팀원들은 반응형 웹으로 제작을 계획해서 개발 과정에서 CSS에 대한 이해도를 높이고 사용자 경험도 향상 시킬 수 있도록 기획하였다.</p>
<h1 id="협업-방식">협업 방식</h1>
<p>협업 방식을 선택할 때 협업 툴의 사용을 최대한 간소화하여 모두가 빠르게 확인이 가능하도록 하는 방향을 선택하였다.
우리 팀의 협업 툴은 크게 Slack, Gather, Notion, GitHub이다.
Slack를 통해 비동기 소통을 하며, Gather를 사용해 팀 스크럼 및 동기 소통을 하고있다.
Notion은 팀 프로젝트 개발 과정에서 수정할 점들이나 회고에 대한 문서화를 담당하고 있고, GitHub를 사용해 스케줄 관리 및 개발 문서화를 진행하고 있다.
처음에는 Jira와 같은 프로젝트 관리 앱을 사용하지 않는 것에 걱정이 있었지만 팀 규모(프론트 3명, 백엔드 3명)가 크지 않고, 각각의 협업 툴의 목적을 확실하게 정하고, 스크럼과 꾸준한 소통을 적절히 가져가다보니 오히려 또 다른 툴을 관리하는 데 시간을 줄이고 팀원들이 모두 빠르게 현재 상황을 공유할 수 있어서 좋은 선택이였다는 생각이 든다.</p>
<h1 id="프로젝트-기술-스택">프로젝트 기술 스택</h1>
<p>프론트엔드의 기술 스택은 아래와 같다.</p>
<blockquote>
<p>React, TypeScript, Vite, Storybook, Daisy UI, Tailwind css, Emotion, React-query</p>
</blockquote>
<p>기술 스택을 정할 때 프론트엔드 팀원들의 가장 큰 고민은 Next js 적용에 대한 고민이였다.
react-query와 tailwind css를 처음 사용하는 팀원도 있고 아직 CSR, SSR, SSG에 대한 이해도가 낮다고 생각되어서 Next js는 과감하게 포기하게 되었다.
프로젝트를 진행하다보니 아직 react에 대해 깊게 배워가야 할 점들이 너무 많고 상태 관리 등 기본적인 부분에서 살짝 부족하다고 생각되는 부분들이 보여서 Next를 선택하지 않은 것은 짧은 프로젝트 기간에 잘했다고 생각되는 선택이다. 하지만 SSG, SSR, server component 등 next js를 공부해보면서 배울 점도 많다고 생각되기 때문에 지금은 틈틈히 next js도 공부하고 있다.</p>
<p>storybook은 이번 중간 팀 회고를 통해 프로젝트에서 삭제하고 더이상 사용하지 않기로 결정하였다. 팀원 모두가 Daisy UI를 적극적으로 사용하려고 노력하면서 공통 컴포넌트가 많이 줄어들기도 했고 3명의 프론트엔드 팀원이 꾸준한 PR 리뷰를 통해 작업 결과물에 대해 잘 이해하고 있기 때문에 필요성을 느끼지 못했다.
필요성을 느끼지 못하는 라이브러리는 과감하게 버리고 불필요한 코드 작성을 줄이면서 빠른 개발 속도를 챙기는 것도 중요하다고 생각되었다.</p>
<p>Tailwind css와 Emotion을 동시에 사용하는 것은 생각하지도 못했지만 멘토님의 피드백과 tailwind로 개발할 수 없는 기능(ex. 변수 값에 따라 색상이 동적으로 변경되어야 할때)등 tailwind만으로는 부족한 부분을 채우기 위해 Emotion을 추가로 사용하였다.
Emotion을 사용해 react-calendar와 같은 라이브러리에 스타일을 적용할 때 잘 사용하고 있지만 아직 팀원들간에 Emotion과 Tailwindcss 적용 기준에 대해 명확한 것 같지 않아 중간 데모가 끝난 지금 다시 한번 규칙을 정하고 개발을 시작하려고 한다.</p>
<h1 id="새로운-상태-관리-방법">새로운 상태 관리 방법</h1>
<p>이번에 프론트엔드 팀원이 가장 신경 쓰고 있는 부분은 로직과 UI 렌더링 코드의 분리이다.
사용자에게 보여줄 UI를 담당하는 컴포넌트는 UI 렌더링만, 로직을 담당하는 파일을 로직만을 담아  사용하여 분리하는 것을 목표로 개발을 진행하고 있고 이 과정에서 react context api를 적극적으로 사용하고 있다. 사실 이전에는 context api를 많이 사용해 본 경험은 없어 어떤 방식으로 사용하면 좋은 사용 방향을 가져갈 수 있을 지 많은 고민을 했지만 <a href="https://yohanpro.com/posts/refactoring/useContext">React State Hooks - useContext</a> 멘토님의 블로그 글이 정말 큰 도움이 되었다.
아직 컨텍스트 단위로 컴포넌트들을 구조화하고 구현하는게 미흡해서 리팩토링이 필요한 부분들이 많이 보이지만 하나의 모달을 관리하는 과정에서 큰 효과를 얻을 수 있었고 계속해서 context api 사용하여 로직과 렌더링 코드를 분리해나가려고 한다.</p>
<h1 id="앞으로">앞으로...</h1>
<p>이번 중간 팀 회고를 통해 서로가 부족하다고 생각한 점들과 추가가 필요한 부분들이 있다는 것을 확인하였다.
이러한 점들은 자세한 규칙 설정, 코드 리팩토링, 문서화를 통해 해결해나가려고 계획하고 있다.</p>
<p>개인적으로는 반응형 디자인 개발 과정에서 불편함을 느껴 이를 해결하고자 관련 툴을 추가하려고 계획하고 있다.
지금은 반응형 디자인을 개발하고 확인하기 위해 chrome 개발자 모드를 사용하고 있다. 하지만 한눈에 모바일, 태블릿, PC 화면을 모두 확인할 수 없어 계속해서 화면 사이즈를 변경해줘야한다는 번거로움이 있고 PR을 남기거나 확인할 때 모바일 화면 캡처를 까먹는 경우가 있어 직접 확인해서 리뷰를 남겨야한다는 불편함이 있다.
이를 해결하기 위해 도움이 되는 툴을 찾아보았고 <a href="https://responsively.app/">responsively</a>라는 툴을 알게되어 이번 쉬어가는 기간에 공부하고 팀원들과 공유해서 적용해볼 예정이다.</p>
<p>백엔드와 프론트엔드 협업이 처음이라 걱정했던 부분이 많았지만, 팀원 모두가 개발 중에 겪는 어려움에 대해 해결하려는 모습과 서로의 피드백을 적극적으로 반영하려는 모습에서 걱정보단 배울 점이 더 많다고 생각되었고 프로젝트 마지막까지 모두가 화이팅해서 좋은 결과물을 만들 수 있으면 좋겠다는 생각과 함께 나도 더 열심히 달려야겠다는 생각이 든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 9월 프로젝트 회고]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-9%EC%9B%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-9%EC%9B%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 04 Oct 2023 14:49:21 GMT</pubDate>
            <description><![CDATA[<p>9월은 팀 프로젝트를 진행했다. 프론트엔드만 모여서 진행하는 팀 프로젝트는 처음이였기 때문에 나에게는 팀 문화, 개발 규칙, 기술 스택 등을 정하는 과정부터 개발까지 모두 새로운 경험이였고 그만큼 시간이 너무 빠르게 지나갔다.
이번 팀 프로젝트에서는 SNS 서비스를 뼈대로 1인가구를 타겟팅한 <a href="https://honkok.vercel.app/">혼콕</a>이라는 서비스를 제작하였다.
서비스를 만들기 위해 기획, 개발, 배포까지 여러 과정들을 경험하면서 느꼈던 점들을 정리해보고자 한다.</p>
<hr>
<h1 id="협업-툴">협업 툴</h1>
<p>협업을 위해 우리 팀은 기획 단계에서는 <a href="https://www.figma.com/figjam/">figjam</a>을 사용하였고 개발 단계에서는 Github를 적극적으로 사용하였다.</p>
<h2 id="figjam">Figjam??</h2>
<p>이번에 처음 사용해보게 되었던 figma 기반의 툴로 실시간으로 공유되는 노트 앱이다.
주제 선정부터 주제 구체화까지 프레인스토밍 형식으로 진행하였는데 간단하게 글로만 표현하는 것 보다 나의 생각을 시각적으로 보여줄 수 있도록 간단한 그림과 함께하니 내 의견을 더 구체화하기 쉬웠고 다른 팀원의 의견을 이해하기 쉬웠다.</p>
<h2 id="github">GitHub</h2>
<p>맨 처음 Github로만 개발 협업툴을 사용하기로 정했을 때 부족할 것 같기도 하다라는 생각이 들었지만 내가 Github의 기능들에 무지했다는 생각이 든다.
issue와 project의 칸반보드를 사용한 일정 관리부터 discussion, 문서화를 위한 wiki, settings를 활용한 규칙 설정까지 소규모 프로젝트를 진행하기에 Github가 제공하는 기능들은 충분하고 유용했다.
진행 예정이나 진행하고 있는 작업에 issue로 등록하고 태그로 진행 상태를 알 수 있어서 서로가 어떤 작업을 하고있는지 한눈에 볼 수 있어서 좋았고 PR에 연결해서 issue가 자동으로 닫히게 하는 과정이 너무 편리했다.
개인적으로는 Action 기능을 추가로 사용하면 더 편리하게 협업할 수 있을 것 같다는 생각이 들어서 공부해볼 예정이다.</p>
<h1 id="팀-문화">팀 문화</h1>
<blockquote>
<ul>
<li>주체성을 가지고 움직이기</li>
</ul>
</blockquote>
<ul>
<li>회의는 모두가 돌아가면서 진행해요. 🧐<ul>
<li>느긋하고 느슨한 것을 지양하기</li>
</ul>
</li>
<li>2일 이내 작업과 스프린트 기반으로 일정과 목표를 선정해요. 🏃<ul>
<li>다른 사람의 의견에는 최소한의 반응하기</li>
</ul>
</li>
<li>침묵보다는 작은 리액션 및 간단한 이모지라도 남겨요. 🙂</li>
<li>이야기가 끝날 때 박수로 마무리해요. 👏<ul>
<li>특이 사항은 즉각적으로 공유하기</li>
</ul>
</li>
<li>일정이 늦어질 것 같으면 바로 이야기해요. 😆</li>
</ul>
<p>우리 팀의 팀 규칙은 위와 같았다. 팀원간의 소통이 원활하게 되는 것을 중요하게 생각해서 이러한 규칙들을 정했고 모두가 지키기 위해 노력했다.
팀 프로젝트를 마무리한 지금 규칙들이 모두 잘 지켜졌나를 생각해보면 대부분 잘 지켜진 것 같다고 생각된다. 모두가 문서화와 소통을 통해 현재 자신의 작업 진행 상황을 공유하려고 노력했다. 하지만 기획 단계에서 유저스토리 작성을 통한 개발해야할 작업들을 세분화하지 못해 스프린트에 대한 아쉬움이 살짝 남는다.</p>
<h1 id="개발-규칙">개발 규칙</h1>
<p><a href="https://github.com/prgrms-fe-devcourse/FEDC4_HONKOK_JunilHwang/wiki/%ED%8C%80-%EA%B0%9C%EB%B0%9C-%EA%B7%9C%EC%B9%99">혼콕 팀 개발 규칙</a>
우리 팀의 개발 규칙은 변수명과 커밋 컨벤션 등을 제외하면 Github 기능과 Eslint, Prettier를 사용해 자동으로 적용할 수 있게 하였다.
좋은 변수명이 무엇인지 이해하고 쉽고 가독성 좋은 컨벤션이 어떤 것인지 다같이 고민하고 이야기하는 과정을 통해 나쁜 변수명 설정 습관이나 컨벤션 습관을 고치려고 노력했다.
또 Eslint와 Prettier의 중요성에 대해 깨닫게 되는 계기가 되었다. 개인 프로젝트를 진행할 때는 Eslint와 Prettier를 모두 코드 포맷터처럼 사용했었다. Eslint와 Prettier의 차이점을 알고 있었지만 그 필요성을 별로 느끼지 못했다. 하지만 Eslint에 다양한 확장을 붙이고 팀원 간의 상의를 통해 필요하지 않은 규칙들을 제거해서 사용하니 너무 편리하게 느껴졌다. 코드 컨벤션에 위반되는 코드나 안티 패턴을 검사해줘서 일관성있는 코드를 작성하기 쉬웠고 때문에 내가 개발하지 않은 코드에 대해 빠르게 이해할 수 있었다.!</p>
<h1 id="기술스택">기술스택</h1>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/76c7de90-e7e2-4f9f-961e-700783f13716/image.png" alt="기술스택"></p>
<h2 id="storybook">StoryBook</h2>
<p>우리 팀은 컴포넌트에 대한 문서화를 위해 storybook을 사용하였다. 초반엔 storybook의 사용법에 대해 공부한 상태가 아니여서 많이 헤매고 어려움을 겪었지만 익숙해진 후 다른 팀원이 개발한 컴포넌트에 대해 테스트 코드를 작성하지 않아도 시각적으로 컴포넌트에 props을 변경하며 확인해 볼 수 있어서 컴포넌트에 대한 이해를 쉽게 할 수 있었다. 프로젝트 막바지에는 시간에 쫓겨 storybook을 잘 사용하진 못했지만 프로젝트의 뼈대를 잡는데 큰 역할을 했다고 생각한다.</p>
<h2 id="react-querytanstack-query">React Query(Tanstack Query)</h2>
<p>이번 프로젝트를 진행하면서 가장 깊게 공부했다고 생각하는 라이브러리는 react query라고 생각한다.
사용자 로그인 상태 관리 부분을 맡았기 때문에 react query를 자세히 공부해야했고 그 결과 로그인 상태 관리 부분을 완성할 수 있었다고 생각한다.
react query를 사용하면서 가장 어려움을 겪었던 부분은 staletime과 cachetime에 대한 이해도가 낮아서 발생했는데 문제를 해결하기위해 공부하면서, 또 해결하고 난 후 문서화(<a href="https://github.com/prgrms-fe-devcourse/FEDC4_HONKOK_JunilHwang/wiki/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85#user%ED%99%95%EC%9D%B8-api%EB%A5%BC-%EC%84%9C%EB%B2%84%EC%97%90-%EA%B3%84%EC%86%8D-%EC%9A%94%EC%B2%AD%ED%95%98%EB%8A%94-%EB%AC%B8%EC%A0%9C">staletime과 cachetime 이란?</a>)를 통해 팀원들과 문제와 해결 방법을 공유하면서 이해도를 높이려고 노력했다.
react query를 사용해본 결과 react query는 서버 상태 패칭, 캐싱, 동기화 및 업데이트를 하는데 너무나 큰 도움을 주는 라이브러리이기 때문에 다른 프로젝트에서도 적극적으로 사용하고 싶고 더 공부해볼 필요가 있는 라이브러리라는 생각이 들었다.</p>
<h1 id="4l">4L</h1>
<h2 id="liked-좋았던-점">Liked (좋았던 점)</h2>
<ul>
<li>기능 개발 중 공식 docs를 많이 활용하려고 노력했다.</li>
<li>PR을 통해 다른 팀원의 코드를 보면서 다양한 방법과 구조에 대해 공부할 수 있었다.</li>
<li>협업 툴로 Github를 사용하다보니 다양한 Github 기능을 경험할 수 있었다.</li>
<li>어려움을 겪었던 문제에 대한 해결방법을 팀원들과 공유하기 위해 노력했다.</li>
</ul>
<h2 id="learned-배운-점">Learned (배운 점)</h2>
<ul>
<li>사용자 로그인 상태 관리 파트를 맡아 개발하면서 react-query에 대해 이해하고 적절하게 사용하려고 노력을 했었다.</li>
<li>리액트에 타입스크립트를 사용하는게 어려웠었는데, 프로젝트를 하면서 학습을 많이 한 것 같다.</li>
<li>팀 프로젝트를 위해 개발 규칙이나 팀 문화를 만들어가는 과정을 통해 팀 프로젝트의 흐름에 대해 배울 수 있었다.</li>
</ul>
<h2 id="lacked-부족했던-점">Lacked (부족했던 점)</h2>
<ul>
<li>추가 요구사항을 포함한 모든 요구사항들을 구현하는 것이 목표였는데 그 중 다크모드를 구현하지 못한 부분이 아쉬웠다. (리팩토링!! 🔥)</li>
<li>스스로 팀 규칙에 대해 잘 지켰는지 생각해보면 그렇지 않은 것 같다. 특히 작업 단위를 작게 가져가는 부분을 많이 지키지 못한 것 같다.</li>
<li>후반에 맡은 기능 구현을 급하게 하다보니 다른 팀원의 PR에 많은 신경을 쓰지 못한 것 같다.</li>
</ul>
<h2 id="longed-for-바라는-점">Longed For (바라는 점)</h2>
<ul>
<li>팀 문화에 대해 더 많이 고민하고 다음 프로젝트에서 더 좋은 팀 문화를 만들 수 있도록 노력하기!</li>
<li>개인 프로젝트도 한번 진행해보기! ⇒ 새로운 것들을 적극적으로 사용해보자!</li>
<li>더 좋은 문서화를 고민하고 작성해보기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 8월 회고]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-8%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-8%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 04 Sep 2023 13:49:02 GMT</pubDate>
            <description><![CDATA[<p>8월에는 내가 무엇을 공부했나 생각해보면 3가지로 줄일 수 있을 것 같다.
Vue! React! Typescript! 생각보다 어려웠던, 지금도 어려운 기술은 typescript인 것 같다. 단순히 type 지정으로만 사용할 수 있지만 개발 편의를 높이는 여러 기능들을 사용하기 위해서는 생각보다 많은 공부가 필요하다고 생각된다.
8월 동안 vue, react, typescript를 사용해 개발했던 과제들과 공부했던 것들을 정리해보며 배우게되었던 점을 다시 상기시켜보고자 한다.</p>
<h1 id="vue를-사용한-영화-검색-서비스">Vue를 사용한 영화 검색 서비스</h1>
<p><a href="https://fedc-4-11-oekix2zoh-honggunwoo.vercel.app/">OMDb PEDIA 바로가기</a>
<img src="https://velog.velcdn.com/images/foxrain_gg/post/f473a942-f6c1-473e-b72e-bcc63c586b73/image.png" alt="OMDb PEDIA">
vue, typescript를 사용해서 영화 검색 사이트를 제작했었다.
vue는 react보단 쉽게 접근할 수 있는 부분이 많다고 생각했다.
아무래도 vue는 프레임워크이다 보니 어떤 기능 구현을 위한 접근 방법이 거의 정해져 있고 사용법만 익힌다면 금방 적용이 가능했었다. 지금 누가 react와 vue 중 어떤 걸 선택할래 라고 물어본다면 쉽게 대답할 순 없을 것 같다... 그만큼 vue도 흥미로운 기술이라고 생각한다.
이 프로젝트에서는 tailwindcss도 적용해서 왓챠피디아 레이아웃 클론코딩도 같이 진행했었다. tailwindcss 사용이 처음에는 너무 어색하고 scss나 css in js 라이브러리를 사용한 것 보다 어려웠지만 이 프로젝트를 통해 적응할 수 있었고 지금은 tailwindcss가 매력적인 css 라이브러리로 생각된다. 특히 상태에 따른 css 적용이나 peer와 같은 형제 요소 선택자는 개발 속도를 더 높혀준다고 생각한다.</p>
<h2 id="잘한-점-or-배우게-된-점">잘한 점 or 배우게 된 점</h2>
<ul>
<li>tailwindcss 사용이 초반에 비해 능숙해져서 빠른 css 적용이 가능해졌다.</li>
<li>그동안 잘 몰랐던 vue에 대해 공부하고 react와 비교해보며 vue만의 장점을 알게 되었다.<h2 id="개선해야-할-점">개선해야 할 점</h2>
</li>
<li>vue를 vue답게 쓰는 법에 대해 좀더 공부해야할 것 같다.</li>
<li>컴포넌트의 역할에 대해 다시 한번 생각해보고 구현을 해야한다.</li>
</ul>
<h1 id="view-네비게이션-시스템-구현react">View 네비게이션 시스템 구현(React)</h1>
<p><a href="https://react-view-navigation-juwgej9zm-honggunwoo.vercel.app/">카드 만들기 바로가기</a></p>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/895cc568-cf8b-4560-9022-99d132e5dcf8/image.png" alt="card">
React를 사용하고 react-router는 사용하지 않는 View 네이게이션 시스템 만들기 과제에서 funnel 구조를 사용해 카드 만들기 서비스를 제작했다. toss의 <a href="https://slash.page/libraries/react/use-funnel/readme.i18n/">useFunnel</a>과 비슷한 custom hook을 만들어<img src="https://velog.velcdn.com/images/foxrain_gg/post/a979d103-9e53-4e19-88e2-b9b33b84ef4e/image.png" alt="">
 구현하려고 했지만 리렌더링 과정에서 문제가 있어서 결국 형식만 비슷하게 구현하였다.
이 과제를 하면서 느낀점은 react에 typescript를 적용을 위해서 더 공부해야겠다는 생각이 들었다. 물론 type을 적용할 순 있지만 더 깔끔한 구조로 개발자에게 적절한 타입을 제공해주는 방법들에 대한 피드백을 받고나서 공부의 필요성을 느꼈다.
typescript에 대한 사용은 미흡했지만 그래도 컴포넌트의 분리나 전체적인 구조는 나름대로 잘 구현한 것 같아서 만족스러웠다.</p>
<h2 id="잘한-점-or-배우게-된-점-1">잘한 점 or 배우게 된 점</h2>
<ul>
<li>컴포넌트 분리를 잘했다.</li>
<li>typescript를 최대한으로 사용하려고 노력했다.</li>
<li>useFunnel에 대해 공부해보며 페이지 전환 구현 방법에 대해 공부할 수 있었다.<h2 id="개선해야-할-점-1">개선해야 할 점</h2>
</li>
<li>react에 typescript를 적용하는 부분이 아직 미흡한 것 같다. 더 공부가 필요하다.</li>
<li>나만의 useFunnel을 성공시켜보자.</li>
<li>외부 라이브러리 도움없이 페이지 전환 애니메이션을 적용해보자.</li>
</ul>
<h1 id="이펙티브-타입스크립트">이펙티브 타입스크립트</h1>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/d95ec04d-75b3-445b-96b8-1137fdfac5bd/image.png" alt="이펙티브 타입스크립트">
이펙티브 타입스크립트를 읽고 있다. 아직 전부 읽은 것은 아니기 때문에 9월에도 이 책을 계속해서 공부할 예정이다. 이제까지 책을 읽으면서 가장 인상 깊었던 점은 타입을 집합이라고 생각하라고 말하는 부분이다. 그동안 typescript의 인터섹션과 유니온을 사용하면서 가끔 이상하다고 생각하는 부분들이 있었는데 타입들을 집합이라고 생각한 순간 궁금증을 해결할 수 있었다.</p>
<h1 id="9월-계획">9월 계획</h1>
<p>9월은 팀 프로젝트가 진행되는 달이다.
이번 팀 프로젝트에서 내 개인적인 목표는 요구사항과 보너스 요구사항을 모두 구현하기 위해 열심히 달려보기! 그리고 팀과 소통하고 소통하기! 이다.
9월이 지난 후 나는 typescript를 잘 이해하고 적절하게 적용하는 사람, react 주니어를 벗어난 사람이 되고 싶다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 7월 회고]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 07 Aug 2023 13:36:43 GMT</pubDate>
            <description><![CDATA[<p>너무 더워서 항상 에어컨 밑에서 시간을 보내는 요즘, 데브코스를 시작한지 벌써 두 달이 넘어가고 있다. 7월에는 내가 어떤 공부를 해왔는지 정리해보고자 한다.
7월은 기존에 알고있던 지식에서 살을 붙이는 공부보단 새롭게 배우는 공부를 더 많이 했던 것 같다.</p>
<h1 id="데브코스-과제들">데브코스 과제들</h1>
<h2 id="고양이-갤러리">고양이 갤러리</h2>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/fd9d38ac-3654-4c5a-bdaa-eac27ed85637/image.png" alt="고양이 갤러리 사진">
Vanilla JS를 사용한 고양이 갤러리에 정합성 체크와 최적화를 개선하는 과제를 했다. 각 컴포넌트들의 상태(state)를 비교해서 상태에 변화가 생긴 경우에만 리렌더링을 하도록 하는 로직 추가가 핵심 이였다.</p>
<h3 id="개선해야-할-점">개선해야 할 점</h3>
<ul>
<li>고양이 갤러리 API는 API 요청에 고의적으로 1~3초로 랜덤 딜레이가 들어가 있다. 빠른 로딩을 위해 Cache Web API를 사용하면 더 좋을 것 같다.</li>
</ul>
<h3 id="잘한-점-or-배우게-된-점">잘한 점 or 배우게 된 점</h3>
<ul>
<li>듣기만 했던 lodash 라이브러리를 조금은 공부할 수 있었다. 컴포넌트의 객체 상태 변화 감지를 lodash를 사용해서 적절하게 구현했다고 생각한다.</li>
<li>Vanilla JS로 컴포넌트 형식으로 구현과 SPA와 비슷하게 구현하는 것에 대해 많이 공부할 수 있었고 Vanilla JS에 대해 자신감이 많이 생긴 프로젝트였다.<h2 id="모바일-네이버-페이지-레이아웃-클론">모바일 네이버 페이지 레이아웃 클론</h2>
<a href="https://bespoke-travesseiro-6f5c22.netlify.app/">네이버 클론 바로가기</a>
<img src="https://velog.velcdn.com/images/foxrain_gg/post/7fce044a-c0ab-4f63-a73f-b6302f8c9926/image.png" alt="">
SCSS를 사용해서 네이버 모바일 페이지 레이아웃을 클론하는 과제를 했다.
이 과제를 통해 원래도 알고 있었지만 CSS는 항상 꾸준히 공부해야 겠다는 생각이 들었다. 다른 개발자 분들이 구현한 CSS코드를 많이 보며 레이아웃 구현 센스를 많이 키워야 겠다는 생각이 든 과제였다.<h3 id="개선해야-할-점-1">개선해야 할 점</h3>
</li>
<li>시멘틱 태그를 더 적극적으로 사용해야 한다. a, main, header와 같은 기본적이 태그 외에 section, article 태그 등 다른 시멘틱 태그도 더 많이 사용해서 웹 접근성을 향상시킬 필요가 있다.</li>
<li>BEM 방법에 대해 좀더 공부해보자... BEM 방법론이 생각보다 어렵게 느껴졌고, 잘 적용하지 못한 것 같다.</li>
<li>&amp;(상위 선택자)를 더 적극적으로 사용하자.</li>
</ul>
<h3 id="잘한-점-or-배우게-된-점-1">잘한 점 or 배우게 된 점</h3>
<ul>
<li>페이지의 크기에 따라 반응형으로 제작하는 과정에 grid 레이아웃을 적용하면서 grid에 대해 많이 공부할 수 있었다.</li>
<li>잘 만들어진 웹 사이트 레이아웃을 클론 코딩하면서 사용하기 편한 레이아웃이 뭔지 생각해보는 계기가 되었다.</li>
</ul>
<h1 id="vue-webpack">Vue? Webpack?</h1>
<p><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S0RtcFAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://qvault.io/wp-content/uploads/2021/04/Webpack-and-Vue-to-Vite.jpg" alt="">
프론트엔드를 공부하면서 Vue를 공부하겠다고 생각해본적은 없었다. React 배우기도 바쁘다는 핑계로 Vue는 공부하려고 하지 않았었다.
이번 데브코스 강의를 통해 Vue에 대해 공부할 수 있었고 Vue가 생각보다 흥미롭다는 생각이 들었다. 라이브러리인 React와 프레임워크인 Vue의 차이점에 대해 알 수 있었고 React와는 다른 매력을 Vue가 가지고 있다고 생각한다.
Vue 프로젝트를 세팅하는 과정에서 Webpack과 Vite 번들러에 대해서도 공부할 수 있었다. 사실 Vite는 세팅 과정이 쉬워서 공부한 부분이 많다고 말할 순 없지만 너무 어렵다고 느껴졌던 webpack에 대해 제대로 배울 수 있었다. 
webpack에 대해 어렵다고 느낀 부분은 eslint, prettier, 외부 라이브러리 등을 프로젝트에 추가하면서 계속해서 생기는 컴파일 오류였다. 하지만 강의의 세팅을 따라해보며 여러 속성들을 추가하는 이유와 속성의 사용 방법을 공부할 수 있었고 webpack도 이제 어느정도 사용할 수 있게 되었다.</p>
<h2 id="개선해야-할-점-2">개선해야 할 점</h2>
<ul>
<li>앞에 배웠던 부분을 벌써 조금은 까먹은 것 같다... Vue의 공식 문서를 읽어보며 복습하는 시간을 가져야 한다!</li>
</ul>
<h2 id="잘한-점-or-배우게-된-점-2">잘한 점 or 배우게 된 점</h2>
<ul>
<li>저번 과제에서 Webpack을 적용하려다가 실패했던 경험을 바탕으로 webpack에 대해 좀더 기억이 남는 공부를 할 수 있었다. 어렵다고 생각되는 부분은 무작정 시도해보고 좌절은 겪은 후 공부하면 더 오래 기억에 남는 걸 이용해야겠다.<h1 id="개인-블로그">개인 블로그...</h1>
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9bipHLLn--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwy6cp17cco1zk8wn0kb.jpeg" alt="">
개인 블로그를 만들기 위해 적용하고 싶은 기술을 들을 공부하고 있다. NextJS, Tailwind CSS등을 공부하면서 새로운 기술들에 대해 많이 공부할 수 있었고 이제는 블로그 제작을 이어갈 단계만 남았다!<h2 id="개선해야-할-점-3">개선해야 할 점</h2>
</li>
<li>공부를 하다보니 계속 욕심이 생겨서 다른 것들을 공부하고 정작 시작은 안하고 있다... 항상 MVP(Minimum Valuable Product)를 기억하고 튜토리얼 지옥에 빠지지 말자.</li>
</ul>
<h2 id="잘한-점-or-배우게-된-점-3">잘한 점 or 배우게 된 점</h2>
<ul>
<li><p>NextJS를 공부하면서 React의 server component의 원리 등을 추가로 공부하면서 이해를 높이기 위해 노력했다.</p>
</li>
<li><p>그동안 공부해보고 싶었던 tailwind에 대해 공부했다. 이제 적용을 통해 사용법에 익숙해져야 한다.</p>
<h1 id="8월-계획">8월 계획</h1>
<p>7월달을 돌아보니 정말 많은 것들을 공부했던 것 같다. 7월엔 이론 학습를 많이 했다면 8월은 실습 학습을 많이한 달로 기억하고 싶기에 다음과 같은 계획들을 가지고 있다.</p>
</li>
<li><p>개인 블로그 배포하기(14일 전까지)</p>
</li>
<li><p>전에 했던 4=10 클론 프로젝트 tailwindCSS로 리팩토링하고 배포하기(9월 전까지)</p>
</li>
<li><p>이펙티브 타입스크립트 책 공부 시작하기(8월은 3장까지 읽기)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 MIL(TypeScript)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILTypeScript</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILTypeScript</guid>
            <pubDate>Wed, 26 Jul 2023 08:48:13 GMT</pubDate>
            <description><![CDATA[<h1 id="typescript란">TypeScript란?</h1>
<ul>
<li><p>타입스크립트는 동적 타입의 자바스크립트에 정적 타입을 부여한 언어로 자바스크립트의 확장된 언어라고 볼 수 있음</p>
<ul>
<li>JS: 동적 타입 ⇒ 런타임에서 동작할 때 타입 오류 확인</li>
<li>TS: 정적 타입 ⇒ 코드 작성 단계에서 타입 오류 확인</li>
</ul>
</li>
<li><p>타입스크립트로 작성된 파일은 실행전 자바스크립트 파일로 컴파일하는 과정이 필요함</p>
<blockquote>
<p>npm i typescript -D // 개발모드에 TS설치</p>
</blockquote>
<blockquote>
<p>npx tsc --init // 타입스크립트의 컴파일 옵션을 기본으로 실행함</p>
</blockquote>
<blockquote>
<p>npx tsc // 프로젝트 폴더에 안에 있는 모든 TS파일이 tsconfig에 맞춰서 JS로 컴파일됨</p>
</blockquote>
</li>
</ul>
<h1 id="typescript에서-제공하는-데이터-타입">TypeScript에서 제공하는 데이터 타입</h1>
<h2 id="ecmascript-표준에-따른-기본-자료형-6가지">ECMAScript 표준에 따른 기본 자료형 6가지</h2>
<ul>
<li>Primitive Type<ul>
<li>Boolean</li>
<li>Number</li>
<li>String</li>
<li>Null</li>
<li>Undefined</li>
<li>Symbol</li>
</ul>
</li>
<li>Array: object형</li>
</ul>
<h2 id="추가적으로-제공하는-타입">추가적으로 제공하는 타입</h2>
<ul>
<li>Any, Void, Never, Unknown</li>
<li>Enum</li>
<li>Tuple: object 형(Array와 유사한 형태)</li>
</ul>
<h2 id="타입-설명">타입 설명</h2>
<h3 id="symbol">Symbol</h3>
<ul>
<li>primitive값을 담아서 사용하며 고유하고 수정불가능한 값으로 만들어 줌. (주로 접근을 제어하는데 쓰는 경우가 많음)</li>
<li>함수로 사용할때는 대문자로 Symbol, 타입으로 사용할 때는 소문자로 symbol을 사용</li>
</ul>
<h3 id="null--undefined">null &amp; undefined</h3>
<ul>
<li>tsconfig(컴파일 옵션)에 설정을 따로 하지 않는 이상 number에 null과 undefined를 할당할 수 있음.</li>
<li>이를 막기위해 컴파일 옵션에서 ‘--strictNullChecks’를 사용하면 null과 undefined는 void(undefined만 가능)나 자기 자신들에게만 할당 가능 ⇒ null과 undefined를 할당할 수 있게 하려면, union type을 이용해야 함</li>
</ul>
<pre><code class="language-tsx">let union: string | null = null;</code></pre>
<h3 id="object">object</h3>
<ul>
<li>primitive type이 아닌 것을 나타내고 싶을 때 사용하는 타입</li>
<li>non-primitive type: not number, string, boolean, bigint, symbol, null, undefined</li>
</ul>
<pre><code class="language-tsx">//create by object literal
const person1 = {name: &#39;gu&#39;, age: 24};
//person1은 &quot;object&quot; type이 아님, person1은 &quot;{name: string, age: number}&quot; type

//create by Object.create
const person2 = Object.create({name: &#39;gu&#39;, age: 24});</code></pre>
<h3 id="array">Array</h3>
<ul>
<li>Array<type> - 이 방식은 jsx, tsx에서 충돌이 발생할 가능성이 있기 때문에 사용하지 않는 것이 좋음</li>
<li>type[]</li>
</ul>
<pre><code class="language-tsx">let list: Array&lt;number&gt; = [1, 2, 3];
let list: number[] = [1, 2, 3];</code></pre>
<h3 id="tuple">tuple</h3>
<ul>
<li>배열의 길이가 고정되고 각 요소의 타입이 지정되어 있는 배열 형식을 의미</li>
<li>즉 순서에 따른 타입이 정확하게 할당되어야 함.</li>
<li>push, splice 등을 통해 배열의 길이가 변경이 가능하므로 사용에 주의해야함</li>
</ul>
<pre><code class="language-tsx">let x: [string, number];
x = [&quot;hello&quot;, 24];
x = [10, &quot;hello&quot;]; //error
x[2] = &#39;go&#39;; //error</code></pre>
<h3 id="any">any</h3>
<ul>
<li><p>모든 타입에 대해 허용</p>
</li>
<li><p>컴파일 옵션중에 any를 작성하지 않으면 오류를 표시하도록 하는 옵션이 있음 → noImplicitAny</p>
</li>
<li><p>any는 계속해서 개체를 통해 전파됨 → 타입 안전성은 TS를 사용하는 주요 동기 중 하나이기 때문에 필요하지 않는 경우에는 any를 사용하지 않도록 해야함</p>
</li>
<li><p>any가 개체를 통해 전파되는 예</p>
<pre><code class="language-tsx">  let looselyTyped: any = {};
  let d = looselyTyped.a.b.c.d;
  //위의 코드는 코드 작성 시 오류가 발생하지 않으며 d의 타입은 any로 추론됨.</code></pre>
</li>
</ul>
<h3 id="unknown">unknown</h3>
<ul>
<li>any가 주는 타입의 불안전함을 어느정도 해소하기 위해 나온 대체제</li>
<li>컴파일러가 타입을 추론할 수 있게끔 타입의 유형을 좁히거나 타입을 확정해주지 않으면 다른 곳에 할당할 수 없고 사용할 수 없음</li>
<li>따라서 any대신 unknown을 사용하는 것이 좋음</li>
</ul>
<pre><code class="language-tsx">declare const maybe: unknown;

const aNumber: number = maybe; //error

if (maybe === true) {
    const aBoolean: boolean =  maybe;
    const aString: string = maybe; //error
}

if(typeof maybe === &#39;string&#39;){
    const aString:string = maybe;
    const aBoolean: boolean =  maybe; //error
}</code></pre>
<p>unknown 타입은 위와 같이 타입가드를 통해서 타입을 한정시켜야지만 사용할 수 있음</p>
<h3 id="never">never</h3>
<ul>
<li><p>never 타입은 모든 타입의 subtype이며, 모든 타입에 할당 할 수 있음, 하지만 never에는 그 어떤 것도 할당할 수 없음. (any도 never에게 할당할 수 없음)</p>
</li>
<li><p>함수의 끝에 절대 도달하지 않는다는 의미 또는 정상적으로 종료되지 않는 함수의 반환 타입으로 사용함</p>
</li>
<li><p>never 사용 예시</p>
<pre><code class="language-tsx">  function error(message: string): never{
      throw new Error(message);
  }

  function fail(){
      return error(&#39;failed&#39;);
  }

  function infiniteLoop(): never{
      while(true) {

      }
  }</code></pre>
</li>
</ul>
<h3 id="void">void</h3>
<p>함수의 반환 값이 없다고 명시적으로 작성하는 타입</p>
<pre><code class="language-tsx">function returnVoid(message: string): void {
    console.log(message);
    return;
}

returnVoid(&quot;no return&quot;);</code></pre>
<h3 id="enum">enum</h3>
<ul>
<li>특정 값(상수)들의 집합을 의미</li>
<li>타입 + 값의 집합으로 역방향 매핑 가능</li>
</ul>
<pre><code class="language-tsx">enum Animals { Cat, Dog, Lion }
console.log(Animals[0]); // Cat
console.log(Animals.Cat); // 0</code></pre>
<ul>
<li>enum의 인덱스를 사용자 편의로 변경하여 사용 가능</li>
</ul>
<pre><code class="language-tsx">enum Animals { Cat = 1, Dog, Lion }
console.log(Animals[1]); // Cat
console.log(Animals[3]); // Lion</code></pre>
<ul>
<li>문자를 할당하게 되면 역방향 매핑이 불가능함</li>
</ul>
<pre><code class="language-tsx">enum Animals {
  Cat = &#39;meow&#39;,
  Dog = 1,
  Lion = 2,
}

console.log(Animals.Cat); // meow
console.log(Animals[0]); //undefined</code></pre>
<h3 id="union">union</h3>
<ul>
<li>2개 이상의 타입이 허용되는 타입</li>
</ul>
<pre><code class="language-tsx">let uni: string | number = 0;
uni = &#39;hi&#39;;
uni = 123;</code></pre>
<h3 id="intersection">intersection</h3>
<ul>
<li>2개 이상의 타입이 병합된 타입</li>
</ul>
<pre><code class="language-tsx">type UserA = {
  name: string;
  age: number;
};

type UserB = {
  isValid: boolean;
};

const userA: UserA = {
  name: &#39;a&#39;,
  age: 12,
  isValid: true, // error
};

const userB: UserB = {
  name: &#39;B&#39;, // error
  age: 11,
  isValid: true,
};

const userC: UserA &amp; UserB = {
  name: &#39;C&#39;, age: 40, isValid: false
};</code></pre>
<h1 id="타입-추론inference">타입 추론(Inference)</h1>
<ul>
<li>TypeScript가 작성된 코드에서 타입을 알 수 있는 경우<ul>
<li>초기화된 변수</li>
<li>기본값이 지정된 매개변수</li>
<li>반환이 있는 함수</li>
</ul>
</li>
<li>타입 추론을 통해 모든 곳에 타입을 명시할 필요가 없음</li>
</ul>
<pre><code class="language-tsx">let a = &#39;Hello&#39;; // string이라는 별도의 타입을 명시할 필요가 없음
a = 123; // error

function join(a: string, b = &#39;&#39;) { //b 매개변수에 타입을 명시할 필요가 없음
  return a + b; // 함수의 반환 타입도 작성하지 않아도 됨
}

const a: number = join(&#39;hello&#39;, &#39;world&#39;); // error</code></pre>
<h1 id="타입-단언assertion">타입 단언(Assertion)</h1>
<ul>
<li>개발자가 typescript에게 타입을 단언해서 명시할 수 있음</li>
<li>as, ! (Non-null 단언 연산자)</li>
</ul>
<pre><code class="language-tsx">// as 키워드를 통해 btn이 버튼 엘리멘트임을 단언함
const btn = document.querySelector(&#39;button&#39;) as HTMLButtonElement;
// (btn as HTMLButtonElement).classList.add(&#39;btn&#39;); 나중에 단언도 가능

// ! 키워드를 통해 btn 변수가 null이나 undefined가 아님을 단언함
const btn = document.querySelector(&#39;button&#39;)!;
// btn!.classList.add(&#39;btn&#39;); 나중에 단언도 가능</code></pre>
<pre><code class="language-tsx">// as 키워드 사용 예
function toTwoDecimals(val: number | string, isNum: boolean) {
  if (isNum) {
    (val as number).toFixed(2);
  } else {
    (val as string).slice(0, 2);
  }
}

toTwoDecimals(3.141592, true);
toTwoDecimals(&#39;hi&#39;, false);</code></pre>
<pre><code class="language-tsx">const json = &#39;{&quot;name&quot;: &quot;gugu&quot;, age: 22}&#39;;
const user = JSON.parse(json);
console.log(user.email); // 에러가 발생하지 않음

// as 키워드 사용 예
const json = &#39;{&quot;name&quot;: &quot;gugu&quot;, age: 22}&#39;;
const user = JSON.parse(json) as { name: string, age: number};
console.log(user.email); // error</code></pre>
<pre><code class="language-tsx">let num: number;
console.log(num); // 초기화가 되지 않아 undefined이므로 오류 발생

let num!: number; // 할당 단언
console.log(num); // 초기화가 되어졌다고 typescript가 판단하기 때문에 오류가 발생하지 않음</code></pre>
<h1 id="타입-가드">타입 가드</h1>
<ul>
<li>타입 추론이 가능한 특정 범위(scope) 안에서 타입을 보장하도록 하는 방법</li>
<li>typeof, instanceof, in 등을 통해 타입 가드가 가능</li>
</ul>
<pre><code class="language-tsx">const btn = document.querySelector(&#39;button&#39;);
if (btn) { // if 조건을 통해 btn이 null이 아님이 보장됨
  btn.classList.add(&#39;btn&#39;);
  btn.id = &#39;abc&#39;;
}

if (btn instanceof HTMLButtonElement) { // 해당 방법도 가능
  btn.classList.add(&#39;btn&#39;);
  btn.id = &#39;abc&#39;;
}</code></pre>
<pre><code class="language-tsx">function toTwoDecimals(val: number | string) {
  if (typeof val === &#39;number&#39;) { // typeof를 통해 val의 타입 가드를 형성함
    val.toFixed(2);
  } else {
    val.slice(0, 2);
  }
}

toTwoDecimals(3.14);
toTwoDecimals(&#39;hi&#39;);</code></pre>
<pre><code class="language-tsx">type UserA = { name: string; age: number };
type UserB = { id: string; email: string };

// is 키워드를 통해 isUserA라는 함수가 UserA 인것을 확인하는 용도의 함수라는 것을 알림
function isUserA(user: unknown): user is UserA {
  if (user &amp;&amp; user.constructor === Object) {
    const u = user as UserA;
    return typeof u.name === &#39;string&#39; &amp;&amp; typeof u.age === &#39;number&#39;;
  }
  return false;
}

fetch(&#39;https://test.com&#39;)
  .then((res) =&gt; res.json())
  .then((user: UserA | UserB) =&gt; {
    if (isUserA(user)) {
      console.log(user.name[0]);
      console.log(user.age - 10);
    }
  });</code></pre>
<h1 id="타입-별칭type-alias">타입 별칭(Type Alias)</h1>
<ul>
<li>Interface와 비슷하게 보임<ul>
<li>Interface: 어떤 타입이 타입으로서 목적, 존재 가치가 명확하면 사용</li>
<li>Type Alias: 다른 대상을 가리키거나 별명으로서만 존재하면 사용</li>
</ul>
</li>
<li>Primitive, Union Type, Tuple, Function, 기타 직접 작성해야하는 타입을 다른 이름을 지정할 수 있음</li>
<li>만들어진 타입의 refer로 사용하는 것이지 타입을 직접만드는 것이 아님</li>
<li>type은 파스칼 케이스를 주로 사용함</li>
</ul>
<h2 id="aliasing-primitive">Aliasing Primitive</h2>
<pre><code class="language-tsx">type MyStringType = string;

const str = &#39;world&#39;;

let myStr: MyStringType = &#39;hello&#39;;
myStr = str;</code></pre>
<h2 id="aliasing-union-type">Aliasing Union Type</h2>
<pre><code class="language-tsx">type StringOrNumber = string | number;

let another: StringOrNumber = 0;
another = &#39;Hi&#39;;</code></pre>
<h2 id="aliasing-tuple">Aliasing Tuple</h2>
<pre><code class="language-tsx">
type PersonTuple = [string, number];

let another: PersonTuple = [&#39;gu&#39;, 24];</code></pre>
<h2 id="aliasing-function">Aliasing Function</h2>
<pre><code class="language-tsx">type EatType = (food: string) =&gt; void;</code></pre>
<h1 id="interface">Interface</h1>
<p>개체(객체, 배열, 함수, 클래스 등)를 정의하는 타입</p>
<ul>
<li>객체의 스펙(속성과 속성의 타입)</li>
<li>함수의 파라미터</li>
<li>함수의 스펙(파라미터, 반환 타입 등)</li>
<li>배열과 객체를 접근하는 방식</li>
<li>클래스</li>
</ul>
<h2 id="optional-property">optional property</h2>
<pre><code class="language-tsx">interface 인터페이스_이름 {
  속성?: 타입;
}</code></pre>
<p>위의 코드와 같이 속성뒤에 ?를 붙이게 되면 해당 속성은 옵션으로 변하게 됨 ⇒ type에서도 사용이 가능함</p>
<h2 id="인덱스-시그니처index-signature">인덱스 시그니처(Index signature)</h2>
<p>인덱싱 가능한 타입을 만들 때 인터페이스의 인덱스 시그니처 방식을 이용함</p>
<pre><code class="language-tsx">interface Arr {
  [key: number]: string;
}
const arr: Arr = [&#39;A&#39;, &#39;B&#39;, &#39;C&#39;];
console.log(arr[1]); // B

interface ArrLike {
  [key: number]: string;
}
const arrLike: ArrLike = { 0: &#39;A&#39;, 1: &#39;B&#39;, 2: &#39;C&#39; };
console.log(arrLike[1]); // B

interface Obj {
  [key: string]: string;
}
const obj: Obj = { a: &#39;A&#39;, b: &#39;B&#39;, c: &#39;C&#39; };
console.log(obj[&#39;b&#39;]); // B
console.log(obj.b); // B</code></pre>
<ul>
<li>인터페이스에 정의하지 않은 속성들을 추가로 사용하고 싶을 경우는 아래와 같은 방법으로 사용할 수 있음</li>
</ul>
<pre><code class="language-tsx">interface Person3 {
  name: string;
  age: number;
  [index: string]: string | number;
}

const p32: Person3 = {
  name: &#39;gugu&#39;,
  email: &#39;test@test.com&#39;,
  person_id: 1,
  age: 23,
};</code></pre>
<h2 id="타입-인덱싱">타입 인덱싱</h2>
<p>인터페이스라는 하나의 타입 안에 들어있는 속성의 또 다른 타입을 타입 인덱싱을 통해 얻어낼 수 있음</p>
<pre><code class="language-tsx">interface User {
  name: string;
  age: number;
}

const a: User[&#39;name&#39;] = &#39;gugu&#39;;
const b: User[&#39;age&#39;] = 123;</code></pre>
<h2 id="function-in-interface">function in interface</h2>
<pre><code class="language-tsx">interface Person4 {
    name: string;
    age: number;
    hello(): void;
}

const p41: Person4 = {
    name: &#39;gugu&#39;,
    age: 12,
    hello: function(): void {
        console.log(`hi ${this.name}`);
    }
};

const p42: Person4 = {
    name: &#39;ququ&#39;,
    age: 11,
    hello(): void{
        console.log(`hi ${this.name}`);
    }
}

// arrow function에서는 this를 사용할 수 없기 때문에 오류 발생
// const p43: Person4 = {
//     name: &#39;dudu&#39;,
//     age: 11,
//     hello: (): void =&gt; {
//         console.log(`hi ${this.name}`);
//     }
// } 

p41.hello();
p42.hello();</code></pre>
<h2 id="class-implements-interface">class implements interface</h2>
<p>인터페이스를 이용해서 클래스(생성(구문) 시그니처(Construct signature))를 만들어내는 방법</p>
<pre><code class="language-tsx">interface UserI {
  name: string;
  getName(): string;
}

interface UserC {
  new (n: string): UserI; // 생성 시그니처
}

class User implements UserI {
  public name;
  constructor(name: string) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}

const user = new User(&#39;Gugu&#39;);
user.getName(); // Gugu

// userClass에는 생성 시그니처 타입이 정의되어야 함
function hello(userClass: UserC, msg: string) {
  const user = new userClass(&#39;Gugu&#39;);
  return `hello ${user.getName()} ${msg}`;
}

hello(User, &#39;hi&#39;);</code></pre>
<h2 id="interface-extends-interface">interface extends interface</h2>
<p>인터페이스를 확장하는데 사용함</p>
<pre><code class="language-tsx">interface IPerson2{
    name: string;
    age?: number;
}

interface IKorean extends IPerson2{
    city: string;
}

const k: IKorean = {
    name: &#39;gugu&#39;,
    city: &#39;seoul&#39;,
    age: 12,
};</code></pre>
<pre><code class="language-tsx">interface User {
  name: string;
  age: number;
}

interface User { // 첫 부분의 User와 합쳐짐
  isValid: boolean;
}

const user: User = {
  name: &#39;Gu&#39;,
  age: 24,
  isValid: true
}</code></pre>
<pre><code class="language-tsx">interface FullName {
  first: string;
  last: string;
}

interface FullName {
  mid: string;
  last: boolean // error
  // 중복해서 인터페이스를 정의할 경우 기존에 존재하는 속성에 다른 타입을 지정할 수 없음
}</code></pre>
<h2 id="function-interface">function interface</h2>
<pre><code class="language-tsx">interface HelloPerson {
    (name: string, age?: number): void;
}

const helloPerson: HelloPerson = function(name: string, age?: number) {
    console.log(`hi ${name}`)
}</code></pre>
<h2 id="readonly-interface-properties">Readonly Interface Properties</h2>
<ul>
<li>readonly: 읽기 전용 속성으로 설정하는 키워드 ⇒ type에서도 사용 가능</li>
</ul>
<pre><code class="language-tsx">interface Person8 {
    name: string;
    age?: number;
    readonly gender: string;
}

const p81: Person8 = {
    name: &#39;gugu&#39;,
    gender: &#39;male&#39;,
}

p81.gender = &#39;female&#39;; //읽기 전용 속성이므로 &#39;gender&#39;에 할당할 수 없음</code></pre>
<h2 id="함수의-명시적-this-타입">함수의 명시적 this 타입</h2>
<pre><code class="language-tsx">interface User {
  name: string
}

// this의 타입을 명시적으로 정의할 수 있음
function greet(this: User, msg: string) {
  return `${msg}, ${this.name}`;
}

const gu = {
  name: &#39;gu&#39;,
  greet
};

gu.greet(&#39;Hi&#39;); // Hi, gu

const neo = {
  name: &#39;Neo&#39;,
};

greet.call(neo, &#39;Bye&#39;);</code></pre>
<h2 id="type-alias-vs-interface">type alias vs interface</h2>
<p>type alias: 어떤 타입을 부르는 이름을 말함</p>
<p>interface: 새로운 타입을 만들어 내는 것 ⇒ 객체 타입을 정의할 땐 interface를 주로 사용함</p>
<ul>
<li><p>function에 대한 차이</p>
<pre><code class="language-tsx">  //type alias
  type EatType = (food: string) =&gt; void;

  //interface
  interface IEat {
      (food: string): void;
  }</code></pre>
</li>
<li><p>array</p>
<pre><code class="language-tsx">  //type alias
  type PersonList = string[];

  //interface
  interface IPersonList {
      [index: number]: string;
  }</code></pre>
</li>
<li><p>intersection</p>
<pre><code class="language-tsx">  interface ErrorHandling {
    success: boolean;
    error?: { message: string };
  }

  interface ArtistsData {
    artists: { name: string }[];
  }

  // type alias
  type ArtistsResponseType = ArtistsData &amp; ErrorHandling;

  // interface
  interface IArtistsResponse extends ArtistsData, ErrorHandling {}

  let art: ArtistsResponseType;
  let iar: IArtistsResponse;</code></pre>
</li>
<li><p>union types</p>
<pre><code class="language-tsx">  interface Bird {
    fly(): void;
    layEggs(): void;
  }

  interface Fish {
    swim(): void;
    layEggs(): void;
  }

  type PetType = Bird | Fish;

  interface IPet extends PetType {} // error

  class Pet implements PetType {} // error</code></pre>
</li>
</ul>
<h3 id="declaration-merging">Declaration Merging</h3>
<ul>
<li><p>interface</p>
<pre><code class="language-tsx">  interface Person {
    name: string;
  }

  interface Person {
    age: number;
  }

  let person: Person = {
    name: &#39;gugu&#39;,
    age: 12
  }

  console.log(person)</code></pre>
</li>
<li><p>type alias는 할 수 없음.</p>
</li>
</ul>
<h1 id="타입스크립트에서-함수-사용">타입스크립트에서 함수 사용</h1>
<pre><code class="language-tsx">const foo1: (a: string, b: number) =&gt; string = (a, b) =&gt; {
  return a;
};

const foo2 = (a: string, b: number): string =&gt; {
  return a;
};

const foo3: (a: string, b: number) =&gt; string = function (a, b) {
  return a;
};

const foo4 = function (a: string, b: number): string {
  return a;
}

function foo5(a: string, b: number): string {
  return a;
}</code></pre>
<h2 id="함수-오버로딩">함수 오버로딩</h2>
<pre><code class="language-tsx">function addString(x: string, y: string): string {
  console.log(x, y);
  return x + y;
}

function addNumber(x: number, y: number): number {
  console.log(x, y);
  return x + y;
}

function add(x: string, y: string): string; // 구현부
function add(x: number, y: number): number; // 구현부
function add(x: any, y: any): any { // 선언부
  console.log(x, y);
  return x + y;
}

add(&#39;Hi&#39;, &#39;World&#39;);
add(12, 13);
add(&#39;Hi&#39;, 13); // error
add(12, &#39;World&#39;); // error</code></pre>
<pre><code class="language-tsx">interface UserBase {
  name: string;
  age: number;
}

interface User extends UserBase {
  updateInfo(newUser: UserBase): User;
  updateInfo(name: string, age: number): User;
}

const user: User = {
  name: &#39;gu&#39;,
  age: 24,
  updateInfo: function (nameOrUser: UserBase | string, age?: number) {
    if (typeof nameOrUser === &#39;string&#39; &amp;&amp; age !== undefined) {
      this.name = nameOrUser;
      this.age = age;
    } else if (typeof nameOrUser === &#39;object&#39;) {
      this.name = nameOrUser.name;
      this.age = nameOrUser.age;
    }
    return this;
  },
};

console.log(user.updateInfo({ name: &#39;gu&#39;, age: 23 })); // { name: &#39;gu&#39;, age: 23, updateInfo: f }
console.log(user.updateInfo(&#39;Leon&#39;, 51)); // { name: &#39;Leon&#39;, age: 51, updateInfo: f }</code></pre>
<h1 id="access-modifiers접근-제어자">Access Modifiers(접근 제어자)</h1>
<ul>
<li>접근 제어자에는 public, private, protected가 있음</li>
<li>클래스 내부의 모든 곳(생성자, 프로퍼티, 메서드)에 설정 가능</li>
<li>JS에서는 private를 지원하지 않아 프로퍼티나 메서드 이름 앞에 _를 붙여서 표현했음</li>
</ul>
<h2 id="initialization-in-constructor-parameters">Initialization in constructor parameters</h2>
<pre><code class="language-tsx">class PersonClass {
    public constructor(public name: string, public age: number) {}

//위의 코드는 아래의 코드와 동일한 결과를 보여줌
    public name: string;
    public age: number;
    public constructor(name: string, age: number){
        this.name = name;
        this.age = age;
    }
}

const p4 = new PersonClass(&#39;Gu&#39;, 13);
console.log(p4);</code></pre>
<h2 id="readonly-properties">readonly properties</h2>
<ul>
<li>접근 제어자와 상관 없이 readonly 키워드가 있는 변수는 초기화 영역에서만 값 설정이 가능하고 나머지 모든 부분(class의 method도 포함)에서는 변경이 불가능함</li>
</ul>
<h2 id="index-signatures-in-class">Index Signatures in class</h2>
<ul>
<li>프로퍼티 이름이 동적으로 들어오는 경우에 사용할 수 있다.</li>
</ul>
<pre><code class="language-tsx">// { gu: &#39;male&#39;, mark: &#39;male, jade: &#39;male&#39;}
// { gu: &#39;male&#39;, chloe: &#39;female&#39;, alex: &#39;male&#39;, anna: &#39;female&#39;}

class Students {
    [index: string]: &quot;male&quot; | &quot;female&quot;;
    gu: &#39;male&#39; = &#39;male&#39;;
}

const a = new Students();
a.mark = &#39;male&#39;;
a.jade = &#39;male&#39;;
console.log(a);

const b = new Students();
b.chloe = &#39;female&#39;;
b.alex = &#39;male&#39;;
b.anna = &#39;female&#39;;
console.log(b);</code></pre>
<h2 id="static-properties--methods">Static Properties &amp; Methods</h2>
<pre><code class="language-tsx">class PersonClass {
    private static CITY = &#39;SEOUL&#39;;
    public static hello() {
        console.log(&#39;hi&#39;, PersonClass.CITY);
    }
}

const p = new PersonClass();
// p.hello();

PersonClass.hello(); //hi SEOUL</code></pre>
<ul>
<li><p>사용 예시</p>
<pre><code class="language-tsx">  class PersonClass {
      private static CITY = &#39;SEOUL&#39;;
      public hello() {
          console.log(&#39;hi&#39;, PersonClass.CITY);
      }
      public change() {
          PersonClass.CITY = &#39;LA&#39;;
      }
  }

  const p = new PersonClass();
  p.hello(); // hi SEOUL
  const p12 = new PersonClass();
  p12.hello(); // hi SEOUL
  p.change();
  p12.hello();  // hi LA</code></pre>
</li>
</ul>
<h2 id="singletons싱글톤-패턴">Singletons(싱글톤 패턴)</h2>
<ul>
<li><p>sigeletons: 애플리케이션이 실행되는 중간에 클래스로부터 단 하나의 오브젝트만 생성해서 사용하는 패턴을 말함</p>
</li>
<li><p>사용법</p>
<ul>
<li><p>private constructor를 사용해 new 키워드로 클래스에 대한 오브젝트 생성을 막는다.</p>
</li>
<li><p>오브젝트를 처음 생성하거나 생성된 오브젝트가 이미 존재한다면 그걸 리턴하는 메서드를 만든다.</p>
<pre><code class="language-tsx">class ClassName {
  private static instance: ClassName | null = null;
  public static getInstance(): ClassName {
      // ClassName으로부터 만든 object가 있으면 그걸 리턴
      // 없으면, 만들어서 리턴
      if (ClassName.instance === null) {
          ClassName.instance =  new ClassName();
      }
      return ClassName.instance;
  }

  private constructor() {}
}

const a = ClassName.getInstance();
const b = ClassName.getInstance();

console.log(a === b); // true</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="abstract-classes">Abstract Classes</h1>
<ul>
<li><p>완전하지 않은 class를 표현하며 new를 이용해서 객체를 생성할 수 없음</p>
</li>
<li><p>abstract class를 상속받으면 abstract function을 구현해야함</p>
<pre><code class="language-tsx">  abstract class AbstractPerson {
    abstract name: string;
    abstract getName(): string;
  }

  // new AbstractPerson(); 에러 발생

  class PersonClass extends AbstractPerson {
    constructor(public name: string) {
      super();
    }
    getName(): string {
      return this.name;
    }
  }

  const p = new PersonClass(&#39;GuGuGu&#39;);
  console.log(p.getName());</code></pre>
</li>
<li><p>interface의 implements와 abstract의 extends를 동시에 사용할 수 있음(extends 키워드가 implements보다 앞으로 와야함)</p>
<pre><code class="language-tsx">  class Cat extends CatA implements AnimalI1, AnimalI2 {
      ...
  }</code></pre>
</li>
</ul>
<h2 id="interface와의-차이점">interface와의 차이점</h2>
<ul>
<li><p>interface를 implements할 때는 super가 필요없지만 abstract를 extends할 때는 super가 필요함</p>
</li>
<li><p>type만을 선언하는 interface와는 다르게 abstract는 type 선언과 구현부 코드를 포함할 수 있음</p>
<pre><code class="language-tsx">  abstract class AnimalA {
    abstract color: string;
    abstract getColor(): string;
    constructor(public sound: string) {}
    speak() {
      return this.sound;
    }
  }

  class Dog extends AnimalA {
    constructor(
      sound: string,
      public color: string,
    ) {
      super(sound);
    }
    getColor() {
      return this.color;
    }
  }</code></pre>
</li>
<li><p>추상 클래스는 단일로(Is-A 관계)만 사용할 수 있지만 interface는 여러개(Has-A)를 사용할 수 있음</p>
<pre><code class="language-tsx">  class Cat implements Animal1, Animal2 {
      ...
  }</code></pre>
</li>
</ul>
<h1 id="데코레이터">데코레이터</h1>
<ul>
<li><p>클래스에서 사용하는 개념</p>
</li>
<li><p>하나의 함수를 클래스, 클래스의 속성, 클래스의 메소드, 메소드의 매개 변수에 연결할 수 있음</p>
<pre><code class="language-tsx">  function deco(target: any) {
    console.log(target);
    return class {
      constructor(
        public a: any,
        public b: any,
      ) {
        console.log(this.a, this.b);
      }
    } as any;
  }

  @deco // 해당 부분에서 User클래스는 자신의 클래스 구조가 아닌
  // deco 함수가 반환한 클래스의 구조를 가지게됨
  class User {
    constructor(public name: string) {}

    hello(msg: string) {
      return `Hello ${this.name}, ${msg}`;
    }
  }

  const gu = new User(&#39;Gu&#39;, 21); // deco 함수의 반환값인 클래스로 객체 생성
  const neo = new User(&#39;Neo&#39;, 22); // deco 함수의 반환값인 클래스로 객체 생성
  console.log(gu);
  console.log(neo);</code></pre>
</li>
<li><p>예: 클래스에서 객체를 생성할 때마다 서버에 데이터를 보내는 코드 작성
⇒ 생성자 함수를 호출할때마다 데코레이터 함수의 반환문이 실행된됨 즉 데코레이터의 반환문 이외의 코드는 클래스에 연결될때 한 번만 실행됨.</p>
<pre><code>  function deco&lt;T extends { new (...args: any[]): any }&gt;(target: T) {
    if (target.name !== &#39;User&#39;) {
      throw new Error(&#39;클래스의 이름이 User가 아님&#39;);
    }
    console.log(&#39;정상적인 클래스의 이름&#39;);

    // 반환하는 클래스의 연결된 클래스를 확장해서 복사함
    return class extends target {
      constructor(...args: any[]) {
        super(args);
        fetch(&#39;서버 주소&#39;, {
          //
        });
        console.log(&#39;서버로 데이터를 보냄&#39;);
      }
    };
  }

  @deco // 해당 부분에서 User클래스는 자신의 클래스 구조가 아닌
  // deco 함수가 반환한 클래스의 구조를 가지게됨
  class User {
    constructor(public name: string) {}

    hello(msg: string) {
      return `Hello ${this.name}, ${msg}`;
    }
  }

  const gu = new User(&#39;Gu&#39;); // deco 함수의 반환값인 클래스로 객체 생성
  const neo = new User(&#39;Neo&#39;); // deco 함수의 반환값인 클래스로 객체 생성
  console.log(gu);
  console.log(neo);</code></pre><p><img src="https://github.com/HongGunWoo/raspAlarm/assets/45515388/08fbd0eb-259f-4101-bc89-a078fd705550" alt="스크린샷 2023-07-24 오후 5.27.45.png"></p>
</li>
</ul>
<h1 id="제네릭generics">제네릭(Generics)</h1>
<h2 id="generic과-any의-차이점">Generic과 Any의 차이점</h2>
<p>Any는 input에 따라 달라지는 연산이 불가능하지만 Generic은 가능함</p>
<pre><code class="language-tsx">function hello(message: any): any {
    return message;
}

console.log(hello(&#39;mark&#39;).length);
console.log(hello(13).length); //오류가 발생하지 않음

function helloGenric&lt;T&gt;(message: T): T {
    return message;
}

console.log(helloGenric(&#39;mark&#39;).length);
console.log(helloGenric(13).length); //오류 발생</code></pre>
<h2 id="generic-basic">Generic basic</h2>
<pre><code class="language-tsx">function helloBasic&lt;T, U&gt;(message: T, commet: U): T {
    return message;
}

helloBasic&lt;string, number&gt;(&quot;dd&quot;, 12); //way 1 타입 직접 지정
helloBasic(23, 21); //way 2 타입 추론</code></pre>
<h2 id="generic-interface">Generic Interface</h2>
<pre><code class="language-tsx">interface ToObj&lt;T&gt; {
  a: T;
  b: T;
}

function toObj&lt;T extends string | number&gt;(a: T, b: T): ToObj&lt;T&gt; {
  return { a, b };
}

toObj&lt;string&gt;(&#39;A&#39;, &#39;B&#39;);
toObj&lt;number&gt;(1, 2);
toObj&lt;boolean&gt;(true, false); // 에러 발생</code></pre>
<h2 id="generic-array--tuple">Generic Array &amp; Tuple</h2>
<pre><code class="language-tsx">function helloArray&lt;T&gt;(message: T[]): T {
    return message[0];
}

helloArray([&#39;hello&#39;, &#39;world&#39;]);
helloArray([&quot;hello&quot;, 4]); //string|number union타입으로 추론

function helloTuple&lt;T, K&gt;(message: [T, K]): T {
        return message[0];
}

helloTuple([&quot;hello&quot;, &quot;world&quot;]);
helloTuple([&quot;hello&quot;, 1]);</code></pre>
<h2 id="generics-function">Generics Function</h2>
<pre><code class="language-tsx">type HelloFunctionGeneric = &lt;T&gt;(message: T) =&gt; T;
const helloFunction1: HelloFunctionGeneric = &lt;T&gt;(message: T): T =&gt; {
    return message;
}

interface HelloFunctionGeneric2 {
    &lt;T&gt;(message: T): T;
}
const helloFunction2: HelloFunctionGeneric2 = &lt;T&gt;(message: T): T =&gt; {
    return message;
}</code></pre>
<h2 id="generic-class">Generic class</h2>
<pre><code class="language-tsx">class Person&lt;T, K&gt; {
    private _name: T;
    private _age: K;

    constructor(name: T, age: K) { // constructor에서 T, K가 정의됨
        this._name = name;
        this._age = age;
    }
}

new Person(&quot;Gu&quot;, 12);
new Person&lt;string, number&gt;(&#39;gu&#39;, 23);</code></pre>
<h2 id="generics-with-extends제약-조건">Generics with extends(제약 조건)</h2>
<p>generic에서 extends는 extends로 정해준 타입만 가능하다는 뜻</p>
<pre><code class="language-tsx">class PersonExtends&lt;T extends string | number&gt; {
    private _name: T;

    constructor(name: T) {
        this._name = name;
    }
}

new PersonExtends(&#39;mark&#39;);
new PersonExtends(123);
new PersonExtends(true); //오류 발생</code></pre>
<h2 id="조건부-타입conditional-types">조건부 타입(Conditional Types)</h2>
<ul>
<li><p>삼항 연산자를 사용하는 타입 부분을 조건부 타입이라고함</p>
<pre><code class="language-tsx">  type MyType&lt;T&gt; = T extends string | number ? boolean : never;

  const a: MyType&lt;string&gt; = true; // MyType이 boolean이 됨
  const b: MyType&lt;number&gt; = true; // MyType이 boolean이 됨
  const c: MyType&lt;null&gt; = true; ; // MyType이 never가 되므로 에러 발생</code></pre>
</li>
</ul>
<h3 id="유틸리티-타입utility-type">유틸리티 타입(Utility Type)</h3>
<pre><code>type MyExclude&lt;T, U&gt; = T extends U ? never : T;
type MyUnion = string | number | boolean | null;

const a: MyExclude&lt;MyUnion, boolean | null&gt; = 123; // a라는 변수는 string이거나 number이여야할 때 사용함
// string, number를 제외한 나머지 타입은 never가 됨

// TS는 이미 내장된 Exclude 타입이 존재함
const a: Exclude&lt;MyUnion, boolean | null&gt; = 123;</code></pre><h3 id="keyof--type-lookup-system">keyof &amp; type lookup system</h3>
<ul>
<li>keyof: 개체의 key 부분만 추출해서 유니온 타입으로 만들어줌</li>
</ul>
<pre><code class="language-tsx">interface IPerson {
    name: string;
    age: number;
}

const person: IPerson = {
    name: &#39;Gu&#39;,
    age: 12,
};

// IPerson[keyof IPerson]
// =&gt; IPerson[&#39;name&#39; | &#39;age&#39;]
// =&gt; IPerson[&#39;name&#39;] | IPerson[&#39;age&#39;]
// =&gt; string | number
function getProp&lt;T, K extends keyof T&gt;(obj: T, key: K): T[K] {
    return obj[key];
}

getProp(person, &#39;name&#39;);

function setProp&lt;T, K extends keyof T&gt;(
    obj: T, 
    key: K, 
    value: T[K]
    ): void {
    obj[key] = value;
}

setProp(person, &#39;name&#39;, &#39;Mark&#39;);</code></pre>
<h3 id="infer추론-키워드">infer(추론 키워드)</h3>
<p>조건부 타입에서 타입 변수를 추론할 때 사용하는 키워드</p>
<pre><code class="language-tsx">type ArrayItemType&lt;T&gt; = T extends (infer I)[] ? I : never;

const numbers = [1, 2, 3];
const a: ArrayItemType&lt;typeof numbers&gt; = 123; // I가 number타입이 됨
const b: ArrayItemType&lt;boolean&gt; = 123; // 에러 발생

const fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;melon&#39;];
const hello = () =&gt; {};
const c: ArrayItemType&lt;typeof fruits&gt; = &#39;ABC&#39;; // I가 string타입이 됨
const d: ArrayItemType&lt;typeof hello&gt; = &#39;ABC&#39; // 에러 발생</code></pre>
<pre><code class="language-tsx">type SecondArgumentType&lt;T&gt; = T extends (f: any, s: infer S) =&gt; any ? S : never;

function hello(a: string, b: number) {}
const a: SecondArgumentType&lt;typeof hello&gt; = 123;</code></pre>
<pre><code class="language-tsx">type MyReturnType&lt;T extends (...args: any) =&gt; any&gt; = T extends (
  ...args: any
) =&gt; infer R
  ? R
  : any;

function add(x: string, y: string) {
  return x + y;
}

const a: MyReturnType&lt;typeof add&gt; = &#39;hello&#39;;

// ReturnType이라는 내장 유틸리티 타입이 있음
const a: ReturnType&lt;typeof add&gt; = &#39;hello&#39;;</code></pre>
<h1 id="타입-가져오기와-내보내기">타입 가져오기와 내보내기</h1>
<ul>
<li>import type 키워드를 통해 타입이라는 것을 명시함</li>
<li>namespace를 사용해 type에도 namespace를 적용할 수 있음</li>
</ul>
<pre><code class="language-tsx">export namespace Utils {
  export interface Add {
    // namespace 안에서도 export 키워드가 필요함
    (a: number, b: number): number;
  }

  export interface Subtract {
    (a: number, b: number): number;
  }
}

export const add: Utils.Add = (a, b) =&gt; a + b;
export const subtract: Utils.Subtract = (a, b) =&gt; a - b;

export default {
  name: &#39;My utils!&#39;,
  add,
  subtract,
};</code></pre>
<pre><code class="language-tsx">import utils, { add, subtract } from &#39;./myUtils&#39;; // // 데이터로 취급
import type { Utils } from &#39;./myUtils&#39;; // 타입으로 취급
// import { add, subtract, Add, Subtract } from &#39;./myUtils&#39;;
// 데이터와 타입을 섞어서 import하는 것도 가능하지만 직관적으로 구분해서 표현하는 것이 좋음

const a = add(4, 7);
const b = subtract(9, 6);

const c = utils.add(4, 7);
const d = utils.subtract(9, 6);

console.log(utils.name); // &#39;My utils!&#39;

const newAdd: Utils.Add = (x, y) =&gt; x + y;
newAdd(1, 2);

const newSubtract: Utils.Subtract = (x, y) =&gt; x - y;
newSubtract(3, 1);</code></pre>
<h1 id="tsconfigjson-옵션">tsconfig.json 옵션</h1>
<ul>
<li>root 경로에 tsconfig.json 파일을 생성하여 옵션들을 설정할 수 있음</li>
</ul>
<h2 id="최상위-프로퍼티">최상위 프로퍼티</h2>
<ul>
<li>compileOnSave</li>
<li>compileOptions</li>
<li>files</li>
<li>include</li>
<li>exclude</li>
<li>extends</li>
<li>references</li>
</ul>
<h2 id="compileonsave">compileOnSave</h2>
<pre><code class="language-tsx">{
  ...,
  &quot;compileOnSaveDefinition&quot;: {
    &quot;properties&quot;: {
      &quot;compileOnSave&quot;: {
                //save하면 컴파일을 활성화함
        &quot;description&quot;: &quot;Enable Compile-on-Save for this project.&quot;,
        &quot;type&quot;: &quot;boolean&quot;
      }
    }
  },
  ...,
}

//따라서 아래와 같이 지정하면 파일을 save하면 자동 컴파일이 됨
{
    &quot;compileOnSave&quot;: true,
}</code></pre>
<h2 id="compileroptions">compilerOptions</h2>
<p>ts파일을 js파일로 변환할 때 어떤 옵션을 사용해서 해석할 것인지 지정</p>
<h3 id="strict">strict</h3>
<p>엄격한 타입 검사를 활성화 하는 옵션, 아래의 옵션들을 자동으로 활성화함(기본 값: false)</p>
<ul>
<li>--noImplicitAny</li>
<li>--noImplicitThis</li>
<li>--strictNullChecks</li>
<li>--strictFunctionTypes</li>
<li>--strictPropertyInitialization</li>
<li>--strictBindCallApply</li>
<li>--alwaysStrict</li>
</ul>
<h3 id="--noimplicitany">--noImplicitAny</h3>
<p>명시적이지 않게 any타입을 사용하여, 표현식과 선어에 사용하면 에러 발생</p>
<ul>
<li>타입스크립트가 추론에 실패한 경우, any가 맞으면 any라고 지정</li>
<li>아무것도 쓰지 않으면 오류 발생</li>
</ul>
<h3 id="--noimplicitthis">--noImplicitThis</h3>
<p>명시적이지 않게 any타입을 사용하여 this 표현식에 사용하면 에러를 발생</p>
<h3 id="--strictnullchecks">--strictNullChecks</h3>
<p>null 및 undefined 값이 모든 유형의 도메인에 속하지 않으며, 그 자신을 타입으로 가지거나, any일 겨우에만 할당이 가능</p>
<ul>
<li>한 가지 예외로 undefined에 void 할당이 가능</li>
</ul>
<p>strictNullChecks를 적용하지 않으면 모든 타입은 null, undefined 값을 가질 수 있음. (string으로 타입을 지정해도 null, undefined값을 할당할 수 있음)</p>
<h3 id="--strictfunctiontypes">--strictFunctionTypes</h3>
<p>엄격한 함수의 매개변수 타입 검사</p>
<h3 id="--strictpropertyinitialization">--strictPropertyInitialization</h3>
<p>정의되지 않은 클래스의 속성이 생성자에서 초기화되었는지 확인</p>
<p>이 옵션을 사용하려면 --strictNullChecks를 사용하도록 설정해야함</p>
<h3 id="--strictbindcallapply">--strictBindCallApply</h3>
<p>Function의 내장 함수인 bind/call/apply를 사용할 때, 엄격하게 체크하도록 하는 옵션</p>
<ul>
<li>bind는 해당 함수 안에서 사용할 this와 인자를 설정해주는 역할</li>
<li>call과 apply는 this와 인자를 설정한 후, 실행까지 함</li>
<li>call vs apply<ul>
<li>call은 함수의 인자를 여러 인자의 나열로 넣어서 사용하고, apply는 모든 인자를 배열 하나로 넣어서 사용</li>
</ul>
</li>
</ul>
<h3 id="--alwaysstrict">--alwaysStrict</h3>
<p>각 소스파일에 대해 JS의 strict mode로 코드를 분석하고, “엄격하게 사용”을 해제</p>
<h3 id="target--lib">target &amp; lib</h3>
<ul>
<li>target<ul>
<li>빌드의 결과물을 어떤 버전으로 할 것인지를 정함</li>
<li>ESNext: 가장 최신의 JS 버전을 뜻함</li>
</ul>
</li>
<li>lib<ul>
<li>기본 type definition 라이브러리를 어떤 것을 사용할 것이지 정함</li>
<li>lib을 지정하지 않으면 target의 버전에 맞는 디폴트 값이 있음</li>
<li>lib을 지정하면 lib 배열로만 라이브러리를 사용함</li>
</ul>
</li>
</ul>
<h3 id="module">module</h3>
<ul>
<li>사용할 모듈 방식을 지정할 수 있는 옵션</li>
<li>ESM 방식을 사용하기 위해선 ES2015(ES6) 버전 이상을 사용해야함</li>
</ul>
<h3 id="moduleresolution">moduleResolution</h3>
<ul>
<li>컴파일러가 사용할 모듈 생성 방식 지정</li>
<li>node나 bundler 속성을 추천함 ⇒ index.ts 파일을 import 할 때 파일 이름을 생략하고 경로까지만 적어도 import가 가능해짐</li>
</ul>
<h3 id="paths">paths</h3>
<ul>
<li><p>경로 별칭 지정</p>
</li>
<li><p>예시</p>
<pre><code class="language-tsx">  // tsconfig.js
  {
    &quot;compilerOptions&quot;: {
      &quot;paths&quot;: {
        &quot;myUtils&quot;: [&quot;./my_module/utils.ts&quot;],
              &quot;~/*&quot;: [&quot;./src/*&quot;]
      }
    },
  }</code></pre>
<pre><code class="language-tsx">  // main.ts
  import { add } from &#39;myUtils&#39;;
  import { add } from &#39;~/my_modules/utils&#39; // === ./src/my_modules/utils</code></pre>
</li>
</ul>
<h3 id="jsx">jsx</h3>
<ul>
<li>jsx 출력 방식 제어
<img src="https://github.com/HongGunWoo/raspAlarm/assets/45515388/04f856cb-0439-404d-aced-04d708bd2ca8" alt="스크린샷 2023-07-25 오후 11.10.56.png"></li>
</ul>
<h3 id="outdir-outfile-rootdir">outDir, outFile, rootDir</h3>
<ul>
<li>outDir: 컴파일 후 생성되는 js 파일이 저장될 폴더명</li>
<li>outFile: 복수 파일을 묶어 하나의 파일로 출력 설정</li>
<li>rootDir: 시작하는 루트 폴더</li>
</ul>
<h2 id="files-exclude-include">files, exclude, include</h2>
<ul>
<li>files: ts를 js로 컴파일할 때 어떤 파일을 사용할 것인지 지정</li>
<li>exclude: 컴파일에 제외할 폴더들을 지정</li>
<li>include: 컴파일에 포함할 폼더들을 지정</li>
<li>우선순위<ul>
<li>files, exclude, include 순으로 우선순위가 높음
⇒ exclude에 포함되는 파일이여도 files에 명시되어 있으면 js파일로 변환됨</li>
<li>셋다 설정이 없으면 전부 다 컴파일함</li>
</ul>
</li>
</ul>
<h2 id="extends">extends</h2>
<ul>
<li>다른 파일에 있는 옵션을 확장할 때 사용하는 키워드</li>
<li>extends와 중복되는 옵션은 tsconfig.json의 옵션 설정으로 덮어씌어짐</li>
</ul>
<h1 id="내장-유틸리티-타입">내장 유틸리티 타입</h1>
<h2 id="partial">Partial</h2>
<ul>
<li>모든 필수 속성들을 선택 속성으로 만들때 사용, ?로 만드는 것과 비슷함</li>
</ul>
<pre><code class="language-tsx">interface User {
  name: string,
  age: number,
}

// error
const userA: User = {
  name: &#39;A&#39;
}

// 에러가 발생하지 않음
const userB: Partial&lt;User&gt; = {
  name: &#39;B&#39;
}</code></pre>
<h2 id="required">Required</h2>
<ul>
<li>모든 선택 속성들을 필수 속성으로 변경할 때 사용</li>
</ul>
<pre><code class="language-tsx">interface User {
  name?: string,
  age?: number,
}

// 에러가 발생하지 않음
const userA: User = {
  name: &#39;A&#39;
}

// error
const userB: Required&lt;User&gt; = {
  name: &#39;B&#39;
}</code></pre>
<h2 id="readonly">Readonly</h2>
<ul>
<li>모든 속성을 읽기 전용 속성으로 바꿈</li>
</ul>
<pre><code class="language-tsx">interface User {
  name?: string;
  age?: number;
}

const userA: User = {
  name: &#39;A&#39;,
  age: 12,
};

const userB: Readonly&lt;User&gt; = {
  name: &#39;B&#39;,
  age: 12,
};

userA.name = &#39;AA&#39;;
userB.name = &#39;BB&#39;; // error</code></pre>
<h2 id="record">Record</h2>
<ul>
<li>Record&lt;U, T&gt;<ul>
<li>U: Union 타입</li>
<li>T: Union 타입의 속성이 어떤 타입이 될 것인지 명시</li>
</ul>
</li>
</ul>
<pre><code class="language-tsx">type Names = &#39;neo&#39; | &#39;gugu&#39;;

const developers: Record&lt;Names, number&gt; = {
  neo: 12,
  gugu: 13,
}

// Record&lt;Names, number&gt;를 통해 만들어지는 타입은 RecordNames와 동일함
type RecordNames = {
  neo: number
  gugu: number
}</code></pre>
<h2 id="pick">Pick</h2>
<ul>
<li>하나의 객체 타입에서 원하는 속성으로 새로운 객체 타입을 만들 수 있음</li>
</ul>
<pre><code class="language-tsx">interface User {
  name: string;
  age: number;
  email: string;
}

// Pick&lt;User, &#39;name&#39; | &#39;email&#39;&gt;의 결과는 PickUser와 동일함
const user: Pick&lt;User, &#39;name&#39; | &#39;email&#39;&gt; = {
  name: &#39;gugu&#39;,
  email: &#39;gugu@gugu.com&#39;,
  age: 11, // error
};

interface PickUser {
  name: string;
  email: string;
}</code></pre>
<h2 id="omit">Omit</h2>
<ul>
<li>Pick과 반대되는 개념</li>
</ul>
<pre><code class="language-tsx">interface User {
  name: string;
  age: number;
  email: string;
}

// Omit&lt;User, &#39;name&#39; | &#39;email&#39;&gt;의 결과는 OmitUser와 동일함
const user: Omit&lt;User, &#39;name&#39; | &#39;email&#39;&gt; = {
  age: 11,
};

interface OmitUser {
  age: number
}</code></pre>
<h2 id="exclude">Exclude</h2>
<ul>
<li>Union 타입에서 특정 타입(Union도 작성 가능)을 제외할 때 사용</li>
</ul>
<pre><code class="language-tsx">type T = string | number | boolean;

const a: Exclude&lt;T, number&gt; = &#39;string&#39;;
const b: Exclude&lt;T, number&gt; = 123; // 에러 발생</code></pre>
<h2 id="extract">Extract</h2>
<ul>
<li>Extract&lt;T, U&gt;: T라는 Union타입에서 U와 일치하는 타입을 추출하여 새로운 Union타입을 반환함</li>
</ul>
<pre><code class="language-tsx">type T = string | number | boolean;
type U = number | boolean | string[];

const a: Extract&lt;T, U&gt; = 123
// Extract&lt;T, U&gt; === number | boolean</code></pre>
<h2 id="return">Return</h2>
<p>어떤 타입이 반환되는지 알아냄</p>
<pre><code class="language-tsx">function hello(msg: string) {
  return msg;
}

const a: ReturnType&lt;typeof hello&gt; = &#39;string&#39;</code></pre>
<h2 id="awaited">Awaited</h2>
<ul>
<li>await를 사용해서 반환되는 데이터의 타입을 사용할 수 있음</li>
</ul>
<pre><code class="language-tsx">(async () =&gt; {
  const promise = Promise.resolve(true);
  console.log(await promise); // true
  const a: Awaited&lt;typeof promise&gt; = false;
})();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(SCSS(Sass))]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILSCSSSass</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILSCSSSass</guid>
            <pubDate>Wed, 19 Jul 2023 14:29:30 GMT</pubDate>
            <description><![CDATA[<h1 id="scsssass란">SCSS(Sass)란?</h1>
<ul>
<li>Sass는 Syntactically Awesome StyleSheet의 약자로 기존의 CSS의 단점을 보완하고 코드의 재활용성과 가독성을 올리기 위해 개발된 CSS Preprocessor(전처리기)</li>
<li>SCSS(Sass)는 전처리기 언어이므로 SCSS 확장자를 가진 파일을 바로 사용할 수는 없고 SCSS파일을 CSS 파일로 컴파일 하는 과정이 필요함.</li>
</ul>
<h2 id="scss와-sass의-차이">SCSS와 Sass의 차이</h2>
<ul>
<li><p>SCSS는 Sass와 거의 동일하지만 Sass에 비해 좀 더 CSS 코드와 유사한 형태를 가지고 있어 SCSS를 더 많이 사용함</p>
<table>
<thead>
<tr>
<th></th>
<th>구문 스타일</th>
<th>mixin 문법</th>
</tr>
</thead>
<tbody><tr>
<td>SCSS</td>
<td>중괄호와 세미콜론을 사용</td>
<td>선언: @mixin, 적용: @include</td>
</tr>
<tr>
<td>Sass</td>
<td>들여쓰기를 사용하고 세미콜론이 없음</td>
<td>선언: =, 적용: +</td>
</tr>
</tbody></table>
</li>
</ul>
<h1 id="주석">주석</h1>
<ul>
<li>/* */ : CSS의 기본 주석 ⇒ 컴파일 결과로 포함됨</li>
<li>// : SCSS의 주석 ⇒ 컴파일 결과로 포함되지 않음</li>
</ul>
<h1 id="중첩nesting">중첩(Nesting)</h1>
<ul>
<li><p>&amp;: 자신이 포함된 범위에 상위 선택자를 참조하는 키워드</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/9906de01-ef84-4d7f-b6d5-8f953af1f222" alt="스크린샷 2023-07-19 오전 2.07.01.png"></p>
</li>
<li><p>@at-root: 중첩을 벗어나서 선언되게 하는 키워드</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/225e1ac7-b5c7-49eb-aaf4-a5ba92488dd5" alt="스크린샷 2023-07-19 오전 2.13.58.png"></p>
</li>
<li><p>중첩된 속성: 반복되는 키워드가 있다면 범위로 만들어서 키워드를 생략해서 작성할 수 있음</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/29237e06-e320-4607-a259-c1b9a2c877a4" alt="스크린샷 2023-07-19 오전 2.18.38.png"></p>
</li>
<li><p>중첩에서 다중 선택자를 사용하면 여러 선택자의 값들을 한번에 제어가 가능함</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/ea9a1d5a-4e3c-4e8a-ae81-4549a613ff05" alt="스크린샷 2023-07-19 오전 2.20.17.png"></p>
</li>
</ul>
<h1 id="변수">변수</h1>
<ul>
<li><p>SCSS에서 변수를 선언하기 위해선 변수명 앞에 “$”키워드를 붙여야함</p>
<ul>
<li>$variable: {변수 값}</li>
</ul>
</li>
<li><p>재할당이 가능함</p>
</li>
<li><p>변수의 유효범위는 변수가 선언된 블럭(중괄호)의 영역임</p>
</li>
<li><p>!global: 변수의 유효범위를 벗어나서 전역 변수로 사용할 수 있게 하는 키워드
global 키워드는 동일한 변수명을 가지고 있는 전역 변수를 덮어쓸 수 있으므로 주의해서 사용해야함</p>
<p> <img src="https://github.com/milooy/Boxiting/assets/45515388/9555f6e4-d1e6-4f89-95ce-9e70e0fe0f1f" alt="스크린샷 2023-07-19 오전 2.27.05.png"></p>
</li>
<li><p>!default: 유효범위 안에서 변수를 지정을 할 때 동일한 이름을 가진 변수가 값을 가지고 있다면 재할당한 변수값을 사용하지 않고 원래의 값을 사용함</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/248411b8-a44a-46df-96d1-60d48ab9bb5d" alt="스크린샷 2023-07-19 오전 2.33.00.png"></p>
</li>
<li><p>보간: “#{변수명}”을 통해 문자열 안에서도 변수를 사용할 수 있음(JS의 탬플릿 리터럴과 비슷함)
선택자에도 보간을 사용할 수 있음 ⇒ 선택자 부분에 변수를 사용할 때는 보간을 사용해야함</p>
<p> <img src="https://github.com/milooy/Boxiting/assets/45515388/0b2435f9-8fa1-4e1e-a801-353559970d70" alt="스크린샷 2023-07-19 오전 2.43.03.png"></p>
</li>
</ul>
<h1 id="데이터-타입">데이터 타입</h1>
<h2 id="number">Number</h2>
<ul>
<li>정수, 실수 등의 데이터 타입</li>
<li>단위가 붙어있는 숫자도 Number 타입으로 취급함 ⇒ ex. 20px, 2fr</li>
</ul>
<h2 id="string">String</h2>
<ul>
<li>문자로 되어져있는 값들과 따옴표로 묶어진 값들은 모두 String 타입</li>
</ul>
<h2 id="color">Color</h2>
<ul>
<li>blue, rgba(255, 0, 0), #fff 등 CSS로 표현할 수 있는 색상들을 color 타입</li>
</ul>
<h2 id="boolean">Boolean</h2>
<ul>
<li>true, false 값</li>
</ul>
<h2 id="null">Null</h2>
<ul>
<li>null 값을 가지고 있는 요소는 컴파일되지 않음</li>
</ul>
<h2 id="list">List</h2>
<ul>
<li>배열 데이터와 유사함</li>
<li>값들이 나열되어 있으면 list 데이터<ul>
<li>$list: (10px, 15px, 20px);</li>
<li>$list: 10px, 15px, 20px;</li>
<li>$list: 10px 15px 20px;</li>
</ul>
</li>
</ul>
<h2 id="map">Map</h2>
<ul>
<li><p>key, value 형태로 값을 작성</p>
</li>
<li><p>$map: ( key: value ); ⇒ 소괄호 생략 불가능</p>
</li>
<li><p>map 타입 데이터의 값을 조회하기 위해서는 sass의 map 내장 모듈을 사용해야함</p>
<pre><code class="language-scss">  @use &quot;sass:map&quot;;

  $mapData: (
      sm: 100px,
      lg: 200px
  );

  .container {
      width: map.get($mapData, &quot;sm&quot;);
  }</code></pre>
</li>
</ul>
<h1 id="산술-연산자">산술 연산자</h1>
<ul>
<li><p>+, -, *, /, % 연산자를 사용할 수 있음</p>
</li>
<li><p>“100% - 50px” 등 단위가 다른 경우 산술연산자를 사용할 수 없음 ⇒ calc함수를 사용해서 해결</p>
</li>
<li><p>“/”(나누기)연산자는 기존의 CSS 문법과 겹치는 부분이 있기 때문에 별도의 사용하는 방법을 지켜야함</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/53b9fb83-6229-43dd-a7a5-739d842e7fc9" alt="스크린샷 2023-07-19 오전 2.59.22.png"></p>
<p>  나누기 연산자가 적용되지 않음</p>
<ul>
<li>적용 방법 1: 괄호로 닫기<ul>
<li>top: (20px / 2); ⇒ top: 10px;</li>
</ul>
</li>
<li>적용 방법 2: 변수에 저장해서 나누기<ul>
<li>top: $변수 / 2</li>
</ul>
</li>
<li>다른 산술 연산자와 혼합해서 사용<ul>
<li>top: 20px / 2 + 1px; ⇒ top: 11px;</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="재활용mixin">재활용(@mixin)</h1>
<ul>
<li><p>@mixin을 사용해서 재활용할 스타일들을 정의하고 @include를 통해서 정의한 스타일들을 사용할 수 있음
Sass는 @mixin을 “=”, @include를 “+” 기호로 바꿔서 사용함</p>
<p> <img src="https://github.com/milooy/Boxiting/assets/45515388/b316af4c-3d6c-43a1-af93-ed379dc7989e" alt="스크린샷 2023-07-19 오후 1.03.17.png"></p>
</li>
<li><p>js 함수처럼 인자를 넘겨주고 기본 매개변수를 지정해주는 등의 동작이 가능</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/10341755-e64e-4c6c-881d-59221f6ab4ca" alt="스크린샷 2023-07-19 오후 1.06.29.png"></p>
</li>
<li><p>@content를 통해 mixin에 스타일을 추가할 수 있음</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/bcce0d01-86c0-4ef6-b597-13d23b71f1a6" alt="스크린샷 2023-07-19 오후 1.51.43.png"></p>
</li>
</ul>
<h1 id="삼항-연산자">삼항 연산자</h1>
<ul>
<li>if (조건, 참일 경우 반환 값, 거짓일 경우 반환값)</li>
</ul>
<h1 id="확장extend">확장(@extend)</h1>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/f700d8a1-33fa-47b2-9804-8acc22c61199" alt="스크린샷 2023-07-19 오후 2.23.29.png"></p>
<ul>
<li>@extend를 중첩해서 사용하는 경우 선택자 폭발이라는 부작용이 생기므로 가급적 @mixin을 사용하는 것을 추천</li>
</ul>
<h2 id="placeholder-선택자">%(placeholder 선택자)</h2>
<ul>
<li>extend를 통해서 확장하는 용도로만 사용되는 선택자</li>
</ul>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/801f876f-9226-41ab-819b-2302b709131f" alt="스크린샷 2023-07-19 오후 2.30.46.png"></p>
<h1 id="함수">함수</h1>
<ul>
<li>JS의 함수와 비슷한 방법으로 사용 가능</li>
<li>@ 키워드를 사용해서 문법을 작성</li>
<li>CSS의 내장 함수와 함수명이 겹치는 문제가 발생할 수 있으므로 두 개 이상의 단어를 사용해서 함수명을 작성하는 것이 좋음
<img src="https://github.com/milooy/Boxiting/assets/45515388/6f4cb2f5-bd57-4ce3-bcda-3150a9c693ac" alt="스크린샷 2023-07-19 오후 2.48.03.png"></li>
</ul>
<h1 id="반복">반복</h1>
<h2 id="for-문">for 문</h2>
<pre><code class="language-scss">@for $i from 1 through 3 {
    // 1~3까지 반복 (1 &lt;= $i &lt;= 3)
}

@for $i from 1 to 3 {
    // 1~2까지 반복 (1 &lt;= $i &lt; 3)
}</code></pre>
<h2 id="while-문">while 문</h2>
<pre><code class="language-scss">$n = 8;
// if문과 동일하게 소괄호는 생략 가능
@while ($n &gt; 0) {
    $n: $n - 1;
}</code></pre>
<h1 id="모듈">모듈</h1>
<h2 id="import">@import</h2>
<ul>
<li>@import {파일 경로} 를 통해 다른 모듈을 import할 수 있음</li>
<li>scss 파일 이름의 시작이 “_”(under score)로 시작하게 된다면 새로운 CSS 파일을 만들어서 컴파일을 하지 않음</li>
<li>확장자 생략이 가능</li>
<li>SCSS파일에서 url함수를 사용하거나, css인 확장자를 사용한 경우, http를 사용한 url 주소를 사용 경우에는 import 코드가 컴파일이 됨</li>
</ul>
<h2 id="use">@use</h2>
<ul>
<li>모듈 속 변수들에 namespace를 부여할 수 있음</li>
<li>함수나 변수 명의 충돌을 방지할 수 있음</li>
<li>as키워드를 통해 namespace를 변경할 수 있음<ul>
<li>@use &quot;./variables&quot; as var;</li>
</ul>
</li>
</ul>
<h2 id="forward">@forward</h2>
<ul>
<li>현재 파일의 바깥쪽으로 사용하는 모듈을 전달 시켜줄 수 있음</li>
<li>as {namespace}*를 통해 namespace 부여 가능</li>
</ul>
<pre><code class="language-scss">// /your-style/main.scss
@use &quot;./variables&quot; as var;
@use &quot;./minxins&quot; as mix;
@forward &quot;./variables&quot; as var-*;

div {
    color: var.$primary;
}

// /my-style/main.scss
@use &quot;../your-style/main&quot;;

div {
    color: main.$var-primary; // 변수 이름 앞에 namespace를 작성
}</code></pre>
<h1 id="디버그-규칙">디버그 규칙</h1>
<ul>
<li><p>@debug: 콘솔에 메시지가 출력됨</p>
<pre><code class="language-scss">  .box {
    @debug &quot;Hello SCSS!&quot;; // Hello SCSS! 출력
  }</code></pre>
</li>
<li><p>@warn: 콘솔에 경고 메시지 출력</p>
<pre><code class="language-scss">  .box {
    @debug &quot;Hello SCSS!&quot;; // Hello SCSS! 경고 메시지 출력
  }</code></pre>
</li>
<li><p>@error: 에러를 발생시켜서 컴파일이 정상적으로 동작하지 않음</p>
<pre><code class="language-scss">  .box {
    @error &quot;Hello SCSS!&quot;;
  }

  // 컴파일된 css파일에 error 메시지가 포함됨
  /* Error: &quot;Hello SCSS!&quot;
   *   ,
   * 3 |   @error &quot;Hello SCSS!&quot;;
   *   |   ^^^^^^^^^^^^^^^^^^^^
   *   &#39;
   *   scss/main.scss 3:3  root stylesheet */</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(float, position, flex, grid)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILfloat-position-flex-grid</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TILfloat-position-flex-grid</guid>
            <pubDate>Tue, 18 Jul 2023 14:23:10 GMT</pubDate>
            <description><![CDATA[<h1 id="float">float</h1>
<ul>
<li><p>요소의 수평정렬을 위해서 많이 사용했지만 요즘은 flex를 더 많이 사용함</p>
</li>
<li><p>float: left | right | none;</p>
</li>
<li><p>float를 해제하는 방법</p>
<ul>
<li><p>float를 사용한 요소의 부모 요소에 <strong>overflow: hidden</strong> 추가 ⇒ 개연성이 없는 속성이므로 추천하지 않음</p>
</li>
<li><p>float를 사용한 요소의 부모 요소에 다음과 같은 css를 추가</p>
<pre><code class="language-css">  .clearfix::after {
      content: &quot;&quot;,
      display: block,
      clear: both /* float: left, right를 모두 닫을 수 있음 */
  }</code></pre>
<ul>
<li>clearfix를 사용한 요소의 안에는 float을 사용하는 자식 요소들만 존재해야함!</li>
</ul>
</li>
</ul>
</li>
<li><p>float은 일부 경우에 display의 값을 block으로 변경함!</p>
</li>
</ul>
<hr>
<h1 id="position">position</h1>
<p>static: html에 정의된 순서대로 브라우저 상에 보여짐
relative: 원래있어야하는 위치에서 상대적으로 이동함
absolute: 아이템과 가장 가까이 있는 컨테이너를 기준으로 위치를 이동함
fixed: 윈도우를 기준으로 위치를 이동
sticky: 원래있어야 하는 자리에 있으면서 스크롤을 해도 사라지지않고 원래 자리에 위치함</p>
<ul>
<li>absolute 속성을 사용할 경우 구조적으로 가장 가까운 부모 요소에 relative를 추가하는 방법이 가장 관리하기 좋은 방법</li>
<li>자식 요소에 fixed 속성을 사용하고 부모 요소에 transform, perspective와 같은 속성들을 사용할 경우 자식 요소는 뷰포트 대신 transform, perspective 등의 속성을 사용한 부모 요소를 컨테이닝 블록으로 사용함</li>
<li>position의 absolute, fixed는 요소의 display 값을 block으로 변경함</li>
</ul>
<hr>
<h1 id="stacking-context쌓임-맥락">Stacking Context(쌓임 맥락)</h1>
<ul>
<li>z축을 사용한 HTML 요소의 3차원 개념화</li>
<li>transform, opacity와 같은 속성들을 z-index를 사용하지 않고도 요소를 쌓임 맥락을 변경할 수 있음</li>
</ul>
<h2 id="z-index">z-index</h2>
<ul>
<li>z-index를 사용하기 위해서는 position의 static을 제외한 relative, absolute, fixed, sticky 속성을 사용해야 함. 또는 flex 아이템이나 grid 아이템도 가능</li>
</ul>
<hr>
<h1 id="flexbox">flexbox</h1>
<ul>
<li>1차원 레이아웃 구조(수직, 수평)를 작업할 때 사용함</li>
<li>container에 적용되는 속성값과 container속 item들에 적용되는 속성값이 있음</li>
</ul>
<h2 id="container-속성값">container 속성값</h2>
<ul>
<li>display: flex, inline-flex 모두 자식 요소(flex items)는 flex의 특성을 통해 1차원 레이아웃 구조를 가지는 정렬이 이루어지지만 컨테이너는 차이가 발생함</li>
</ul>
<h3 id="display-flex">display: flex</h3>
<ul>
<li>block 요소의 특성과 유사함</li>
<li>flex가 부여된 container의 가로 넓이가 최대한 늘어나려고 함</li>
</ul>
<h3 id="display-inline-flex">display: inline-flex</h3>
<ul>
<li>inline 요소의 특성과 유사함</li>
<li>flex가 부여된 container의 가로 넓이가 최소한으로 사용됨</li>
</ul>
<h3 id="flex-direction">flex-direction</h3>
<p>기본값은 row(왼쪽에서 오른쪽으로), main-axis를 정함</p>
<p>컨테이너 안에서 요소들이 정렬해야 할 방향을 지정한다.</p>
<ul>
<li>row: 요소들을 가로로 정렬</li>
<li>row-reverse: 요소들을 텍스트의 반대 방향으로 정렬</li>
<li>column: 요소들을 위에서 아래로 정렬</li>
<li>column-reverse: 요소들을 아래에서 위로 정렬</li>
</ul>
<p>reverse 사용 시 요소들의 start와 end의 순서도 뒤바뀐다.</p>
<p>Flex의 방향이 column일 경우 justify-content의 방향이 세로(y)로, align-items의 방향이 가로(x)로 바뀜</p>
<table>
<thead>
<tr>
<th></th>
<th>main-axis(주축)</th>
<th>cross-axis(교차축)</th>
<th>flex-start</th>
<th>flex-end</th>
</tr>
</thead>
<tbody><tr>
<td>column</td>
<td>x축</td>
<td>y축</td>
<td>컨테이너 상단</td>
<td>컨테이너 하단</td>
</tr>
<tr>
<td>column-reverse</td>
<td>x축</td>
<td>y축</td>
<td>컨테이너 하단</td>
<td>컨테이너 상단</td>
</tr>
<tr>
<td>row</td>
<td>y축</td>
<td>x축</td>
<td>컨테이너 좌측</td>
<td>컨테이너 우측</td>
</tr>
<tr>
<td>row-reverse</td>
<td>y축</td>
<td>x축</td>
<td>컨테이너 우측</td>
<td>컨테이너 좌측</td>
</tr>
</tbody></table>
<h3 id="flex-wrap">flex-wrap</h3>
<p>기본값은 nowrap, 페이지의 크기에 따라 item을 다음줄로 나눔</p>
<ul>
<li>nowrap: 모든 요소들을 한 줄에 정렬</li>
<li>wrap: 요소들을 여러 줄에 걸쳐 정렬</li>
<li>wrap-reverse: 요소들을 여러 줄에 걸쳐 반대로 정렬</li>
</ul>
<h3 id="flex-flow">flex-flow</h3>
<p>direction과 wrap을 합침</p>
<ul>
<li>flex-flow: {direction 인자} {wrap 인자}</li>
</ul>
<h3 id="justify-content">justify-content</h3>
<p>요소들을 가로선 상에서 정렬</p>
<ul>
<li>flex-start: 컨테이너의 왼쪽으로 정렬</li>
<li>flex-end: 컨테이너의 오른쪽으로 정렬</li>
<li>center: 가운데 정렬</li>
<li>space-between: 요소들 사이에 동일한 간격을 둠</li>
<li>space-around: 요소들 주위에 동일한 간격을 둠</li>
</ul>
<h3 id="align-items">align-items</h3>
<p>요소들을 세로선 상에서 정렬</p>
<ul>
<li>flex-start: 요소들을 컨테이너의 꼭대기로 정렬</li>
<li>flex-end: 요소들을 컨테이너의 바닥으로 정렬</li>
<li>center: 요소들을 컨테이너의 세로선 상의 가운데로 정렬</li>
<li>baseline: 요소들을 글자의 baseline에 맞춰 정렬</li>
<li>stretch: 요소들을 컨테이너에 맞도록 늘림</li>
</ul>
<h3 id="align-content">align-content</h3>
<p>여러 줄 사이의 간격을 지정할 수 있음</p>
<ul>
<li>flex-start: 여러 줄들을 컨테이너의 꼭대기에 정렬</li>
<li>flex-end: 여러 줄들을 컨테이너의 바닥에 정렬</li>
<li>center: 여러 줄들을 세로선 상의 가운데에 정렬</li>
<li>space-between: 여러 줄들 사이에 동일한 간격을 둠</li>
<li>space-around: 여러 줄들 주위에 동일한 간격을 둠</li>
<li>stretch: 여러줄들을 컨테이너에 맞도록 늘림</li>
</ul>
<blockquote>
<p>align-content는 여러 줄들 사이의 간격을 지정하며, align-items는 컨테이너 안에서 어떻게 모든 요소들이 정렬하는 지를 지정. 한 줄만 존재할 경우 align-content는 효과를 보이지 않음</p>
</blockquote>
<h2 id="item-속성값">item 속성값</h2>
<h3 id="order">order</h3>
<ul>
<li>아이템의 표시 순서를 정함</li>
<li>기본 값은 0이며, 양수나 음수로 바꿀 수 있음. 따라서 모든 item이 0이 기본 값이므로 하나의 item을 맨 앞으로 이동하려 할 때 음수를 사용해야함.</li>
</ul>
<h3 id="align-self">align-self</h3>
<ul>
<li>item별로 item을 정렬 가능하며 align-items가 사용하는 값을 인자로 받음.</li>
</ul>
<h3 id="flex-grow">flex-grow</h3>
<ul>
<li>flex-item 요소가, flex-container 요소 내부에서 할당 가능한 공간의 정도를 선언</li>
<li>만약 형제요소로 렌더링 된 모든 flex-item 요소들이 동일한 flex-grow 값을 갖는다면, flex-container 내부에서 동일한 공간을 할당</li>
<li>하지만 flex-grow 값으로 다른 값을 지정한다면, 그에 따라 다른 공간값을 나누어 할당받게 됨</li>
</ul>
<h3 id="flex-shrink">flex-shrink</h3>
<ul>
<li>컨테이너가 작아졌을때 아이템들의 크기 퍼센트를 정함</li>
<li>flex-shrink 속성은 플렉스박스에 &quot;flex-wrap: wrap;&quot; 속성을 부여한 경우 적용되지 않음</li>
<li>자동으로 아이템 너비가 축소되지 않도록 하려면 반드시 &quot;flex-shrink: 0;&quot;을 아이템에 선언해야함</li>
</ul>
<h3 id="flex-basis">flex-basis</h3>
<ul>
<li>아이템의 크기 퍼센트를 정함(컨테이너가 작아지거나 커질경우 모두 적용)</li>
<li>flex-basis는 Flex 아이템의 기본 크기를 설정(flex-direction이 row일 때는 너비, column일 때는 높이).</li>
<li>flex-basis로 설정해 준 것과 상관없이 콘텐츠 너비에 따라서 늘어남</li>
<li>flex-basis와 width를 동시에 적용할 경우 flex-basis가 우선순위를 갖게됨</li>
</ul>
<h3 id="flex-단축-속성">flex 단축 속성</h3>
<ul>
<li>flex: grow, shrink, basis를 한번에 설정</li>
<li>flex: flex-grow flex-shrink flex-basis 순으로 작성함</li>
<li>flex-grow 기본 속성 = 0, flex-shrink 기본 속성 = 1, flex-basis 기본 속성 = auto</li>
<li>flex: 1;과 flex: 1 1 auto;는 서로 다름!<ul>
<li>flex: 1; ⇒ flex: 1 1 0; 과 같음(flex 단축 속성을 사용했을 때 basis 값을 생략하게 된다면 기본 값인 auto가 대입되는 것이 아닌 0이 됨!)</li>
</ul>
</li>
<li>flex 단축 속성을 사용하기보단 flex-grow, flex-shink, flex-basis 개별 속성을 사용하는 것이 가독성이 좋음!</li>
</ul>
<hr>
<h1 id="grid">Grid</h1>
<ul>
<li>2차원 레이아웃 구조(row, column)를 작업할 때 사용함</li>
</ul>
<h2 id="grid-container">Grid Container</h2>
<h3 id="grid-template-columns">grid-template-columns</h3>
<p>colums의 개수와 사이즈 설정</p>
<ul>
<li>grid-template-colums: 20% 20% 20%;</li>
</ul>
<h3 id="grid-template-rows">grid-template-rows</h3>
<p>rows의 개수와 사이즈 설정</p>
<ul>
<li>grid-template-rows: 20% 20% 20%;</li>
</ul>
<blockquote>
<p>columns와 rows에 %, 픽셀, em과 같은 길이 단위도 허용됨</p>
</blockquote>
<h3 id="grid-auto-rowscolumns">grid-auto-rows(columns)</h3>
<p>grid-template-rows(columns)로 만든 행과 열에 포함되지 않는 cell들의 행과 열의 크기를 암시적으로 지정할 수 있음</p>
<h3 id="grid-template">grid-template</h3>
<ul>
<li>grid-tempate-columns와 grid-template-rows를 조합한 단축 속성</li>
<li>행과 열 순으로 입력한다.<ul>
<li>grid-template: 50% 50% / 200px; → 각각 50%인 두개의 행과 200px인 한개의 열의 그리드 생성</li>
</ul>
</li>
</ul>
<h3 id="grid-auto-flow">grid-auto-flow</h3>
<ul>
<li>grid의 기본 축을 정의하는 속성</li>
<li>기본 값: row</li>
<li>dense를 사용해서 빈 공간을 매울 수 있음<ul>
<li>row dense (row 생략 가능)</li>
<li>column dense</li>
</ul>
</li>
</ul>
<h3 id="justify-content-1">justify-content</h3>
<ul>
<li>row축에 Grid content를 제외한 빈공간이 있는 경우에 사용할 수 있음</li>
<li>row축을 기준으로 Grid content를 정렬함</li>
<li>속성<ul>
<li>normal: 기본 값으로 행 축을 기준으로 Grid content를 최대한 늘림 ⇒ stretch와 동일</li>
<li>start: row축의 시작점에 정렬</li>
<li>center: row축의 가운데에 정렬</li>
<li>end: row축의 끝점에 정렬</li>
<li>space-between: 시작열과 마지막열은 start와 end에 붙고 나머지 열은 여백을 균등하게 분배해서 정렬</li>
<li>space-around: 각 열의 왼쪽과 오른쪽의 여백을 균등하게 분배해서 정렬</li>
<li>space-evenly: row축의 여백을 모든 열에 균등하게 분배함</li>
</ul>
</li>
</ul>
<h3 id="align-content-1">align-content</h3>
<ul>
<li>column축에 Grid content를 제외한 빈공간이 있는 경우에 사용할 수 있음</li>
<li>column축을 기준으로 Grid content를 정렬함</li>
<li>속성은 justify-content와 동일</li>
</ul>
<h3 id="justify-items--align-items">justify-items / align-items</h3>
<ul>
<li>각각의 cell 영역에 빈 공간이 있을 때 사용 가능</li>
<li>normal(stretch), start, center, end 속성이 존재함</li>
</ul>
<h3 id="grid-template-areas">grid-template-areas</h3>
<ul>
<li>grid-area의 이름은 원하는 이름으로 변경 가능</li>
<li>마침표(.) 대신 none도 가능</li>
</ul>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/be570069-ff49-4fc0-9c93-9a7b2babad8f" alt="스크린샷 2023-07-17 오후 5.51.13.png"></p>
<h3 id="grid-gap">grid-gap</h3>
<ul>
<li>grid-column-gap은 열 사이의 간격(Line 또는 Gutter), grid-row-gap은 행 사이의 간격, grid-gap은 행과 열의 간격을 동시에 정할 수 있다.</li>
<li>하위 호환성을 원한다면 grid 키워드를 붙이고 통합성을 생각한다면 grid 키워드를 뺄 수 있음(gap, column-gap, row-gap)<ul>
<li>grid-column-gap<ul>
<li>grid-column-gap: 20px;</li>
</ul>
</li>
<li>grid-row-gap<ul>
<li>grid-row-gap: 20px;</li>
</ul>
</li>
<li>grid-gap: 행, 열 순으로 입력<ul>
<li>grid-gap: 20px 10px;</li>
<li>grid-gap: 10px;</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="grid-cellitems">grid cell(items)</h2>
<h3 id="grid-column-start--grid-row-start">grid-column-start / grid-row-start</h3>
<ul>
<li>그리드 요소의 시작 열/행 위치를 지정</li>
<li>음수로도 지정이 가능하며 음수는 그리드의 오른쪽을 기준으로 사용<ul>
<li>grid-column-start: <int>;</li>
</ul>
</li>
<li>그리드 선의 시작과 끝 위치를 기준으로 그리드 항목을 정의하는 대신, span을 이용하여 열/행의 넓이를 지정할 수 있음(양수만 가능)<ul>
<li>grid-column-end: span <int>;</li>
</ul>
</li>
</ul>
<h3 id="grid-column-end--grid-row-end">grid-column-end / grid-row-end</h3>
<ul>
<li>grid-column-start 단독으로 사용될 때는, 한개의 그리드 열/행을 나타내지만 grid-column-end 속성을 같이 사용하면 여러 열에 걸쳐 확장이 가능</li>
<li>음수로도 지정이 가능하며 음수는 그리드의 오른쪽을 기준으로 사용<ul>
<li>grid-column-end: <int>;</li>
</ul>
</li>
<li>그리드 선의 시작과 끝 위치를 기준으로 그리드 항목을 정의하는 대신, span을 이용하여 열/행의 넓이를 지정할 수 있음.(양수만 가능)<ul>
<li>grid-column-end: span <int>;</li>
</ul>
</li>
</ul>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/312ab687-3cc4-4547-827a-8a4565f105a3" alt="스크린샷 2023-07-17 오후 6.51.18.png"></p>
<h3 id="grid-column--grid-row">grid-column / grid-row</h3>
<ul>
<li>grid-column(row)-start/end를 한 번에 설정가능, /로 구분<ul>
<li>grid-column(row): <int> / <int>;</li>
<li>grid-column(row): <int> / span <int>; 도 가능</li>
</ul>
</li>
</ul>
<h3 id="grid-area">grid-area</h3>
<ul>
<li>grid-row-start, grid-column-start, grid-row-end, grid-column-end  순으로 한 번에 입력 가능, /로 구분</li>
<li>span 사용도 가능<ul>
<li>grid-area: <int> / <int> / <int> / <int></li>
</ul>
</li>
</ul>
<h3 id="justify-self--align-self">justify-self / align-self</h3>
<ul>
<li>개별적으로 cell을 정렬할 수 있음</li>
</ul>
<h3 id="order-1">order</h3>
<ul>
<li>grid-area, grid-column, grid-row 등을 사용하지 않고 표시될 경우 소스코드에 기입된 순서대로 표기하는데 order 속성을 이용하면 재정의가 가능</li>
<li>기본은 0이며 양수, 음수 모두 가능<ul>
<li>order: <int></li>
</ul>
</li>
</ul>
<h2 id="grid-container-functions">Grid Container Functions</h2>
<p>grid-template-rows/columns, grid-auto-rows/columns에 사용 가능한 함수</p>
<h3 id="repeat">repeat</h3>
<p>grid-template-rows: 20% 20% 20%;를 줄여서 표현 가능</p>
<ul>
<li>grid-template-rows: repeat(3, 20%);</li>
<li>100px, 200px이 반복된다면 ⇒ repeat(2, 100px 200px)</li>
</ul>
<h3 id="minmax">minmax</h3>
<ul>
<li>행과 열(명시적, 암시적 모두 가능)의 최소 값과 최대 값을 동시에 정의</li>
<li>minmax(최소 값, 최대값)</li>
</ul>
<h3 id="fit-content">fit-content</h3>
<ul>
<li><p>fit-content({최대 넓이})</p>
</li>
<li><p>grid-template-colums: fit-content(300px) 100px;</p>
<p>  ⇒ 열의 너비가 최대 300px까지 될 수 있지만, fit-content가 된다면 너비가 늘어나지 않음</p>
</li>
</ul>
<h2 id="grid-units">Grid Units</h2>
<h3 id="fr-fractional-공간-비율">fr (fractional, 공간 비율)</h3>
<ul>
<li>각 fr 단위들은 사용가능한(빈) 공간을 하나로 공유하여 할당</li>
<li>예시로 두 개의 element들을 1fr과 3fr로 설정 시, 공간이 4개의 동일한 크기로 공유됨 ⇒ 첫번째 element는 사용가능한 공간의 1/4를 차지하고 두번째 element는 3/4를 차지<ul>
<li>grid-template-columns: 1fr 3fr;</li>
</ul>
</li>
</ul>
<h3 id="min-content--max-content">min-content / max-content</h3>
<ul>
<li><p>min-content: content가 가질 수 있는 최소 넓이까지 넓이를 줄여서 표현함</p>
<ul>
<li><p>한글은 글자 단위, 영어는 단어 단위 ⇒ word-break: keep-all; 속성을 통해 한글도 단어 단위로 줄바꿈이 일어나게 변경할 수 있음</p>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/c5527227-794c-49aa-823d-417cae197549" alt="스크린샷 2023-07-18 오후 1.45.06.png"></p>
</li>
</ul>
</li>
</ul>
<h3 id="auto-fill--auto-fit">auto-fill / auto-fit</h3>
<ul>
<li>repeat 함수와 같이 사용함<ul>
<li>grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));</li>
</ul>
</li>
<li>auto-fit: 지정할 수 있는 최대 넓이를 우선해서 적용</li>
<li>auto-fill: 지정할 수 있는 최소 넓이를 우선해서 적용</li>
</ul>
<hr>
<h1 id="transform3d">Transform3d</h1>
<h2 id="transform-origin">transform-origin</h2>
<ul>
<li>요소가 transform하는 기준을 변경할 수 있는 속성</li>
<li>transform-origin: {x축} {y축};</li>
</ul>
<h2 id="perspective">perspective</h2>
<ul>
<li>3차원 변환 함수에서만 적용이 됨 (ex. rotateY)</li>
<li>perspective({원근의 거리값})</li>
<li>원근의 거리값이 클수록 멀리서 보이는 효과를 가짐</li>
<li>함수와 속성으로 모두 사용이 가능<ul>
<li>속성으로 사용하는 방법이 관리가 유리함</li>
<li>함수: 변환이 되는 아이템에 사용해야함 ⇒ transform: perspective({원근의 거리값})</li>
<li>속성: 변환이 되는 아이템의 부모 요소에 사용해야함 ⇒ perspective: {원근의 거리값}</li>
</ul>
</li>
</ul>
<h2 id="perspective-origin">perspective-origin</h2>
<ul>
<li>perspective 속성이 적용된 요소의 기준을 변경할 수 있는 속성</li>
<li>transform-origin과 동일하게 사용<ul>
<li>perspective-origin: {x축} {y축};</li>
</ul>
</li>
</ul>
<h2 id="transform-style-perserve-3d">transform-style: perserve-3d;</h2>
<p><img src="https://github.com/milooy/Boxiting/assets/45515388/799cc0c3-5401-4a42-9ce4-df20f85b41bc" alt="스크린샷 2023-07-18 오후 2.25.23.png"></p>
<ul>
<li>3차원 변환 효과가 추가되어진 요소의 자식 요소에 3차원 변환 효과를 추가하기 위해 부모 요소에 사용해야함</li>
<li>자식 요소만 유효한 속성이며 후손 요소에는 영향을 주지 않음</li>
</ul>
<h2 id="backface-visibility-hidden">backface-visibility: hidden;</h2>
<ul>
<li><p>rotateY(180deg) 등 요소의 뒷면이 보이는 경우에 요소의 뒷면을 보이지 않게 할 수 있음</p>
<p>  <img src="https://github.com/milooy/Boxiting/assets/45515388/d45a8db3-f611-4aa9-92ea-3947191f4696" alt="스크린샷 2023-07-18 오후 2.37.11.png"> </p>
</li>
</ul>
<hr>
<h1 id="columns다단">Columns(다단)</h1>
<ul>
<li>column-count: 단의 개수를 정할 수 있음</li>
<li>column-width: 단의 최적의 넓이를 지정할 수 있음</li>
<li>columns: {width} {count} ⇒ 단의 최적 넓이와 개수를 한번에 정의할 수 있는 단축 속성</li>
<li>column-rule: 단과 단 사이의 구분선을 추가할 수 있음(border 속성과 동일하게 사용, 개별 속성도 동일하게 존재)</li>
<li>column-gap: 단과 단 사이의 넓이를 지정(gap으로 대체 가능)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Notion 클로닝(Vanilla JS) 프로젝트 회고]]></title>
            <link>https://velog.io/@foxrain_gg/Notion-%ED%81%B4%EB%A1%9C%EB%8B%9DVanilla-JS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/Notion-%ED%81%B4%EB%A1%9C%EB%8B%9DVanilla-JS-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 17 Jul 2023 15:04:29 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스 데브코스 활동을 진행하면서 Vanilla JS 사용해 Notion 클로닝 프로젝트를 진행했다.
아직 프로젝트<a href="https://cheery-shortbread-7a15b9.netlify.app/">(노션 클로닝 프로젝트 바로가기)</a>에 수정해야할 부분과 추가해야할 부분이 많다고 생각되지만 이제까지 프로젝트를 진행하면서 <strong>새롭게 배운 부분, 잘하고 있는 부분, 부족한 부분</strong>을 알아보고 싶어서 회고를 적어본다.</p>
<p><video autoplay muted controls src="https://user-images.githubusercontent.com/45515388/251482948-f8e0e44a-97d8-439f-ab10-d9d9ab22eb40.mov
"></video></p>
<h1 id="getselection-createrange">getSelection? createRange?</h1>
<p>editor에 &quot;# 제목&quot;을 입력하고 enter를 입력하면 notion과 동일하게 <code>&lt;h1&gt;제목&lt;/h1&gt;</code>으로 즉각적으로 변경될 수 있는 rich editor를 구현을 하려고 시도했다. 그 과정에서 가장 큰 문제는 editor의 innerHTML을 변경하는 과정에서 현재 사용자가 가지고 있는 커서 위치를 유지하는 부분이였다.
요소가 변경될 경우 editor의 내용이 다시 렌더링되어야 하는데 리렌더링시 커서의 위치가 유지되지 않고 처음으로 돌아가는 현상이 있었고 이를 해결하기위해 열심히 구글링을 하던 중 selection과 range의 개념에 대해 알게되었다.
selection과 range를 통해 사용자가 선택한 범위를 알 수 있다. 이를 사용해서 editor가 리렌더링되기 전에 커서의 위치에 보이지 않는 요소를 추가하고 리렌더링 후 추가한 요소의 위치를 가져오는 식으로 커서의 위치를 유지할 수 있었다.
결과적으로 완벽하진 않지만 rich editor의 일부분을 완성할 수 있었고 selection과 range를 더 공부한다면 버그가 없는 rich editor를 만들 수 있을 것같다.</p>
<h1 id="잘한-점">잘한 점</h1>
<ul>
<li>클린 코드를 위해 노력했다.
파일 구조와 컴포넌트 구조, 함수의 역할까지 어떻게 하면 재사용성이 높고 가독성이 높은 코드로 작성할 수 있을지 많은 부분은 고민하면서 프로젝트를 완성해갔다. 가장 이상적인 구조라고 말할 순 없지만 컴포넌트 구조에 대해선 가독성을 많이 높였다고 생각되고 api와 router의 구현은 재사용성을 많이 높였다고 생각된다.</li>
<li>프로젝트의 기본 요구사항과 보너스 요구사항을 모두 구현하려고 시도했다.
노션 클로닝 프로젝트에서 기본 요구사항과 보너스 요구사항을 모두 구현하려고 시도하였고, 1가지(에디터에 하위 문서 출력) 부분을 제외하고 모두 구현하였다. 이 과정에서 위에 적은 selection, range 개념에 대해 알게 되었다.<h1 id="부족한-점">부족한 점</h1>
</li>
<li>함수의 분리가 잘 이루어지지 않고 있다.
아직 함수를 분리하는 부분은 많이 부족한 것 같다. 하나의 역할은 하나의 함수가 담당하게 함수들을 분리하여 재사용성을 높이고 코드의 가독성을 더 높이는 노력이 필요하다.</li>
<li>rich editor의 버그가 많다.
한글을 입력하고 enter를 입력하면 커서의 위치가 제대로 유지되지 않고, 링크 태그가 다음 줄에도 계속해서 적용되는 등의 버그들이 아직 존재한다. selection, range의 개념을 더 공부해서 버그들을 고칠 필요가 있다.</li>
<li>editor에 하위 문서 출력 기능
하나의 문서를 클릭했을 때 해당 문서의 하위 문서가 존재한다면 editor에 출력하는 기능을 구현하지 못했다. 문서의 하위에 문서가 존재하는 구조가 아닌 폴더 구조로 변경해서 하위 요소들을 가져오기 어려운 부분 때문에 구현하지 못했는데 더 고민해서 해당 기능도 추가해야한다.<h1 id="시도해-볼-것">시도해 볼 것</h1>
</li>
<li>rich editor의 버그를 수정하기 위해 selection, range 개념을 좀더 공부하기</li>
<li>editor에 하위 문서 출력 기능 추가하기</li>
<li>여러 역할을 수행하는 하나의 함수를 분리해보기</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2023 상반기 (예비? 주니어?) 개발자 회고]]></title>
            <link>https://velog.io/@foxrain_gg/2023-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@foxrain_gg/2023-%EC%83%81%EB%B0%98%EA%B8%B0-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Wed, 05 Jul 2023 07:11:07 GMT</pubDate>
            <description><![CDATA[<p>2023년 상반기가 벌써 끝났다. 2023년에는 대학 생활의 마침표를 찍는 학년인만큼 알찬 한 해를 보내겠다고 다짐하였고, 프론트엔드 개발자로 성장하기위해 다양한 활동과 프로젝트를 경험하겠다고 계획했다. 나름 바쁘다면 바쁘게 시간을 보낸만큼 과연 나의 계획에 문제점은 없고 잘 지켜가고 있었는지를 돌아보기 위해 개발자로서 활동에 대해 회고를 적어보고자 한다.
내가 이제까지 무엇을 했는지 갑자기 물어보면 항상 말문이 막히곤 한다. 이럴 때마다 캘린더를 다시 들여다보곤 하는데, 캘린더를 작성하는 습관은 잘 까먹는 나에겐 큰 도움이 되는 것 같다.</p>
<p align="center"><img src="https://github.com/HongGunWoo/paintjs/assets/45515388/cb9e57ca-8260-4030-affc-45f4a5abeccf" width=80%></p>

<h2 id="정보처리기사-취득">정보처리기사 취득</h2>
<p align="center"><img src="https://github.com/HongGunWoo/paintjs/assets/45515388/313bed88-fb33-45ee-afbd-b80b834e0dc9" width="200"></p>

<p>2023년에 가장 먼저 했던 일은 정보처리기사 자격증을 취득한 것이였다. 개편 전에는 취득 난이도가 낮기도 했고 인정 받을 수 있는 곳이 많지 않다는 말도 많아서 도전을 할까말까 고민도 많이 했지만 <strong>&quot;컴퓨터공학과 학생이라면!&quot;</strong> 이라는 생각과 공부하는 과정에서 그동안 배웠던 개발 지식들을 복습하는데에도 도움이 될 것 같아 도전하게 되었다.
개편 후 난이도가 높아졌다고 해서 내용들을 봤는데 생각보다 어려웠다...! 같은 과 선배나 동기들도 쉽게 생각했다가 실기에서 한번씩 좌절을 겪는 경우도 있었다. 개발 방법론, 보안 관련 지식, 기초 프로그래밍 등의 내용들이 출제되어서 컴퓨터공학과 학생은 복습한다는 생각으로 공부하며 취득하는 것을 추천한다.
그래도 <strong>컴퓨터공학과 학생인데</strong>라는 생각과 알 수 없는 자존심으로 필기, 실기를 책없이 공부했는데 실기 정도는 책을 구매해서 공부했으면 조금 더 체계적으로 공부해서 시간을 아낄 수 있었을 것 같다.</p>
<h2 id="위치기반-아동급식카드-가맹점-조회-서비스-개발">위치기반 아동급식카드 가맹점 조회 서비스 개발</h2>
<p>아동급식카드란 국내의 각 지방자치단체는 저소득층의 결식 우려 아동을 대상으로 결식을 예방하고자 매달 일정 금액을 충전해주어 아동이 자유롭게 연계된 가맹점에서 식품을 구매할 수 있는 전자카드를 말한다.
그런데 아동급식카드를 사용이 가능한 가맹점을 조회하는데 어렵다는 문제점이 있어서 이를 해결하고자 프로젝트를 진행했다.</p>
<blockquote>
<p><a href="https://www.forunderwater.life">아동급식카드 가맹점 조회 서비스</a> (현재 구미 지역만 조회 가능)</p>
</blockquote>
<p align="center"><img src="https://github.com/HongGunWoo/paintjs/assets/45515388/8c0c2d63-3863-46fa-8612-c2c3a1a2ee71" width="80%"></p>


<h3 id="잘한-점-or-배운-점">잘한 점 or 배운 점</h3>
<ul>
<li>계획한 기능들을 거의 구현했다(네이버 로그인 API만 빼고...).</li>
<li>사용 접근성을 높이기 위해 모바일 웹 페이지에서도 서비스를 이용할 수 있도록 반응형으로 제작했다.<p align="center"><img src="https://github.com/HongGunWoo/paintjs/assets/45515388/bbf99ef4-cda2-409d-bb07-833b7a71f626" width="250px"></p></li>
<li>Nelify와 AWS EC2를 사용해 배포하는 방법을 배우게 되었다.</li>
</ul>
<h3 id="아쉬운-점">아쉬운 점</h3>
<ul>
<li>아동급식카드 가맹점의 정보(대표 메뉴와 가격, 종류)를 크롤링하는 과정이 필요한데 생각보다 시간이 오래걸려서 아직은 구미 지역만 지원하고 있다.</li>
<li>후기 정보를 남기는게 과연 로그인이 필요했는가? 익명으로도 작성이 가능해서 더 많은 후기 데이터를 모을 수 있도록 하는 방법이 더 좋을 것 같다.</li>
</ul>
<h2 id="파이썬-멘토링-활동">파이썬 멘토링 활동</h2>
<p>학교에서 진행하는 전공 과목 멘토링 프로그램에서 멘토로 뽑히게 되어 파이썬 과목의 멘토로 활동했다. 약 30시간 정도 활동을 했는데 멘티들에게 파이썬의 기초 지식들을 가르쳐주며 1학년 시절 파이썬을 배울 때 객체 지향의 개념에 대해 이해하는데 고생했던 기억이 떠올라 재미있었던 활동이었다.</p>
<h3 id="잘한-점-or-배운-점-1">잘한 점 or 배운 점</h3>
<ul>
<li>남들에게 내 지식을 설명하는 것은 힘들다!
내가 알고 있는 지식들을 다른 사람들에게 이해하기 쉽게 설명하는 것은 항상 어렵게 느껴진다. 나름대로 이해하기 쉽게 강의 자료를 정리하고 또 어떻게 하면 쉽게 전달할 수 있을까를 고민하며 예시 코드를 작성하면서 다른 사람에게 설명하는 능력을 기를 수 있었다.<h3 id="아쉬운-점-1">아쉬운 점</h3>
</li>
<li>학교 강의 시간 외에도 4명의 학생들에게 멘토 활동을 했었다. 더 많은 멘티들과 함께 파이썬 멘토링 활동을 하지 못한 것이 아쉽게 느껴진다.</li>
</ul>
<h2 id="데브코스-합격-및-활동">데브코스 합격 및 활동!!</h2>
<p align="center"><img src="https://github.com/HongGunWoo/paintjs/assets/45515388/54ab03ab-b9bf-4c3b-965e-f4870c5f3cf6" width="350px"></p>

<p>프론트엔드 개발자를 희망하는 나는 프론트엔드 분야의 인턴 활동이나 부트캠프 활동을 꼭 해보고 싶었다. 그래서 데브코스에 지원하게 되었고 서류 -&gt; 코테 -&gt; 면접 과정을 거쳐서 합격했다!!
학교 생활을 하면서 틈틈히 알고리즘 문제를 풀어가면서 코테를 준비했는데 이 과정이 데브코스 합격에 큰 도움이 되었던 것 같아 뿌듯했다.
6월 1일부터 활동을 시작해서 계속해서 활동을 이어가고 있는데 활동할 때마다 새로운 프론트엔드 지식을 얻어가는 것 같아 2023년 상반기에 가장 잘한 선택이라고 생각된다.</p>
<h3 id="지금까지-활동하면서-후기">지금까지 활동하면서 후기</h3>
<ul>
<li>JS는 계속해서 배울게 많다...
이번 활동을 통해 Vanilla JS를 사용한 프로젝트들을 하면서 정말 새롭게 배우는 것들이 많았다. 그동안 React를 공부한다고 소홀히 했던 Vanilla JS를 심도있게 공부하며 JS의 기초, 심화 지식들과 다른 JS 라이브러리를 공부할 수 있는 바탕을 쌓아가고 있다는 생각이 든다.</li>
<li>멘토가 있다는 것이 큰 힘이 된다.
나는 주위에 프론트엔드 개발자로 활동하는 사람이 많지 않다. 그래서 프론트엔드 관련 지식이나 프론트엔드 개발자에 대해 궁금한게 생겨도 물어볼 사람이 없었다... 하지만 데브코스 멘토 시스템은 현업 개발자님들과 팀을 만들어줘서 프론트엔드에 대해 궁금한 점을 바로 해결할 수 있다. 이 점이 가장 좋다고 생각된다.</li>
<li>프론트엔드 공부에 자극이 된다.
같이 활동하는 멘티들을 보며 다들 너무 잘한다는 생각이 든다. 자만하지 않고 겸손한 자세로 계속해서 프론트엔드를 공부하는 것에 큰 자극이 되고 있는 것 같다.<h3 id="아쉬운-점-2">아쉬운 점</h3>
</li>
<li>데브코스에는 공부하는데 도움이 될 수 있도록 지원해주는 시스템이 많다. 코어타임 중 실시간으로 질의응답, 도서 지원, 특강, 공부 장소 대여 등 다양한 지원을 아직은 잘 활용하지 못하는 것 같다. 하반기에는 이러한 지원들을 최대한 많이 활용해서 프론트엔드 개발자의 성장에 도움이 될 수 있도록 하고 싶다.</li>
<li>스스로가 데브코스 활동을 핑계로 다른 공부를 소홀히 하는 것 같다. 토익, 데브코스 활동 이외의 공부 등 다른 활동도 열심히 해야할 필요가 있다.<h2 id="2023-하반기에는-꼭-해야할-것">2023 하반기에는 꼭 해야할 것!</h2>
</li>
<li>7월 - 개인 블로그(Github Blog) 만들기
항상 어려워 하던 TypeScript를 사용해서 개인 블로그를 제작할 것이다.</li>
<li>8월 - 토익 점수 좀 높이자...
토익 점수 850점 이상으로 높이고 싶다. 일단 800점부터 넘기는 것이 계획이다.</li>
<li>CS 지식 공부하기
데브코스 면접이나 이미 취직한 선배들의 면접 후기를 통해 깊은 CS 지식이 필요하다는 것을 느꼈다. 틈틈히 CS 지식들을 공부하며 정리하는 것이 계획이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(13일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL13%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL13%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 22 Jun 2023 14:22:26 GMT</pubDate>
            <description><![CDATA[<h1 id="promise">Promise</h1>
<ul>
<li>비동기 작업을 제어하기 위해 나온 개념</li>
<li>callback hell에서 어느정도 벗어날 수 있게 도와줌</li>
<li>Promise로 정의된 작업끼리는 연결이 가능하며 이를 사용해 코드의 depth가 크게 증가히지 않는 효과가 있음</li>
</ul>
<h2 id="기본-사용-방법">기본 사용 방법</h2>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject) =&gt; {
  // promise 내부에서 비동기 상황이 종료될 때, resolve 함수 호출
  // promise 내부에서 오류 상황일 때, reject 함수 호출
})

function asyncPromiseWork() {
  // ...
  return new Promise((resolve, reject) =&gt; {
    // promise 내부에서 비동기 상황이 종료될 때, resolve 함수 호출
    // promise 내부에서 오류 상황일 때, reject 함수 호출
    // ...
    return resolve(&#39;completed&#39;);
  })
}

// Promise는 then을 이용해 비동기 작업 이후 실행할 작업을 지정함
// then의 result에는 resolve를 호출하며 넘긴 completed가 들어있음
asyncPromiseWork().then(result =&gt; console.log(result));</code></pre>
<h2 id="promise-chaining">promise chaining</h2>
<ul>
<li>순차적으로 처리해야하는 비동기 작업이 여러 개 있을 경우 사용</li>
<li>promise.then의 결과 값으로 promise가 반환되기 때문에 .then을 체인 형식으로 사용이 가능</li>
</ul>
<pre><code class="language-jsx">new Promise((resolve, reject) =&gt; setTimeout(() =&gt; resolve(1), 100))
  .then(result =&gt; {
    console.log(result); // 1
    return result + 1;
  }).then(result =&gt; {
    console.log(result); // 2
    return result + 2;
  }).then(result =&gt; {
    console.log(result); // 4
  })</code></pre>
<pre><code class="language-jsx">/*
 .then의 return 값으로 promise를 반환하는 경우 이어지는 .then은 반환된 promise가
    처리될 때 까지 기다렸다가 결과 값을 받는다.
*/
new Promise((resolve, reject) =&gt; setTimeout(() =&gt; resolve(1), 100))
  .then(result =&gt; {
    console.log(result); // 1
    return new Promise((resolve, reject) =&gt;
            setTimeout(() =&gt; resolve(result + 1), 100)
        );
  }).then(result =&gt; {
    console.log(result); // 2
    return result + 2;
  }).then(result =&gt; {
    console.log(result); // 4
  })</code></pre>
<h2 id="promise-chaining-오류-처리">promise chaining 오류 처리</h2>
<pre><code class="language-jsx">// Promise의 then내에서 promise를 return하는 경우 또 다른 then으로 연결 가능
fisrtPromiseWork()
  .then(result =&gt; {
    return secondPromiseWork(result);
  }).then(result =&gt; {
    return thirdPromiseWork(result);
  }).then(result =&gt; {
    return finalPromiseWork(result);
  }).catch(e =&gt; { // promise chain중 작업이 실패했을 경우 catch로 잡기 가능
    console.log(&#39;오류 발생&#39;);
  }).finally(() =&gt; { // 작업의 성공 여부와 상관 없이 마지막으로 실행
    console.log(&#39;작업 끝&#39;);
  })</code></pre>
<ul>
<li>catch를 넣지 않은 경우 promise chain 중 에러가 발생했을 때 chain이 멈춤 ⇒ catch를 사용하자!</li>
<li>catch를 중간에 넣고 작업을 연결해도 동작함</li>
</ul>
<h2 id="callback함수를-promise-형태로-만들기">callback함수를 promise 형태로 만들기</h2>
<pre><code class="language-jsx">const delay = (delayTime) =&gt; new Promise((resolve) =&gt; {
  setTimeout(resolve, delayTime);
})

delay(5000)
  .then(() =&gt; {
    return delay(3000);
  }).then(() =&gt; {
    console.log(&#39;complete&#39;);
  })</code></pre>
<h2 id="promise-내장-함수">promise 내장 함수</h2>
<h3 id="promisealliterable">Promise.all(iterable)</h3>
<ul>
<li>iterable에 주어진 모든 promise가 동시에 실행된 후 새로운 promise를 반환</li>
<li>여러 promise를 동시에 처리할 때 유용함</li>
<li>주어진 promise 중 하나라도 reject되는 경우 첫 번째로 reject된 promise를 이유로 자신도 거부함</li>
</ul>
<pre><code class="language-jsx">Promise.all([
  new Promise(resolve =&gt; setTimeout(resolve, 3000, 1)), // 1
  new Promise(resolve =&gt; setTimeout(resolve, 2000, 2)), // 2
  new Promise(resolve =&gt; setTimeout(resolve, 1000, 3))  // 3
]).then(result =&gt; console.log(result)); // 프라미스 전체가 처리되면 1, 2, 3이 반환</code></pre>
<h3 id="promiseraceiterable">Promise.race(iterable)</h3>
<ul>
<li>Promise.all과 비슷하지만 가장 먼저 처리되는 프로미스의 결과(성공, 실패)를 반환</li>
<li>많이 사용하진 않음</li>
</ul>
<pre><code class="language-jsx">Promise.race([
  new Promise(resolve =&gt; setTimeout(resolve, 3000, 1)), // 1
  new Promise(resolve =&gt; setTimeout(resolve, 2000, 2)), // 2
  new Promise(resolve =&gt; setTimeout(resolve, 1000, 3))  // 3
]).then(result =&gt; console.log(result)); // 3 반환</code></pre>
<h3 id="promiseanyiterable">Promise.any(iterable)</h3>
<ul>
<li>Promise.all과 비슷하지만 가장 먼저 성공(resolve)한 promsie가 존재하면 종료</li>
</ul>
<pre><code class="language-jsx">Promise.any([
  new Promise(resolve =&gt; setTimeout(resolve, 3000, 1)), // 1
  new Promise(resolve =&gt; setTimeout(resolve, 2000, 2)), // 2
  new Promise(resolve =&gt; setTimeout(resolve, 1000, 3))  // 3
]).then(result =&gt; console.log(result)); // 3 반환</code></pre>
<h3 id="promiseallsettled">Promise.allSettled()</h3>
<ul>
<li>주어진 모든 프로미스를 수행한 후 각 프로미스에 대한 결과를 나타내는 객체 배열을 반환</li>
<li>각 promise의 실행 결과를 알고 싶을 때 사용</li>
</ul>
<pre><code class="language-jsx">Promise.allSettled([
  new Promise(resolve =&gt; setTimeout(resolve, 3000, 1)), // 1
  new Promise(resolve =&gt; setTimeout(resolve, 2000, 2)), // 2
  new Promise(resolve =&gt; setTimeout(resolve, 1000, 3))  // 3
]).then(result =&gt; console.log(result));
// [
//   { status: &#39;fulfilled&#39;, value: 1 }, 
//   { status: &#39;fulfilled&#39;, value: 2 },
//   { status: &#39;fulfilled&#39;, value: 3 }
// ]
// reject된 경우 status 값이 rejected로 반환됨</code></pre>
<h3 id="promiseresolve">Promise.resolve</h3>
<ul>
<li>주어진 값으로 이행하는 Promise.then 객체를 만듬</li>
<li>주어진 값이 promise인 경우 promise가 반환됨</li>
<li>return type을 promise로 맞춰줄 때 종종 사용함</li>
</ul>
<pre><code class="language-jsx">const promise1 = Promise.resolve(123);

promise1.then((value) =&gt; {
  console.log(value); // 123
});</code></pre>
<h1 id="async-await">async, await</h1>
<ul>
<li>Promise가 callback depth를 1단계로 줄여주지만 아직 불편한 점이 있음<ul>
<li>.then() 체이닝을 통해 비동기 작업을 하므로 코드가 복잡함</li>
<li>.catch()를 통해 오류를 처리하므로 오류 처리 로직이 분리되어 가독성이 떨어짐
⇒ async, await는 try, catch, finally를 사용!</li>
</ul>
</li>
<li>async, await를 사용하면 Promise를 비동기 작업이 수행되지만 동기 코드처럼 보이게 코드 작성이 가능</li>
</ul>
<pre><code class="language-jsx">const delay = (delayTime) =&gt; new Promise((resolve) =&gt; {
  setTimeout(resolve, delayTime);
})

// Promise를 사용
const work = () =&gt; {
  delay(100)
    .then(() =&gt; {
      console.log(&#39;work 1 complete&#39;);
      return delay(100);
    }).then(() =&gt; {
      console.log(&#39;work 2 complete&#39;);
      return delay(100);
    }).then(() =&gt; {
      console.log(&#39;work 3 complete&#39;);
      return delay(100);
    }).then(() =&gt; {
      console.log(&#39;all complete&#39;);
    })
}

work();

// async, await를 사용 =&gt; 코드 가독성이 좋음!
const work2 = async () =&gt; {
  await delay(100);
  console.log(&#39;work 1 complete&#39;);
  await delay(100);
  console.log(&#39;work 2 complete&#39;);
  await delay(100);
  console.log(&#39;work 3 complete&#39;);
  await delay(100);
  console.log(&#39;all complete&#39;);
}
work2();</code></pre>
<h2 id="async-함수-정의-방법">async 함수 정의 방법</h2>
<ul>
<li>async 키워드가 붙은 함수는 실행 결과를 Promise로 감싸게됨</li>
</ul>
<pre><code class="language-jsx">async function asyncFunc () {
  const res = await request(...);
}

const asyncFunc = async () {
  const res = await request(...);
}</code></pre>
<h1 id="fetch-api">fetch api</h1>
<ul>
<li>비동기 https 요청을 좀 더 편하게 사용할 수 있는 API</li>
<li>XMLHTTPRequest를 대체</li>
<li>Promise 기반으로 동작 ⇒ promise chaining 응용 가능!</li>
<li>fetch의 기본 응답 결과는 Response 객체!<ul>
<li>Response 객체를 얻은 뒤엔 응답을 json으로 바꾸거나 text로 바꾸는 등의 처리를 해줘야함</li>
</ul>
</li>
<li>fetch는 HTTP error가 발생해도 reject되지 않음(네트워크 에러나 요청이 완료되지 않은 경우만 reject 됨) ⇒ fetch가 성공했는지 확인하는 과정이 필요함(response의 status code나 ok를 확인)</li>
</ul>
<h2 id="사용-방법">사용 방법</h2>
<pre><code class="language-jsx">fetch(&#39;https://dummyjson.com/products/1&#39;)
  .then(res =&gt; res.json())
  .then(json =&gt; console.log(json))</code></pre>
<pre><code class="language-jsx">// 오류 처리
fetch(&#39;https://dummyjson.com/products/undefined&#39;) // 존재하지 않는 url
  .then(res =&gt; {
    if (res.ok){
      return res.json();
    }
    throw new Error(&#39;요청 중 오류 발생&#39;);
  })
  .then(json =&gt; console.log(json))
  .catch(e =&gt; console.log(e.message));</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(11, 12일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL11-12%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL11-12%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 19 Jun 2023 09:20:01 GMT</pubDate>
            <description><![CDATA[<h1 id="client-side에서-데이터-저장하기">Client Side에서 데이터 저장하기</h1>
<h2 id="cookie">Cookie</h2>
<ul>
<li>브라우저에서 저장되는 작은 문자열</li>
<li>다른 저장 방식에 비해 가장 오래된 방식</li>
<li>HTTP 요청 시 헤더에 쿠키가 포함되어있어 쿠키 사이즈가 커지면 HTTP 요청 크기도 커짐</li>
<li>사이즈에 제한이 있음</li>
<li>여러가지 보안 취약점이 존재하기 때문에 사용에 주의</li>
</ul>
<h3 id="cookie-추가">Cookie 추가</h3>
<ul>
<li>key, value 값의 관계를 “=”(equal)로 표현</li>
</ul>
<pre><code class="language-jsx">document.cookie = &#39;name=gugugu&#39;</code></pre>
<ul>
<li>쿠기에 유효기간을 설정하지 않은 상태면 브라우저를 닫는 순간 쿠키가 사라짐</li>
</ul>
<pre><code class="language-jsx">// 쿠키에 유효기간 추가
// expries의 경우 GMT String을 넣어야하며 한국 시간과 다르다는 것을 알아야함
new Data().toGMTString() //현재 GMT 시간을 읽어올 수 있음
document.cookie = &#39;name=gugugu; expires=Mon, 2 Aug 2023 12:12:11 GMT&#39;

// max-age를 통해 생성시점 기준으로 유효기간 설정가능 단위는 1초
document.cookie = &#39;name=gugugu; max-age=3600&#39;</code></pre>
<h3 id="cookie-읽기">Cookie 읽기</h3>
<ul>
<li>각 쿠키는 ‘;’로 구분되어 있어 split으로 쪼개서 사용해야함</li>
</ul>
<pre><code class="language-jsx">const cookies = doument.cookie;
console.log(cookies.split(&#39;;&#39;);</code></pre>
<h2 id="local-storage">Local Storage</h2>
<ul>
<li>key, value 기반으로 Local에 데이터 저장 가능 ⇒ string만 넣을 수 있으므로 JSON.stringify와 JSON.parse를 사용하는 것을 추천</li>
<li>도메인 기반으로 Storage가 생성됨 ⇒ 도메인만 같다면, 도메인이 같은 다른 탭에서도 같은 Storage 공유 가능</li>
<li>삭제하거나 Storage를 날리지 않는 한 삭제되지 않음</li>
</ul>
<h3 id="local-storage-사용-방법">Local Storage 사용 방법</h3>
<ul>
<li><p>localStrage에 저장하는 3가지 방법</p>
<pre><code class="language-jsx">  window.localStorage.name = &#39;gugu&#39; // 방법1
  window.localStorage[&#39;name&#39;] = &#39;roto&#39; // 방법2
  window.localStorage.setItem(&#39;name&#39;, &#39;roto&#39;) // 방법3
  // 방법 3 - setItem을 사용하는 것을 권장함
  // 방법 1, 2는 localStorage의 내장 함수들을 덮어 씌울 수 있어서 권장하지 않음</code></pre>
</li>
</ul>
<ul>
<li><p>Local Storage의 전체적인 사용 방법</p>
<pre><code class="language-jsx">  // 저장
  localStorage.setItem(&#39;name&#39;, &#39;gugu&#39;);

  // 값 가져오기
  const storedName = localStorage.getItem(&#39;name&#39;);

  // 삭제
  localStorage.removeItem(&#39;name&#39;);

  // 전체 삭제
  localStorage.clear();</code></pre>
</li>
<li><p>JSON.stringify와 JSON.parse로 값을 한 번에 저장하고 읽어오기</p>
<pre><code class="language-jsx">  const user = {
      id: &#39;gugu&#39;,
      name: &#39;gugugu&#39;,
  }

  localStorage.setItem(&#39;user&#39;, JSON.stringify(user))

  const storedUser = JSON.parse(localStorage.getItem(&#39;user&#39;))</code></pre>
</li>
</ul>
<h2 id="session-strorage">Session Strorage</h2>
<ul>
<li><p>Local Storage와 비슷하지만 브라우저를 닫으면 저장된 내용이 초기화된다는 차이점이 있음</p>
<pre><code class="language-jsx">  const user = {
      id: &#39;gugu&#39;,
      name: &#39;gugugu&#39;,
  };

  sessionStorage.setItem(&#39;user&#39;, JSON.stringify(user));
  const storedUser = JSON.parse(sessionStorage.getItem(&#39;user&#39;));</code></pre>
</li>
</ul>
<h1 id="es6-module">ES6 Module</h1>
<h2 id="import">import</h2>
<ul>
<li>export 키워드로 내보내진 변수, 함수 등을 불러올 수 있는 키워드</li>
<li>스크립트 의존성을 훨씬 간편하게 관리할 수 있음 ⇒ 각 JS 별로 사용되는 모듈을 명시적으로 import 해오기 때문에 사용되지 않는 스크립트 추적이 가능!</li>
<li>script src로 불러오는 것과 달리 전역오염이 발생하지 않음</li>
</ul>
<pre><code class="language-jsx">// moduleName 내에 export default로 내보내진 것을 가져옴
import defaultExport from &quot;moduleName&quot;;

// moduleName 내에서 export 된 모든 것을 가져옴, as 이후 이름은 자유롭게 정할 수 있음(중복 불가능)
// 사용하지 않은 모듈까지 가져올 가능성이 있음!!!
import * as allExport from &quot;moduleName&quot;;

// moduleName 내에서 export 된 것 중 특정 값만 가져옴
import { someExport } from &quot;moduleName&quot;;

// moduleName 내에서 export 된 것 중에 특정 값만 이름을 바꿔서 가져옴
import { someExport as myExport } from &quot;moudleName&quot;;

// export default 된 것과 개별 export 된 것을 한번에 가져옴
import defaultExport, { someExport } from &quot;moduleName&quot;;

// 별도의 모듈 바인딩 없이 불러오기만 함, 불러오는 것 만으로 효과가 있는 스크립트의 경우 사용
import &quot;moduleName&quot;</code></pre>
<pre><code class="language-html">&lt;HTML&gt;
.
.
.
        &lt;!-- module 사용 시 type=&quot;module&quot;을 잊지 말자! --&gt;
        &lt;script src=&quot;index.js&quot; type=&quot;module&quot;&gt;&lt;/script&gt; 
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2 id="export">export</h2>
<ul>
<li>export 한 모듈은 무조건 ‘use strict’가 적용됨</li>
<li>자바스크립트 스타일 가이드는 함수나 클래스 선언 끝에 세미콜론을 붙이지 않는 것을 권유함 → 같은 이유로 <code>export class</code>나 <code>export function</code> 끝에 세미콜론을 붙이지 않음!</li>
<li>“export default” 키워드를 통해 해당 모듈엔 하나의 개체만 있다는 사실을 명확히 나타낼 수 있음 → 하나의 파일엔 대개 하나의 “export default”만 있음</li>
</ul>
<pre><code class="language-jsx">// 유명 내보내기
// import 할 경우 export 한 이름과 동일한 이름을 사용해야함
// import 시 중괄호 필요!
export let variable = 1;
export function myFunc() {}

// 기본 내보내기
// import 할 경우 어떤 이름으로도 import 가능
// import 시 중괄호 필요 없음!
export default function myFunc() {}
export default function () {}

// export as
export { myFunc as exportFunc, varibale, as exportVal };

// import한 객체를 다시 내보내기
export { myFunc } from &#39;./my.js&#39;
export { default as User } from &#39;./user.js&#39; // default export를 다시 내보내기함</code></pre>
<h1 id="callback---비동기-다루기">callback - 비동기 다루기</h1>
<ul>
<li>비동기 처리란 ⇒ 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 JS의 특성</li>
<li>JS는 싱글 스레드이기 때문에 sync(동기) 방식을 사용하게 되면 요청 후 응답이 오기 전까지 브라우저가 다른 함수나 스크립트를 실행 할 수 없는 상태가 됨… → async(비동기)를 사용하는 이유</li>
<li>비동기 처리를 하는 함수(ex. api 요청)들은 하나의 담당 파일에 빼두고 중복을 최소화하는 것이 좋음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(9, 10일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL9-10%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL9-10%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 15 Jun 2023 09:32:57 GMT</pubDate>
            <description><![CDATA[<h1 id="new-연산자에서의-this">new 연산자에서의 this?</h1>
<ul>
<li>아래의 코드에서 에러가 발생하는 이유는 Cat 함수 실행 시 this는 window를 가리키게 되고 const cat에서 name은 undefined가 발생하게 된다.</li>
</ul>
<pre><code class="language-jsx">function Cat(name, age) {
  this.name = name;
  this.age = age;
}

const cat = Cat(&#39;gugu&#39;, 9);
console.log(cat.name) // error!</code></pre>
<ul>
<li>new를 붙여주면 this는 window가 아닌 새로 생긴 객체를 가리킴</li>
</ul>
<pre><code class="language-jsx">function Cat(name, age) {
  this.name = name;
  this.age = age;
}

const cat = new Cat(&#39;gugu&#39;, 9);
console.log(cat.name) // gugu 출력</code></pre>
<h2 id="new-키워드의-동작-순서">new 키워드의 동작 순서</h2>
<ol>
<li>빈 객체를 만들어 this에 할당</li>
<li>함수 본문을 실행하며 this에 새로운 프로퍼티를 추가해 this를 수정</li>
<li>this를 반환</li>
</ol>
<pre><code class="language-jsx">function Person(name) {
    // this = {}; 빈 객체를 임시로 만듬
    this.name = name; // 새로운 프로퍼티를 this에 추가
    // return this; this가 암시적으로 반환
}

let person = new Person(&#39;Gugu&#39;);
// 즉 위의 new Person 코드는 아래와 같다.
let person = {
    name: &#39;Gugu&#39;,
};</code></pre>
<h1 id="arrow-function의-this">arrow function의 this</h1>
<ul>
<li>화살표 함수는 일반 함수와 달리 고유한 this를 가지지 않음</li>
<li>화살표 함수에서 this는 외부 함수의 this를 말함</li>
</ul>
<pre><code class="language-jsx">let person = {
  title: &quot;구구구&quot;,
  students: [&quot;치킨&quot;, &quot;회&quot;, &quot;피자&quot;],

  showLikes() {
    this.students.forEach(
            // forEacth에서 화살표 함수를 사용했으므로 화살표 함수 본문의 this.title은
            // 함수 밖같의 showLikes가 가리키는 대상과 동일해 짐 this.title = person.title
      student =&gt; console.log(this.title + &#39;의 최애 음식&#39; + student)
    );
  }
};

person.showLikes();</code></pre>
<h1 id="즉시-실행-함수iife">즉시 실행 함수(IIFE)</h1>
<ul>
<li>IIFE를 사용하지 않고 여러개의 JS파일을 모듈화 한다면 서로 다른 JS 파일에서 동일한 이름을 가진 변수나 함수가 오염될 수 있음 ⇒ IIFE를 사용하여 전역 오염을 최소화 시킬 수 있음</li>
<li>활용 방법<pre><code class="language-jsx">const counter = (function() {
// 외부에서는 count 변수에 직접적으로 접근할 수 없음 =&gt; private 효과
let count = 0;
function log(message) {
  console.log(message);
  count += 1;
}
function getCount() {
  return count;
}
return {
  log: log,
  getCount: getCount
}
})()
</code></pre>
</li>
</ul>
<p>console.log(counter.getCount()); // 2
console.log(counter.count); // undefined</p>
<pre><code>
# 명령형(imperative) 프로그래밍

- 컴퓨터가 수행할 명령들을 순서대로 써 놓은 것
- “어떻게 구현하는가?”(How)에 관점을 둠

# 선언형(declarative) 프로그래밍

- 프로그램이 어떤 방법으로 해야 하는지를 나타내기보다 ”무엇과 같은지”(What)를 설명하는 경우
- 목표를 명시하고 알고리즘을 명시하지 않는 것 ⇒ HTML이 대표적인 선언형 프로그래밍 언어
- 코드가 간결하고 확정성도 좋아져서 명령형보다는 선언형 사용을 지향함

# 명령형과 선언형의 차이

```jsx
// 명령형
function imperativeDouble(arr) {
  let results = [];
  for (let i = 0; i &lt; arr.length; i++) {
    results.push(arr[i] * 2);
  }
  return results;
}

// 선언형
function declarativeDouble(arr) {
  return arr.map((num) =&gt; num * 2);
}</code></pre><h1 id="파일의-마지막에-공백을-추가">파일의 마지막에 공백을 추가??</h1>
<ul>
<li>줄바꿈을 하므로서 개행 문자를 추가함</li>
<li>파일 마지막 줄 바꿈은 유닉스에서 관용적으로 사용되던 것</li>
<li>줄 바꿈이 없으면 파일을 올바르게 처리하지 못하는 프로그램들이 존재함 ⇒ GitHub에서는 마지막 줄바꿈이 추가되지 않으면 경고 메시지를 띄워줌</li>
<li>손상된 파일을 쉽게 찾을 수 있음</li>
<li>JS, HTML, CSS 파일에는 줄 바꿈을 하지 않아도 문제가 발생하지는 않음 ⇒ 그래도 만약을 위해 사용하자</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(7, 8일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL7-8%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL7-8%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 13 Jun 2023 08:17:25 GMT</pubDate>
            <description><![CDATA[<h1 id="백트래킹">백트래킹</h1>
<ul>
<li>모든 경우의 수를 탐색하는 알고리즘</li>
<li>DFS나 BFS를 이용할 수 있음</li>
<li>가지치기(Pruning): 효율을 위해 탐색하지 않아도 되는 곳을 미리 막는 것 ⇒ <strong>백트래킹의 핵심!</strong><ul>
<li>효율성을 결정하는 부분</li>
</ul>
</li>
<li>JS는 재귀 효율이 좋지 않기 때문에 DFS를 구현할 경우 스택을 이용하는 것이 좋음</li>
<li>탐색에서 순환(Cycle)이 발생할 가능성이 있다면 BFS를 이용하는 것이 좋음</li>
</ul>
<h2 id="구현-과정">구현 과정</h2>
<ul>
<li>먼저 모든 경우의 수를 찾을 수 있도록 코딩</li>
<li>문제에서 특정한 조건을 만족하는 것만 탐색하고 나머지는 탐색하지 않도록 조건문을 작성 ⇒ 절대로 답이 될 수 없는 것은 탐색을 종료</li>
</ul>
<h1 id="동적계획법dynamic-programming-dp">동적계획법(Dynamic Programming, DP)</h1>
<ul>
<li>** 작은 문제부터 해결하면서 점점 범위를 넓혀가 큰 문제를 해결하는 방식 **</li>
<li>특정 알고리즘이 아닌 문제 해결 방식을 의미함</li>
<li>Dynamic Programming이지만 Dynamic하지 않고 Programming과도 관련이 없음 ⇒ 단지 멋있어 보여서 지은 이름이다…</li>
<li>메모리를 많이 사용하는 대신 빠른 성능</li>
<li>두 가지 방법론이 있음<ul>
<li>메모이제이션(Memoization)</li>
<li>타뷸레이션(Tabulation)</li>
</ul>
</li>
</ul>
<h2 id="메모이제이션">메모이제이션</h2>
<ul>
<li>하향식 접근법</li>
<li>작은 문제들의 결과를 저장해두었다가 필요할 때 꺼내쓰는 방식(동적 계획법에서 작은 문제들의 결과는 항상 같음)</li>
</ul>
<h2 id="타뷸레이션">타뷸레이션</h2>
<ul>
<li>상향식 접근법</li>
<li>필요한 값들을 미리 계산해두는 것<ul>
<li>메모이제이션은 필요할 때 계산한다면 타뷸레이션은 미리 계산해둔 값을 꺼내쓰는 방식</li>
</ul>
</li>
<li>실제 업무에서는 타뷸레이션을 많이 사용하지만 코딩 테스트에서는 메모이제이션을 많이 사용함</li>
</ul>
<h2 id="동적-계획법-문제-접근법">동적 계획법 문제 접근법</h2>
<ul>
<li>동적 계획법 유형은 키워드만으로 동적 계획법 문제임을 알기 어려움</li>
<li>문제 유형을 알 수 없으면 다음을 확인해야함<ul>
<li>가장 작은 문제로 정의할 수 있는가?</li>
<li>작은 문제를 통해 큰 문제를 해결할 수 있는 규칙이 있는가?</li>
<li>위의 두가지가 가능하다면 동적 계획법 문제로 볼 수 있음</li>
</ul>
</li>
</ul>
<h1 id="간결하고-가독성-좋은-코드-작성법">간결하고 가독성 좋은 코드 작성법</h1>
<ul>
<li>변수, 함수의 이름을 적절하게 선언</li>
<li>중복 코드 제거</li>
<li>함수형 프로그래밍을 이용하기 → map, filter, reduce와 같은 고차함수 이용</li>
<li>일관성을 잘 유지하기 → 조금 더러워도 일관성있는 코드가 좋음<ul>
<li>var과 let 혼용하지 않기</li>
<li>snake_case와 camelCase를 혼용하지 않기</li>
<li>변수명, 함수명을 줄임말과 전체 작성을 혼용하지 않기</li>
</ul>
</li>
</ul>
<h1 id="코딩테스트-입출력-제한">코딩테스트 입출력 제한</h1>
<ul>
<li>입력이 100 이하인 경우<ul>
<li>완전 탐색</li>
<li>백트래킹</li>
</ul>
</li>
<li>입력이 10,000 이하인 경우<ul>
<li>최대 O(n^2) 이내로 끝내야함</li>
<li>문제에 따라 O(n^2 log n)까지 가능</li>
<li>n*n 2차원 리스트를 모두 순회해야하는 문제가 많음</li>
</ul>
</li>
<li>입력이 최대 1,000,000 이하인 경우<ul>
<li>최대 O(n log n)으로 끝내야하는 문제</li>
<li>힙, 우선순위 큐</li>
<li>정렬</li>
<li>동적 계획법(DP)</li>
<li>위상 정렬</li>
<li>다익스트라 알고리즘</li>
</ul>
</li>
<li>입력이 100,000,000 이하인 경우<ul>
<li>최대 O(n)으로 끝내야하는 문제</li>
<li>동적 계획법</li>
<li>그리디</li>
</ul>
</li>
<li>그 이상인 경우 → 거의 출제되지 않음<ul>
<li>최대 O(log n)으로 끝내야하는 경우가 많음</li>
<li>이진탐색</li>
</ul>
</li>
</ul>
<h1 id="문제-유형">문제 유형</h1>
<ul>
<li>입력 값이 작은 문제 → 높은 확률로 완전 탐색 혹은 백트래킹 문제</li>
<li>지도가 주어지고 채워진 영역을 찾아야하는 경우 → 높은 확률로 BFS, DFS 문제</li>
<li>그래프 그림이 있는 경우<ul>
<li>최단 거리 찾기, 최소 신장 트리, 위상 정렬 중 한 가지를 사용해야할 확률이 높음</li>
<li>최단 거리 찾기: 문제에 “가장 빠른 길”, “최단 거리”, “x비용 내로 갈 수 잇는 길” 같은 키워드</li>
<li>최소 신장 트리: “가장 저렴한 방법으로 모든 경로 연결”, “가장 저렴하게 연결” 같은 키워드 ⇒ 크루스칼, 프림 알고리즘 사용</li>
<li>위상 정렬: “순서”, “차례” 같은 키워드</li>
</ul>
</li>
<li>X라는 조건을 만족하는 가장 최대/최소값을 찾아라 → 높은 확률로 결정 문제, 파라메트릭 서치 이용</li>
<li>실시간으로 정렬이 이루어져야 하는 경우 - 높은 확률로 우선순위 큐 혹은 힙을 사용하는 문제</li>
<li>DP 문제<ul>
<li>완전 탐색처럼 시간이 오래걸리면 안되는데 특별한 알고리즘을 사용하는 문제가 아닐 경우 높은 확률로 DP 문제</li>
<li>유형을 판단하기 힘든 경우 DP처럼 풀 수 있는지 생각해봐야함<ol>
<li>문제를 따라 초기값을 작성</li>
<li>초기값을 포함해 모든 상태값을 작성</li>
<li>현재 상태를 통해 다음 값을 구할 수 있는지 판단</li>
<li>혹은 이전 상태들을 통해 현재 값을 구할 수 있는지 판단</li>
<li>식을 만들 수 있다면 DP 문제임</li>
</ol>
</li>
</ul>
</li>
<li>문자열이 주어지는 경우 → 구현력 문제인 경우가 많음</li>
<li>현재 상황에서 가장 최적인 선택을 해야하는 경우 → “가장 많은 선택을 할 수 있는”, “가장 작은/큰” 등의 키워드가 들어가면 그리디 문제일 확률이 높음</li>
</ul>
<h1 id="엣지케이스-찾는-법">엣지케이스 찾는 법</h1>
<ul>
<li>엣지케이스: 일반적인 테스트 케이스와는 다른, 주로 특수한 상황이나 극단적인 입력값을 가지는 테스트 케이스를 말함</li>
<li>엣지케이스의 종류<ul>
<li>입력 값의 크기가 굉장히 작은 케이스</li>
<li>입력 값의 크기가 굉장히 큰 케이스</li>
<li>입력 값의 범위가 넓은 케이스</li>
<li>음수 입력이 허용된 경우 음수만 입력받는 케이스</li>
<li>리스트를 입력 받을 때 값이 없거나 하나만 있는 케이스</li>
<li>그래프에서 사이클이 발생하는 경우</li>
<li>길찾기 문제에서 지그재그로 움직일 경우</li>
<li>부동소수점 오차</li>
</ul>
</li>
</ul>
<h1 id="js-코드-트릭">JS 코드 트릭</h1>
<h2 id="배열-생성으로-루프-제거">배열 생성으로 루프 제거</h2>
<ul>
<li>일반적인 범위 루프 방법</li>
</ul>
<pre><code class="language-jsx">let sum = 0;
for (let i = 1; i &lt; 5; i += 1) {
    sum += i;
}
// sum = 15</code></pre>
<ul>
<li>함수형 프로그래밍 방식으로 범위 루프 작성</li>
</ul>
<pre><code class="language-jsx">const sum = Array
  .from(new Array(5), (_, k) =&gt; k+1)
  .reduce((acc, cur) =&gt; acc + cur, 0);
// sum = 15</code></pre>
<h2 id="배열-내-같은-요소-제거">배열 내 같은 요소 제거</h2>
<ul>
<li>Set을 사용</li>
</ul>
<pre><code class="language-jsx">const fruits = [&#39;apple&#39;, &#39;banana&#39;, &#39;apple&#39;, &#39;banana&#39;, &#39;melon&#39;];
const uniqueFruitsWithArrayFrom = Array.from(new Set(fruits));
const uniqueFruitsWithSpread = [...new Set(fruits)];

console.log(uniqueFruitsWithArrayFrom); // [ &#39;apple&#39;, &#39;banana&#39;, &#39;melon&#39; ]
console.log(uniqueFruitsWithSpread); // [ &#39;apple&#39;, &#39;banana&#39;, &#39;melon&#39; ]</code></pre>
<h2 id="객체-생성시-키-생략하기">객체 생성시 키 생략하기</h2>
<ul>
<li>객체를 생성할 때 프로퍼티 키를 변수 이름으로 생략할 수 있음</li>
</ul>
<pre><code class="language-jsx">const name = &#39;GunWoo&#39;;
const FullName = &#39;HongGunWoo&#39;;
const person = {
  name,
  FullName
}
console.log(person); // { name: &#39;GunWoo&#39;, FullName: &#39;HongGunWoo&#39; }</code></pre>
<h2 id="동적-속성-이름">동적 속성 이름</h2>
<ul>
<li>ES6에 추가된 기능으로 객체의 키를 동적으로 생성 가능</li>
</ul>
<pre><code class="language-jsx">const nameKey = &#39;name&#39;;
const emailKey = &#39;email&#39;;
const person = {
  [nameKey]: &#39;GunWoo&#39;,
  [emailKey]: &#39;test@test.com&#39;
};
console.log(person); // { name: &#39;GunWoo&#39;, email: &#39;test@test.com&#39; }</code></pre>
<h2 id="-연산자를-사용하여-boolean-값을-바꾸기">!! 연산자를 사용하여 Boolean 값을 바꾸기</h2>
<ul>
<li>!! 연산자를 통해 0, null, 빈 문자열, ndefined, NaN을 false로 그 외에는 true로 변경할 수 있음</li>
</ul>
<pre><code class="language-jsx">function check(variable) {
  if (!!variable) {
    console.log(variable);
  } else {
    console.log(&#39;false&#39;);
  }
}
check(0); // false
check(null); // false
check(&#39;&#39;); // false
check(undefined); // false
check(NaN); // false

check(&#39;Good&#39;); // Good
check(5); // 5
check(3.1); // 3.1</code></pre>
<h1 id="css란">CSS란?</h1>
<ul>
<li><p>css : Cascading Style Sheets</p>
<p>  cascading: ‘위에서 아래로 흐르는’, 선택자에 적용된 많은 스타일 중에 어떤 스타일로 브로우저에 표현할지 결정해주는 원리를 의미한다.</p>
</li>
</ul>
<h2 id="css-선택자-종류">CSS 선택자 종류</h2>
<ul>
<li>*: 전체 선택</li>
<li>type(태그 이름): 태그 선택</li>
<li>id( # ): id 선택</li>
<li>class( . ): 클래스 선택</li>
<li>state( : ): 상태에 따라 변경 가능</li>
<li>attribute( [ ] ): 해당 속성값 선택</li>
<li>자식( &gt; ): 특정 요소의 자식요소를 선택(ex. ul &gt; li ⇒ ul 요소의 자식인 모든 li를 선택)</li>
<li>후손(공백): 특정 요소의 모든 하위 요소를 선택(ex. div p ⇒ div 요소의 모든 p를 선택</li>
</ul>
<h2 id="id와-class의-차이점">id와 class의 차이점</h2>
<ul>
<li>유일성(Uniqueness)<ul>
<li>id는 문서 내에서 유일한 식별자로 사용되어야함 → 동일한 id를 여러 요소에 할당할 수 없음</li>
<li>class는 여러 요소에 동일한 class를 할당할 수 있음 → 여러 요소를 그룹화하고 스타일을 일괄적으로 적용하는 데 유용함</li>
</ul>
</li>
<li>우선순위(Priority)<ul>
<li>id 선택자의 우선순위는 class 선택자보다 높음 →id는 class보다 더 특정하고 구체적인 스타일을 적용하고자 할 때 유용함</li>
</ul>
</li>
<li>재사용성(Reusablility)<ul>
<li>id는 고유성을 가져야 하므로 특정 요소에 한 번만 사용함 → 해당 요소에 대한 스타일을 재사용할 수 없음</li>
<li>class는 여러 요소에 동일한 class를 할당할 수 있으므로 스타일의 재사용성이 높음</li>
</ul>
</li>
<li>JavaScript 접근성<ul>
<li>id는 JS에서 요소를 식별하고 조작하는 데 사용</li>
<li>class도 JS에서 사용할 수 있지만, id보다는 한정적인 용도로 사용됨<ul>
<li>JS에서 class를 선택하여 해당 클래스를 가진 모든 요소에 스타일을 적용하거나 조작하는 경우</li>
<li>이벤트 핸들러를 일괄적으로 적용하는 경우</li>
<li>그룹화된 동작을 수행하는 경우</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="동일한-id가-여러개-있다면">동일한 id가 여러개 있다면?</h2>
<ul>
<li>동일한 id를 가진 여러 요소에 대해 어떤 요소의 스타일이 적용될지 예측할 수 없음</li>
<li>CSS는 id 선택자에 매칭되는 첫 번째 요소에 스타일을 적용하고 나머지 동일한 id를 가진 요소는 무시함</li>
</ul>
<h1 id="domdocument-object-model">DOM(Document Object Model)</h1>
<ul>
<li>브라우저가 웹 문서를 이해할 수 있도록 구성한 것으로 html 모든 요소들과의 관계를 부자관계로 표현된 트리 구조로 구성한 것</li>
<li>트리 구성 노드<ul>
<li>문서 노드: 최상위 노드로 DOM 트리의 시작점</li>
<li>요소 노드: HTML태그 그 자체를 나타냄, HTML 문서 구조를 그대로 표현함</li>
<li>속성 노드: 요소 노드에 붙어있는 노드(자식 노드 X)로 태그에 정의되어있는 속성을 말함</li>
<li>텍스트 노드: 요소의 텍스트를 표현하며 자식 노드를 가질 수 없어 DOM 트리의 단말 노드가 됨</li>
</ul>
</li>
<li>DOM의 각 요소는 프로토타입 객체로 정의되어 있음</li>
</ul>
<h2 id="js로-dom-선택하기">JS로 DOM 선택하기</h2>
<ul>
<li>getElementById: DOM Tree에서 요소 노드를 id로 찾음, 제일 먼저 찾은 요소 하나를 반환</li>
<li>getElementByClassName: DOM Tree에서 요소 노드를 class로 찾음, 일치하는 모든 요소를 반환</li>
<li>getElementByTagName: DOM Tree에서 요소 노드를 태그 이름으로 찾음, 일치하는 모든 요소를 반환</li>
<li>querySelector: DOM Tree에서 요소 노드를 CSS Selector 문법으로 찾음. 제일 먼저 찾은 요소 하나를 반환</li>
<li>querySelectorAll: DOM Tree에서 요소 노드를 CSS Selector 문법으로 찾음. 일치하는 모든 요소를 반환</li>
<li>window.[id]: id가 있는 요소는 window 객체를 통해 찾을 수 있음, 여러 개라면 리스트로 반환</li>
</ul>
<h2 id="dom-탐색-방법">DOM 탐색 방법</h2>
<ul>
<li>parentNode: 선택한 요소 노드의 부모 노드를 불러옴</li>
<li>firstElementNode: 선택한 요소 노드의 자식 요소 노드 중 첫 번째를 불러옴, 없을 경우 null 반환</li>
<li>chilren: 선택한 요소 노드의 자식 요소 노드를 불러옴, 없을 경우 빈 배열 반환</li>
<li>nextElementSibiling: 선택한 요소 노드의 다음 형제 요소 노드를 불러옴, 없을 경우 null 반환</li>
<li>previousElementSibiling: 선택한 요소 노드의 이전 형제 요소 노드를 불러옴, 없을 경우 null 반환</li>
</ul>
<h2 id="dom-조작-방법">DOM 조작 방법</h2>
<ul>
<li>class 접근: 선택한 요소 노드에서 className과 classList로 요소의 class 속성을 불러오고 변경할 수 있음</li>
<li>hasAttribute: 선택한 요소 노드에서 속성을 가지고 있는지 확인</li>
<li>getAttribute: 선택한 요소 노드에서 속성의 값을 반환, 없을 경우 null 반환</li>
<li>setAttribute: 선택한 요소 노드에서 속성을 정의</li>
<li>removeAttribute: 선택한 요소 노드에서 속성을 제거</li>
<li>textContent: 선택한 요소 노드에서 텍스트 노드에 접근, 변경 가능</li>
<li>innerHTML: 선택한 요소 노드 내부 HTML을 수정 → XSS 위험이 있음</li>
<li>createElement: 요소 노드를 태그 이름으로 생성할 수 있음</li>
<li>appendChild: 선택한 요소 노드 마지막 자식 요소로 추가</li>
<li>removeChild: 선택한 요소 노드 자식 노드 중 해당하는 요소를 제거</li>
</ul>
<h2 id="documentcreatedocumentfragment"><strong>document.createDocumentFragment</strong></h2>
<ul>
<li><p>비어있는 DocumentFragment 객체를 생성하는 메서드</p>
</li>
<li><p>DocumentFragment는 메모리에 존재하는 가상의 문서 조각으로 실제 DOM에 직접 추가되지 않고 메모리 상에서 조작할 수 있음</p>
</li>
<li><p>DocumentFragment를 사용하면 여러 DOM 요소를 생성하고 조작하는 작업을 효율적으로 수행할 수 있음</p>
</li>
<li><p>DOM 요소를 동적으로 생성하여 DocumentFragment에 추가하고 나중에 한 번에 실제 DOM에 추가할 수 있음 → DocumentFragment를 사용하여 여러 요소를 조작하는 동안 불필요한 리플로우나 리레이아웃 계산이 발생하지 않아 성능 향상에 도움이 됨</p>
</li>
<li><p>예시 코드</p>
<pre><code class="language-jsx">  const fragment = document.createDocumentFragment();

  for (let i = 0; i &lt; 5; i++) {
    const div = document.createElement(&#39;div&#39;);
    div.textContent = `div ${i}`;
    fragment.appendChild(div);
  }

  // 실제 DOM에 추가
  document.body.appendChild(fragment);</code></pre>
</li>
</ul>
<h1 id="virtual-dom">Virtual DOM</h1>
<ul>
<li>실제 DOM Tree를 JS 객체로 만든 것으로 필요한 정보만을 담아 만들어짐</li>
<li>이벤트나 DOM이 수정되는 한 틱 내에 Virtual DOM에서 바뀌는 부분만 수정한 후 렌더링하면 브라우저 렌더링 프로세스 과정이 줄어들게 됨</li>
<li>Virtual DOM는 유지보수가 용이한 애플리케이션을 만들도록 도와주고 대부분의 유스케이스에서 DOM보다 충분히 빠를 뿐이지 Virtual DOM이 DOM보다 빠른 것은 아니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(6일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 09 Jun 2023 09:50:45 GMT</pubDate>
            <description><![CDATA[<h1 id="bfsbreadth-first-search-너비-우선-탐색"><strong>BFS(Breadth First Search,</strong> 너비 우선 탐색)</h1>
<ul>
<li>같은 깊이에 해당하는 노드부터 탐색하는 알고리즘</li>
<li>Queue를 이용하여 구현</li>
<li>시작 지점에서 가까운 노드부터 탐색</li>
<li>V가 노드의 수 , E가 간선의 수일 때, 시간 복잡도는 O(V+E)</li>
</ul>
<h2 id="구현">구현</h2>
<pre><code class="language-jsx">function bfs(graph, start, visitied) {
  let queue = [start];
  visitied[start] = true;
  while (queue.length) {
    v = queue.shift();
    console.log(v);
    for(i of graph[v]) {
      if (!visitied[i]) {
        queue.push(i)
        visitied[i] = true;
      }
    }
  }
}

graph = [
  [],
  [2, 3, 8],
  [1, 7],
  [1, 4, 5],
  [3, 5],
  [3, 4],
  [7],
  [2, 6, 8],
  [1, 7]
]

visitied = Array.from({length: 9}, () =&gt; false);

bfs(graph, 1, visitied);</code></pre>
<h1 id="dfsdepth-first-search-깊이-우선-탐색"><strong>DFS(Depth-First Search, 깊이 우선 탐색)</strong></h1>
<ul>
<li>그래프에서 최대한 깊은 노드부터 우선적으로 탐색하는 알고리즘</li>
<li>stack을 이용하여 구현</li>
<li>시작 노드에서 깊은 것 부터 찾음</li>
<li>V가 노드의 수 , E가 간선의 수일 때, 시간 복잡도는 O(V+E)</li>
</ul>
<h2 id="구현-1">구현</h2>
<pre><code class="language-jsx">function dfs(graph, v, visitied) {
  visitied[v] = true;
  console.log(v);

  for(i of graph[v]) {
    if (!visitied[i]) {
      dfs(graph, i, visitied);
    }
  }
}

graph = [
  [],
  [2, 3, 8],
  [1, 7],
  [1, 4, 5],
  [3, 5],
  [3, 4],
  [7],
  [2, 6, 8],
  [1, 7]
]

visitied = Array.from({length: 9}, () =&gt; false);

dfs(graph, 1, visitied);</code></pre>
<h1 id="bfs-dfs-그림설명">BFS, DFS 그림설명</h1>
<blockquote>
<p><a href="https://velog.io/@foxrain_gg/Python-DFSBFS-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98">[Python, JS] DFS/BFS 알고리즘</a></p>
</blockquote>
<h1 id="그리디greedy">그리디(Greedy)</h1>
<ul>
<li><p>매 선택에서 지금 이 순간 가장 최적인 답을 선택하는 알고리즘 ⇒ 최적해를 보장하지 않음</p>
</li>
<li><p>최적해를 구하는 알고리즘보다 빠른 경우가 많음</p>
</li>
<li><p>크루스칼, 다익스트라 알고리즘에 활용</p>
<h1 id="git의-목적">Git의 목적</h1>
</li>
<li><p>Git: 분산 버전 관리 시스템</p>
<ul>
<li>원하는 시점마다 버전을 만들고 버전 사이를 자유롭게 돌아다니는 것이 가능</li>
<li>내가 만든 버전 뿐 아니라 동료가 만든 버전으로 이동이 가능하고 동료와 내 버전을 비교해서 최신 코드로 업데이트가 가능</li>
<li>즉 버전 관리, 백업, 협업이 가능하게 하는 도구</li>
</ul>
</li>
</ul>
<h1 id="git의-기본-개념">Git의 기본 개념</h1>
<ul>
<li>Working tree<ul>
<li>현재 내가 작업하고 있는 공간, 수정한 내용이 들어있음</li>
</ul>
</li>
<li>Staging Area<ul>
<li>git repository에 저장하기 전 단계에 있는 공간, working tree에서 수정한 내용들중 commit하고 싶은(버전을 만들고 싶은) 파일들을 선택해서 repository에 올림</li>
</ul>
</li>
<li>Repository<ul>
<li>git repository, staging area에서 commit을 한 내용들이 저장됨</li>
</ul>
</li>
</ul>
<h1 id="git-초기-설정">Git 초기 설정</h1>
<ul>
<li>git config --global user.name “your name”</li>
<li>git config --global user.email <a href="mailto:youremail@example.com">youremail@example.com</a></li>
<li>git config --list → 설정한 config 목록을 확인</li>
<li>git init .<ul>
<li>현재 디렉터리를 git 버전 관리를 시작함. 생성되는 .git 파일은 git repository(저장소)이다.</li>
<li>내가 만든 버전 정보, 원격 저장소 주소 등이 저장됨</li>
<li>원격 저장소에서 내 컴퓨터로 코드를 받아오면 자동으로 생성됨</li>
</ul>
</li>
</ul>
<h2 id="1-버전version-관리">1. 버전(version) 관리</h2>
<ul>
<li>git status<ul>
<li>working tree의 status를 알 수 있음</li>
</ul>
</li>
<li>git add<ul>
<li>staging area에 추가하고 싶은 파일들을 선택</li>
</ul>
</li>
<li>git commit -m &quot;~&quot;<ul>
<li>version 생성</li>
</ul>
</li>
<li>git commit -am “~”<ul>
<li>최초 한 번은 add 되어있는 파일들에 대해 add를 하지 않아도 자동으로 add가 실행됨 즉 add와 commit을 한번에 실행함</li>
</ul>
</li>
<li>git log<ul>
<li>버전 확인(생성한 커밋 확인)</li>
</ul>
</li>
<li>git log --stat<ul>
<li>commit에 연루되어있는 파일 출력</li>
</ul>
</li>
<li>git diff id1 id2<ul>
<li>파일의 차이점 출력</li>
</ul>
</li>
<li>git log -p<ul>
<li>각 commit간 diff한 결과를 나타냄</li>
</ul>
</li>
<li>git checkout (commit id or ‘main’)<ul>
<li>현재 working tree를 특정 버전(commit)으로 변경할 수 있음, branch도 변경할 수 있음</li>
</ul>
</li>
</ul>
<h2 id="2-백업backup">2. 백업(backup)</h2>
<ul>
<li>git push<ul>
<li>local repository(지역 저장소)에 있는 파일들을 remote repository(원격 저장소에 복사)</li>
</ul>
</li>
<li>git clone<ul>
<li>remote repository에 있는 파일들을 새로운 컴퓨터 즉 작업을 새로이 연결해서 시작하고자 하는 local repository에 복사하는 과정</li>
</ul>
</li>
<li>git pull<ul>
<li>remote repository에 있는 파일들을 local repository에 가져옴(clone은 전체 복사이고 pull은 다른점을 가져온다)</li>
</ul>
</li>
<li>git remote add origin ‘remote repository 주소’ → origin은 원격 저장소 별명이다.</li>
<li>git remote -v → 연결되어있는 원격 저장소의 주소 확인</li>
<li>git push --set-upstream origin main<ul>
<li>지역 저장소는 여러개의 원격 저장소에 연결될 수 있는데 그 중에 어떤 원격 저장소에 기본적으로 연결할지 세팅하는 과정</li>
</ul>
</li>
<li>git push -u origin main 으로 줄일 수 있음</li>
</ul>
<h2 id="3-협업collaborate">3. 협업(collaborate)</h2>
<ul>
<li>항상 git pull, git push를 자주 해야한다. 작업을 시작하기 전에 git pull은 필수!</li>
<li>git pull = git fetch + git merge FETCH_HEAD<ul>
<li>git fetch → 원격 저장소의 내용만 업데이트</li>
<li>git merge FETCH_HEAD → 가장 최근에 fetch했던 branch를 merge해준다.</li>
</ul>
</li>
</ul>
<h1 id="git-branch">Git branch</h1>
<ul>
<li>브랜치(Branch): 나뭇가지, 분기된 흐름 = 특정 커밋을 가리키는 포인터</li>
<li>git branch → 현재 생성된 branch 목록 출력</li>
<li>git branch ‘만들 branch 이름’ → 새로운 branch 생성</li>
<li>git checkout ‘branch 이름’ → 해당 branch로 전환</li>
<li>git log --all --graph --oneline → 아래의 그림과 같이 출력
<img src="https://private-user-images.githubusercontent.com/45515388/244657605-c7e90339-2ec9-4bbe-bce3-c11f1b5303ee.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3NjA1LWM3ZTkwMzM5LTJlYzktNGJiZS1iY2UzLWMxMWYxYjUzMDNlZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0wZGFiMzhmYTY4MzBmYzAyMjVhZWJjMzJjZTYwNzllMGM1ODRmYjBlOGYzMmNiMGVmOGY1NjBhNWViYjM0ZTViJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.0bUvK4T9OICUZk3L41xZHKRd-xsfo4AoBPIrPPF5H-U" alt="Untitled"></li>
</ul>
<h2 id="merge병합">merge(병합)</h2>
<p>base: merge하려는 branch들의 공통의 부모(조상)을 말함</p>
<p>git merge ‘merge할 branch 이름’ → 현재 가리키고 있는 branch에서 입력한 branch를 merge한다.</p>
<h2 id="conflict충돌">conflict(충돌)</h2>
<p><img src="https://private-user-images.githubusercontent.com/45515388/244657658-3693756b-2580-4111-898a-45d953e574da.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3NjU4LTM2OTM3NTZiLTI1ODAtNDExMS04OThhLTQ1ZDk1M2U1NzRkYS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0wZmEzODQwNWIxMWUzNWIwNGJmNTVlMzc1ZTRjNjQzMzA2Y2M5ZjFlNjE2ZGRkMTJhMThhNTViMTQ5OTgwZGZkJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.f5DqNNAbDSUqqxnoL-QSJe0tMeNbXVcFxbVXz21l7Gk" alt="Untitled"></p>
<p>같은 파일의 같은 부분을 수정한 경우 위와 같이 conflict가 발생하게 된다.</p>
<p><img src="https://private-user-images.githubusercontent.com/45515388/244657670-f80fb032-d59c-4e02-a027-be3a3740b98e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3NjcwLWY4MGZiMDMyLWQ1OWMtNGUwMi1hMDI3LWJlM2EzNzQwYjk4ZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0zZTkzOWY5YmRlMGJiNzlhNGY4MjVmNjg3ODMxNjEyNzgwNWZhOTdlMTljMzJlNWE3NGY1MDQ4ZDE5M2VjZDA0JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.xZqZI70c45BDI81tBtOr5_-bUAou6OJtoo6dPzHh7hw" alt="Untitled"></p>
<p>======= → 구분자를 뜻하며 구분자 위쪽은 현재 branch의 내용이 master이고 구분자 아래쪽은 o2 branch의 내용은 o2임을 나타낸다.</p>
<p>이런 경우 파일을 수동으로 수정한 후 git add ‘해당 파일 이름’ → git commit을 입력하면 merge를 계속 진행할 수 있다.</p>
<h1 id="fork">fork</h1>
<ul>
<li>저장소를 통째로 복제하는 것<ul>
<li>다른 사람의 저장소를 통째로 자기의 계정으로 복제해와서 커밋, 푸시를 하고 내 저장소와 포크 해온 저장소의 브랜치를 머지해달라고 요청하면 됨</li>
</ul>
</li>
</ul>
<h1 id="brach-vs-fork">brach vs fork</h1>
<table>
<thead>
<tr>
<th></th>
<th>의미</th>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>branch</td>
<td>하나의 원본 저장소에서 분기를 나눔</td>
<td>코드 커밋 이력을 확인하기 쉬움</td>
<td>많은 사용자가 브랜치를 만든다면 관리가 어려움</td>
</tr>
<tr>
<td>fork</td>
<td>여러 원격저장소를 만들어 분기를 나눔</td>
<td>원본 저장소에 영향을 미치지 않음</td>
<td>원본 저장소의 이력을 보려면 따로 주소를 추가해야함</td>
</tr>
</tbody></table>
<p>⇒ 주로 소규모 팀 등 팀 단위일 때는 branch, 오픈 소스 등 대규모 팀 단위일 때는 fork를 사용함</p>
<h1 id="pull-requestmerge-request-pr">pull request(merge request, PR)</h1>
<p>main branch에 merge하기전 팀원들과 코드 리뷰를 통해 merge를 할지 말지를 결정하는 것 → 통합 branch의 안정성을 높일 수 있다.</p>
<p><img src="https://private-user-images.githubusercontent.com/45515388/244657688-7f4e796c-2e3e-457b-b220-7bb001fef045.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3Njg4LTdmNGU3OTZjLTJlM2UtNDU3Yi1iMjIwLTdiYjAwMWZlZjA0NS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1hMjM5NDgyYTM1Y2NkOGJmMDNkZGJlMDZhNzE4ZjllZDQ4N2JlMWZkYjM4YWY2ZjJlNWIzY2E3ZTkwZGYxNjkxJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.-hqLFauAXfISQe2S2_3RLK1lsDrzlAA1mYjbfd4tQzo" alt="Untitled"></p>
<p>assignees: 이 작업에 참여한 사람을 지정</p>
<p>reviewers: 이 코드에 리뷰를 줬으면 하는 사람을 지정</p>
<h1 id="amend">amend</h1>
<ul>
<li>가장 마지막에 commit한 내용을 수정할 때 사용</li>
<li>git commit --amend</li>
<li>이력을 변경하기 때문에 주의해서 사용해야함(ex 다른 사람이 커밋을 pull해서 수정 중 내가 amend 해버렸다면 히스토리가 꼬이게됨 ⇒ 혼자 사용하는 브랜치에서 사용하자!)</li>
</ul>
<h1 id="stash">stash</h1>
<ul>
<li>변경사항을 커밋하지 않고 기억만 해두고 싶을 경우 사용(ex 다른 브랜치로 급하게 옮겨야하는 경우가 있을 때 현재 브랜치에서 작업한 내용들을 기억해두고 싶다!)</li>
</ul>
<h1 id="reset">reset</h1>
<ul>
<li>옛날 커밋으로 브랜치를 되돌리고 싶을 때 사용</li>
<li>amend와 마찬가지로 혼자 사용하는 브랜치에서만 사용하는 것을 권장함</li>
<li>git reset --hard (바꿀commit id)<ul>
<li>입력한 commit id의 버전으로 리셋함</li>
<li>--hard: 버전뿐만 아니라 수정본까지 삭제</li>
<li>--soft: 수정본은 남겨두고 버전만 삭제</li>
<li>--mixed: 변경 사항이 있는 파일들은 Working directory에 보존하고 HEAD와 branch만 이동하게 됨</li>
</ul>
</li>
</ul>
<h1 id="checkout과-reset의-차이점">checkout과 reset의 차이점</h1>
<blockquote>
<p><a href="https://opentutorials.org/module/3927/23693">https://opentutorials.org/module/3927/23693</a></p>
</blockquote>
<p><img src="https://private-user-images.githubusercontent.com/45515388/244657699-92aca667-a883-4aae-80d9-987f8c666b3e.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3Njk5LTkyYWNhNjY3LWE4ODMtNGFhZS04MGQ5LTk4N2Y4YzY2NmIzZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT05YWRmZjY5NTVjNmQ0MDllZWZmNWRkMDBlNGVkZDA2MDQ2OTYxOWY2NzY5YTZkYmUwYTE5NmY0NDNlZmJhMjg2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.Vievi-gX7v1YC4pYsYLQMWfhbIojBi89YV_aEnHT8G8" alt="Untitled"></p>
<p>checkout은 HEAD를 바꾸기 때문에 change의 의미가 있고</p>
<p>reset는 branch를 바꾸기 때문에 delete의 의미가 있다.</p>
<ul>
<li>만약 HEAD가 google을 가리키고 있는 생태에서 reset 1을 한다면 google은 1번 버전을 가리키게 된다.</li>
</ul>
<h1 id="revert">revert</h1>
<ul>
<li>git revert (revert할 commit id)</li>
<li>기존의 커밋(입력한 id)는 그대로 두고 해당 커밋에서의 수정사항을 취소함(여러 단계 전의 commit으로 돌아가고 싶다면 한번에 revert할게 아니라 역순으로 한 단계씩(한 개의 commit씩 revert를 해야 충돌을 피할 수 있다.)</li>
<li>reset은 히스토리를 완전히 삭제시키지만 revert는 히스토리를 새로 쌓아가면서 변경함 ⇒ 다른사람과 같이 사용하는 브랜치에서 사용하면 좋음</li>
</ul>
<h1 id="cherry-pick">cherry-pick</h1>
<ul>
<li>여러가지 커밋 중 원하는 커밋만 선택해서 지금 브랜치에 붙이고 싶은 경우 사용</li>
<li>ex) 버그 수정이 된 커밋만 현재 커밋에 가져오고 싶은 경우</li>
</ul>
<h1 id="git-flow-model">git flow model</h1>
<blockquote>
<p><a href="https://www.youtube.com/watch?v=EzcF6RX8RrQ">https://www.youtube.com/watch?v=EzcF6RX8RrQ</a></p>
</blockquote>
<p>branch를 어떻게 운영할 것인가에 대한 좋은 모델(사례)</p>
<p>main 브렌치의 최신 버전은 언제나 실행 가능한 상태여야한다!</p>
<p><img src="https://private-user-images.githubusercontent.com/45515388/244657712-c2c12b3c-7819-4d93-9958-d47845f3f9cd.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJrZXkxIiwiZXhwIjoxNjg2MzA0Mzc5LCJuYmYiOjE2ODYzMDQwNzksInBhdGgiOiIvNDU1MTUzODgvMjQ0NjU3NzEyLWMyYzEyYjNjLTc4MTktNGQ5My05OTU4LWQ0Nzg0NWYzZjljZC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBSVdOSllBWDRDU1ZFSDUzQSUyRjIwMjMwNjA5JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDIzMDYwOVQwOTQ3NTlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0yNjczOTVhMzE1Zjc0MDQxMzYxNzVjYTEyZGJjZDZmZTE2MDVkZDZhNzM5ZGI1MTY5NzQ0MzRlOTQyOGFhOTE2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.qPrv25mJ1Jt2R8OSUbYAMiAag1MOsbqAIhXIo_9HxrM" alt="55"></p>
<ul>
<li>develop: 개발할 때 사용하는 브렌치<ul>
<li>feature branches: 신규 기능 개발 브렌치</li>
</ul>
</li>
<li>release branches: 출시 준비 시 사용하는 브렌치</li>
<li>hotfixes: 긴급한 수정사항 반영</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(5일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 08 Jun 2023 08:53:07 GMT</pubDate>
            <description><![CDATA[<h1 id="직접-구현한-queue-vs-shift">직접 구현한 Queue vs shift()</h1>
<ul>
<li>shift의 시간복잡도는 O(N)이지만 N의 수가 적은 경우 JS엔진에서 최적화를 시켜주기 때문에 큐에 들어갈 데이터가 적은 경우 사용해도 좋음(N이 적은 경우직접 구현한 Queue보다 빠르게 동작할 수도 있음)</li>
<li>요소가 많아질 경우 직접 구현한 Queue가 shift 함수보다 빠르게 동작함</li>
</ul>
<h1 id="트리">트리</h1>
<ul>
<li>방향 그래프의 일종으로 노드을 가리키는 간선이 하나 밖에 없는 구조를 가짐</li>
</ul>
<h2 id="특징">특징</h2>
<ul>
<li>루트 노드를 제외한 모든 노드는 반드시 하나의 부모 노드를 가짐</li>
<li>노드가 N개인 트리의 간선의 개수 = N - 1</li>
<li>루트에서 특정 노드로 가는 경로는 유일함</li>
</ul>
<h2 id="이진-트리">이진 트리</h2>
<ul>
<li>각 노드가 최대 2개의 자식 노드를 가지는 트리</li>
<li>완전 이진 트리: 마지막 레벨을 제외하고 모든 노드가 채워진 상태</li>
<li>포화 이진 트리: 모든 정점이 채워진 상태</li>
<li>편향 트리: 한 방향으로만 노드가 이어진 상태</li>
<li>이진 탐색 트리, 힙, AVL 트리, 레드 블랙 트리 등에 사용함</li>
</ul>
<h3 id="이진-트리의-특징">이진 트리의 특징</h3>
<ul>
<li>노드가 N개일 때 이진 트리는 최약의 경우 높이가 N이 될 수 있음</li>
<li>노드가 N개인 포화 또는 완전 이진트리의 높이는 logN</li>
<li>높이가 h인 포화 이진트리는 (2^h) - 1개의 노드을 가짐</li>
</ul>
<h2 id="트리의-구현-방법">트리의 구현 방법</h2>
<ul>
<li><p>인접 행렬, 인접 리스트 방식, 연결 리스트 방식으로 구현할 수 있다.</p>
</li>
<li><p>JS로 이진 트리 구현</p>
<pre><code class="language-jsx">  // 0번 indx는 편의를 위해 사용하지 않음
  // left = index * 2
  // right = index * 2 + 1
  // parent = floor(index / 2)
  const binaryTree = [
    undefined,
    9,
    1, 2,
    3, 4, undefined, 5,
    undefined, undefined, undefined, 6,
  ]</code></pre>
</li>
</ul>
<h1 id="힙heap">힙(Heap)</h1>
<ul>
<li>이전 트리 형태를 가지며 우선순위가 높은 요소가 먼저 나가기 위해 요소 삽입, 삭제 시 바로 정렬됨</li>
<li>힙은 우선 순위 큐를 구현할 때 가장 적합한 방법이다.<ul>
<li>우선 순위 큐: 일반적인 큐와 다르게 우선 순위가 높은 요소가 먼저 나가는 큐 ⇒ 자료구조가 아닌 개념</li>
</ul>
</li>
</ul>
<h2 id="힙의-특징">힙의 특징</h2>
<ul>
<li>우선 순위가 높은 요소를 루트 노드로 배치함</li>
<li>루트가 가장 큰 값 = Max Heap, 루트가 가장 작은 값 = Min Heap</li>
</ul>
<h2 id="힙-요소-추가-알고리즘">힙 요소 추가 알고리즘</h2>
<ol>
<li>추가할 요소를 트리의 가장 마지막 노드로 위치</li>
<li>추가 후 부모 노드보다 우선 순위가 높다면 부모 노드와 순서를 바꿈</li>
<li>위의 과정을 반복하여 루트 노드에 우선 순위가 높은 노드가 위치하도록 함</li>
<li>완전 이진 트리의 높이는 logN 이므로 힙의 요소 추가 알고리즘은 O(logN)의 시간복잡도를 가짐</li>
</ol>
<h2 id="힙-요소-제거-알고리즘">힙 요소 제거 알고리즘</h2>
<ol>
<li>루트 노드에서 요소를 제거</li>
<li>루트 노드가 제거된 후 가장 마지막 노드가 루트에 위치</li>
<li>루트 노드의 두 자식 노드 중 더 우선순위가 높은 노드와 바꿈</li>
<li>두 자식 노드가 우선순위가 더 낮을 때 까지 반복</li>
<li>힙 요소 추가 알고리즘과 동일하게 O(logN)의 시간복잡도를 가짐</li>
</ol>
<h2 id="힙의-구현-방법">힙의 구현 방법</h2>
<pre><code class="language-jsx">// Max Heap으로 구현
class Heap {
  constructor() {
    this.heap = [null];
  }

  push(value) {
    this.heap.push(value);
    let curIdx = this.heap.length - 1;
    let parentIdx = Math.floor(curIdx / 2);

    while (parentIdx !== 0 &amp;&amp; this.heap[parentIdx] &lt; value) {
      const temp = this.heap[parentIdx];
      this.heap[parentIdx] = value;
      this.heap[curIdx] = temp;

      curIdx = parentIdx;
      parentIdx = Math.floor(curIdx / 2);
    }
  }

  pop() {
    const returnVal = this.heap[1];
    this.heap[1] = this.heap.pop();

    let curIdx = 1;
    let leftIdx = 2;
    let rightIdx = 3;
    while (
      this.heap[curIdx] &lt; this.heap[leftIdx] ||
      this.heap[curIdx] &lt; this.heap[rightIdx]
    ) {
      const temp = this.heap[curIdx];
      if (this.heap[leftIdx] &lt; this.heap[rightIdx]) {
        this.heap[curIdx] = this.heap[rightIdx];
        this.heap[rightIdx] = temp;
        curIdx = rightIdx;
      } else {
        this.heap[curIdx] = this.heap[leftIdx];
        this.heap[leftIdx] = temp;
        curIdx = leftIdx;
      }
      leftIdx = curIdx * 2;
      rightIdx = curIdx * 2 + 1;
    }
    return returnVal;
  }
}</code></pre>
<h1 id="트라이">트라이</h1>
<ul>
<li>문자열을 효율적으로 저장하고 탐색하기 위한 트리 형태의 자료구조</li>
<li>검색어 자동완성, 사전 찾기 등에 응용 가능</li>
<li>문자열 탐색에 단순 비교보다 효율적임</li>
<li>문자열을 길이를 L이라고 할때 탐색, 삽입이 O(L)만큼 걸림</li>
<li>각 노드에 자식에 대한 링크를 전부 가지고 있기에 많은 저장 공간을 사용</li>
</ul>
<h2 id="트라이-구조">트라이 구조</h2>
<ul>
<li>루트는 공백</li>
<li>각 간선(링크)은 추가될 문자를 키로 가짐</li>
<li>각 노드는 이전 노드의 값 + 간선의 키를 값으로 가짐</li>
<li>해시 테이블과 연결 리스트를 이용하여 구현</li>
</ul>
<h2 id="트라이-구현">트라이 구현</h2>
<p><a href="https://velog.io/@foxrain_gg/JS-Trie-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0">[JS] Trie 자료구조 구현</a></p>
<h1 id="정렬-알고리즘">정렬 알고리즘</h1>
<ul>
<li>정렬은 크게 비교식 정렬과 분산식 정렬로 나눌 수 있음</li>
<li>정렬 알고리즘 비교 사이트 =&gt; <a href="http://www.toptal.com/developers/sorting-algorithms">Sorting Algorithms Animations</a></li>
</ul>
<h2 id="비교식-정렬">비교식 정렬</h2>
<ul>
<li>다른 요소와 비교를 통해 정렬하는 방식</li>
<li>버블, 선택, 삽입 정렬이 있다.</li>
</ul>
<h2 id="분산식-정렬">분산식 정렬</h2>
<ul>
<li>요소를 분산하여 정렬하는 방식</li>
<li>분할 정복: 문제를 작은 2개의 문제로 분리하고 더 이상 분리가 불가능 할 때 처리 후 합치는 전략</li>
<li>합병, 퀵 정렬이 있다.</li>
</ul>
<p><a href="https://velog.io/@foxrain_gg/JS-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A0%95%EB%A6%AC#%EB%B3%91%ED%95%A9%ED%95%A9%EB%B3%91-%EC%A0%95%EB%A0%ACmerge-sort">[JS] 정렬 알고리즘 정리 및 구현</a></p>
<h2 id="js의-sort">JS의 sort()</h2>
<pre><code class="language-jsx">const arr = [5, 9, 3, 10, 1, 2];

// JS의 sort는 default로 ASCII 문자 순서로 정렬하기 때문에 주의
arr.sort()
console.log(arr); // [ 1, 10, 2, 3, 5, 9 ]
// ASCII 문자 순서로 정렬하기 때문에 10이 앞에 위치하게 됨

// 오름차순 정렬
arr.sort((a, b) =&gt; a - b);
console.log(arr); // [ 1, 2, 3, 5, 9, 10 ]

// 내림차순 정렬
arr.sort((a, b) =&gt; b - a);
console.log(arr); // [ 10, 9, 5, 3, 2, 1 ]</code></pre>
<h1 id="이진-탐색">이진 탐색</h1>
<ul>
<li>정렬 되어있는 요소들을 반씩 제외하며 찾는 알고리즘</li>
<li>시간복잡도는 O(log n)</li>
</ul>
<h2 id="이진-탐색-특징">이진 탐색 특징</h2>
<ul>
<li>반드시 정렬 상태에서 사용해야함</li>
<li>배열 또는 이진 트리를 이용하여 구현</li>
</ul>
<h2 id="이진-탐색-트리의-문제점">이진 탐색 트리의 문제점</h2>
<ul>
<li>최악의 경우 한쪽으로 편향된 트리가 생성됨 ⇒ 순차 탐색과 동일한 시간복잡도를 가짐</li>
<li>위의 문제를 해결하기 위해 AVL 트리, 레드-블랙 트리를 사용할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(4일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 07 Jun 2023 13:33:06 GMT</pubDate>
            <description><![CDATA[<h1 id="단순-구조">단순 구조</h1>
<ul>
<li>정수, 실수, 문자열, 논리</li>
</ul>
<h1 id="선형-구조">선형 구조</h1>
<blockquote>
<p>한 원소 뒤에 하나의 원소 만이 존재하는 형태로 자료들이 선형으로 나열되어 있는 구조</p>
</blockquote>
<ul>
<li>배열: 추가와 삭제가 반복되는 로직이면 권장하지 않음, 탐색이 많은 경우에 유리한 자료구조</li>
<li>연결 리스트: 추가와 삭제가 반복되는 로직에 권장됨</li>
<li>스택: LIFO(Last In First Out)</li>
<li>큐: FIFO(First In First Out)</li>
</ul>
<h2 id="큐queue">큐(Queue)</h2>
<ul>
<li><p>JS에서 shift 함수로 큐를 구현하지 말자! ⇒ shift는 선형 시간이 걸리기 때문에 효율이 좋지 않다!</p>
</li>
<li><p>JS에서의 큐 구현</p>
<pre><code class="language-jsx">  class Queue {
    constructor() {
      this.queue = [];
      this.front = 0;
      this.rear = 0;
    }

    enqueue(inputValue) {
      this.queue[this.rear++] = inputValue;
    }

    dequeue() {
      const returnValue = this.queue[this.front];
      delete this.queue[this.front++];
      return returnValue;
    }

    peek() {
      return this.queue[this.front];
    }

    size() {
      return this.rear - this.front
    }
  }</code></pre>
</li>
</ul>
<h2 id="해시-테이블hash-table">해시 테이블(Hash Table)</h2>
<ul>
<li>키와 값을 받아 키를 해싱(Hashing)하여 나온 index에 값을 저장하는 선형 자료구조</li>
<li>삽입, 삭제, 탐색의 시간복잡도가 모두 O(1)</li>
<li>Bucket: 각 테이블에 해당 하는 index를 말함</li>
<li>사용자 정보 관리 등에 유용함</li>
</ul>
<h3 id="해시-함수">해시 함수</h3>
<ul>
<li>입력 받은 값을 특정 범위 내 수로 변경하는 함수</li>
<li>해시 함수 결과가 동일한 경우 ⇒ 해시 충돌(Hash Collision) 발생</li>
</ul>
<h3 id="해시-충돌-해결-방법">해시 충돌 해결 방법</h3>
<ol>
<li>선형 탐사법: 충돌이 발생하면 한 칸 옆으로 이동<ul>
<li>단점: 특정 영역에 데이터가 몰릴 수 있음, 최악의 경우 탐색에 선형 시간이 걸릴 가능성이 있음</li>
</ul>
</li>
<li>제곱 탐사법: 충돌이 발생하면 충돌이 발생한 횟수의 제곱만큼 옆으로 이동</li>
<li>이중 해싱: 충돌이 발생하면 다른 해시 함수를 이용, 충돌이 발생하지 않을 때 까지 두번째 해시로 index를 계속 생성</li>
<li>분리 연결법: 충돌이 발생한 버킷(인덱스)에 버킷의 값을 연결 리스트로 사용하여 값을 추가<ul>
<li>단점: 하나의 버킷에 값들이 무한정 늘어날 수 있는 가능성</li>
</ul>
</li>
</ol>
<h3 id="js에서-해시-테이블-구현">JS에서 해시 테이블 구현</h3>
<ul>
<li>Object로 구현</li>
</ul>
<pre><code class="language-jsx">// Object를 이용
const hashTable = {};
hashTable[&#39;key&#39;] = 10;
hashTable[&#39;key2&#39;] = &#39;hi&#39;;
console.log(hashTable[&#39;key&#39;]); // 10
delete hashTable[&#39;key&#39;];
console.log(hashTable[&#39;key&#39;]); // undefined</code></pre>
<ul>
<li>Map으로 구현</li>
</ul>
<pre><code class="language-jsx">// Map을 사용, Object도 Key로 사용 가능
const hashTable = new Map();
hashTable.set(&#39;key&#39;, 10);

//object를 key로 사용
const obj = { a: 2 };
hashTable.set(obj, &#39;aa&#39;);
console.log(hashTable.get(obj)); // a

hashTable.delete(obj);

console.log(hashTable.keys()); // { &#39;key&#39; }
console.log(hashTable.values()); // { 10 }
hashTable.clear();
console.log(hashTable.keys()); // { }
console.log(hashTable.values()); // { }</code></pre>
<ul>
<li>Set으로 구현</li>
</ul>
<pre><code class="language-jsx">// key와 Value가 동일함
const hashTable = new Set();
hashTable.add(&#39;key&#39;);
hashTable.add(&#39;key2&#39;);
console.log(hashTable.has(&#39;key&#39;)); // true
hashTable.delete(&#39;key2&#39;);
console.log(hashTable.has(&#39;key2&#39;)); // false</code></pre>
<h1 id="비선형-구조">비선형 구조</h1>
<blockquote>
<p>원소 간 다대다 관계를 가지는 구조로 계층적 구조나 망형 구조를 표현하기에 적합</p>
</blockquote>
<ul>
<li>트리</li>
<li>그래프</li>
</ul>
<h2 id="그래프">그래프</h2>
<ul>
<li>정점과 정점 사이를 연결하는 간선으로 이루어진 비선형 자료구조</li>
<li>정점(Node) 집합과 간선(Edge) 집합으로 표현할 수 있음</li>
<li>특징<ul>
<li>정점은 여래 개의 간선을 가질 수 있음</li>
<li>크게 방향 그래프와 무방향 그래프로 나눌 수 있음<ul>
<li>무방향 그래프: 정점이 간선으로 이어진 경우 양방향으로 이동 가능( A→B와 B→A는 같은 간선으로 취급)</li>
<li>방향 그래프: 간선에 바향성이 존재하는 그래프</li>
</ul>
</li>
<li>간선은 가중치를 가질 수 있음</li>
<li>사이클이 발생할 수 있음 ⇒ 탐색 시 무한루프에 빠지지 않도록 사이클을 찾아야함<ul>
<li>사이클: 그래프의 정점과 간선이 부분 집합에서 순환되는 부분을 말함</li>
</ul>
</li>
</ul>
</li>
<li>연결 그래프: 모든 정점이 서로 이동 가능한 상태인 그래프</li>
<li>비연결 그래프: 정점에 연결된 간선이 0개인 정점이 존재하는 그래프</li>
<li>완전 그래프: 모든 정점끼리 연결된 상태인 그래프</li>
</ul>
<h3 id="js-인접-행렬로-구현">JS 인접 행렬로 구현</h3>
<ul>
<li>행렬의 열 부분 ⇒ 시작 정점</li>
<li>행렬의 행 부분 ⇒ 도착 정점</li>
<li>true로 간선이 연결된 것으로 설정</li>
<li>무방향 그래프의 경우 모든 값을 대칭으로 대입</li>
</ul>
<pre><code class="language-jsx">const graph = Array.from(Array(5), () =&gt; Array.fill(false));
graph[0][1] = true; // 0에서 1로 가는 간선이 존재하는 경우</code></pre>
<h3 id="js-인접-리스트로-구현">JS 인접 리스트로 구현</h3>
<ul>
<li>정점의 수 만큼 배열을 만든 후 연결할 정점을 배열에 추가</li>
</ul>
<pre><code class="language-jsx">const graph = Array.from(Array(5), () =&gt; []);
graph[0].push(1) // 0에서 1로 가는 간선이 존재하는 경우</code></pre>
<h1 id="some">some()</h1>
<ul>
<li><p>array 타입에서 사용 가능한 함수로 주어진 판별 함수를 실행하여 배열 안의 요소들 중 참이 되는 결과가 있는지 테스트한다.</p>
</li>
<li><p>판별 함수가 true를 반환하면 some은 true를 반환한다.</p>
</li>
<li><p>예시</p>
<pre><code class="language-jsx">  arr = [1, 2, 3, 4, 5, 6];

  console.log(arr.some((num) =&gt; num &gt; 5)); // true
  console.log(arr.some((num) =&gt; num &gt; 7)); // false</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(3일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL3%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL3%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 06 Jun 2023 05:50:59 GMT</pubDate>
            <description><![CDATA[<h1 id="자료구조란">자료구조란?</h1>
<ul>
<li>메모리를 효율적으로 사용하면서 데이터를 빠르고 안정적으로 처리하는 것이 목표</li>
<li>상황에 따라 유용하게 사용될 수 있도록 특정 구조를 이루고 있음 ⇒ 상황에 맞는 올바른 자료구조를 선택해야함</li>
<li>즉, 자료구조는 일차원인 컴퓨터 메모리를 현실에 대응되도록 만든 구조</li>
</ul>
<h2 id="자료구조의-종류">자료구조의 종류</h2>
<h3 id="단순-구조">단순 구조</h3>
<ul>
<li>정수</li>
<li>실수</li>
<li>문자열</li>
<li>논리<h3 id="선형-구조">선형 구조</h3>
선형 구조: 한 원소 뒤에 하나의 원소 만이 존재하는 형태로 자료들이 선형으로 나열되어 있는 구조</li>
<li>배열: 추가와 삭제가 반복되는 로직이면 권장하지 않음, 탐색이 많은 경우에 유리한 자료구조</li>
<li>연결 리스트: 추가와 삭제가 반복되는 로직에 권장됨</li>
<li>스택: LIFO(Last In First Out)</li>
<li>큐</li>
</ul>
<h3 id="비선형-구조">비선형 구조</h3>
<p>비선형 구조: 원소 간 다대다 관계를 가지는 구조로 계층적 구조나 망형 구조를 표현하기에 적합</p>
<ul>
<li>트리</li>
<li>그래프</li>
</ul>
<h1 id="알고리즘">알고리즘</h1>
<ul>
<li>특정 문제를 효율적이고 빠르게 하는 것이 목표</li>
<li>정해진 일련의 절차나 방법을 공식화한 형태로 표현한 것</li>
</ul>
<blockquote>
<p>자료구조 + 알고리즘 = 프로그램!</p>
</blockquote>
<h1 id="시간-복잡도">시간 복잡도</h1>
<ul>
<li>특정한 크기의 입력에 대하여 알고리즘이 얼마나 오래 걸리는지를 의미함</li>
<li>프로그램의 성능을 정확히 파악하는 것은 불가능 ⇒ 대략적인 성능을 비교하기 위한 상대적인 표기법을 사용함</li>
</ul>
<h2 id="문제의-크기">문제의 크기</h2>
<ul>
<li>문제의 크기란? 예) 쇼핑몰 장바구니 물건의 개수, 게임 동시 접속자의 수 등
이러한 문제의 크기를 보통 N이라고 하고, 문제의 크기 N에 따라 걸리는 시간이 다르다.</li>
<li>문제를 해결할 때 문제의 크기에 따라 알맞는 방법을 선택하는 것이 중요</li>
</ul>
<h2 id="빅오표기법big-o-notation">빅오표기법(Big O notation)</h2>
<p><img src="https://github.com/HongGunWoo/four_equal_ten_clone_app/assets/45515388/40a928b1-8486-4e6a-9282-0a62376ed1ce" alt="빅오표기법 그래프"></p>
<table>
<thead>
<tr>
<th align="center">빅오 표기법</th>
<th align="center">n = 1</th>
<th align="center">n = 4</th>
<th align="center">n = 8</th>
</tr>
</thead>
<tbody><tr>
<td align="center">O(1)</td>
<td align="center">1</td>
<td align="center">1</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">O(logn)</td>
<td align="center">0</td>
<td align="center">2</td>
<td align="center">3</td>
</tr>
<tr>
<td align="center">O(n)</td>
<td align="center">1</td>
<td align="center">4</td>
<td align="center">8</td>
</tr>
<tr>
<td align="center">O(nlogn)</td>
<td align="center">2</td>
<td align="center">8</td>
<td align="center">24</td>
</tr>
<tr>
<td align="center">O(n^2)</td>
<td align="center">1</td>
<td align="center">16</td>
<td align="center">64</td>
</tr>
<tr>
<td align="center">O(2^n)</td>
<td align="center">2</td>
<td align="center">16</td>
<td align="center">256</td>
</tr>
<tr>
<td align="center">O(n!)</td>
<td align="center">1</td>
<td align="center">24</td>
<td align="center">40,326</td>
</tr>
</tbody></table>
<h3 id="빅오표기법-4가지-법칙">빅오표기법 4가지 법칙</h3>
<ol>
<li>계수 법칙: 이 무한에 가까울 수록 k의 크기는 의미가 없음</li>
<li>합의 법칙: 빅오는 더해질 수 있음</li>
<li>곱의 법칙: 빅오는 곱해질 수 있음</li>
<li>다항 법칙: f(n)이 k차 다항식이면 f(n)은 O(n^k)</li>
</ol>
<h2 id="시간-복잡도-계산하기">시간 복잡도 계산하기</h2>
<ul>
<li>상수는 버림 ex) O(5) = O(1), O(3N^2) = O(N^2)</li>
<li>두가지 항이 있을 때, 변수가 같으면 큰것만 빼고 다 버림 ex) O(N^2 + N) = O(N^2), O(N^2 + NlgN) = O(N^2)</li>
<li>두가지 항이 있는데 변수가 다르면 놔둠 ex) O(N^2 + M)</li>
</ul>
<h1 id="공간-복잡도">공간 복잡도</h1>
<ul>
<li>알고리즘의 실행 중에 사용되는 메모리 공간의 양을 나타내는 것</li>
<li>보통 가장 많은 공간을 사용하는 것은 배열(배열이 사용한 공간: 배열의 크기 X 자료형의 크기)</li>
<li>일반적으로 공간 복잡도는 추가적인 입력 데이터를 저장하는 데 필요한 공간과 알고리즘이 실행되는 동안 생성되는 임시 데이터를 저장하는 데 필요한 공간으로 구성됨<h1 id="js의-date-객체로-성능-측정">JS의 Date 객체로 성능 측정</h1>
<pre><code class="language-jsx">const start = new Date().getTime();
const N = 1000000000;
</code></pre>
</li>
</ul>
<p>let total = 0;
for (let i = 0; i &lt; N; i += 1) {
  total += 1;
}</p>
<p>const end = new Date().getTime();
console.log(end - start);
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(2일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 05 Jun 2023 12:52:04 GMT</pubDate>
            <description><![CDATA[<h1 id="네트워크-기초">네트워크 기초</h1>
<h2 id="브라우저에-url을-입력하면-발생하는-일">브라우저에 URL을 입력하면 발생하는 일</h2>
<ol>
<li><p>URL 해석</p>
<ul>
<li>URL의 구조: scheme://<user>:<password>@<host>:<port>/<url-path><ul>
<li>//은 생략 가능</li>
</ul>
</li>
</ul>
</li>
<li><p>DNS(Domain Name System) 조회</p>
<ul>
<li><p>DNS는 도메인과 IP 주소를 서로 변환</p>
</li>
<li><p>DNS로 요청을 보내기 전에 브라우저 캐시와 로컬 컴퓨터의 hosts파일을 참조</p>
<ul>
<li>브라우저 캐시나 hosts에 이미 정의가 되있다면 내부적으로 IP를 반환</li>
<li>정의가 되어있지 않다면 DNS 호출</li>
</ul>
</li>
<li><p>DNS를 운영하는 서버를 Name Server라고 함</p>
</li>
<li><p>presnet.do, <a href="http://www.present.do">www.present.do</a>, gateway.dev.present.do
전부 도메인은 present.do, 나머지 서브 도메인이 붙는 경우는 host라고 함</p>
<p><img src="https://github.com/HongGunWoo/four_equal_ten_clone_app/assets/45515388/a9a7a0b3-9efb-46f0-a4ae-1735f9dccd76" alt="스크린샷 2023-06-02 오후 4.30.20.png"></p>
</li>
</ul>
</li>
<li><p>해당 IP가 존재하는 서버로 이동</p>
<ul>
<li>네트워크 장비 라우터를 통해 이동하며 동적 라우팅을 통해 이동한다.</li>
</ul>
</li>
<li><p>ARP(Address Resolution Protocol)를 이용하여 MAC 주소 변환</p>
<ul>
<li>논리 주소인 IP 주소를 물리주소인 MAC 주소로 변환하는 프로토콜</li>
<li>실제 통신을 위해 고유한 MAC 주소가 필요(MAC 주소를 통해 기계의 실제 위치를 알 수 있다.)</li>
<li>네트워크 내에 ARP를 Broadcasting하면 해당 IP 주소를 가지고 있는 기기가 MAC주소를 반환</li>
<li>논리적인 주소와 물리적인 주소를 나눈 이유<ul>
<li>논리적 주소 = 도로명 주소, 물리적 주소 = GPS 좌표로 생각하자</li>
<li>IP는 대역을 통해 범위를 좁혀나가는 용도로 사용</li>
<li>MAC은 실제 위치를 알아내는데 사용</li>
</ul>
</li>
</ul>
</li>
<li><p>TCP 통신을 통해 Socket을 연다.</p>
<ul>
<li>네트워크를 통해 해당 기기로 패킷을 전달</li>
<li>3 way handshake 연결 요청</li>
<li>요청이 수락되면 기기는 패킷을 받아 처리</li>
</ul>
</li>
<li><p>서버가 응답을 반환</p>
<ul>
<li>HTTP 프로토콜로 들어온 패킷을 읽고 처리</li>
<li>요청에 따른 적절한 응답 값 반환</li>
</ul>
</li>
<li><p>브라우저가 렌더링함</p>
<ul>
<li>HTML을 읽어 DOM Tree를 구축</li>
<li>만들어진 DOM Tree를 이용하여 화면에 그림</li>
<li>스크립트 실행</li>
</ul>
</li>
</ol>
<h2 id="http와-https의-차이">HTTP와 HTTPS의 차이</h2>
<ul>
<li>HTTP(HyperText Tranfer Protocol)</li>
<li>HTTPS(Hypertext Transfer Protocol Secure)</li>
</ul>
<p>이름에서 알 수 있듯이 HTTP는 암호화되지 않은 통신을 사용하고 HTTPS는 암호화된 통신을 사용한다.</p>
<h2 id="https">HTTPS</h2>
<ul>
<li>SSL(Secure Sockets Layer) 또는 TLS(Transport Layer Security) 프로토콜을 사용하여 데이터를 암호화 ⇒ 데이터의 기밀성과 무결성을 보호하고 제3자가 데이터를 엿보는 것을 방지</li>
<li>443번 포트를 사용(HTTP는 80번 포트 사용)</li>
<li>암호화된 연결을 설정하기 위해 인증서를 사용<ul>
<li>인증서를 통해 웹 사이트의 신원을 확인하고, 클라이언트와 서버 간의 통신에 대한 암호화를 제공한다.</li>
<li>인증서는 신뢰할 수 있는 인증 기관(Certificate Authority)에 의해 발급됨</li>
</ul>
</li>
<li>SEO(Search Engine Optimization, 검색 엔진 최적화)<ul>
<li>HTTPS를 사용하는 웹 페이지는 검색 엔진에 의해 보다 긍정적으로 평가됨</li>
</ul>
</li>
</ul>
<h3 id="https의-통신-과정">HTTPS의 통신 과정</h3>
<p>HTTPS는 기존의 HTTP 통신 위에 SSL/TLS 프로토콜을 추가하여 암호화와 인증을 제공함</p>
<ul>
<li>클라이언트와 서버 간에 SSL/TLS handshake가 이루어짐 ⇒ 이 과정에서 서버의 인증서 확인, 클라이언트와 서버 간의 암호화 알고리즘 및 암호 키 교환 등이 이루어짐</li>
</ul>
<h1 id="컴퓨터-시간-동작-원리">컴퓨터 시간 동작 원리</h1>
<h2 id="시간이-결정되는-기준">시간이 결정되는 기준</h2>
<h3 id="물리-법칙에-따른-표현">물리 법칙에 따른 표현</h3>
<ul>
<li>물리량: 시간은 물리학 관점에서 봤을 때 시간과 시각 사이 간격을 표현하는 단위를 뜻함</li>
<li>위치: 시간은 위치에 따라 다르게 표현될 수 있음(나라, 지역마다 시간이 다름)</li>
<li>천문 현상: 지구 자전 속도의 불규칙성, 자전주기와 공전주기 등 천문 현상으로 인한 시간 보정이 필요</li>
</ul>
<h3 id="협의에-따른-표현">협의에 따른 표현</h3>
<ul>
<li>문화: 문화에 따라 시간 표현이 달라짐(태양력, 태음력 등)</li>
<li>역사: 역사적 사건에 의해 시간은 다르게 표현될 수 있음</li>
<li>사회: 사회적 제도에 의해 시간이 변할 수 있음(Summer Time)</li>
</ul>
<h2 id="협정-세계시utc">협정 세계시(UTC)</h2>
<ul>
<li>원자 시계와 윤초 보정을 기반으로 표준화한 시각</li>
<li>모든 시간대는 UTC+0을 기준으로 환산</li>
<li>표기법은 ISO 8601을 따름</li>
</ul>
<h2 id="컴퓨터가-시간을-표현하는-방법">컴퓨터가 시간을 표현하는 방법</h2>
<ul>
<li>하드웨어의 시스템 클럭을 이용</li>
<li>시스템 시간: 특정 시간(Epoch)를 기준으로 시스템 클럭의 틱을 세는 것으로 구현</li>
<li>타임스탬프(Timestamp): 시스템 시간을 값으로 표현한 것</li>
</ul>
<h3 id="시스템-클럭">시스템 클럭</h3>
<ul>
<li>RTC(Real Time Clock)라는 모듈을 사용함</li>
<li>RTC는 메인보드에 붙어있어 전원을 끄더라고 계속 작동</li>
<li>RTC는 카운터 회로를 통해 클럭을 발생시킴</li>
</ul>
<h2 id="컴퓨터가-시간을-알아내는-법">컴퓨터가 시간을 알아내는 법</h2>
<ul>
<li>시스템 시간을 네트워크 타임 프로토콜(NTP)를 통해 동기화 할 수 있음</li>
<li>NTP 서버에 네트워크 요청을 하여 현재 시간을 받을 수 있음</li>
<li>NTP 서버는 계층으로 이루어져 있으며 그 계층을 Stratum이라고 함</li>
<li>최상위 계층을 PRC(Primary Reference Clock)이라고 함</li>
</ul>
<h2 id="컴퓨터가-시간대를-고려하는-방법">컴퓨터가 시간대를 고려하는 방법</h2>
<ul>
<li>Time Zone 데이터를 이용</li>
<li>현실 세계에 이벤트가 발생되면 업데이트 됨</li>
<li>표기법<ul>
<li>대륙/도시 형태를 따른다. ex) Asia/Seoul</li>
<li>하나의 값을 ZoneId라고 한다.</li>
</ul>
</li>
</ul>
<h2 id="시간을-어떤-기준으로-사용해야-할까">시간을 어떤 기준으로 사용해야 할까?</h2>
<p>글로벌 서비스 같은 경우 시간이 매우 중요해짐 ⇒ 서비스에서 사용되는 시간을 용도에 맞춰서 기록할 필요가 있음</p>
<ul>
<li>순수한 시간: 시간대와 지역, 문화, 사회를 고려하지 않고 순수하게 시간을 기록하는 경우(ex 생일, 기념일 등)</li>
<li>UTC: 역사, 사회, 문화에 대한 맥락 없이 사건이 발생한 시각만을 고려할 때 사용(ex 로깅, 감사, 시계열 데이터)</li>
<li>Time Zone이 적용된 시간: 역사, 사회, 문화를 고려하여 사용자가 이용한 시각을 정확히 알아햐할 때 사용(UI에 표시되는 시간을 사용자 기준으로 보여줄 때 사용, ex 결제 시각, 푸시 알림 시간, 캘린더)</li>
</ul>
<p>JS에서는 Date 객체나 date-fns, luxon 라이브러리를 사용할 수 있음</p>
<h1 id="암호화">암호화</h1>
<ul>
<li>암호화: 평문을 해독할 수 없는 암호문으로 변환하는 것을 말함<ul>
<li>단방향(해싱)과 양방향이 존재함</li>
</ul>
</li>
</ul>
<h2 id="단방향-암호화">단방향 암호화</h2>
<ul>
<li>한 방향으로만 이루어지는 암호화 알고리즘</li>
<li>해시 알고리즘을 이용함(MD5, SHA)</li>
<li>사용자 비밀번호 등을 저장할 때 자주 사용함</li>
<li>MD5, SHA-0, SHA-1은 해시 충돌 가능성이 있어 사용을 권하지 않음</li>
</ul>
<h3 id="고려할-점">고려할 점</h3>
<ul>
<li>복호화가 불가능하지만 Rainbow Table을 통해 원문을 알아낼 가능성이 있음 ⇒ 불의의 사고로 암호화된 데이터를 탈취당하더라도 원문을 알아 낼 수 없도록 조치를 해야함<ul>
<li>Rainbow Table: 평문과 해시 함수로 만든 문자열을 모두 저장시켜 놓은 표</li>
</ul>
</li>
<li>Salt, Key stretching를 이용하여 해결함<ul>
<li>Salt: 평문에 임의의 문자열을 추가하여 암호하 하는 방법, 128bit 이상으로 만드는 것이 좋고 사용자마다 다른 Salt를 사용하면 보안성이 높아짐</li>
<li>Key stretching: 해시를 여러번 반복하여 원문을 알기 힘들게 만드는 방법, 일반적인 시스템에서 0.2초이상 반복되면 안전함</li>
</ul>
</li>
</ul>
<h2 id="양방향-암호화">양방향 암호화</h2>
<ul>
<li>평문을 복호화 할 수 있는 형태로 암호화하는 방법</li>
<li>대칭키와 비대칭키 알고리즘으로 나뉨<ul>
<li>대칭키 암호 알고리즘: 대표적으로 AES가 있음, 같은 키를 이용하여 암호화, 복호화가 가능</li>
<li>비대칭키 알고리즘: 대표적으로 RSA가 있음, 공개키와 개인키 두 가지 키가 존재, 소인수 분해를 기반으로 만들어진 알고리즘</li>
</ul>
</li>
</ul>
<h1 id="함수형-프로그래밍의-특징">함수형 프로그래밍의 특징</h1>
<h2 id="장점">장점</h2>
<ul>
<li>상태가 없기 때문에 사이드 이펙트가 없음</li>
<li>높은 재사용성</li>
<li>코드가 짧고 간결함</li>
</ul>
<h2 id="단점">단점</h2>
<ul>
<li>상태가 없기 때문에 상태 조작이 쉽지 않음</li>
<li>재사용을 위해 함수를 나눠야하고 많은 함수들이 생길 수 있음</li>
</ul>
<h2 id="객체지향의-오해">객체지향의 오해</h2>
<ul>
<li>객체지향은 패러다임일 뿐 언어와는 관계가 없음 → 언어는 지향하는 것을 조금 더 편하게 구현할 수 있도록 도와줄 뿐, 따라서 클래스가 없는 언어로도 객체지향 프로그래밍을 할 수 있음</li>
<li>JS는 프로토타입을 통해 객체지향을 표현함</li>
<li>절차지향, 객체지향 중 우위가 없는 것은 없음<ul>
<li>간단한 프로그램일 수록 절차지향이 더 쉽고 직관적임</li>
<li>객체지향은 객체간 통신하기 때문에 흐름이 더 직관적이어서 더 복잡한 프로그램에 적합함</li>
</ul>
</li>
</ul>
<h1 id="js의-객체-생성-방법">JS의 객체 생성 방법</h1>
<ol>
<li><p>객체 리터럴</p>
<pre><code class="language-jsx"> const Person = {
   name: &#39;GunWoo&#39;,
   move: function() {
     console.log(&quot;이동합니다.&quot;);
   },
 }</code></pre>
</li>
<li><p>Object</p>
<pre><code class="language-jsx"> const person = new Object();
 person.name = &quot;GunWoo&quot;;
 person.move = function () {
   console.log(&quot;이동합니다.&quot;);
 };</code></pre>
</li>
<li><p>생성자 함수</p>
<pre><code class="language-jsx"> function Person(name) {
   this.name = name;
   this.move = function () {
     console.log(&quot;이동합니다.&quot;);
   }
 }</code></pre>
</li>
</ol>
<h1 id="프로토타입">프로토타입</h1>
<ul>
<li>객체 지향 프로그래밍에서 객체 간의 상속과 프로퍼티 공유를 구현하는 메커니즘</li>
<li>JavaScript 객체는 내부적으로 <strong><code>prototype</code></strong>이라는 프로퍼티를 가지고 있는데 <strong><code>prototype</code></strong>은 해당 객체의 프로토타입 객체를 가리킴</li>
<li>프로토타입 객체 역시 자체적으로 <strong><code>prototype</code></strong>을 가지며, 이를 통해 다른 프로토타입과 연결되는 프로토타입 체인을 형성함</li>
<li>프로토타입 체인은 객체가 특정 프로퍼티나 메소드를 찾을 때, 해당 객체의 프로토타입에도 없으면 상위 프로토타입으로 이동하여 계속해서 찾는 동작을 수행</li>
<li>함수 객체가 생성자 함수로 사용될 때, 해당 함수의 <strong><code>prototype</code></strong> 프로퍼티에 정의된 프로퍼티와 메소드는 생성된 객체들이 상속받게 됨. 즉, <strong><code>prototype</code></strong>은 객체 생성자 함수의 프로토타입 객체를 가리킴</li>
</ul>
<h2 id="프로토타입이-필요한-이유">프로토타입이 필요한 이유</h2>
<ul>
<li>prototype을 사용하지 않은 경우 ⇒ move함수가 중복되어 메모리가 낭비된다.</li>
</ul>
<pre><code class="language-jsx">function Person(name) {
  this.name = name;
  this.move = function () {
    console.log(&quot;이동합니다.&quot;);
  }
}

const p1 = new Person(&#39;gun&#39;);
const p2 = new Person(&#39;woo&#39;);
console.log(p1); // Person { name: &#39;gun&#39;, move: [Function (anonymous)] }
console.log(p2); // Person { name: &#39;woo&#39;, move: [Function (anonymous)] }</code></pre>
<ul>
<li>prototype을 사용한 경우 ⇒ 하위 객체의 <strong>proto</strong>가 상위 객체를 링크하기 때문에 객체를 효율적으로 사용할 수 있다.</li>
</ul>
<pre><code class="language-jsx">function Person(name) {
  this.name = name;
  Person.prototype.move = function () {
    console.log(&quot;이동합니다.&quot;);
  }
}

const p1 = new Person(&#39;gun&#39;);
const p2 = new Person(&#39;woo&#39;);
console.log(p1); // Person { name: &#39;gun&#39; }
console.log(p2); // Person { name: &#39;woo&#39; }
console.log(p1.__proto__); //{ move: [Function (anonymous)] }</code></pre>
<h2 id="effective-prototype">Effective Prototype</h2>
<h3 id="상속을-흉내내기---1">상속을 흉내내기 - 1</h3>
<p>부모 객체를 이용하여 프로토타입 함수 정의하기</p>
<pre><code class="language-jsx">function Person (name) {
  this.name = name;
}

Person.prototype.getName = function () {
  return this.name || &quot;건우&quot;;
}

function Korean (name) {}

// 상위 객체의 함수가 링크됨 하지만 내부적으로 생성된 프로토타입 변수는 사용 불가
Korean.prototype = new Person(); 

const gun = new Person(&#39;gun&#39;);
const woo = new Korean(&#39;woo&#39;);

console.log(gun.getName()); // gun
console.log(woo.getName()); // 건우</code></pre>
<h3 id="상속을-흉내내기---2">상속을 흉내내기 - 2</h3>
<p>부모 생성자를 빌려 쓰기</p>
<pre><code class="language-jsx">function Person (name) {
  this.name = name;
}

Person.prototype.getName = function () {
  return this.name || &quot;건우&quot;;
}

function Korean (name) {
    // apply함수를 통해 Korean 생성자 함수에 전달된 인자들을 Person 생성자 함수에 적용시키는 역할을 함
  Person.apply(this, arguments);
}
Korean.prototype = new Person();

const gun = new Person(&#39;gun&#39;);
const woo = new Korean(&#39;woo&#39;);

console.log(gun.getName()); // gun
console.log(woo.getName()); // woo</code></pre>
<h3 id="objectcreate">Object.create</h3>
<p>기존 객체를 재활용함</p>
<pre><code class="language-jsx">const woo = {
  name: &#39;woo&#39;,
  getName: function () {
    return this.name;
  },
};

const gun = Object.create(woo);
gun.name = &quot;gun&quot;

console.log(woo.getName()); // woo
console.log(gun.getName()); // gun
console.log(woo.__proto__); // [Object: null prototype] {}
console.log(gun.__proto__); // { name: &#39;woo&#39;, getName: [Function: getName] }</code></pre>
<h1 id="이벤트-루프">이벤트 루프</h1>
<ul>
<li>JS는 싱글 스레드로 call stack이 하나만 존재함 ⇒ 브라우저는 어떻게 비동기적으로 동작할까?<ul>
<li>브라우저에는 Multi Threaded로 event loop가 존재하여 비동기적으로 동작할 수 있음</li>
</ul>
</li>
</ul>
<h2 id="브라우저의-비동기적-동작">브라우저의 비동기적 동작</h2>
<ul>
<li>JavaScript Runtime Environment에는 WebAPIs, Render, Microtask Queue, Task Queue</li>
<li>브라우저는 Multi Threaded</li>
<li>Event Loop: Event Loop가 콜 스택과 테스크 큐를 반복해서 관찰하여 일을 처리하는데 콜 스택이 모두 비었을때 테스크 큐에 있는 함수 한 개를 콜 스택으로 옮김</li>
</ul>
<h3 id="javascript-runtime-environment">JavaScript Runtime Environment</h3>
<ul>
<li>JS의 Runtime 환경은 WebAPIs, Render, Microtask Queue, Task Queue가 존재</li>
<li>WebAPIs<ul>
<li>브라우저에서 제공하는 API로 브라우저의 멀티쓰레딩을 이용할 수 있음 (ex setTimeout)</li>
<li>사용자가 등록한 콜백함수를 원하는때 task Queue에 삽입</li>
</ul>
</li>
<li>Task Queue<ul>
<li>Web APIs에서 사용자가 등록한 콜백 함수를 특정한 이벤트가 발생했을때 테스크 큐에 삽입</li>
</ul>
</li>
<li>Microtack Queue<ul>
<li>프로미스와 Mutation Observer API가 마이크로태스크 큐를 사용해 콜백을 호출</li>
<li>Event Loop는 task queue의 콜백 함수를 한 개씩만 콜 스택으로 이동시키지만 microtask queue에서는 큐가 모두 비어있는 상태가 될때까지 콜 스택으로 콜백함수를 이동시킴</li>
</ul>
</li>
<li>Render: 주기적으로 브라우저에서 사용자가 요소들을 움직이거나 애니메이션 할때 화면에 업데이트를 함<ul>
<li>Request Animation Frame이라는 API를 사용한 콜백은 Render의 가장 앞부분에 등록된다.</li>
<li>Requset Animation Frame은 브라우저에서 다음 랜더링이 발생하기 전에 해당 콜백이 수행되는 것을 보장</li>
</ul>
</li>
</ul>
<h3 id="microtask-queue와-task-queue-차이점">Microtask Queue와 Task Queue 차이점</h3>
<ul>
<li><p>Task Queue</p>
<pre><code class="language-jsx">  &lt;body&gt;
    &lt;button&gt;Click&lt;/button&gt;
    &lt;script&gt;
      function handleClick(){
        console.log(&#39;handleClick&#39;);
        setTimeout(() =&gt; {
          console.log(&#39;setTimeout&#39;);
          handleClick();
        }, 0);
      }
      const button = document.querySelector(&#39;button&#39;);
      button.addEventListener(&#39;click&#39;, handleClick)
    &lt;/script&gt;
  &lt;/body&gt;

  //handleClick과 setTimeout이 계속해서 출력되고 버튼 클릭등이 계속 가능하다.</code></pre>
<p>  setTimeout 호출 → 콜백함수 호출 → 태스크 큐에 삽입 → 콜 스택 이동 → 콜백 함수 수행 → setTimeout 호출 ..... 반복</p>
</li>
<li><p>Microtask Queue</p>
<pre><code class="language-jsx">  &lt;body&gt;
    &lt;button&gt;Click&lt;/button&gt;
    &lt;script&gt;
      function handleClick(){
        console.log(&#39;handleClick&#39;);
        Promise.resolve(0)
          .then(() =&gt; {
            console.log(&#39;then&#39;);
            handleClick();
          })
      }
      const button = document.querySelector(&#39;button&#39;);
      button.addEventListener(&#39;click&#39;, handleClick)
    &lt;/script&gt;
  &lt;/body&gt;

  //handleClick과 setTimeout이 계속해서 출력되지만 버튼 클릭 등이 작동하지 않는다.</code></pre>
<p>  버튼 클릭 → 콜백함수가 테스크 큐에 삽입 → 콜 스택으로 콜백 함수 이동 → 프로미스 생성 및 프로미스가 완료되었을때 프로미스 then이 마이크로 테스크 큐에 삽입 → 마이크로 테스크 큐에 있는 then을 콜스택으로 이동 →
  then 수행 및 또 다른 then을 마이크로 테스크 큐에 삽입 → 마이크로 테스크 큐에 들어온 새로운 then을 다시 콜 스택에 삽입(마이크로 테스크 큐가 모두 비어있는 상태가 될때까지 반복)</p>
</li>
</ul>
<h1 id="모듈">모듈</h1>
<p>모듈을 사용할 시 스크립트간 의존도 파악이 가능하고 실행 순서를 쉽게 제어할 수 있다.</p>
<h2 id="모듈과-컴포넌트의-차이">모듈과 컴포넌트의 차이</h2>
<ul>
<li>모듈: 설계 시점에 의미있는 요소</li>
<li>컴포넌트: 런타임 시점에 의미있는 요소</li>
</ul>
<h2 id="js의-모듈">JS의 모듈</h2>
<ul>
<li><p>JS의 모듈은 직접적으로 런타임에 실행이 됨</p>
<ul>
<li>제대로된 모듈 역할을 하기 위해 디렉토리 단위를 모듈 개념에 가깝게 사용함</li>
</ul>
</li>
<li><p>JS 모듈의 특징</p>
<ul>
<li><p>항상 use strict로 실행된다.</p>
</li>
<li><p>모듈 레벨 스코프가 있음</p>
<pre><code class="language-html">  &lt;body&gt;
    &lt;script type=&quot;module&quot;&gt;
      let a = 5;
      let b = 10;
      const c = a+b;
    &lt;/script&gt;
    &lt;script type=&quot;moudle&quot;&gt;
      alert(c); //오류 발생
    &lt;/script&gt;
  &lt;/body&gt;</code></pre>
</li>
<li><p>단 한번만 평가됨</p>
<pre><code class="language-html">  &lt;body&gt;
    &lt;script type=&quot;module&quot;&gt;
      import &#39;./hello.js&#39;; // Hello, World 출력
    &lt;/script&gt;
    &lt;script type=&quot;moudle&quot;&gt;
      import &#39;./hello.js&#39;; // 한 번만 평가되기 때문에 출력되지 않음
    &lt;/script&gt;
  &lt;/body&gt;</code></pre>
</li>
<li><p>지연이 됨(defer를 적용한 것과 같다.)</p>
<pre><code class="language-html">  &lt;body&gt;
    &lt;script type=&quot;module&quot;&gt;
      console.log(text); // DOM 생성이 안된 상태, 아직 text가 정의되지 않음
    &lt;/script&gt;
    &lt;script type=&quot;moudle&quot;&gt; 
      console.log(text); // text 출력됨
    &lt;/script&gt;
      &lt;p id=&quot;text&quot;&gt;Hello, World&lt;/p&gt;
  &lt;/body&gt;</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="유니코드">유니코드</h1>
<h2 id="ccs-coded-caracter-set">CCS (Coded Caracter Set)</h2>
<ul>
<li>문자들을 Code Point(정의해둔 정수값)에 대응시켜 만든 코드화된 문자들의 집합 ⇒ Code Point가 Character의 식별자 역할을 함</li>
</ul>
<h2 id="ces-caracter-encoding-scheme">CES (Caracter Encoding Scheme)</h2>
<ul>
<li>CCS를 8bit 집합에 대응시키는 것</li>
<li>CES와 CCS는 1:1로 대응됨</li>
<li>인코딩에 해당됨(UTF-8, euc-kr 등)</li>
</ul>
<h2 id="tes-tranfer-encoding-syntax">TES (Tranfer Encoding Syntax)</h2>
<ul>
<li>인코딩된 문자가 특정 프로토콜을 타고 전송되도록 변환하는 것 ⇒ 통신 프로토콜에 제약이 있을 수 있어 사용함(ex. URL에서 공백은 사용할 수 없어 변환이 필요함)</li>
</ul>
<h2 id="유니코드-1">유니코드</h2>
<ul>
<li>전 세계 문자(이모티콘 포함)를 컴퓨터로 다룰 수 있도록 만든 표준 시스템</li>
<li>다양한 나라가 서로 다른 인코딩 방식을 사용해서 호환성 및 확장성 문제를 해결하기 위해 탄생함</li>
<li>유니코드에서 영어, 한글 모두 2바이트로 읽힘 ⇒ 한글은 한 글자당 길이 1을 차지함</li>
<li>유니코드의 CCS: Code Point 범위(0x0 ~ 0x10FFFF, 1114112개 문자)</li>
<li>유니코드의 CES: Code Point가 어떤 단위로 조합되어 인코딩되는 지 정의한 것</li>
</ul>
<h1 id="정규표현식">정규표현식</h1>
<ul>
<li><p>정규표현식의 목적: 패턴을 이용하여 문자열에서 원하는 문자를 검색, 대체, 추출이 가능하다.</p>
</li>
<li><p>성능은 느리지만 매우 편해서 짧은 문자열의 경우엔 많이 사용한다.</p>
</li>
<li><p>정규표현식 테스트 페이지</p>
<p>  <a href="https://rubular.com/">Rubular</a></p>
</li>
</ul>
<h2 id="정규표현식-표현">정규표현식 표현</h2>
<p>/regexr/i ⇒ /: 시작, 종료 기호, regexr: 패턴, i: 플래그</p>
<h3 id="예시1">예시1</h3>
<ol>
<li>휴대폰 번호 패턴 ⇒ 세 자리 숫자 + 하이픈, 셋 또는 네 자리 숫자 + 하이픈, 네 자리 숫자 패턴으로 이루어져 있음</li>
<li>\d{3} = 세 자리 아무 숫자
\d{3, 4} = 세, 네 자리 아무 숫자
위의 패턴을 조합</li>
<li>\d{3}-\d{3, 4}-\d{4}</li>
</ol>
<h3 id="예시2">예시2</h3>
<ol>
<li>이메일 주소 패턴 ⇒ 문자열, @, 문자열, ., 문자열 패턴으로 이루어져 있음</li>
<li>.+ = 한개 이상의 문자열
(…) = 캡처(그룹으로 묶어주기 때문에 중복 사용이 가능)
이메일 패턴 = .+@.+..+</li>
<li>중간 문자열만 추출하려면?
패턴 = .+@(.+)..+  ⇒ 캡처를 사용하자</li>
</ol>
<h2 id="정규표현식-연습-페이지">정규표현식 연습 페이지</h2>
<p><a href="https://regexone.com/">RegexOne - Learn Regular Expressions - Lesson 1: An Introduction, and the ABCs</a></p>
<p><a href="https://alf.nu/RegexGolf">Regex Golf</a></p>
<h2 id="js에서-정규표현식-사용하기">JS에서 정규표현식 사용하기</h2>
<ul>
<li><p>JS는 RegExp 객체로 정규표현식 기능을 제공함 (Array, Object 처럼 Literal로 생성 가능함)</p>
<pre><code class="language-jsx">  // 생성자 함수 방식
  const regExp1 = new RegExp(&quot;^\d+&quot;);
  const regExp2 = new RegExp(&quot;^\d+&quot;, &quot;gi&quot;);

  // 리터럴 방식
  const regExp3 = /^\d+/;
  const regExp4 = /^\d+/gi;</code></pre>
</li>
</ul>
<h3 id="정규표현식-객체-함수">정규표현식 객체 함수</h3>
<ul>
<li><p>test 함수: 입력받은 문자열에 찾는 패턴이 있는지 찾은 후 있다면 true 반환</p>
<pre><code class="language-jsx">  const msg1 = &quot;안녕하세요 제 전화번호는 010-8741-4496입니다.&quot;;
  const msg2 = &quot;아직 전화번호가 없어요...&quot;

  const regExp1 = /\d{3}-\d{3,4}-\d{4}/;
  const regExp2 = new RegExp(&quot;\\d{3}-\\d{3,4}-\\d{4}&quot;);

  console.log(regExp1.test(msg1)); // true
  console.log(regExp1.test(msg2)); // false

  console.log(regExp2.test(msg1)); // true
  console.log(regExp2.test(msg2)); // false</code></pre>
</li>
<li><p>exec: 입력받은 문자열에 찾는 패턴이 있는지 찾은 후 일치한 패턴 정보를 반환하고 없으면 null을 반환(문자 추출)</p>
<pre><code class="language-jsx">  const msg1 = &quot;안녕하세요 제 전화번호는 010-8741-4496입니다.&quot;;
  const msg2 = &quot;아직 전화번호가 없어요...&quot;

  const regExp1 = /\d{3}-\d{3,4}-\d{4}/;
  const regExp2 = new RegExp(&quot;\\d{3}-\\d{3,4}-\\d{4}&quot;);

  console.log(regExp1.exec(msg1));
  console.log(regExp1.exec(msg2));

  console.log(regExp2.exec(msg1));
  console.log(regExp2.exec(msg2));

  // 패턴이 존재하는 경우
  // [
  //   &#39;010-8741-4496&#39;,
  //   index: 14,
  //   input: &#39;안녕하세요 제 전화번호는 010-8741-4496입니다.&#39;,
  //   groups: undefined
  // ]

  // 패턴이 존재하지 않는 경우
  // null 반환</code></pre>
</li>
</ul>
<h3 id="string-객체-함수">String 객체 함수</h3>
<ul>
<li><p>match: String 객체에서 사용할 수 있는 함수로 정규표현식 객체를 파라미터로 받아 패턴이 있는지 찾은 후 일치하는 패턴 정보를 반환(정규표현식 객체의 exec 함수와 같음)</p>
<pre><code class="language-jsx">  const msg1 = &quot;안녕하세요 제 전화번호는 010-8741-4496입니다.&quot;;
  const msg2 = &quot;아직 전화번호가 없어요...&quot;

  const regExp1 = /\d{3}-\d{3,4}-\d{4}/;
  const regExp2 = new RegExp(&quot;\\d{3}-\\d{3,4}-\\d{4}&quot;);

  console.log(msg1.match(regExp2));
  console.log(msg2.match(regExp1));
  // 출력결과는 exec 함수와 동일</code></pre>
<ul>
<li><p>캡처가 적용된 정규표현식을 이용하면 match 반환값의 1번 인덱스부터 순차적으로 캡처 결과가 들어간다.</p>
<pre><code class="language-jsx">  const msg2 = &quot;010-1234-5677말고 010-2222-2222로 전환주세요.&quot;

  const regExp1 = /(\d{3})-(\d{3,4})-(\d{4})/; 

  console.log(msg2.match(regExp1));
  // [
  //   &#39;010-1234-5677&#39;,
  //   &#39;010&#39;,
  //   &#39;1234&#39;,
  //   &#39;5677&#39;,
  //   index: 0,
  //   input: &#39;010-1234-5677말고 010-2222-2222로 전환주세요.&#39;,
  //   groups: undefined
  // ]</code></pre>
</li>
</ul>
</li>
<li><p>replace: 정규표현식 객체를 파라미터로 받아 패턴이 있는지 찾은 후 일치한 패턴 정보를 원하는 문자열로 바꿈(문자열 대체)</p>
<pre><code class="language-jsx">  const msg1 = &quot;안녕하세요 제 전화번호는 010-8741-4496입니다.&quot;;
  const msg2 = &quot;010-1234-5677말고 010-2222-2222로 전환주세요.&quot;

  const regExp1 = /\d{3}-\d{3,4}-\d{4}/g; // 옵션으로 g를 붙이면 패턴에 맞는 모든 문자열이 변경됨
  const regExp2 = new RegExp(&quot;\\d{3}-\\d{3,4}-\\d{4}&quot;);

  console.log(msg1.replace(regExp2, &quot;전화번호&quot;)); // 안녕하세요 제 전화번호는 전화번호입니다.
  console.log(msg2.replace(regExp2, &quot;전화번호&quot;)); // 전화번호말고 010-2222-2222로 전환주세요.
  console.log(msg2.replace(regExp1, &quot;전화번호&quot;)); // 전화번호말고 전화번호로 전환주세요.</code></pre>
</li>
<li><p>search: 정규표현식 객체를 파라미터로 받아 패턴이 있는지 확인 후, 일치한 패턴 정보의 위치를 반환(문자 검색)</p>
<pre><code class="language-jsx">  const msg1 = &quot;안녕하세요 제 전화번호는 010-8741-4496입니다.&quot;;
  const msg2 = &quot;010-1234-5677말고 010-2222-2222로 전환주세요.&quot;

  const regExp1 = /\d{3}-\d{3,4}-\d{4}/g; // 옵션으로 g를 붙이면 패턴에 맞는 모든 문자열이 변경됨
  const regExp2 = new RegExp(&quot;\\d{3}-\\d{3,4}-\\d{4}&quot;);

  console.log(msg1.search(regExp2)); // 14
  console.log(msg2.search(regExp1)); // 0, 옵션에 상관 없이 처음 매칭된 값을 반환함</code></pre>
</li>
<li><p>개미 수열</p>
<ul>
<li><p>수학적인 수열 중 하나로, 이전 항에서 반복되는 숫자들의 개수를 나타내는 수열</p>
</li>
<li><p>개미 수열의 시작은 항상 1 이고 다음 항부터는 이전 항에서 반복되는 숫자들의 개수를 순서대로 기록함, 각 숫자의 개수는 해당 숫자를 연속해서 나타내는 횟수를 의미</p>
<ul>
<li>예시</li>
</ul>
<ol>
<li>1 ⇒ 시작은 1</li>
<li>11 ⇒ 첫 번째 항의 수 1은, 1개의 1</li>
<li>21 ⇒ 두 번째 항의 수 11은, 2개의 1</li>
<li>1211 ⇒ 세 번째 항의 수 21은, 1개의 2, 1개의 1</li>
<li>111221 ⇒ 네 번째 항의 수 1211은, 2개의 1, 1개의 2, 1개의 1</li>
</ol>
</li>
<li><p>정규표현식으로 풀어보기</p>
<pre><code class="language-jsx">  function getAntSeq(n) {
    let seq = &#39;1&#39;;

    for (let i = 1; i &lt; n; i++) {
      // \1*은 캡처된 문자와 동일한 문자들의 반복을 의미
      seq = seq.replace(/(.)\1*/g, match =&gt; match.length + match[0]);
    }

    return seq;
  }

  console.log(getAntSeq(5)); // 출력: 111221</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="쿠키와-세션-웹-스토리지">쿠키와 세션, 웹 스토리지</h1>
<h2 id="http-통신">HTTP 통신</h2>
<ul>
<li>HTTP Request는 기본적으로 상태가 존재하지 않음</li>
<li>서버는 어떤 브라우저에서 요청이 온 것인지 알 수 없는데 이를 해결하기위해 헤더에 쿠키를 담아서 요청하면 서버가 어디서 요청이 온 것인지 알 수 있음</li>
</ul>
<h2 id="cookie쿠키">Cookie(쿠키)</h2>
<ul>
<li>클라이언트에서 저장, 관리하는 데이터로 브라우저를 닫아도 데이터 유지가 가능함</li>
<li>서버가 Set-Cookie를 응답 헤더로 내려주면 클라이언트는 받아서 저장</li>
<li>클라리언트에서 자체적으로 조작 가능</li>
<li>각 상태에 수명 설정 가능</li>
</ul>
<h3 id="set-cookie">Set-Cookie</h3>
<ul>
<li>키와 값, 옵션을 가지고 있음</li>
<li>응답 헤더에 담으면 브라우저가 알아서 저장</li>
<li>옵션<ul>
<li>Expires: 쿠키 만료 날짜 지정</li>
<li>Secure: HTTPS에서만 쿠기 전송</li>
<li>HttpOnly: JS에서 쿠키 접근을 막음 ⇒ XSS 공격을 막을 수 있음</li>
<li>Max-Age: 쿠키 수명을 설정(Expires 설정은 무시됨)</li>
<li>Domain: 도메인이 일치하는 요청만 쿠키를 전송</li>
<li>Path: 패스와 일치하는 요청만 쿠기를 전송</li>
</ul>
</li>
</ul>
<h3 id="쿠키의-취약점">쿠키의 취약점</h3>
<ul>
<li>XSS(Cross-Site Script, JS를 사용해 다른 사용자의 쿠키 값을 탈취하는 것)공격을 당할 수 있음<ul>
<li>HttpOnly로 막을 수 있지만 최근 SPA로 웹페이지를 제작하기 때문에 사용이 어려움</li>
<li>쿠키를 암호화하지 않고 보낼 경우 쿠키값을 중간에 탈취 당할 수 있음 ⇒ HTTPS를 이용하여 해결함</li>
</ul>
</li>
</ul>
<h2 id="session세션">Session(세션)</h2>
<ul>
<li>쿠기에 HTTP Session ID를 식별자로 담아 보내면 해당 식별자로 서버는 사용자를 구분한</li>
<li>클라리언트는 HTTP Session ID를 쿠키 형태로 저장</li>
<li>서버 자체적으로 기록하고 관리</li>
</ul>
<h3 id="세션의-문제점">세션의 문제점</h3>
<ul>
<li>세션은 서버에 파일로 저장되기 때문에 사용자가 많은 경우 저장 공간에 한계가 생긴다</li>
<li>서버가 2대일 경우 세션 관리가 어려움</li>
</ul>
<p>⇒ 이러한 문제를 해결하기위해 서버와 클라이언트 간의 인증은 JWT같은 별도 토큰을 이용하고 쿠키관리 는 클라이언트 자체적으로 지속적인 데이터 관리 용도로 많이 사용함</p>
<h2 id="웹-스토리지">웹 스토리지</h2>
<ul>
<li>클라이언트에 데이터를 저장하기 위해 쿠키 대신 등장한 새로운 방법</li>
<li>HTML5부터 등장</li>
<li>쿠키에서 하기 힘든 것들을 지원함</li>
<li>로컬 스토리지와 세션 스토리지가 있음<ul>
<li>로컬 스토리지<ul>
<li>로컬 스토리지에 저장된 데이터는 반영구적으로 데이터가 저장됨</li>
<li>브라우저를 종료해도 데이터가 남음</li>
<li>저장했던 도메인과 이용하는 도메인이 다른 경우엔 접근할 수 없음</li>
<li>Key와 Value 형태로 저장</li>
</ul>
</li>
<li>세션 스토리지<ul>
<li>새 창을 생성할 때마다 개별적으로 저장되는 데이터</li>
<li>브라우저를 닫는 순간 사라짐</li>
<li>같은 도메인이어도 세션이 다르면 데이터에 접근할 수 없음</li>
<li>Key와 Value 형태로 저장</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="indexed-db">Indexed DB</h2>
<ul>
<li>Transactional한 로컬 데이터베이스로 새로운 웹 브라우저 표준 인터페이스</li>
<li>브라우저에서 데이터를 영구적으로 저장하고 검색하기 위한 웹 스토리지 기술 ⇒ 클라이언트 측에 대량의 구조화된 데이터를 저장할 수 있는 고급 웹 스토리지 솔루션</li>
<li>RDB와 유사한 개념을 가지고 있으며 Key와 Value 형태로 저장</li>
<li>JS API를 통해 사용되며 웹 애플리케이션에서 데이터를 영구적으로 저장하고 쿼리가 가능</li>
<li>객체 스토어(Object Store)라는 개념을 사용하여 데이터를 저장, 객체 스토어는 테이블과 비슷한 개념으로 이해으로 각 객체 스토어에는 Key-Value 쌍이 저장</li>
<li>데이터 검색을 위한 인덱스를 지원</li>
<li>비동기 작업이 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데브코스] 프론트엔드 엔지니어링 TIL(1일차)]]></title>
            <link>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@foxrain_gg/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-TIL1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 02 Jun 2023 06:57:11 GMT</pubDate>
            <description><![CDATA[<h1 id="프론트엔드-개발자-관련">프론트엔드 개발자 관련</h1>
<h2 id="프론트엔드-개발자의-핵심-역량">프론트엔드 개발자의 핵심 역량</h2>
<ul>
<li>커뮤니케이션: 프론트엔드 개발자는 다른 직군과 협업을 위한 소통 능력이 상당히 중요하다.</li>
<li>UI</li>
<li>네트워크</li>
<li>보안</li>
<li>브라우저</li>
<li>디자인</li>
</ul>
<h2 id="프론트엔드-개발자가-주의할-점">프론트엔드 개발자가 주의할 점</h2>
<ul>
<li>컴퓨터 과학 파트를 무시하는 것: 알고리즘, 설계 패턴, 메모리와 같은 부분은 어떤 개발자도 꼭 필요함</li>
<li>CSS를 안하는 것: CSS를 대충 공부하는 것</li>
<li>코더가 되는 것: 오로지 프레임워크나 라이브러리의 기능을 가져다 쓰기만 하는 것(복잡한 제품을 만들 수 없게 된다.)</li>
</ul>
<h1 id="변수">변수</h1>
<h2 id="var">var</h2>
<ul>
<li><p>변수를 선언하기도 전에 값 할당이 가능하다. (var hoisting: 선언의 위치와 상관 없이 제일 위로 선언을 끌어올림)
hoisting: 인터프리터가 코드를 로드할때 변수의 선언을 항상 코드 내의 최상위로 끌어올리는 것을 의미함. 선언과 동시에 대입하는 코드는 호이스팅하지 않는다.(선언부는 호이스팅하지만 대입부는 호이스팅하지 않는다.)</p>
</li>
<li><p>중복 선언이 가능하다.</p>
<pre><code class="language-jsx">  var name = &#39;Hong&#39;;
  console.log(name); //Hong

  var name = &#39;GunWoo&#39;;
  console.log(name); //GunWoo</code></pre>
</li>
<li><p>함수 레벨 스코프를 가진다.</p>
<pre><code class="language-jsx">  function func() {
      if (true) {
          var a = 5;
          console.log(a); //5
      }
      console.log(a); //5
  }

  func()
  console.log(a); //Uncaught ReferenceError: a is not defined</code></pre>
</li>
</ul>
<h2 id="let">let</h2>
<ul>
<li><p>호이스팅이 발생하지만 JS내부에서 코드 실행 전 변수 선언만 해둘뿐 초기화는 코드 실행 과정에서 변수 선언문을 만났을 때 수행 →
변수 선언 전에 값 할당이 불가능하다.(변수 선언문을 만나기 전까지는 변수 값을 참조할 수 없다.)</p>
</li>
<li><p>중복 선언이 불가능하다.</p>
</li>
<li><p>블록 레벨 스코프를 가진다.</p>
<pre><code class="language-jsx">  function func() {
      if (true) {
          let a = 5;
          console.log(a); // 5
      }
      console.log(a); //Uncaught ReferenceError: a is not defined
  }

  func();
  console.log(a); //Uncaught ReferenceError: a is not defined</code></pre>
</li>
</ul>
<h2 id="var과-let의-블록-스코프-차이">var과 let의 블록 스코프 차이</h2>
<pre><code class="language-jsx">{
    var a = 3;
    console.log(a); //3
}

console.log(a); //3</code></pre>
<pre><code class="language-jsx">{
    let a = 3;
    console.log(a); //3
}

console.log(a); //Uncaught ReferenceError: a is not defined</code></pre>
<h2 id="var과-let의-차이점">var과 let의 차이점</h2>
<ul>
<li>var은 변수를 선언하기도 전에 값 할당이 가능하다. (var hoisting: 선언의 위치와 상관 없이 제일 위로 선언을 끌어올림)</li>
<li>var은 block scope가 없다.</li>
</ul>
<p>scope란 밖에서는 안이 보이지 않고 안에서만 밖을 볼 수 있는 것을 말한다.</p>
<h1 id="상수">상수</h1>
<ul>
<li>security (보안성이 좋다.)</li>
<li>thread safety (쓰레드들에서 동시에 값 변경이 불가능하다)</li>
<li>reduce human mistake (실수를 막을 수 있다.)</li>
<li>const문으로 선언한 상수 값은 수정할 수 없지만, 상수 값이 객체이거나 배열일 경우에는 프로퍼티 또는 프로퍼티 값을 수정할 수 있다.</li>
</ul>
<h1 id="자료형">자료형</h1>
<ul>
<li>Number<ul>
<li>정수, 실수 등 수를 의미함</li>
<li>NaN, Infinity도 Number타입이다</li>
</ul>
</li>
<li>String: 문자열을 의미</li>
<li>Boolean: true, false</li>
<li>Object: 여러 값을 키-값 형태로 결합시킨 복합 타입</li>
<li>Array: 연관된 데이터를 연속적인 형태로 저장하는 복합 타입</li>
<li>Function</li>
<li>Undefined<ul>
<li>변수, 상수가 선언되었지만 값이 대입되지 않은 경우</li>
<li>값이 정의되지 않은 상태를 의미</li>
</ul>
</li>
<li>Null<ul>
<li>null을 직접 지정한 경우</li>
<li>해당 변수가 비어있음을 사용자가 의도적으로 나타낼 때 사용</li>
</ul>
</li>
</ul>
<p>false로 판정되는 값들: false, undefined, null, 0, NaN, ‘’(빈 문자열)</p>
<h1 id="메모리">메모리</h1>
<ul>
<li><p>할당 → 사용 → 해제
3가지 과정을 거침</p>
</li>
<li><p>JS 엔진은 Garbage Collector를 통해 메모리를 정리한다.</p>
</li>
<li><p>Gabage Collector</p>
<ul>
<li><p>Gabage Collection이라는 자동 메모리 관리 알고리즘을 통해 만들어진 객체</p>
</li>
<li><p>사용하지 않는 메모리를 해제하는 역할을 한다.</p>
<ul>
<li><p>Mark and Sweep Algorithm을 사용</p>
<ul>
<li><p>닿을 수 없는 주소를 더 이상 필요없는 주소로 정의하고 지우는 알고리즘</p>
</li>
<li><p>예시</p>
<pre><code class="language-jsx">let a = 126
  let b = a
  a = a + 1
  b = a + 1
  // 위의 경우 126을 참조하는 변수가 없기 때문에 GC가 126이 할당된 메모리를 정리한다.</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>JS에서 원시타입은 변경이 불가능하다. → 원시 타입의 값이 변경될 때는 새로운 메모리가 할당된다.</p>
<pre><code class="language-jsx">  let variable = 126 // 주소: 111
  let variable2 = variable //variable2는 variable의 주소를 가리키고 있는 상태(주소: 111)
  variable = variable + 1 // 주소:111의 값이 변경되지 않고 variable은 주소: 112를 가리킴(값은 127)</code></pre>
</li>
<li><p>JS의Virtual Machine(가상 머신)의 메모리 모델</p>
<ul>
<li><p>Heap: 참조타입이 들어감, 동적으로 크기 변경이 가능함</p>
</li>
<li><p>Call Stack: 원시타입이 들어감</p>
</li>
<li><p>예시</p>
<pre><code class="language-jsx">  let a = 10; // call stack
  let b = 20; // call stack
  const arr = []; // Heap (call stack에서 생성된 배열 변수 arr이 Heap의 배열 영역을 메모리 주소를 참조)
  arr.push(5); // Heap 메모리를 변경하는 것이기 때문에 상수여도 push가 동작함
  arr.push(3);
  arr.push(1);</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="배열과-객체">배열과 객체</h1>
<h2 id="배열">배열</h2>
<h3 id="배열-생성">배열 생성</h3>
<pre><code class="language-jsx">const arr1 = new Array();
const arr2 = [];
const arr3 = [1, 2, 3, 4, 5];
const arr4 = new Array(5);
const arr5 = new Array(5).fill(5); // [5, 5, 5, 5, 5]
const arr6 = Array.from(Array(5), function(v, idx) {
  return idx + 1;
}) // [1, 2, 3, 4, 5]</code></pre>
<h3 id="배열-요소-추가-삭제">배열 요소 추가, 삭제</h3>
<pre><code class="language-jsx">const arr = [1, 2, 3];
// push 배열 끝에 새로운 요소 추가
arr.push(4); // [1, 2, 3, 4]

// pop 배열 끝의 요소 삭제
arr.pop(); // [1, 2, 3]

// shift 배열 맨 앞의 요소 삭제
arr.shift(); // [2, 3]

// unshift 배열 맨 앞에 요소 추가
arr.unshift(1); // [1, 2, 3]</code></pre>
<h3 id="배열-관련-함수">배열 관련 함수</h3>
<pre><code class="language-jsx">const joinArr = [1, 2, 3, 4, 5, 6];
// join
console.log(joinArr.join(&quot;, &quot;)); // 1, 2, 3, 4, 5, 6

// reverse
console.log(joinArr.reverse()); // [ 6, 5, 4, 3, 2, 1 ]
console.log(joinArr); // [ 6, 5, 4, 3, 2, 1 ] =&gt; 원본 배열에도 영향을 준다.

// concat
const a = [1, 2, 3];
const b = [4, 5, 6];
console.log(a.concat(b)); // [ 1, 2, 3, 4, 5, 6 ]

// slice
const arr = [1, 2, 3, 4, 5, 6];
// 첫 번째 인자: 시작점, 두 번째 인자: 끝나는 점
console.log(arr.slice(2, 4)); // [ 3, 4 ]
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ] =&gt; 원본 배열이 변하지 않음

// splice: 중간의 요소 삭제
arr.splice(2, 2); // 첫 번째 인자: 시작점, 두 번째 인자: 삭제할 개수
console.log(arr); // [ 1, 2, 5, 6 ]</code></pre>
<h3 id="배열-순회">배열 순회</h3>
<pre><code class="language-jsx">for (let i = 0; i &lt; 5; i += 1) {
  console.log(arr[i]);
}

// 추천하는 방식
for (const item of arr) {
  console.log(item);
}</code></pre>
<h3 id="배열을-객체처럼-사용한다">배열을 객체처럼 사용한다?</h3>
<pre><code class="language-jsx">const arr = [1, 2, 3, 4, 5];
console.log(typeof arr); //object 출력 =&gt; 배열은 객체 타입이다.
arr[&#39;key&#39;] = &#39;value&#39;;
console.log(arr); // [ 1, 2, 3, 4, 5, key: &#39;value&#39; ]
console.log(arr.length); // 5 =&gt; key가 추가되었지만 배열의 길이는 변하지 않는다.</code></pre>
<h2 id="객체">객체</h2>
<p>여러 값을 키-값 형태로 결합시킨 복합 타입</p>
<h3 id="객체-생성">객체 생성</h3>
<pre><code class="language-jsx">const obj1 = new Object();
const obj2 = {};
const obj3 = {name: &#39;Gun&#39;, company: &#39;dev&#39;};</code></pre>
<h3 id="객체-요소-추가-삭제">객체 요소 추가, 삭제</h3>
<pre><code class="language-jsx">const obj = {};
obj[&quot;email&quot;] = &quot;foxrain.gg@gmail.com&quot;; // 요소 추가 방법1
obj.phone = &#39;01012345678&#39;; // 요소 추가 방법2
console.log(obj); // { email: &#39;foxrain.gg@gmail.com&#39;, phone: &#39;01012345678&#39; }

delete obj.phone;
console.log(obj); // { email: &#39;foxrain.gg@gmail.com&#39; }

// 객체 요소 유무 확인 방법
console.log(&#39;email&#39; in obj); // true
console.log(&#39;phone&#39; in obj); // false</code></pre>
<h3 id="객체의-키-값의-집합-구하기">객체의 키, 값의 집합 구하기</h3>
<pre><code class="language-jsx">const obj = {
  email: &quot;foxrain.gg@gmail.com&quot;,
  phone: &quot;01012345678&quot;,
};

// 키의 집합
console.log(Object.keys(obj)); // [ &#39;email&#39;, &#39;phone&#39; ]
// 값의 집합
console.log(Object.values(obj)); // [ &#39;foxrain.gg@gmail.com&#39;, &#39;01012345678&#39; ]</code></pre>
<h3 id="객체-순회">객체 순회</h3>
<pre><code class="language-jsx">const obj = {
  email: &quot;foxrain.gg@gmail.com&quot;,
  phone: &quot;01012345678&quot;,
};

// for in은 객체의 키 값을 순회함
for (const key in obj) {
  console.log(key, obj[key]);
    // 1번째 실행: email foxrain.gg@gmail.com
    // 2번째 실행: phone 01012345678
}</code></pre>
<h1 id="스코프와-클로저">스코프와 클로저</h1>
<h2 id="스코프유효-범위">스코프(유효 범위)</h2>
<p>변수가 어느 범위까지 참조되는 지를 뜻함</p>
<pre><code class="language-jsx">const a = 5; // Global Scope
{
    const b = 3; // Local Scope
    console.log(a, b); // 5 3
}
console.log(a, b); // Error</code></pre>
<h2 id="클로저">클로저</h2>
<p>함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될 때에도 기억한 스코프에 접근할 수 있게 만드는 문법</p>
<pre><code class="language-jsx">function makeGreeting(name) {
  const greeting = &quot;Hello, &quot;;

  return function() {
    console.log(greeting + name);
  };
}

const world = makeGreeting(&quot;World!&quot;);
const gunwoo = makeGreeting(&quot;GunWoo&quot;);

world();
gunwoo();</code></pre>
<ul>
<li>greeting 변수는 지역 스코프라서 함수가 종료되면 메모리에서 사라지지만 word(), gunwoo()에서 사용할 수 있다.</li>
</ul>
<h3 id="은닉화">은닉화</h3>
<p>클로저를 사용하여 내부 변수와 함수를 숨길 수 있다.</p>
<pre><code class="language-jsx">function Counter() {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }

  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    getValue: function() {
      return privateCounter;
    },
  }
}

const counter = Counter();
const counter2 = Counter();

console.log(counter.getValue()); // 0
counter.increment();
counter.increment();
console.log(counter.getValue()); // 2
counter.decrement();
console.log(counter.getValue()); // 1

console.log(counter2.getValue()); // 0 =&gt; 별개의 클로저</code></pre>
<h3 id="클로저-관련-오류">클로저 관련 오류</h3>
<pre><code class="language-jsx">function counting() {
  let i = 0;
  for (i = 0; i &lt; 5; i += 1) {
    setTimeout(function () {
      console.log(i);
    }, i * 100);
  }
}

counting(); // 5가 다섯번 출력됨
// setTimeout의 대기시간이 끝나 callback fuction이 실행되는 시점에는 루프가 종료되어
// i가 5인 상태이기 때문이다.</code></pre>
<h4 id="해결방법-1">해결방법 1</h4>
<p>IIFE(Immediately Invoked Function Expression, 즉시 실행 함수)를 사용한다.</p>
<pre><code class="language-jsx">function counting() {
  let i = 0;
  for (i = 0; i &lt; 5; i += 1) {
    (function (number) {
      setTimeout(function () {
        console.log(number);
      }, number * 100);
    })(i);
  }
}

counting(); //0 1 2 3 4 출력</code></pre>
<h4 id="해결방법-2">해결방법 2</h4>
<p>let을 사용한다. ⇒ let은 블록 수준 스코프이기 때문에 매 루프마다 클로저가 생성된다.</p>
<pre><code class="language-jsx">function counting() {
  for (let i = 0; i &lt; 5; i += 1) {
    setTimeout(function () {
      console.log(i);
    }, i * 100);
  }
}

counting(); //0 1 2 3 4 출력</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[PWA(Progressive Web Apps)란?]]></title>
            <link>https://velog.io/@foxrain_gg/PWAProgressive-Web-Apps%EB%9E%80</link>
            <guid>https://velog.io/@foxrain_gg/PWAProgressive-Web-Apps%EB%9E%80</guid>
            <pubDate>Fri, 14 Apr 2023 15:26:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/407daa6c-e7f7-485a-83b9-63039ed6ce3c/image.png" alt="">
최근 IOS 버전 16.4에 웹 앱 알림를 지원하는 기능에 추가되었다. 그래서 웹 개발자들 사이에서 PWA에 대한 기대감이 커지고 있는데 PWA는 무엇일까?</p>
<h1 id="pwa">PWA</h1>
<p>PWA는 프로그레시브 웹 앱(progressive web app)의 준말로, 웹 기술(HTML, CSS, Javascript)을 가지고 모바일 네이티브 앱과 비슷하게 만들 수 있는 기술을 말한다.(Apple은 PWA를 웹 응용 프로그램이라고 부르기도한다.)
모바일 웹 사이트와 네이티브 앱의 중간 형태로, 모바일 앱과 웹 사이트의 장점을 결합하여 사용자 친화적인 앱 경험을 제공할 수 있다고 한다.</p>
<blockquote>
<p>즉 PWA은 HTML, CSS, JavaScript를 포함한 일반적인 웹 기술을 사용하여 개발된 응용 프로그램 소프트웨어이며 표준적인 웹 브라우저를 포함한 모든 플랫폼에서 작동한다. </p>
</blockquote>
<p>사용자의 관점에서 PWA는 App Store나 Play store에서 다운로드하지 않고도 장치의 홈 화면에 추가할 수 있는 웹 사이트에 비유할 수 있다.</p>
<p>사실 iOS는 PWA의 아이디어를 지원하는 최초의 플랫폼이었다. iPhone이 처음 소개되었을 때 App Store가 아직 존재하지 않았고 초기 앱은 HTML5를 사용하여 제작되었다. 하지만 App Store가 도입된 후 PWA에 대한 Apple의 지원이 줄어들기 시작했고 최근에서야 다시 PWA에 대한 지원이 추가된 것이다.</p>
<h2 id="장점">장점</h2>
<ul>
<li>빠른 성능을 제공한다.</li>
<li>앱 스토어를 거치지 않아도 웹 브라우저에서 바로 앱을 사용할 수 있다.</li>
<li>앱 스토어를 거치지 않아도 앱 업데이트가 자동으로 이루어진다.</li>
<li>오프라인에서도 작동이 가능하다.</li>
<li>검색 엔진 최적화(SEO)에 유리하다.</li>
<li>모바일 앱과 웹의 장점을 모두 활용할 수 있다.</li>
</ul>
<h2 id="단점">단점</h2>
<ul>
<li>아직 모든 기능이 네이티브 앱과 같지는 않다. OS에서 지원하지 않는 경우 하드웨어 접근이나 네이티브 기능에 대한 제한이 있을 수 있다. 따라서 사용자 경험이 모든 디바이스에서 동일하지 않을 수 있다.</li>
<li>브라우저에서 실행되기 때문에 네이티브 앱에 비해서 지연 속도가 크고 배터리 소모량이 더 많을 수 있다.</li>
</ul>
<h1 id="pwa-도입-사례">PWA 도입 사례</h1>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/c45ea3f7-fc94-4ab4-9a4e-4a9b3b9de13c/image.png" alt=""></p>
<blockquote>
<p>출처: <a href="https://noogoonaa.tistory.com/108">https://noogoonaa.tistory.com/108</a></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/foxrain_gg/post/0f7bd035-91b9-4c41-a8ef-bff66c2927c7/image.png" alt=""></p>
<blockquote>
<p>출처: <a href="https://www.joinc.co.kr/w/man/12/pwa">https://www.joinc.co.kr/w/man/12/pwa</a></p>
</blockquote>
<p>Pinterest : 전체 모바일 사이트를 PWA로 재구성했다. 핵심 참여자가 60% 증가했으며, 사용자 광고수익도 44% 증가했다.
Tinder : 로딩시간을 11.91초에서 4.69초로 줄였다. PWA는 안드로이드앱보다 90% 작은 크기를 유지한다.
Uber : 2G에서도 빠르게 작동하도록 설계했다. 기본앱은 50k이며, 2G 네트워크에서도 3초이내에 로드 할 수 있다.</p>
<h1 id="pwa의-미래">PWA의 미래</h1>
<p>PWA는 현재 구글과 함께 마이크로소프트, 모질라 등 많은 기업들이 참여하고 있다.
구글은 PWA기술을 통해 크롬 OS를 성장시키고 발전 시킬 가능성이 있으며, 마이크로소프트는 부진했던 모바일 시장에 진입할 수 있는 통로가 될 수 있기 때문이다.
<img src="https://velog.velcdn.com/images/foxrain_gg/post/4218ff41-3b0d-4944-a9e8-a6d3a2f4cd96/image.png" alt=""></p>
<blockquote>
<p>출처: <a href="https://www.donga.com/news/Economy/article/all/20220705/114307914/1">https://www.donga.com/news/Economy/article/all/20220705/114307914/1</a>
[구글 “카톡, 인앱결제 위반” 업데이트 거부… “소비자 볼모 기싸움”]</p>
</blockquote>
<p>또한 요즘 많은 기업들이 App store, Play store의 인앱결제 수수료에 불만을 가지고 있어 법적 싸움까지 가는 경우가 많아지고 있다. PWA는 앱 스토어를 거치지 않고 사용자에게 바로 브라우저를 통해 앱을 제공할 수 있기 때문에 인앱결제 수수료에 대해 고민하고 있는 많은 기업들의 대안이 될 수 있다.
물론 OS에서 지원해주지 않는 이상 PWA는 힘을 쓸 수 없지만 기업과 사용자의 지속적인 요구에 PWA에 대한 OS의 지원은 지속적으로 이루어질 것이라 예상되고 PWA의 미래는 밝다고 개인적으로 생각한다.</p>
]]></description>
        </item>
    </channel>
</rss>