<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sj_dev_js.log</title>
        <link>https://velog.io/</link>
        <description>JavaScript TypeScript React Next.js</description>
        <lastBuildDate>Tue, 09 Jan 2024 07:43:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sj_dev_js.log</title>
            <url>https://images.velog.io/images/sj_dev_js/profile/1d46edcf-c22a-44b2-8bb4-c1914331bd52/프사.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sj_dev_js.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sj_dev_js" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Next.js 14] Routing : Defining Routes]]></title>
            <link>https://velog.io/@sj_dev_js/Next.js-14-Routing-Defining-Routes</link>
            <guid>https://velog.io/@sj_dev_js/Next.js-14-Routing-Defining-Routes</guid>
            <pubDate>Tue, 09 Jan 2024 07:43:24 GMT</pubDate>
            <description><![CDATA[<h2 id="defining-routes">Defining Routes</h2>
<p><a href="https://nextjs.org/docs/app/building-your-application/routing/defining-routes">https://nextjs.org/docs/app/building-your-application/routing/defining-routes</a></p>
<p>이 페이지는 route 들을 어떻게 정의하고 구성해야하는지 안내합니다.</p>
<h3 id="creating-routes">Creating Routes</h3>
<p>Next.js 는 폴더들이 routes를 정의하는, 파일시스템을 기반으로 하는 라우터를 사용합니다.
각 폴더는 route segment 를 나타내고 URL segment 에 매핑됩니다. nested route (중첩된 경로) 를 사용하기 위해서는 폴더를 중첩시키면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/1ba57468-c534-4ee0-87d8-f5f87ca0abbc/image.avif" alt="중첩"></p>
<p>page.js 파일은 route segment 들을 접근 가능하도록 만듭니다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/0e4a2763-6222-4c02-bd7e-7d44ae8ff44d/image.avif" alt="page"></p>
<p>예를 들어, <code>/dashboard/analytics</code> URL path 는 웹에서 접근할 수 없습니다. 대응하는 page.js 파일이 없기 때문입니다. 이 폴더는 단지 컴포넌트, 스타일시트, 이미지 등등을 저장할수 있을 뿐입니다.</p>
<h3 id="creating-ui">Creating UI</h3>
<p>특정 파일들에 대한 규칙은 각 route segment 들의 UI를 만드는데 사용됩니다. 흔히 page 파일들은 route 에 대한 유일한 UI를 보여줍니다. 그리고 layout 파일은 route 들간에 공유되는 UI 를 보여줍니다.</p>
<p>예를들어, 첫번째 파일을 만들기 위해서는 <code>page.js</code> 파일을 <code>app</code> 폴더 안에 만들고 React component 를 export 해야합니다.</p>
<pre><code class="language-typescript">export default function Page() {
  return &lt;h1&gt;Hello, Next.js!&lt;/h1&gt;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js 14] Routing]]></title>
            <link>https://velog.io/@sj_dev_js/Next.js-14-Routing</link>
            <guid>https://velog.io/@sj_dev_js/Next.js-14-Routing</guid>
            <pubDate>Tue, 09 Jan 2024 02:01:36 GMT</pubDate>
            <description><![CDATA[<h1 id="routing-fundamentals">Routing Fundamentals</h1>
<p>모든 어플리케이션의 뼈대는 라우팅입니다. 이번 페이지에서는 라우팅 구조 그리고 Next.js에서 라우팅을 어떻게 다루는지를 소개합니다.</p>
<h3 id="terminology">Terminology</h3>
<p>당신은 문서내내 아래와 같은 용어들을 보게 될 것입니다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/6d7754d2-d95a-4ca1-9128-ebc1636ae66a/image.png" alt="tree"></p>
<ul>
<li>Tree: 계층적 구조를 형상화하는 용어. 예를 들어 부모 컴포넌트와 자식 컴포넌트 그리고 폴더 구조로 이루어진 것을 컴포넌트 트리라고 부릅니다.</li>
<li>SubTree: 트리의 일부, 새 root 에서 시작해서 leave 로 끝납니다.</li>
<li>Root: Tree 혹은 SubTree 의 첫번째 노드, root layout(후술) 처럼요.</li>
<li>Leaf: 자식이 없는 노드. URL path 의 마지막 segment 같은 것이요.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/87563422-6522-4c17-b1e0-77d0e23f9343/image.avif" alt="url"></p>
<ul>
<li>URL Segment: URL path 를 <code>/(슬래시)</code> 로 나눈 부분들입니다.</li>
<li>URL Path: URL 중 domain 이후에 오는 부분입니다. (segment 들로 이루어져있음)</li>
</ul>
<h3 id="the-app-router">The app Router</h3>
<p>버전 13에서 <a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">React Server Components</a> 를 기반으로 하고, shared layouts, nested routing, loading states, error handling 등을 지원하는 새로운 App Router 를 소개해드렸었죠.</p>
<p>App Router 는 <code>app</code> 이라는 이름의 폴더에서 동작합니다. <code>app</code> 디렉토리는 <code>pages</code> 디렉토리와 함께 작동함으로써 점진적 적용을 가능하게 합니다. 어떤 경로들은 app에서 작동하게 하고, 다른 경로들은 pages에서 작동하도록 할 수 있죠. 당신의 어플리케이션이 <code>pages</code> 폴더도 사용한다면 <a href="https://nextjs.org/docs/pages/building-your-application/routing">Pages Router</a> 문서도 봐주세요.</p>
<blockquote>
<p>Good to know: App router 가 Pages Router 보다 우선권을 가집니다. 같은 경로를 두 Router 에서 동시에 사용하는 것은 허용되지 않으며, 에러를 막기위해 빌드타임 에러가 발생합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/a79cb46b-55c4-4496-bf21-a9b75ed9c985/image.avif" alt="router"></p>
<p>기본적으로 <code>app</code> 폴더 안의 컴포넌트들은 전부 React Server Components 들 입니다. 이것은 성능 최적화되며 아주 쉽게 그것들을 사용할 수 있습니다. 그리고 Client Component 들도 사용할 수 있습니다.</p>
<h3 id="roles-of-folders-and-files">Roles of Folders and Files</h3>
<p>Next.js 는 파일시스템에 기반한 라우터를 사용합니다:</p>
<ul>
<li>폴더들은 route(경로)를 정의하는데 사용됩니다. 중첩된 폴더들의 파일 구조를 따라 root 폴더에서 leaf 폴더로 내려가며 만들어지는 path가 route 가 됩니다. <a href="https://nextjs.org/docs/app/building-your-application/routing/defining-routes">Defining Routes</a> 문서를 참고해주세요.</li>
<li>파일들은 route segment의 UI 를 만드는데 사용됩니다.</li>
</ul>
<h3 id="route-segments">Route Segments</h3>
<p>route 의 각 폴더는 각각 route segment 를 나타냅니다. 각 route segment 는 URL path의 segment 들에 대응됩니다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/2828cdc7-c07f-4291-aed6-0f2f94ad2e62/image.avif" alt="corresponding"></p>
<h3 id="nested-routes">Nested Routes</h3>
<p>nested route 를 만들기 위해, 당신은 폴더들을 중첩시킬 수 있습니다. 예를 들어 당신은 app 폴더에 두 폴더를 중첩시킴으로써 <code>/dashboard/settings</code> route를 만들 수 있습니다.</p>
<p><code>/dashboard/settings</code> route 는 세 segment 들로 이루어집니다 :</p>
<ul>
<li><code>/</code> (Root segment)</li>
<li><code>dashboard</code> (Segment)</li>
<li><code>settings</code> (Leaf segment)</li>
</ul>
<h3 id="file-conventions">File Conventions</h3>
<p>Next.js 는 UI 를 생성하기 위한 special files 를 제공합니다.</p>
<ul>
<li><code>layout</code>    segment와 그 children 에게서 공유되는 UI</li>
<li><code>page</code>    해당 route 의 유일한 UI 이며 해당 route를 접근가능하게 만든다.</li>
<li><code>loading</code>    segment 와 그 children 을 위한 로딩 UI</li>
<li><code>not-found</code>    segment 와 그 children 을 위한 Not found UI</li>
<li><code>error</code>    segment 와 그 children 을 위한 Error UI</li>
<li><code>global-error</code>    Global Error UI</li>
<li><code>route</code>    Server-side API endpoint</li>
<li><code>template</code>    리렌더링되는 Layout UI</li>
<li><code>default</code>    Parallel Routes(후술) 를 위한 Fallback UI</li>
</ul>
<h3 id="component-hierarchy">Component Hierarchy</h3>
<p>route segment 를 위한 special files 로 정의된 React components 들은 특정한 순서대로 렌더링됩니다.</p>
<ul>
<li><code>layout.js</code></li>
<li><code>template.js</code></li>
<li><code>error.js</code> (React error boundary)</li>
<li><code>loading.js</code> (React suspense boundary)</li>
<li><code>not-found.js</code> (React error boundary)</li>
<li><code>page.js</code> or nested <code>layout.js</code></li>
</ul>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/ff210866-0c41-428a-b1a8-5237b178f27e/image.avif" alt="hierarchy"></p>
<p>nested route 에서, segment 의 컴포넌트들은 부모 segment의 컴포넌트로 감싸집니다. 
<img src="https://velog.velcdn.com/images/sj_dev_js/post/ee815f47-d771-4a9f-aa4a-b183c9f2ac4c/image.avif" alt="nested components"></p>
<h3 id="colocation">Colocation</h3>
<p><code>app</code> 폴더에 special files 말고도 다른 파일들(e.g. components, styles, tests, etc)을 위치시킬 수 있습니다. 폴더들이 routes 를 정의하지만, page.js 나 route.js 에 의해 리턴되는 컨텐츠만 접근 가능하기 때문입니다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/4ef6e7a2-fc4a-4fd0-89ce-f4b081770d9f/image.avif" alt="colocation"></p>
<p>더 자세한 것은 <a href="https://nextjs.org/docs/app/building-your-application/routing/colocation">Project Organization and Colocation</a> 를 참고하세요</p>
<h3 id="advanced-routing-patterns">Advanced Routing Patterns</h3>
<p>app router 는 더 진보한 routing 패턴을 적용하기 위한 방법들을 제공합니다.</p>
<ul>
<li><p><a href="https://nextjs.org/docs/app/building-your-application/routing/parallel-routes">Parallel Routes</a> (후술): 한 view 에서 두개 이상의 페이지를 동시에 보여줄 수 있습니다. 각 sub-navigation 을 가지는 split view 를 만들때 사용할 수 있습니다. (E.g. Dashboards.)</p>
</li>
<li><p><a href="https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes">Intercepting Routes</a> (후술): route 를 가로채 다른 route 의 내용을 보여줄 수 있습니다. 현재 페이지의 내용을 유지하는 것이 중요할 때 사용합니다. (E.g. 하나의 과제를 수정할 때 다른 과제들도 한번에 볼 수 있도록 하거나 피드에서 사진을 확장하여 보여줄 때 사용할 수 있습니다.)</p>
</li>
</ul>
<p>이러한 패턴은 더 풍부하고 복잡한 UI 들을 만들 수 있게합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Next.js 14] Getting Started]]></title>
            <link>https://velog.io/@sj_dev_js/Next.js-14-Getting-Started</link>
            <guid>https://velog.io/@sj_dev_js/Next.js-14-Getting-Started</guid>
            <pubDate>Sun, 07 Jan 2024 07:15:21 GMT</pubDate>
            <description><![CDATA[<p>Next.js14 공부 겸 영어공부로 공식문서 번역하기
중요하다고 생각되는 부분만 요약 번역하여 실제 공식문서와 다를 수 있습니다.</p>
<hr>
<h1 id="getting-started">Getting Started</h1>
<p><a href="https://nextjs.org/docs">https://nextjs.org/docs</a></p>
<h3 id="nextjs-란-무엇인가요">Next.js 란 무엇인가요?</h3>
<p>Next.js 는 풀스텍 웹 어플리케이션을 만들 수 있는 리액트 기반 프레임워크 입니다. 유저 인터페이스를 만드는데에 리액트 컴포넌트를 사용하고, 추가적인 기능들과 최적화를 위해 Next.js 를 사용합니다.</p>
<p>내부적으로 Next.js는 번들링, 컴파일 등과 같이 React에 필요한 도구를 추상화하고 자동으로 구성합니다. 이것은 당신으로 하여금 환경구성에 시간을 쏟는 대신 당신의 어플리케이션을 만드는데에만 집중할 수 있도록 합니다.</p>
<p>당신이 개인 개발자든, 팀에 소속되어있는 개발자든, Next.js 는 당신이 상호작용하고, 동적이고, 빠른 리액트 어플리케이션을 만들도록 도울 수 있습니다.</p>
<h3 id="main-features">Main Features</h3>
<h4 id="routing">Routing</h4>
<p>파일시스템에 기반하는, 서버컴포넌트들로 이루어진 라우팅으로, layouts, nested routing, loading states, error handling 등을 지원합니다.</p>
<h4 id="rendering">Rendering</h4>
<p>클라이언트컴포넌트와 서버컴포넌트를 통해 CSR 과 SSR 을 지원합니다.
Next.js 서버에서 정적 및 동적 렌더링으로 더욱 최적화되었습니다. 
Edge 및 Node.js 런타임에서 Streaming 기능도 지원합니다.</p>
<h4 id="data-fetching">Data Fetching</h4>
<p>서버컴포넌트에서 async/await data fetching 이 간단화되었습니다. 그리고 확장된 fetch API 를 통해 요청 메모이제이션, 데이터 캐싱 그리고 재검증을 지원합니다.</p>
<h4 id="styling">Styling</h4>
<p>여러가지 스타일링 방법들을 지원합니다. CSS 모듈, Tailwind CSS, CSS-in-JS</p>
<h4 id="optimizations">Optimizations</h4>
<p>웹 성능과 유저경험 향상을 위해 이미지, 폰트, 스크립트 최적화를 지원합니다.</p>
<h4 id="typescript">TypeScript</h4>
<p>향상된 타입스크립트 지원을 통해 향상된 타입체킹 그리고 효율적인 컴파일이 가능합니다.</p>
<h3 id="이-문서공식문서를-사용하는-방법">이 문서(공식문서)를 사용하는 방법</h3>
<p>왼쪽에 문서 네비게이션바가 보이는데요. 문서들이 basic 부터 advanced 까지 순서대로 정리되어있습니다. 따라서 당신의 어플리케이션을 만들기 위해서 하나씩 순서대로 읽는 것이 좋습니다. 하지만 당신의 사용방법에 따라 얼마든지 순서를 바꿔읽거나 스킵할 수 있습니다.</p>
<p>페이지 내의 섹션을 빠르게 이동하고 싶다면 오르쪽에 섹션 테이블을 사용하면 됩니다. 페이지를 빠르게 찾고싶다면 가장 위 검색창을 사용하거나 단축어 <code>Ctrl+K</code> or <code>Cmd+K</code> 를 사용하여 검색할 수 있습니다.</p>
<p>시작하고 싶다면 <a href="https://velog.io/@sj_dev_js/Next.js-14-Getting-Started#installation">Installation</a> 가이드를 참고하세요.</p>
<h3 id="app-router-vs-pages-router">App Router vs Pages Router</h3>
<p>Next.js 는 두 개의 서로 다른 Router를 지원합니다. App Router 와 Pages Router 입니다. App Router 는 최신 라우터로서 서버 컴포넌트나 Streaming 같은 리액트의 최신기능을 지원합니다. Page Router 는 Next.js 이전 버전에서 사용하던 라우터로 서버렌더링되는 리액트 애플리케이션을 지원하여 이전 버전의 Next.js 로 만들어진 어플리케이션들을 지원합니다.</p>
<p>왼쪽 사이드바의 최상단에 (App Router &lt;-&gt; Page Router)로 서로 바꿀 수 있는 드롭다운 메뉴가 보일 것 입니다. 기능들이 서로 다르므로 하나의 메뉴를 선택하여 쭉 문서를 읽는 것이 중요합니다.</p>
<p>페이지 상단의 breadcrumbs 는 당신이 App Router docs 와 Pages Router docs 중 어디를보고 있는지 알려줍니다.</p>
<p>breadcrumbs 예시:
<img src="https://velog.velcdn.com/images/sj_dev_js/post/f14a79f1-080c-414a-8efb-19f9eba7332a/image.png" alt="breadcrumbs"></p>
<h3 id="pre-requisite-knowledge-선수지식">Pre-Requisite Knowledge (선수지식)</h3>
<p>처음 시작하는 사람도 문서를 읽기 쉽도록 만들었지만 Next.js를 배우는데만 집중할 수 있도록 어느정도 기본지식은 필요합니다. HTML, CSS, and React 에 대한 기본지식은 갖추고 있기를 권장합니다. 
리액트를 좀더 배워야한다면 <a href="https://nextjs.org/learn/react-foundations">https://nextjs.org/learn/react-foundations</a> 를 참고하세요. </p>
<h2 id="installation">Installation</h2>
<p><a href="https://nextjs.org/docs/getting-started/installation">https://nextjs.org/docs/getting-started/installation</a></p>
<ul>
<li>Node.js 18.17 이상이 필요합니다</li>
<li>mac OS, Windows, Linux 를 지원합니다</li>
</ul>
<h3 id="automatic-installation-자동-설치">Automatic Installation (자동 설치)</h3>
<p><code>create-next-app</code> 을 사용하여 Next.js 앱을 자동으로 설치할 것을 권장합니다.</p>
<pre><code>npx create-next-app@latest</code></pre><p>다음과 같은 프롬프트들을 보게 될 것 입니다.</p>
<pre><code>What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*</code></pre><p>이후 당신이 지정한 project name 과 설정들을 통해 프로젝트 폴더가 만들어질 것 입니다.</p>
<blockquote>
<p>Good to know:</p>
<ul>
<li>어플리케이션 코드를 설정 파일과 분리하기 위해 <code>src</code> 폴더를 프로젝트 폴더 최상단에 만들 수 있습니다.</li>
</ul>
</blockquote>
<h3 id="manual-installation-수동-설치">Manual Installation (수동 설치)</h3>
<p>스킵</p>
<h3 id="run-the-development-server">Run the Development Server</h3>
<ol>
<li>로컬 개발 서버를 실행하기 위해 <code>npm run dev</code> 명령어를 콘솔에 입력하세요. (프로젝트 폴더 내부에서)</li>
<li>브라우저에서 <code>http://localhost:3000</code> 에 접속하여 당신의 어플리케이션을 확인하세요.</li>
<li>app/page.tsx (or pages/index.tsx) 파일을 수정하고 저장하여 브라우저에 반영되는 것을 확인하세요. </li>
</ol>
<h2 id="nextjs-project-structure">Next.js Project Structure</h2>
<p><a href="https://nextjs.org/docs/getting-started/project-structure">https://nextjs.org/docs/getting-started/project-structure</a></p>
<p>Next.js 프로젝트의 폴더 구조 및 파일을 전반적으로 보는 페이지입니다. 최상단 파일, 폴더들과 설정파일, 그리고 라우팅 컨벤션을 확인 할 수 있습니다.</p>
<p>~ 해당부분은 추후 번역합니다 ~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js 에 대한 거의 모든 것]]></title>
            <link>https://velog.io/@sj_dev_js/Next.js-%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B1%B0%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83</link>
            <guid>https://velog.io/@sj_dev_js/Next.js-%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B1%B0%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83</guid>
            <pubDate>Sun, 11 Sep 2022 09:15:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/f1ba1d3c-ee11-4048-ad34-e8fc1b7e0b35/image.png" alt=""></p>
<p>면접 준비를 하면서 Next.js 를 깊게 공부할 기회가 생겼다. </p>
<p>이번 기회에 평소 헷갈렸던 Next.js 개념들을 정리해보고자 한다.</p>
<p>상당히 내용이 많으므로 Next.js 가 CSR을 사용하는지, </p>
<p>SSG 는 언제 사용하는지 SSR 는 어떻게 사용하는지 빠르게 알고싶다면 맨 밑부터 읽으면 된다.</p>
<h1 id="nextjs-를-시작하기-전에--csr와-ssr">Next.js 를 시작하기 전에 : CSR와 SSR</h1>
<h2 id="csr">CSR</h2>
<p>CSR(Client Side Rendering)은 뼈대가 되는 빈 HTML 과 JS 파일을 전부 가져와 클라이언트(브라우저) 측에서 HTML 을 구성하는 방식이다. 초기에 빈 HTML 파일을 보여준 후 API 요청을 통해 데이터를 받아와 다시 렌더링 하기 때문에 사용자가 화면을 인식하는데 상대적으로 오래걸린다. 하지만 초기 로딩 후 버튼이나 링크를 클릭해 페이지간 전환이 일어날 때 클라이언트에서 화면을 다시 구성하므로 화면 전환 속도가 빠르다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/a3b51c8f-9630-4c45-9594-6cf79402c12d/image.png" alt="csr"></p>
<h2 id="ssr">SSR</h2>
<p>SSR(Server Side Rendering)은 서버에서 HTML을 구성하여 클라이언트로 보내주는 방식이다. 서버에서 구성한 화면은 유저가 인식할 수 있으나, JS 를 다운받아 실행하기 전에는 이벤트 등이 작동하지 않는다. 따라서 유저의 interaction을 기록했다가 JS 파일을 다운 받은 후 실행시킨다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/57c0a0a1-8db0-4108-8647-c7a6eac5c20b/image.png" alt="ssr"></p>
<h2 id="csr-vs-ssr">CSR vs SSR</h2>
<p>CSR은 최초 화면을 유저에게 보여주기까지의 시간이 SSR 보다 오래걸린다. 또한 검색엔진이 크롤링을 했을 때 빈 HTML 만을 확인할 수 있기 때문에 SEO(검색엔진 최적화)에 불리하다.</p>
<p>SSR은 매번 서버에서 연산을 수행해야하기 때문에 서버에 부하가 더 크다. 또한 화면 전환시 깜빡임이 있다.</p>
<p>이렇게 각각 장단점이 있지만, 초기 로딩과 SEO 측면에서는 SSR의 장점이 두드러진다.</p>
<hr>
<h1 id="nextjs-란--react-를-기반으로-하는-웹-개발-프레임워크">Next.js 란 : React 를 기반으로 하는 웹 개발 프레임워크</h1>
<p>React는 기본적으로 CSR 방식을 사용하는데, SSR을 사용하려면 개발자가 직접 환경을 구성해야한다.</p>
<p>Next.js 는 직접 환경을 구성할 필요 없이, SSR (SSG) 을 쉽게 사용할 수 있도록 도와주는 React 기반 프레임워크다. Next.js 가 SPA(Single Page Application) 이 아니라든가, CSR 없이 SSR(SSG) 만을 사용한다는 이야기는 아니다. Next.js 는 SPA 이며 SSG를 기본으로 사용하고, SSR을 사용할 수 있으며 페이지 전환시에는 CSR을 사용한다.</p>
<p>SSG는 무엇인지, CSR을 사용하는 근거에 대해서는 아래에서 서술할 예정이다. </p>
<p>다만 알아두어야할 것은 Next.js 는 Pre-rendering과 CSR의 장점을 모두 사용할 수 있게 해준다는 것이다.</p>
<h2 id="nextjs-의-특징">Next.js 의 특징</h2>
<ul>
<li>Page 기반 라우팅</li>
<li>Pre-rendering</li>
<li>코드 스플리팅과 pre-fetch</li>
</ul>
<h3 id="page-기반-라우팅">Page 기반 라우팅</h3>
<p>Next.js 에서는 직관적인 라우팅 방식을 제공한다. pages 폴더에서 생성한 tsx(jsx) 파일의 경로 그대로 url 의 path가 된다. 예를 들어 파일 경로가 <code>pages/users/detail.tsx</code> 라면 url은 <code>hostname/users/detail</code> 이 된다. </p>
<p>파일 경로를 동적으로 정하고 싶다면 대괄호를 활용할 수 있다. 파일 경로가 <code>pages/users/[username].tsx</code> 라면 대괄호 부분에 어떤 것을 넣어도 해당 페이지로 접근한다. 또한 <code>next/router</code> 의 useRouter() 를 통해 대괄호에 들어가는 변수를 확인할 수 있다. </p>
<p>라우팅에 대한 더 자세한 내용은 아래 링크 참조</p>
<p><a href="https://nextjs.org/docs/routing/introduction">Routing: Introduction | Next.js</a></p>
<h3 id="pre-rendering">Pre-rendering</h3>
<p>(프론트) 서버에서 HTML 파일을 미리 구성한다. </p>
<p>주소창에 url 입력시 브라우저는 pre-rendering 된 HTML 파일을 받게된다.</p>
<ul>
<li>SSG (default) : 빌드 시 HTML 파일을 구성한다.</li>
<li>SSR : 해당 page에서 getServerSideProps()를 사용할 시, 요청을 받을 때마다 서버에서 HTML을 새로 구성해 반환한다.</li>
</ul>
<p>page 파일에서 getInitialProps() 나 getServerSideProps() 를 사용하지 않으면 기본적으로 SSG를 사용하게 된다. 따라서 url 입력을 통해 접근하는 페이지는 모두 pre-rendering 된 페이지이다.</p>
<h3 id="코드-스플리팅과-pre-fetch">코드 스플리팅과 pre-fetch</h3>
<p>모듈화 했던 파일들을 하나로 묶는 것을 번들링이라고 하는데, 번들링된 JS파일은 너무 커서 다운받는데 오랜 시간이 걸릴 수 있다. JS파일을 다운받는데 걸리는 시간동안 화면의 기능(버튼 이벤트 등) 작동하지 않기 때문에 하나로 번들링된 JS 파일을 페이지 별로 필요한 JS 파일로 분리한 것이 코드 스플리팅이다.</p>
<p>pre-fetch는 관련된 데이터를 미리 로딩하는 것을 말한다. url을 통해 페이지를 요청했을 때, 코드 스플리팅을 통해 현재 페이지에서 필요한 JS 파일을 받는다. 이후 페이지에 <code>&lt;Link/&gt;</code> 가 있다면 연결된 페이지의 JS 파일을 미리 다운로드 받아 <code>&lt;Link/&gt;</code>  클릭시 페이지 전환이 빠르게 일어나도록 한다.</p>
<hr>
<h1 id="ssg-static-site-generation">SSG (Static Site Generation)</h1>
<p>빌드시 HTML 파일을 미리 렌더링하는 것이 SSG 이다. 정적인 페이지에 주로 쓰인다. HTML 파일을 미리 생성하기 때문에 서버에서 매번 연산을 하지 않아도 될 뿐 아니라, 별다른 설정 없이 CDN 캐시 사용이 가능하기 때문에 SSR 보다도 훨씬 빠른 속도를 보여준다. </p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/98270ee5-b532-493d-94b0-4fe0126ea219/image.jpeg" alt="SSG"></p>
<p>앞서 말했듯이 SSG는 Next.js 의 기본적인 렌더링 방식이다. 하지만 백엔드 서버로부터 데이터를 받아서 렌더링하는 경우를 생각해보자. 페이지에서 useEffect()를 사용한다면 url을 통한 페이지 접근시 SSG로는 데이터가 필요없는 부분만 구성하고, 데이터를 필요로하는 부분은 CSR로 렌더링하게 된다. 페이지에서 데이터를 필요로 하는 부분이 클수록 사용자가 화면을 인식하는데 시간이 오래걸리며 이는 SSG의 장점을 전혀 활용하지 못하게 되는 것을 의미한다.</p>
<p>이는 Next.js 에서 제공하는 페이지 단위 함수 getStaticProps()를 통해 해결할 수 있다.</p>
<h2 id="getstaticprops">getStaticProps()</h2>
<p>아래 코드는 공식문서에서 제공하는 getStaticProps()의 예제이다.</p>
<pre><code class="language-tsx">function Blog({ posts }) {
  return (
    &lt;ul&gt;
      {posts.map((post) =&gt; (
        &lt;li&gt;{post.title}&lt;/li&gt;
      ))}
    &lt;/ul&gt;
  )
}

// getStaticProps 함수는 server-side에서 build 타임에만 실행된다.
export async function getStaticProps() {
  // build 타임에 데이터를 받아온다.
  const res = await fetch(&#39;https://.../posts&#39;)
  const posts = await res.json()

  // { props: { posts } }를 반환함으로써, 
  // Blog 컴포넌트는 빌드타임에 props 로 posts를 받을 수 있다.
  return {
    props: {
      posts,
    },
  }
}

export default Blog</code></pre>
<p>보이는 바와 같이 getStaticProps는 빌드타임에 서버로부터 데이터를 받아와 반환하고, getStaticProps를 사용하는 페이지는 빌드타임에 getStaticProps 로부터 props를 받아올 수 있다. 따라서 빌드타임에 데이터에 따른 화면 구성이 가능해진다.</p>
<h3 id="ssg-페이지의-데이터가-변경되면-어떡하지--revalidate">SSG 페이지의 데이터가 변경되면 어떡하지? : revalidate</h3>
<p>여기까지 서술한 바에 따르면 SSG는 몇가지 문제점이 존재한다. </p>
<p>빌드 타임에 정적파일을 생성하기 때문에 이후 데이터 변경이 일어나도 페이지에 반영이 되지 않는다. 이런 문제를 해결하기 위해 getStaticProps() 에는 <code>revalidate</code>라는 옵션이 존재하며 초 단위로 입력할 수 있다. </p>
<p>빌드를 통해 페이지가 생성된 후 revalidate 값(초)이 지나기 전 들어오는 요청에 대해서는 기존의 페이지를 반환한다. revalidate 값이 지나고 들어오는 최초 요청에 대해서는 기존 페이지를 반환하고 페이지를 새로 빌드한다. 이후 들어오는 요청에 대해서는 새로 빌드된 페이지를 반환한다.(반복) 즉 revalidate에 10을 입력했다면 10초마다 재빌드 되는 것이 아니라, 10초 이후 요청이 새로 들어왔을 떄 재빌드 하여 새로운 페이지를 만드는 것이다.</p>
<pre><code class="language-tsx">export async function getStaticProps() {
  const res = await fetch(&#39;https://.../posts&#39;)
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // 초 단위
  }
}</code></pre>
<p>더 자세한 사항에 대해서는 아래에서 ISR(Incremental Static Regeneration) 에 대해 서술할 것이다.</p>
<h2 id="getstaticpaths">getStaticPaths()</h2>
<p>SSG의 또 한가지 문제점으로 동적라우팅을 사용하는 경우가 있다. (ex: <code>hostname/users/[username]</code>)</p>
<p>동적라우팅을 사용하여 query에 들어오는 값은 빌드타임에는 알 수가 없다. 따라서 getStaticPaths()를 사용하여 동적라우팅으로 가능한 모든 path에 대한 정보를 getStaticProps()에 전달할 수 있다.</p>
<p>아래는 공식문서에서 제공하는 예제이다.</p>
<pre><code class="language-tsx">// pages/posts/[id].js

function Post({ post }) {
  // post 렌더링 하는 코드
}

export async function getStaticPaths() {
  // API 호출을 통해 posts 에 대한 데이터를 가져온다.
  const res = await fetch(&#39;https://.../posts&#39;)
  const posts = await res.json()

  // paths 를 추출한다.
  const paths = posts.map((post) =&gt; ({
    params: { id: post.id },
  }))
  /*
      [{params : {id : 1} }, {params : {id : 2} }]
  */

  return { paths, fallback: false }
}

export async function getStaticProps({ params }) {
  // getStaticProps로부터 params 를 받아 path 를 구성하고 데이터를 받아온다.
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  return { props: { post } }
}

export default Post</code></pre>
<h3 id="모든-페이지를-미리-만들-수는-없다--fallback-옵션">모든 페이지를 미리 만들 수는 없다 : fallback 옵션</h3>
<p>getStaticPaths() 를 통해 미리 만들어진 path가 아닌, 임의의 path가 url 로 들어온다면 어떻게 해야할까? 당연히 404페이지를 띄워야한다는 생각이 들 수도 있다. 하지만 상품 상세페이지를 정적 페이지로 생성한다고 생각해보자. 쇼핑몰의 모든 상품에 대한 페이지를 미리 빌드하는 것은 아주 오랜 시간이 걸릴 수도 있는 일이다. 뿐만 아니라, 새로운 상품이 등록된다면 그 상품에 대한 상세페이지도 만들어야하는데 새로운 상품을 빌드 타임에 알 수는 없다. 따라서 미리 만들어놓지 않은 path에 대해서도 페이지를 보여줄 수 있어야한다. 이를 위해 getStaticPaths() 에는 <code>fallback</code> 옵션이 존재한다.</p>
<pre><code class="language-tsx">export async function getStaticPaths() {
  return {
    paths: [
      { params: { ... } } 
    ],
    fallback: true, false or &quot;blocking&quot;
  };
}</code></pre>
<p>fallback 옵션에 들어갈 수 있는 값은 <code>true</code>, <code>false</code>, <code>“blocking”</code> 이며, </p>
<p>fallback 값에 따라 path가 미리 정의되지 않은 경우 <code>getStaticProps()</code>의 동작이 달라진다. </p>
<ul>
<li><code>false</code> : 404 페이지를 반환한다.</li>
<li><code>true</code> : 우선 페이지의 fallback 버전을 보여주고 getStaticProps 를 통해서 요청을 보내서 HTML 파일과 JSON 파일을 만든다. 만들어지면 브라우저는 JSON 파일을 받아서 렌더링한다. Next.js 는 만들어진 HTML 파일을 미리 렌더링된 페이지 목록에 추가한다. 이후 요청부터는 미리 렌더링된 HTML 파일을 반환한다.</li>
<li><code>blocking</code> : true 와 비슷하게 작동하나, 파일을 렌더링하는 동안 fallback 버전을 보여주는 것이 아니라 SSR 처럼 작동하여 HTML파일을 새로 만들어 반환한다. 이후 요청부터는 만들어진 HTML 파일을 반환한다.</li>
</ul>
<p><code>true</code> 옵션과 <code>blocking</code> 옵션은 <code>next export</code> 에서는 작동하지 않는다.</p>
<h3 id="fallback-page">Fallback Page</h3>
<p>getStaticPaths() 에서 <code>fallback : true</code> 이면 fallback 페이지를 우선 보여준다는데 도대체 fallback 페이지는 무엇일까? 사실 fallback 페이지 또한 개발자가 만들어야한다. getStaticPaths() 는 getStaticProps()로 하여금 page 에게 <code>isFallback: true</code> 를 줄 뿐이다. 페이지에서 useRouter()의 isFallback을 통해 조건을 분기하여 fallback 페이지를 보여줄 수 있다.</p>
<pre><code class="language-tsx">// pages/posts/[id].js
import { useRouter } from &#39;next/router&#39;

function Post({ post }) {
  const router = useRouter()

    // 만약 페이지가 아직 생성되지 않았다면 getStaticProps()가 실행되는 동안
    // isFallback을 통해 조건을 분기하여 fallback(대체) 페이지를 보여줄 수 있다.
  if (router.isFallback) {
    return &lt;div&gt;Loading...&lt;/div&gt;
  }

  // post 렌더링 하는 코드 생략...
}

export async function getStaticPaths() {
  return {
    // `/posts/1`,`/posts/2`만 빌드타임에 생성된다.
    paths: [{ params: { id: &#39;1&#39; } }, { params: { id: &#39;2&#39; } }],
    // fallback 값을 true로 줌으로써 `/posts/3` 같은 추가 페이지를
    // 정적인 방식으로 생성할 수 있다.
    fallback: true,
  }
}

export async function getStaticProps({ params }) {

  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  return {
    props: { post },
    revalidate: 1,
  }
}

export default Post</code></pre>
<hr>
<h1 id="ssr-server-side-rendering">SSR (Server Side Rendering)</h1>
<p>페이지에 대한 요청이 있을 때마다 (프론트)서버에서 페이지를 만들어 반환한다. 서버에서 매번 연산을 해야하며 캐시를 사용하는 것이 상대적으로 어렵기 때문에 SSG에 비해 느리다. 하지만 항상 최신의 정보를 보여주어야하는 경우, SSR를 사용하는 것이 좋다.</p>
<p>(프론트)서버에서 HTML 파일을 만들어서 보내기 때문에 CSR에 비해 사용자가 더 빠르게 화면을 인식할 수 있다. 하지만 이벤트 등 페이지의 동작을 위해서는 hydrate라는 과정을 통해서 JS 코드가 실행되어야한다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/383b55f4-b94d-4092-84e9-e9d95e6bea7d/image.jpeg" alt="SSR"></p>
<h2 id="hydrate">hydrate</h2>
<p>서버에서 렌더링된 HTML 페이지와 JS 파일을 클라이언트에게 보내면, 클라이언트에서 HTML 파일에 JS 코드를 매칭 시키는 작업이다. 이벤트 등록이나 스타일 적용이 일어난다. SSR과 SSG 모두 Hydrate가 일어나는데, SSG의 경우 빌드타임에 query 가 없기 때문에 런타임에서 query에 대한 hydrate가 일어난다.</p>
<h2 id="getserversideprops">getServerSideProps()</h2>
<p>Next.js에서 SSR을 사용하기 위해서는 페이지에서 getServerSideProps() 를 통해 데이터를 받아와야한다.</p>
<p>빌드타임에만 실행되는 getStaticProps()와는 달리 getServerSideProps()는 페이지에 대한 요청이 있을 때마다 실행된다.</p>
<pre><code class="language-tsx">function Page({ data }) {
  // 데이터를 통해 페이지 렌더링...
}

export async function getServerSideProps() {
  // 페이지를 요청할 때마다 매번 실행된다.
    // 데이터를 받아온다.
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page</code></pre>
<hr>
<h1 id="csr-client-side-rendering">CSR (Client Side Rendering)</h1>
<p>Next.js 에서 CSR을 사용하는 경우는 두가지로 나누어볼 수 있다.</p>
<ul>
<li>url을 입력을 통해 pre-rendering 된 페이지를 받고 useEffect()를 통해 데이터를 추가로 불러오는 경우</li>
<li><code>&lt;Link/&gt;</code> 나 <code>router.push()</code>를 통해 페이지 전환이 일어나는 경우이다.</li>
</ul>
<h2 id="csr을-권장하는-경우">CSR을 권장하는 경우</h2>
<p>( 페이지 전환시 CSR을 사용하는 것은 당연하므로 url 입력을 통해 페이지를 요청하는 경우를 이야기한다. )</p>
<p>만약 페이지를 pre-rendering 할 필요가 없거나, 데이터의 업데이트가 자주 일어난다면 CSR을 사용하는 것을 권장한다. 예를 들어 유저 대시보드 페이지는 해당 유저만을 위한 비밀 페이지이기 때문에 SEO가 필요하지 않으며 따라서 pre-rendering할 필요도 없다. 또한 데이터가 자주 변경되기때문에 CSR이 적합하다.</p>
<p><img src="https://velog.velcdn.com/images/sj_dev_js/post/4f5b216b-bcc8-46f8-a704-b6a310db61b8/image.jpeg" alt=""></p>
<h2 id="페이지-전환시-csr을-사용한다는-근거">페이지 전환시 CSR을 사용한다는 근거</h2>
<p><a href="https://nextjs.org/docs/api-reference/next/link">공식문서</a> 에 적혀있다.</p>
<blockquote>
<p>Client-side transitions between routes can be enabled via the <code>Link</code>component exported by <code>next/link</code>.</p>
</blockquote>
<blockquote>
<p>Handles client-side transitions, this method is useful for cases where <code>next/link</code>
 is not enough. (router.push() 에 대한 설명)</p>
</blockquote>
<h2 id="페이지-전환시-getstaticprops와-getserversideprops의-작동">페이지 전환시 getStaticProps와 getServerSideProps의 작동</h2>
<h3 id="getstaticprops-1">getStaticProps()</h3>
<p>빌드타임에 getStaticProps()가 실행되면, HTML 뿐만 아니라 JSON 파일 또한 생성된다. 이 JSON 파일은 <code>next/link</code> 나 <code>next/router</code>를 통해 CSR 화면전환이 일어날 때 쓰인다. getStaticProps 를 사용하는 페이지로 이동할 때 이 JSON 파일을 받아와 페이지 컴포넌트의 props로 사용한다. </p>
<h3 id="getserversideprops-1">getServerSideProps()</h3>
<p>next/link 또는 next/router를 통해 페이지 전환 시 Next.js가 getServerSideProps를 실행하는 (프론트)서버에 API 요청을 보낸다.</p>
<hr>
<h1 id="isr-incremental-static-regeneration">ISR (Incremental Static Regeneration)</h1>
<p>Next.js는 사이트를 빌드한 이후에도 정적페이지를 생성하거나 업데이트 할 수 있는 기능을 제공하는데 이것이 ISR 이다. ISR은 모든 페이지를 재빌드할 필요없이 각 페이지를 정적생성한다. </p>
<p>ISR에는 두가지 방법이 있는데 하나는 앞서 살펴보았던, getStaticProps()의 revalidate 속성을 사용하는 것이다. 페이지를 방문한 이후로 revalidate 시간동안은 캐시된 페이지를 보여주고, 이후 들어오는 첫번째 요청에 대해서는 역시 캐시된 페이지를 보여주며 해당 페이지를 재빌드한다. 이후에는 새로 빌드된 페이지를 보여준다.</p>
<pre><code class="language-tsx">export async function getStaticProps() {
  const res = await fetch(&#39;https://.../posts&#39;)
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // 초 단위
  }
}</code></pre>
<h2 id="on-demand-revalidation">On-demand Revalidation</h2>
<p>다른 한가지 방법은 데이터 변경시 재빌드를 하는 것이다.</p>
<p>앞서 살펴본 revalidate 옵션을 사용하면 revalidate 의 값만큼은 캐시된 페이지를 보게된다. 이 캐시를 무효화하려면 revalidate 값만큼의 시간 이후 요청이 있어야한다. on-demand revalidation 방식은 <code>데이터 변경이 일어났으니 재빌드를 해달라</code>는 요청을 받으면 재빌드를 함으로써 캐시를 갱신한다.</p>
<p>on-demand revalidation 방식에서는 revalidation 옵션을 사용하지 않는다. revalidation 을 사용하지 않으면 기본값이 false가 되어 <code>revalidate()</code> 함수를 사용할 때만 on-demand revalidation이 일어난다.</p>
<p>On-demand Revalidation을 사용하기 위해서는 Next.js 만 알고있는 토큰을 생성해서 환경변수에 저장해야한다. 해당 토큰을 사용해야 인가된 사용자만 아래와 같은 url로 Next.js api에 revalidate를 요청할 수 있다.</p>
<pre><code>https://&lt;your-site.com&gt;/api/revalidate?secret=&lt;token&gt;</code></pre><p>데이터에 변경이 일어나서 재빌드를 해야하는 상황이라면 url</p>
<p><code>https://&lt;your-site.com&gt;/api/revalidate?secret=&lt;token&gt;</code> 를 통해 Next.js 서버에 요청을 보낸다.</p>
<p>그러면 Next.js api 의 해당 파일이 실행된다. Next.js API 파일에서 res.revalidate(<code>재빌드할 경로명</code>)을 사용함으로써 해당 경로의 파일이 재빌드 된다.</p>
<pre><code class="language-tsx">// pages/api/revalidate.js

export default async function handler(req, res) {
  // 토큰 검사
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: &#39;Invalid token&#39; })
  }

  try {
    // 재빌드할 경로명을 정확하게 입력해야한다. req의 body를 통해 받아올 수 있다.
    // 파일명이 &quot;/blog/[slug]&quot; 이더라도 &quot;/blog/post-1&quot; 처럼 입력해야한다.
    await res.revalidate(&#39;재빌드할 경로명&#39;)
    return res.json({ revalidated: true })
  } catch (err) {
    // 만약 에러가 발생하면 최근에 생성된 페이지를 보여준다.
    return res.status(500).send(&#39;Error revalidating&#39;)
  }
}</code></pre>
<hr>
<h1 id="바쁜-당신-이것만은-알고-nextjs-사용하자">바쁜 당신, 이것만은 알고 Next.js 사용하자</h1>
<blockquote>
<ol>
<li>Next.js로 만들어진 웹 페이지는 url로 접근시 pre-rendering(SSG, SSR) 된 페이지를 반환한다. </li>
<li>pre-rendering 은 프론트엔드 서버에서 돌아가는 Next.js 에서 일어난다.</li>
<li>Next.js 는 SSG가 기본이다. getServerSideProps() 을 사용하지 않은 페이지는 모두 SSG로, 빌드 타임에 미리 렌더링 된다. </li>
<li>SSR을 하려면 getServerSideProps()를 사용해야한다.</li>
<li>Link를 클릭하거나 router.push()를 통해 이동하면 CSR 방식으로 페이지를 전환한다.</li>
</ol>
</blockquote>
<p>이렇게 길게 적었음에도 불구하고 아직 공부해야할 것이 많이 남아있다. (캐시라든가… 배포라든가… )</p>
<p>그래도 내가 헷갈렸던 부분에 대해서는 최대한 자세하게 적어서 다른 사람들이 쉽게 의문을 풀 수 있도록 노력했다.</p>
<p>더 자세한 사항에 대해서는 <a href="https://nextjs.org/docs/getting-started">공식문서</a>를 읽을 것을 권장한다. 본문의 모든 것은 이미 공식문서에 적혀있는 내용이다. Next.js는 공식문서가 잘 만들어져서 상당히 간결해보이는데, 그 간결해보이는 문서 안에 정말 많은 내용이 숨어있다. 문서가 굉장히 친절하니 영어라고 겁먹지 말고 꼭 한번은 정독할 것을 추천한다.</p>
<h2 id="참고">참고</h2>
<p><a href="https://nextjs.org/docs/getting-started">Next.js 공식문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러 해결] Next.js : url을 통해 특정 페이지에 직접 접근하는 것 막기 ~Redirect~]]></title>
            <link>https://velog.io/@sj_dev_js/%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-Next.js-url%EC%9D%84-%ED%86%B5%ED%95%B4-%ED%8A%B9%EC%A0%95-%ED%8E%98%EC%9D%B4%EC%A7%80%EC%97%90-%EC%A7%81%EC%A0%91-%EC%A0%91%EA%B7%BC%ED%95%98%EB%8A%94-%EA%B2%83-%EB%A7%89%EA%B8%B0-Redirect</link>
            <guid>https://velog.io/@sj_dev_js/%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-Next.js-url%EC%9D%84-%ED%86%B5%ED%95%B4-%ED%8A%B9%EC%A0%95-%ED%8E%98%EC%9D%B4%EC%A7%80%EC%97%90-%EC%A7%81%EC%A0%91-%EC%A0%91%EA%B7%BC%ED%95%98%EB%8A%94-%EA%B2%83-%EB%A7%89%EA%B8%B0-Redirect</guid>
            <pubDate>Mon, 11 Jul 2022 09:22:01 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-인식">문제 인식</h1>
<p>Next.js 는 pages 라는 폴더 하위에 파일을 작성하면 해당 페이지를 자동으로 라우팅해주는 편리한 기능을 제공한다. 
ex ) <code>pages/manual.tsx</code> ⇒ <code>/manual</code></p>
<p>하지만 pages 하위에 있는 모든 파일에 url로 직접 접근할 수 있도록 허용하는 것은 문제가 발생할 수 있다.</p>
<p>예를 들어 로그인 된 상태에서 <code>/login</code> 페이지에 접근한다든가, <code>/error</code> 페이지에 직접 접근한다든가 하는 문제가 있다.</p>
<p>실제로 프로젝트를 하던 도중 로그인된 상태에서 url로 <code>/login</code> 페이지에 접근할 수 있는 것🤦🏻‍♀️을 확인하고 고치게 되었다.</p>
<h1 id="문제-해결">문제 해결</h1>
<p>Next.js 는 특정 url 로 접근시 다른 path로 이동시켜주는 redirect 기능을 제공한다.</p>
<p>Next.js 프로젝트 폴더 루트에 있는 next.config.js 파일에서 설정할 수 있다.</p>
<pre><code class="language-jsx">//next.config.js

const nextConfig = {
  ...
  async redirects() {
    return [
      {
        source: &#39;/login&#39;,
        destination: &#39;/&#39;,
        permanent: true,
      },
      {
        source: &#39;/error&#39;,
        destination: &#39;/&#39;,
        permanent: true,
      },
    ];
  },
    ...
};

module.exports = nextConfig;</code></pre>
<p><code>source</code> 에는 접근을 막을 페이지, <code>destination</code> 에는 redirect 할 페이지를 적어주면 된다.</p>
<p><code>permament</code> 는 영구적으로 redirect 할 지 여부를 정하여 http 상태 코드를 307 혹은 308로 넘겨준다.</p>
<p>permanent 와 http status code 에 대해 자세히 알고 싶으면 아래 블로그 글을 참고하면 좋을 것 같다.</p>
<h3 id="참고">참고</h3>
<p><a href="https://velog.io/@himprover/Nextjs-Redirect-%EC%98%B5%EC%85%98%EC%97%90-Permanent%EB%8A%94-%EB%AD%90%EC%A7%80">Nextjs Redirect 옵션에 Permanent는 뭐지?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러 해결] Next.js :  동적 라우팅된 페이지 배포시 404 에러]]></title>
            <link>https://velog.io/@sj_dev_js/Next.js-%EB%8F%99%EC%A0%81-%EB%9D%BC%EC%9A%B0%ED%8C%85%EB%90%9C-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%B0%B0%ED%8F%AC%EC%8B%9C-404-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@sj_dev_js/Next.js-%EB%8F%99%EC%A0%81-%EB%9D%BC%EC%9A%B0%ED%8C%85%EB%90%9C-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%B0%B0%ED%8F%AC%EC%8B%9C-404-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Mon, 11 Jul 2022 08:36:42 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-인식">문제 인식</h1>
<p>Next.js 는 pages 라는 폴더내에 파일을 작성하면 자동으로 라우팅을 해준다. <code>pages/manual</code> ⇒ <code>/manual</code></p>
<p>정적인 라우팅 이름이 아닌, 유저 이름같이 동적인 변수로 라우팅을 해주고 싶은 경우,</p>
<p>파일 이름을 [변수명].tsx (typescript 인 경우) 으로 해주면 된다.</p>
<p>이번 프로젝트에서는 유저 페이지의 경로를 <code>&lt;hostname&gt;/users/[intraId]</code> 로 정하여 </p>
<p>S3 와 Cloudfront 를 사용해 배포했다.</p>
<p>그러나 여기서 문제가 발생했다.</p>
<p><code>&lt;hostname&gt;/users/[intraId]</code> 로 된 페이지에서 <strong>새로고침</strong>을 하면 404 가 뜨는 것이다.</p>
<p>S3은 정적으로 빌드된 파일을 저장하는데 [intraId].tsx 파일로 그대로 저장되어있는 것이 문제였다.</p>
<p>만약 main 페이지에서 sujpark 이라는 아이디를 가진 유저페이지로 가는 링크를 클릭한다면</p>
<p>자바스크립트 코드가 /users/[intraId] 파일을 찾아서 /users/sujpark 페이지로 렌더링을 하지만 </p>
<p>/users/sujpark 페이지에서 새로고침을 한다면, 즉 url을 통해 직접 접근한다면</p>
<p>/users 폴더에서 sujpark.tsx 파일을 찾으려고 할 것이고,</p>
<p>sujpark.tsx 파일은 존재하지 않기 때문에 404 에러가 뜨게 된다.</p>
<h1 id="문제-해결">문제 해결</h1>
<p>이를 해결하는 방법으로</p>
<blockquote>
<ol>
<li>동적라우팅을 사용하지 않고 변수를 url 쿼리로 처리하기</li>
<li>Next.js 의 getStaticPaths, getStaticProps 함수를 사용해서 빌드시 각 유저의 정적 페이지를 모두 만들기</li>
</ol>
</blockquote>
<p>가 있다.</p>
<p>2를 사용하면 페이지를 렌더링 한 후 서버에 데이터를 요청할 필요 없이 빌드과정에서 페이지가 모두 만들어지기 때에 성능상으로 훨씬 이점을 가질 수 있다.</p>
<p>하지만 getStaticPaths, getStaticProps 함수를 모두 작성해야할 뿐 아니라, 모든 유저명을 보내주는 API를 서버에서 새로 만들어야한다.</p>
<p>동적라우팅의 문제를 알게된 시점은 출시를 앞두고 있는 상황이었기 때문에 우선 1의 방법을 사용하고, 출시 후 업데이트할 때 2의 방법을 사용하기로 했다.</p>
<p>[intraId].tsx 파일의 이름을 detail.tsx 로 바꾸고,</p>
<p><code>/users/detail?intraId=sujpark</code> 라는 url 로 접근하면</p>
<p> <code>const { intraId } = router.query()</code> 코드를 통해 intraId를 받아와 유저에 대한 데이터 요청에 사용할 수 있다.</p>
<p>이때 유저페이지로 향하는 링크들의 href 도 모두 바꿔주는 것을 잊어서는 안된다.</p>
<pre><code class="language-tsx">// 변경 전
&lt;Link href={`/users/${intraId}`}&gt;...&lt;/Link&gt;

// 변경 후
&lt;Link href={`/users/detail?intraId=${intraId}`}&gt;...&lt;/Link&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러 해결?] Chromium : possible side effect in debug evaluate]]></title>
            <link>https://velog.io/@sj_dev_js/%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-Chromium-possible-side-effect-in-debug-evaluate</link>
            <guid>https://velog.io/@sj_dev_js/%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-Chromium-possible-side-effect-in-debug-evaluate</guid>
            <pubDate>Mon, 11 Jul 2022 08:34:04 GMT</pubDate>
            <description><![CDATA[<h3 id="possible-side-effect-in-debug-evaluate">possible side-effect in debug-evaluate</h3>
<p>2022년 5월 31일 답변</p>
<p>[<a href="https://stackoverflow.com/questions/72396527/evalerror-possible-side-effect-in-debug-evaluate-in-next-js/72402135">A recent Chromium update broke that, and not just for FC.</a>]</p>
<p>Looks like a fix has already been produced, just need to wait for its implementation into Chrome.</p>
<p>Console commands in Chrome do still <em>work</em> once you dismiss the warning, but typing them in is going to be a much bigger pain in the ass. If you want to continue using Chrome, you could keep a text file open to type your console commands into and copy/paste into the actual console, or some such workaround.</p>
<p>I&#39;d generally just recommend using Firefox anyway, though.</p>
<p>[<a href="https://www.reddit.com/r/freecitiesgame/comments/v11utw/cant_seem_to_edit_variables_anymore_in_console/">Can&#39;t seem to edit variables anymore in console</a>]</p>
<hr>
<p>개발자 도구를 켜서 콘솔에 입력하면 뜨는 오류.</p>
<p>팀 내에서 크롬 버전 101.0.4951.64(x86_64)은 문제가 없으나 버전 102.0.5005.61(arm64) 에서는 문제가 발생했다.</p>
<p>찾아보니 크로니움 자체의 문제인 것으로 보인다. </p>
<p>크롬은 업데이트 버전을 기다리거나 firefox를 사용하라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[에러 해결] Recoil : Duplicate atom key]]></title>
            <link>https://velog.io/@sj_dev_js/Recoil-Duplicate-atom-key</link>
            <guid>https://velog.io/@sj_dev_js/Recoil-Duplicate-atom-key</guid>
            <pubDate>Mon, 11 Jul 2022 08:32:19 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Expectation Violation: Duplicate atom key &quot;<del>~</del>&quot;. </p>
<p>This is a FATAL ERROR in production.
But it is safe to ignore this warning if it occurred because of hot module replacement.</p>
</blockquote>
<h3 id="원인">원인</h3>
<p><a href="https://github.com/facebookexperimental/Recoil/issues/733">https://github.com/facebookexperimental/Recoil/issues/733</a></p>
<p>In development, when a file is changed, Next.js re-builds the relevant page entry file.Because it&#39;s the same Node.js process, the <code>atom</code> has already been declared.The same thing can happen with HMR when the file change triggers a rebuild of the whole file, or even when the <code>atom</code> is declared inside a component lifecycle/hook and only that is being hot-replaced.</p>
<p>Next.js 개발 중 파일이 변경되면 다시 빌드되는 과정에서 atom으로 만든 state가 재선언된다.</p>
<p>key는 항상 고유값을 가져야하는데 재선언되는 과정에서 이미 key로 선언된 값을 key로 사용해서 문제가 발생한다.</p>
<p>Next.js 개발 중 recoil을 사용할 때 발생하는 고질적인 문제인 것 같다. 기능적으로는 문제가 없다고한다.</p>
<p>문제를 해결하는 방법으로는 </p>
<p>interrupt-stdout 모듈을 사용해서 에러메세지를 무시하는 방법과</p>
<p>난수를 사용해서 에러메세지가 뜨지 않게 하는 방법이 있다.</p>
<h3 id="해결">해결</h3>
<ol>
<li>난수 생성해주는 uuid 모듈 설치 (typescript)</li>
</ol>
<p><code>npm i --save-dev @types/uuid</code></p>
<ol start="2">
<li>key 에 난수 추가하기</li>
</ol>
<pre><code class="language-tsx">import { atom } from &quot;recoil&quot;;
import { v1 } from &quot;uuid&quot;;
import { UserData } from &quot;../types/mainType&quot;;

export const userState = atom&lt;UserData | null&gt;({
  key: `userState/${v1()}`
  default: null
});</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] JavaScript 는 어떤 언어인가?]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript-JavaScript-%EB%8A%94-%EC%96%B4%EB%96%A4-%EC%96%B8%EC%96%B4%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript-JavaScript-%EB%8A%94-%EC%96%B4%EB%96%A4-%EC%96%B8%EC%96%B4%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Tue, 24 May 2022 02:39:05 GMT</pubDate>
            <description><![CDATA[<p>JavaScript는 어떤 언어인가? 라는 질문을 받았을 때 정확하게 대답하지 못했다.
이력서에 JavaScript skill 을 1.5로 적을지 2로 적을지 고민하는 입장에서 JavaScript 는 너무 다양한 모습을 하고 있기 때문이다. </p>
<p>&quot;JavaScript 는 브라우저를 제어하는 언어이다.&quot; 라고 하기엔, JavaScript는 서버도 만들 수 있는 언어이다.</p>
<p>자바스크립트가 지향하는 패러다임 또한 명령형, 함수형, 객체지향형으로 다양하다. 그런데 명령형과 함수형(선언형)은 대립하는 개념이라 두 패러다임을 모두 지원하는 JavaScript의 정체성은 과연 무엇인지 확신하기 힘들었다. 또한 JavaScript는 프로토타입을 기반으로하는 객체지향형 언어인데, class의 껍데기를 쓰고 있기도 하다.</p>
<p>어떤 사람은 JavaScript의 이런 점을 이상하게 생각하기도 하지만 이런 점을 매력으로 느끼는 사람도 분명히 존재한다.
JavaScript 의 <strong>메타몽같은 매력</strong>에 빠진 사람으로서 내가 사랑하는 JavaScript 란 어떤 언어인지 알아보고자 한다.</p>
<h1 id="javascript-는-무엇을-하는-언어인가">JavaScript 는 무엇을 하는 언어인가?</h1>
<h2 id="간략하게-보는-javascript-연대기">간략하게 보는 JavaScript 연대기</h2>
<h3 id="javascript">Java&quot;Script&quot;</h3>
<p>자바스크립트는 본래 스트립트 언어이다. 스크립트 언어란 <code>이미 존재하는 프로그램을 제어하기 위해 사용되는 언어</code> 를 말한다. 본래 JavaScript는 브라우저를 제어하기 위해 탄생한 언어이다. HTML이 웹페이지의 기본 구조, CSS이 웹페이지의 디자인, JavaScript가 웹페이지의 동작을 담당한다.</p>
<h3 id="v8-엔진의-등장">V8 엔진의 등장</h3>
<p>2008년 구글에서 V8 자바스크립트 엔진을 발표했다. V8 엔진은 C++로 작성된 자바스크립트 엔진으로 JavaScript의 실행속도를 획기적으로 빠르게 만들었다. 또한 V8 엔진은 독립형으로 개발되었기 때문에 브라우저 뿐만 아니라 다른 C++ 프로그램에 내장해서 사용할 수 있다. V8 엔진 덕분에 브라우저 내 웹페이지의 동작 속도가 매우 빨라졌을 뿐 아니라 브라우저 밖에서도 JavaScript를 사용할 수 있게 되는 기반이 된다.</p>
<h3 id="nodejs">Node.js</h3>
<p>V8의 출현으로 우리가 흔히 사용하는 Node.js가 등장하게 되었다. Node.js 는 V8 엔진을 기반으로 하는 JavaScript 런타임 프로그램이다. JavaScript는 원래 브라우저라는 실행환경에서만 동작하는 언어였는데 이제 Node.js라는 실행환경 위에서도 작동할 수 있게 된 것이다. 덕분에 우리는 Node.js 로 웹서버를 구축하는 등 자체 어플리케이션을 만들 수 있게 되었다. JavaScript 하나로 프론트엔드, 백엔드를 모두 다룰 수 있게 되었기 때문에 JavaScript는 최고의 인기 언어로 떠오르게 되었다.</p>
<h2 id="그래서-javascript-는-무엇을-하는-언어인가요">그래서 JavaScript 는 무엇을 하는 언어인가요?</h2>
<blockquote>
<p>본래 브라우저를 제어하는 언어였으나 Node.js 라는 새로운 실행 환경의 등장으로 자체 어플리케이션을 만들 수 있게 된 언어.
프론트엔드와 백엔드 코드를 모두 작성할 수 있다.</p>
</blockquote>
<br>

<h1 id="javascript는-어떻게-쓰는-언어인가">JavaScript는 어떻게 쓰는 언어인가?</h1>
<p>프로그래밍 언어가 설계 될 때 각자 지향하는 패러다임이 있다. 
JavaScript는 명령형, 함수형, 객체지향 프로그래밍을 지향하는 멀티 패러다임 언어이다.</p>
<h2 id="명령형-vs-선언형-프로그래밍">명령형 vs 선언형 프로그래밍</h2>
<p>명령형 프로그래밍은 내가 <em>어떻게(how)</em> 할 것인지,
선언형 프로그래밍은 내가 _어떤(what) 일_을 할 것인지를 말한다.</p>
<p>예를 들어서 마트에 가서 당근을 1개 산다면
명령형 프로그래밍은 
<code>두 블록을 지나 신호등을 건너 마트에 간다.</code>
<code>가장 안쪽으로 들어가 야채코너에서 당근을 찾는다</code>
<code>입구쪽으로 돌아와 계산대에서 당근을 구매한다</code></p>
<p>선언형 프로그래밍은
<code>마트에 간다</code>
<code>당근을 구매한다</code> 라고 작성할 것이다.</p>
<p>명령형 프로그래밍은 절차적, 객채지향적 프로그래밍을 포함하는 개념이며
선언형 프로그래밍은 논리형, <strong>함수형 프로그래밍</strong>을 포함하는 개념이다.</p>
<p>그렇다면 명령형과 선언형(함수형) 패러다임을 모두 가지는 JavaScript는 대체 어떻게 써야할까?</p>
<h3 id="예시">예시</h3>
<p>배열에서 &#39;banana&#39; 라는 문자열을 포함하는 요소들을 추출하는 코드를 작성한다고 생각해보자</p>
<pre><code class="language-javascript">// 명령형 프로그래밍

const arr = [&#39;yellow banana&#39;, &#39;red apple&#39;, &#39;black banana&#39;];
function getBananas() {
  const bananas = [];
  for (let i = 0; i &lt; arr.length; i++){
      if (arr[i].includes(&#39;banana&#39;))
      bananas.push(arr[i]);
  }
  return bananas;
}
getBananas(); // [&quot;yellow banana&quot;, &quot;black banana&quot;]</code></pre>
<pre><code class="language-javascript">// 선언형 프로그래밍

const arr = [&#39;yellow banana&#39;, &#39;red apple&#39;, &#39;black banana&#39;];
const getBananas = array =&gt; array.filter(el =&gt; el.includes(&#39;banana&#39;));
getBananas(arr); // [&quot;yellow banana&quot;, &quot;black banana&quot;]</code></pre>
<p><code>명령형 프로그래밍</code> 으로 작성한 코드는 개발자들에게 친숙한 <code>if</code>, <code>for</code> 등의 예약어들을 사용한다. for 문을 사용하기 때문에 매 반복문마다 제어하기가 쉽다(ex: 반복문 중간에 중단). 또한 어떤 코드에서는 선언형 프로그래밍에서 사용하는 함수들보다 속도가 빠르기도 하다. 
<em><strong>하지만</strong></em> 코드의 길이가 길어져서 가독성이 떨어진다. for 문에서 변수를 초기화하고 조건을 명시적으로 작성해야하기 때문에 잘못된 코드 작성으로 버그가 발생할 가능성이 높아진다.</p>
<p><code>선언형 프로그래밍</code> 으로 작성한 코드는 코드 길이가 짧아서 함수가 무엇을 하려는지 빠르게 파악할 수 있다. 
<em><strong>하지만</strong></em> 배열의 반복 중 섬세한 제어가 힘들고, 어떤 함수는 속도가 느리다는 단점이 있다.</p>
<p>JavaScript 코드를 명령형으로 작성하느냐, 선언형으로 작성하느냐는 개인의 취향이기도 하지만 대부분의 개발자들이 <code>선언형(함수형) 프로그래밍</code> 을 지향한다. <code>React</code> 의 상태관리 측면에서 함수형 프로그래밍이 확실한 이점을 가지기도 한다.</p>
<p>그렇다고해서 명령형으로 작성할 수 없으며 모든 코드를 함수형으로 작성해야하는 것은 아니다. 애초에 JavaScript는 함수형 프로그래밍만을 위해서 나온 것이 아니기 때문에 함수형만으로 작성하는 것은 불가능하다. JavaScript는 다양한 선택지를 제공하는 언어이며 멀티패러다임은 서로를 상호보완할 수 있다. 다만 C 와 Java 를 통해 익숙해졌던 명령형 프로그래밍의 틀에서 어느정도 벗어나야 한다는 점을 기억해야겠다.</p>
<h2 id="함수형-프로그래밍">함수형 프로그래밍</h2>
<p>선언형 프로그래밍이 무엇인지는 알겠는데, 선언형 프로그래밍중 하나라는 함수형 프로그래밍은 도대체 무엇일까? </p>
<p>함수형 프로그래밍에 대해 알기위해서는 우선 JavaScript 의 함수는 일급객체라는 사실을 알아야한다.</p>
<h3 id="javascript-의-함수는-일급객체">JavaScript 의 함수는 일급객체</h3>
<p>다음과 같은 조건을 만족하는 객체를 일급 객체라고 한다.</p>
<blockquote>
<ol>
<li>무명의 리터럴로 생성할 수 있다. 즉 런타임에 생성이 가능하다.</li>
<li>변수나 자료구조(객체, 배열 등)에 저장할 수 있다.</li>
<li>함수의 매개변수에 전달할 수 있다.</li>
<li>함수의 반환값으로 사용할 수 있다.</li>
</ol>
</blockquote>
<p>자바스크립트의 함수는 위 조건을 모두 만족하므로 일급객체다.
함수가 일급객체라는 말은 함수를 객체와 동일하게 사용할 수 있다는 의미다.
객체는 값으로 평가되므로 함수도 값으로 취급할 수 있다.</p>
<p>일급객체로서 함수가 가지는 가장 큰 특징은 일반 객체와 같이 함수를 
<code>함수의 매개변수에 전달할 수 있으며</code>, <code>함수의 반환값으로도 사용할 수 있다</code> 는 것이다. 
이는 함수형 프로그래밍을 가능하게한다.</p>
<p>다시 함수형 프로그래밍으로 돌아와서, 
함수형 프로그래밍의 필수요소는 다음과 같다.</p>
<blockquote>
<ol>
<li>순수함수를 사용하여 side-effect를 지양할 것</li>
<li>데이터의 불변성을 유지할 것</li>
<li>순수함수를 조합하여 선언적 패턴을 가질 것</li>
</ol>
</blockquote>
<h3 id="순수함수-vs-side-effect">순수함수 vs side-effect</h3>
<p><code>side-effect(부수효과)</code> 란 함수 외부의 데이터를 변경하는 것을 말한다.
<code>순수함수</code> 는 <code>side-effect</code> 가 없으며, 인풋에 대한 아웃풋이 항상 같은 함수를 말한다.</p>
<pre><code class="language-javascript">const number = 0;

function pureFunc(num, offset) {
  return num + offset;
}

function sideEffect(offset) {
  number += offset;
  return number;
}

console.log(pureFunc(number, 1)); // 1
console.log(number); // 0 : pureFunc로 인해 값이 달라지지는 않음
console.log(sideEffect(1)); // 1
console.log(sideEffect(1)); // 2: 바로 위 sideEffect()와 input 이 같으나 결과는 다름
console.log(number); // 2 : sideEffect 함수가 외부의 변수를 변경함</code></pre>
<p>위 코드에서 pureFunc 함수는 인자 num 가 같으면 항상 같은 값을 반환하며, 외부의 상태를 변경하지 않는 함수이다.
하지만 sideEffect 함수는 외부 상태에 의존하기 때문에 같은 인자에 대해 다른 값을 반환할 수 있다. 뿐만 아니라 외부의 상태를 함수 내부에서 바꾸게 된다. 이런 <code>side-effect</code> 는 상태변경을 추적하기 어렵게 만들어서 가독성을 해친다. 코드를 자세히 읽어야 상태변경이 일어나는지 확인할 수 있기 때문이다.</p>
<p>하지만 프론트엔드에서 필수적인 작업인 DOM 조작, 서버와의 통신도 <code>side-effect</code> 에 해당한다.
따라서 오로지 순수함수만 사용하는 것은 불가능하다. 
최대한 순수함수 위주로 작성하여 의도치 않은 상태변경을 막고 코드를 간결하게 만드는 것이 JavaScript 의 함수형 프로그래밍이다. 논리를 간단하게 만들어야 버그가 스며들지 못한다.</p>
<h3 id="데이터의-불변성">데이터의 불변성</h3>
<p>JavaScript 에서 함수에 인수를 전달할 때 원시값(number, string, boolean 등) 은 passed by value 로 전달되지만 객체는 passed by &quot;copy of reference&quot; 방식으로 전달된다. 객체를 함수에 전달하면 함수에서 객체의 내부를 바꿀 수 있다는 뜻이다.</p>
<pre><code class="language-javascript">const obj = {name : &quot;sujeong&quot;, id: &quot;sj_dev_js&quot;};
const addNickname = (o) =&gt; {
  o.nickname = &quot;sujpark&quot;;
}
addNickname(obj);
console.log(obj); // {name: &quot;sujeong&quot;, id: &quot;sj_dev_js&quot;, nickname: &quot;sujpark&quot;}</code></pre>
<p>위에서 말한 바와 같이 순수함수는 외부의 상태(<code>obj</code>)를 변경해서는 안된다.
위 코드를 순수함수로 작성하면 다음과 같다.</p>
<pre><code class="language-javascript">const obj = {name : &quot;sujeong&quot;, id: &quot;sj_dev_js&quot;};
const addNicknamePure = (o) =&gt; {
  return {...o, nickname: &quot;sujpark&quot;}; // 새로운 객체 생성
}
const newObj = addNicknamePure(obj);
console.log(obj); // {name: &quot;sujeong&quot;, id: &quot;sj_dev_js&quot;}
console.log(newObj); // {name: &quot;sujeong&quot;, id: &quot;sj_dev_js&quot;, nickname: &quot;sujpark&quot;}</code></pre>
<p>JavaScript 에서는 배열 또한 객체이기 때문에 같은 방식을 따른다.
JavaScript 는 함수형 프로그래밍을 위한 고차함수들 (<code>map</code>, <code>filter</code>, <code>slice</code> 등) 을 제공하기 때문에 적절히 사용하면 된다.</p>
<pre><code class="language-javascript">const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const mappedArr = arr.map(el =&gt; el + 1);
const filteredArr = arr.filter(el =&gt; el % 2 === 0)
const slicedArr = arr.slice(0, 2);

console.log(mappedArr); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(filteredArr); // [0, 2, 4, 6, 8]
console.log(slicedArr); // [0, 1]
console.log(arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
// 원본함수 arr는 변하지 않는다.</code></pre>
<h3 id="선언적-패턴을-통한-관심사-분리">선언적 패턴을 통한 관심사 분리</h3>
<p> 버튼을 클릭하면 화면의 숫자가 증가하는 코드를 <code>React</code> 로 작성한다고 생각해보자</p>
<pre><code class="language-javascript">function App() {
  const [count, setCount] = useState(0);
  const onClick = () =&gt; setState(count + 1);

  return &lt;div&gt;
    &lt;div&gt;{count}&lt;/div&gt;
    &lt;button onClick={onClick}&gt;+&lt;/button&gt;
  &lt;div&gt;
}</code></pre>
<p>이 코드는 겉보기에 별 문제가 없어보인다.
하지만 화면의 숫자가 감소하는 버튼을 넣는다면 어떨까?</p>
<pre><code class="language-javascript">function App() {
  const [count, setCount] = useState(0);
  const onIncreaseClick = () =&gt; setState(count + 1);
  const onDecreaseClick = () =&gt; setState(count - 1);

  return &lt;div&gt;
    &lt;div&gt;{count}&lt;/div&gt;
    &lt;button onClick={onIncreaseClick}&gt;+&lt;/button&gt;
    &lt;button onClick={onDecreaseClick}&gt;-&lt;/button&gt;
  &lt;div&gt;
}</code></pre>
<p><code>count + 1</code> 과 <code>count - 1</code> 만 다를 뿐인데 외부의 상태 <code>count</code>를 변경하는 함수를 두개나 만들어버렸다. 이는 함수의 관심사를 확실하게 분리하지 않았기 때문이다. &quot;계산&quot; 기능을 click 함수들로부터 분리해보자.</p>
<pre><code class="language-javascript">function App() {
  const [count, setCount] = useState(0);
  const increase = (value) =&gt; value + 1;
  const decrease = (value) =&gt; value - 1;
  const onClick = (calculate) =&gt; setState(calculate(count));

  return &lt;div&gt;
    &lt;div&gt;{count}&lt;/div&gt;
    &lt;button onClick={() =&gt; onClick(increase)}&gt;+&lt;/button&gt;
    &lt;button onClick={() =&gt; onClick(decrease)}&gt;-&lt;/button&gt;
  &lt;div&gt;
}</code></pre>
<p>함수의 관심사를 <code>계산</code> 과 <code>상태관리</code> 를 기준으로 나누었다. JavaScript 에서 함수는 일급객체이기 때문에 다른 함수의 매개변수에 전달할 수 있다. 이제 onClick 은 상태를 변경하는 일을 맡고, increase 와 decrease 는 onClick의 매개변수에 전달되어 계산을 담당한다. 계산 과정이 바뀔때 상태관리 함수를 다시 작성할 필요없이 계산 과정만 바꾸어주면된다.</p>
<p>우리가 분리해낸 함수를 살펴보면 <code>순수함수</code> 라는 것을 알 수 있다. 그리고 상태 <code>count</code>를 변경하는 onClick 함수는 여전히 <code>side-effect</code> 를 가지고 있다. 위 코드와 같이 순수함수를 <code>side-effect</code> 로부터 최대한 분리해 계층화 하면 <code>선언적 패턴을 통한 관심사 분리</code> 가 된다. 우리는 이 패턴을 통해 함수를 간략하게 만들어 가독성을 높이고, 관심사를 분리하여 재사용성을 높일 뿐 아니라 의도치 않은 상태변경을 방지하여 버그를 최소화할 수 있다.</p>
<p>함수형 프로그래밍에 대해 더 자세히 알고 싶다면 아래 글을 적극 추천한다.
<em><a href="https://velog.io/@teo/functional-programming#%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9A%A9%EC%96%B4-%EB%8B%A4%EC%8B%9C%EC%93%B0%EA%B8%B0">다시 쓰는 함수형 프로그래밍</a></em></p>
<h2 id="프로토타입기반-객체지향-프로그래밍">프로토타입기반 객체지향 프로그래밍</h2>
<p>많은 개발자들이 Java의 Class기반 객체지향에 익숙할 것이라고 생각한다. 하지만 JavaScript 는 <strong>Java 의 Class 와는 다른</strong> 프로토타입 기반의 객체지향 프로그래밍을 지원한다. 많은 과정을 거쳐서 JavaScript 또한 Java의 Class 와 비슷한 모양새를 갖추게 되었지만 그 안에 든 객체지향에 대한 철학은 결코 같지 않다.</p>
<p>Java 에서 class 를 통해 생성된 instance 는 class 라는 설계도면을 따라서 만든 것 같은 형태를 하고 있다.
class Bird 에 fly 라는 메소드가 있다면 class Bird를 통해 생성된 인스턴스는 모두 fly라는 메소드를 가지고 있다.</p>
<p>JavaScript 에서 prototype 을 통해 생성된 instance 는 instance 가 내부에 메소드를 가질 수도 있지만 그보다 prototype 에 메소드를 두고 instance 와 연결해서 사용하는 방식을 사용한다. </p>
<pre><code class="language-javascript">function Bird() {
  this.eat = function () {
    console.log(&#39;eat&#39;);
  }
}

Bird.prototype.fly = function () {
  console.log(&#39;fly!&#39;);
}

const bird = new Bird();
console.log(bird); // Bird {eat: ƒ}
// intance 내부에는 eat 함수밖에 없다.
bird.eat(); // eat
bird.fly(); // fly!
// prototype 에만 선언된 fly 함수를 instance에서 사용할 수 있다.

Bird.prototype.jump = function () {
  console.log(&#39;jump&#39;);
}

bird.jump(); // jump
// instance가 생성된 후에도 prototype 에 추가된 함수를 사용할 수 있다.
</code></pre>
<p>이런 방식을 통해 메모리에서 인스턴스가 차지하는 공간을 줄일 수 있다.
뿐만 아니라 prototype 이 또다른 prototype 을 참조하는 프로토타입 체인을 통해서
상위 prototype 의 메소드를 사용할 수 있다.</p>
<h1 id="참고">참고</h1>
<p><a href="https://velog.io/@teo/functional-programming#%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9A%A9%EC%96%B4-%EB%8B%A4%EC%8B%9C%EC%93%B0%EA%B8%B0">(강추!!) 다시 쓰는 함수형 프로그래밍</a></p>
<p><a href="https://medium.com/weekly-webtips/imperative-vs-declarative-programming-in-javascript-25511b90cdb7">Imperative vs Declarative programming in JavaScript | by Martin Novak | Weekly Webtips | Medium</a></p>
<p><a href="https://codeburst.io/imperative-vs-declarative-javascript-8b5e45a602dd">Imperative vs Declarative JavaScript | by Cliff Hall | codeburst</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 클로저 Closure]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript-%ED%81%B4%EB%A1%9C%EC%A0%80-Closure-h7z6h3mm</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript-%ED%81%B4%EB%A1%9C%EC%A0%80-Closure-h7z6h3mm</guid>
            <pubDate>Sat, 14 May 2022 11:32:24 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<h3 id="클로저란-">클로저란 ?</h3>
<p>클로저는 자바스크립트 고유의 개념이 아니다. 
함수를 일급객체로 취급하는 함수형 프로그래밍 언어에서 공통적으로 사용되는 특성이다. 
따라서 ECMAScript 사양에 정의되어있지 않다.
대신 MDN에 따른 클로저의 정의는 다음과 같다.</p>
<blockquote>
<p><strong>클로저</strong>는 <code>함수</code>와 <code>그 함수가 선언된 렉시컬 환경</code>과의 조합이다.</p>
</blockquote>
<p>렉시컬 환경? 렉시컬 환경과의 조합? 처음 읽을 때는 무슨 말인지 도통 이해가 가질 않는다.
정의를 이해하기 위해 먼저 아래 코드들을 살펴보자</p>
<pre><code class="language-javascript">// 1. inner 함수가 outer 함수 바깥에서 정의된 경우
const x = 1;

function outer() {
    const x = 10;
      inner();
}

function inner() {
    console.log(x);
}

outer(); // 1
</code></pre>
<pre><code class="language-javascript">// 2. inner 함수가 outer 함수 내부에서 정의된 경우
const x = 1;

function outer() {
    const x = 10;
    function inner() {
      console.log(x);
    }

    inner();
}

outer(); // 10</code></pre>
<p>코드를 실행해보면, <code>inner</code> 함수가 정의된 위치에 따라 참조하는 변수 <code>x</code> 가 달라지는 것을 확인할 수 있다.
<code>outer</code> 함수 외부에서 <code>inner</code> 함수를 선언했을 때는 <code>outer</code> 외부의 변수 <code>x</code> 를 참조하고,
<code>outer</code> 함수 내부에서 <code>inner</code> 함수를 선언했을 때는 <code>outer</code> 내부의 변수 <code>x</code> 를 참조한다.</p>
<p>자바스크립트는 정적 스코프를 따르는 언어이다. (대부분의 언어가 그렇다)
정적 스코프를 따르는 언어는 함수가 선언된 위치에 따라 상위 스코프가 정해진다.
즉 어디에 함수를 정의했는지에 따라서 상위 스코프가 정해진다.</p>
<p>또한 자바스크립트에서 스코프라는 개념은 <code>렉시컬 환경</code> 을 통해 구현된다.
즉 <code>렉시컬 환경</code> 이 스코프의 실체라고 할 수 있다.</p>
<h3 id="쉽게-보는-정의">쉽게 보는 정의</h3>
<p>MDN에 의한 클로저의 정의를 다시 한번 보자</p>
<blockquote>
<p><strong>클로저</strong>는 <code>함수</code>와 <code>그 함수가 선언된 렉시컬 환경</code>과의 조합이다.</p>
</blockquote>
<p>위에서 말했듯이 정적 스코프를 따르는 언어는 함수가 선언된 위치에 따라 상위 스코프(상위 렉시컬 환경)가 정해진다.
따라서 정의를 쉽게 바꾸면 다음과 같다.</p>
<blockquote>
<p><strong>클로저</strong>는 <code>함수</code>와 <code>그 함수의 상위 스코프</code>와의 조합이다.</p>
</blockquote>
<h3 id="그래서-함수와-그-함수의-상위-스코프를-어떻게-조합할-수-있을까">그래서 함수와 그 함수의 상위 스코프를 어떻게 조합할 수 있을까?</h3>
<pre><code class="language-javascript">const x = 1;
function outer() {
  const x = 10;
  const inner = function () {
    console.log(x);
  }
  return inner;
}

const inner = outer(); // ...(*)
inner(); // 10</code></pre>
<p>위 코드는 <code>outer</code> 함수 외부와 내부에 각각 다른 값을 가지는 변수 <code>x</code>를 선언하고,
중첩함수 <code>inner</code> 로 하여금 <code>console.log</code> 를 통해 <code>x</code> 를 출력하게 만든다.
<code>(*)</code> 에서 <code>outer</code> 함수의 호출 후 <code>outer</code> 함수의 실행이 끝나면 <code>outer</code> 함수의 생명주기도 종료되어
<code>outer</code> 함수 내부 변수 <code>x</code> 에 접근할 수 없을 것 처럼 보인다.</p>
<p>하지만 코드를 실행해보면 내부 변수 <code>x</code>의 값인 10을 출력한다.
이는 <code>outer</code> 함수의 스코프(렉시컬 환경)가 아직 유효하다는 것을 의미한다.</p>
<p>사실 참조되고 있는 렉시컬 환경은 해당 문맥의 생명주기가 종료되어도 가비지 컬렉터에 의해 메모리가 해제되지 않는다.
<code>outer</code> 함수는 <code>outer</code> 함수의 스코프를 외부 스코프로 참조하는 <code>inner</code> 함수를 반환해서 저장했기 때문에 <code>outer</code> 함수의 렉시컬 환경은 사라지지 않았다.</p>
<blockquote>
<p>이처럼 중첩함수가 외부함수보다 오래 유지되는 경우
중첩함수는 이미 생명주기가 종료된 외부함수의 변수를 참조할 수 있는데
이 중첩함수를 <strong>클로저</strong>라고 한다.</p>
</blockquote>
<br>

<h1 id="활용">활용</h1>
<p>클로저는 특정 함수에게만 상태 변경을 허용함으로써 상태가 의도치 않게 변경되는 것을 막는다.</p>
<h3 id="잘못된-예시">잘못된 예시</h3>
<pre><code class="language-javascript">let num = 0;

const increase() {
  return ++num;
}

console.log(increase()); // 1
console.log(++num); // 2
console.log(increase()); // 3</code></pre>
<p>위 코드는 <code>increase</code> 함수가 변수 <code>num</code> 의 상태를 변경하고 있지만,
<code>++num</code> 처럼 다른 코드에 의해 변수 <code>num</code> 의 상태가 변경될 수 있는 위험을 가지고 있다.</p>
<br>

<pre><code class="language-javascript">const increase() {
  let num = 0;
  return ++num;
}

console.log(increase()); // 1
console.log(increase()); // 1
console.log(increase()); // 1 </code></pre>
<p>위 코드는 함수를 사용할 때마다 변수 <code>num</code> 이 새롭게 선언되기 때문에 의도한 대로 사용할 수 없다.</p>
<h3 id="올바른-예시">올바른 예시</h3>
<pre><code class="language-javascript">const increase =( function () {
  let num = 0;
  return function () {
      return ++num;
  }
}())

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3</code></pre>
<p>변수 <code>num</code> 을 은닉하고 <code>increase</code> 함수에 의해서만 상태가 변경되는 올바른 예시이다.</p>
<p>아래는 <code>decrease</code> 함수까지 제공하는 예시이다.</p>
<pre><code class="language-javascript">const counter = (function () {
  let num = 0;
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return num &gt; 0 ? --num : 0;
    }
  }
}());

console.log(counter.increase()); // 1
console.log(counter.increase()); // 2
console.log(counter.increase()); // 3
console.log(counter.decrease()); // 2
console.log(counter.decrease()); // 1
console.log(counter.decrease()); // 0
console.log(counter.decrease()); // 0</code></pre>
<h1 id="참고">참고</h1>
<p>이웅모, 『모던 자바스크립트 Deep Dive - 자바스크립트의 기본 개념과 동작 원리』, 위키북스(2020), p388-408</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Array.from() 과 Array.prototype.map() 비교하기]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript-Array.from-%EA%B3%BC-Array.prototype.map-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript-Array.from-%EA%B3%BC-Array.prototype.map-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 09 May 2022 05:07:11 GMT</pubDate>
            <description><![CDATA[<p><code>Array.from()</code> 과 <code>Array.prototype.map()</code> 모두 기존 배열의 각 요소에 함수를 적용해서 새로운 배열을 만든다. </p>
<pre><code class="language-javascript">const arr = [0, 1, 2];
const usingFrom = Array.from(arr, (item)=&gt; item + 1);
const usingMap = arr.map((item) =&gt; item + 1);
console.log(usingFrom); // [1, 2, 3];
console.log(usingMap); // [1, 2, 3];</code></pre>
<p>그렇다면 <code>Array.from()</code> 과 <code>Array.prototype.map()</code> 의 차이는 무엇일까?</p>
<h2 id="static-method-vs-instance-method">Static Method vs Instance Method</h2>
<p><code>Array.from()</code> 과 <code>Array.prototype.map()</code> 차이는 우선 생김새에서부터 나타난다.
<code>Array.from()</code> 은 Static Method 이기 때문에 instance로 생성된 배열에 대해 사용할 수 없다.</p>
<pre><code class="language-javascript">const arr = [1, 2, 3];
// 잘못된 사용
arr.from(); // Uncaught TypeError: arr.from is not a function

// 올바른 사용
const newArr = Array.from(arr);
console.log(newArr); // [1, 2, 3];</code></pre>
<p><code>Array.prototype.map()</code> 은 Instance Method 이기 때문에 Array에 직접 사용할 수 없고, instance로 생성된 배열에 대해 사용할 수 있다.</p>
<pre><code class="language-javascript">const arr = [1, 2, 3];
// 잘못된 사용
Array.map(); // TypeError: Array.map is not a function

// 올바른 사용
const newArr = arr.map((i) =&gt; i); 
console.log(newArr) // [1, 2, 3];</code></pre>
<h2 id="with-array-like-and-iterable">With array-like and iterable</h2>
<p><code>Array.from()</code> 는 유사배열 객체, 이터러블 객체를 배열로 바꿔주는 기능을 가지고 있다.</p>
<pre><code class="language-javascript">const obj = {&#39;0&#39;:&#39;apple&#39;, &#39;1&#39;:&#39;banana&#39;, &#39;2&#39;:&#39;carrot&#39;, length: 3}; // array-like
const objArr = Array.from(obj);
console.log(objArr); // [&quot;apple&quot;, &quot;banana&quot;, &quot;carrot&quot;]

const str = &quot;abcde&quot;; // iterable
const strArr = Array.from(str);
console.log(strArr); // [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;e&quot;];</code></pre>
<p><code>Array.prototype.map()</code> 는 유사배열 객체나 이터러블 객체에 대해 사용할 수 없다.</p>
<pre><code class="language-javascript">const obj = {&#39;0&#39;:&#39;apple&#39;, &#39;1&#39;:&#39;banana&#39;, &#39;2&#39;:&#39;carrot&#39;, length: 3};
const objArr = obj.map(); // Uncaught TypeError: obj.map is not a function

const str = &quot;abcde&quot;;
const strArr = str.map(); // Uncaught TypeError: str.map is not a function</code></pre>
<h2 id="performance">Performance</h2>
<p><code>Array.from()</code> 과 <code>Array.prototype.map()</code> 는 몇가지 차이가 있지만 일반 배열에 대해서는 똑같이 사용할 수 있다. 
그렇다면 둘 중 무엇을 사용해야할까?</p>
<h4 id="검사해보자">검사해보자</h4>
<pre><code class="language-javascript">const fromWrapper = () =&gt; Array.from([{&quot;count&quot;: 3},{&quot;count&quot;: 4},{&quot;count&quot;: 5}], x =&gt; x.count);
const mapWrapper = () =&gt; [{&quot;count&quot;: 3},{&quot;count&quot;: 4},{&quot;count&quot;: 5}].map(item =&gt; item.count);

const iterations = 1000000;
console.time(&#39;Array.from()&#39;);
for(let i = 0; i &lt; iterations; i++){
    fromWrapper();
};
console.timeEnd(&#39;Array.from()&#39;)

console.time(&#39;Array.prototype.map()&#39;);
for(let i = 0; i &lt; iterations; i++){
    mapWrapper();
};
console.timeEnd(&#39;Array.prototype.map()&#39;)</code></pre>
<h4 id="결과">결과</h4>
<pre><code class="language-bash"># Google Chrome Version 89.0.4389.90 (Official Build) (x86_64)
Array.from(): 179.098876953125 ms
Array.prototype.map(): 24.609130859375 ms</code></pre>
<p><code>iterations</code> 가 10 정도로 매우 작은 경우는 from 이 더 빠른데,
<code>iterations</code> 이 좀만 커져도 map이 빨라지는 것을 확인할 수 있다.</p>
<p>고로 둘다 사용할 수 있는 상황에서는 <code>Array.prototype.map()</code> 를 사용하는 것이 좋다</p>
<h2 id="참고">참고</h2>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from">Array.from() - JavaScript | MDN</a></p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map">Array.prototype.map() - JavaScript | MDN</a></p>
<p><a href="https://stackoverflow.com/questions/26052699/array-from-vs-array-prototype-map">stackoverflow : javascript - Array.from vs Array.prototype.map</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Array.prototype.fill() 은 객체를 참조복사한다]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript%EB%8B%A4%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%EC%8B%9C-%EC%9C%A0%EC%9D%98%ED%95%98%EC%9E%90</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript%EB%8B%A4%EC%B0%A8%EC%9B%90-%EB%B0%B0%EC%97%B4-%EC%83%9D%EC%84%B1%EC%8B%9C-%EC%9C%A0%EC%9D%98%ED%95%98%EC%9E%90</guid>
            <pubDate>Wed, 20 Apr 2022 11:52:24 GMT</pubDate>
            <description><![CDATA[<p>예전에 C++로 풀었던 BFS 문제를 JavaScript 로 풀었는데, 같은 로직임에도 불구하고 풀리지 않았다.</p>
<p>코드를 한줄씩 테스트 해보고서야 배열을 생성하는 코드에 문제가 있었다는 것을 알아냈다.
평소에 선언과 동시에 초기화 하기 위해 <code>new Array(5).fill(0)</code> 같은 코드를 작성하곤 했는데, 다차원 배열에 그대로 적용한 것이 문제였다.
5x5 배열을 생성하면서 -1로 초기화를 하기위해 다음과 같은 코드를 사용했었다.</p>
<pre><code class="language-javascript">const distance = new Array(5).fill(new Array(5).fill(-1));</code></pre>
<blockquote>
<p><code>Array.prototype.fill()</code> 에 객체를 넣으면 객체를 <strong>참조복사</strong>한다.</p>
</blockquote>
<p>따라서 위 코드는 하나의 1x5 배열을 생성하여 5번 push 하는 코드이다.
한 배열의 참조가 5번 들어간 것이기 때문에 하나의 배열을 고치면 다른 배열도 똑같이 바뀌게 된다.</p>
<pre><code class="language-javascript">const distance = new Array(5).fill(new Array(5).fill(-1));
distance[0][0] = 1;
console.log(distance) 
// [[1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0], [1,0,0,0,0]]</code></pre>
<p>다차원 배열을 선언하면서 초기화하기 위해서는 아래와 같은 코드를 작성해야한다.</p>
<pre><code class="language-javascript">const distance = Array.from(new Array(5), () =&gt; new Array(5).fill(-1));</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] [프로그래머스] 표 편집 : falsy 값에 유의하자!]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%91%9C-%ED%8E%B8%EC%A7%91-falsy-%EA%B0%92%EC%97%90-%EC%9C%A0%EC%9D%98%ED%95%98%EC%9E%90</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%ED%91%9C-%ED%8E%B8%EC%A7%91-falsy-%EA%B0%92%EC%97%90-%EC%9C%A0%EC%9D%98%ED%95%98%EC%9E%90</guid>
            <pubDate>Wed, 20 Apr 2022 08:00:06 GMT</pubDate>
            <description><![CDATA[<h2 id="falsy값-이란">falsy값 이란?</h2>
<p><code>falsy</code> 값이란 <code>Boolean</code> 문맥에서 <code>false</code>로 평가되는 값이다.</p>
<h2 id="falsy-값-종류">falsy 값 종류</h2>
<p><code>falsy</code> 값은 8가지가 있다.</p>
<blockquote>
<ol>
<li><code>false</code> </li>
<li><code>0</code> : 숫자 0</li>
<li><code>-0</code> : 음수 0</li>
<li><code>0n</code> : BigInt 0</li>
<li><code>&quot;&quot;</code> : 빈 string</li>
<li><code>null</code> : 아무런 값도 없음</li>
<li><code>undefined</code></li>
<li><code>NaN</code> : 숫자가 아님</li>
</ol>
</blockquote>
<h2 id="코테에서">코테에서...</h2>
<p><code>falsy</code> 값에 대해서 알고는 있었는데, 실제로 주의를 기울여야한다는 것은 코딩테스트를 연습하면서 체감하게 되었다.
다음은 2021년 카카오 채용연계형 인턴십 문제이다.</p>
<p><a href="https://programmers.co.kr/learn/courses/30/lessons/81303#">2021 카카오 채용연계형 인턴십 - 표 편집</a></p>
<p>당시 코테 후기를 찾아보면 이 문제가 코테부문 당락을 갈랐다는 것을 알 수 있다.
(이 문제가 3번째 문제인데 4,5번째 문제는 각각 Lv.4, Lv.5 이다.)</p>
<p>처음엔 단순한 리스트로 문제를 풀었다가 효율성 부문에서 통과가 안되어서 리스트 내에 객체를 넣어서 양방향 리스트와 유사하게 작동하게끔 구현하였다.</p>
<pre><code class="language-javascript">const list = [];

for (let i = 0; i &lt; n; i++) {
    if (i == 0)
        list[i] = {prev : null, next : i + 1, exist: true};
    else if (i === n - 1)
        list[i] = {prev : i - 1, next : null, exist: true};
    else
        list[i] = {prev : i - 1, next : i + 1, exist: true};
}</code></pre>
<p>다음은 입력으로 들어오는 명령 각각에 대해서 수행하는 로직이다.</p>
<pre><code class="language-javascript">const list = [];
const deleted = [];
let cursor = k;
...
cmd.forEach((command) =&gt; {
    const [order, num] = command.split(&#39; &#39;);
    if (order === &#39;U&#39;) {
        let t = parseInt(num);
        while (t--) {
            cursor = list[cursor].prev;
        }
    } else if (order === &#39;D&#39;) {
        let t = parseInt(num);
        while (t--) {
            cursor = list[cursor].next;
        }
    } else if (order === &#39;C&#39;) {
        const {prev, next} = list[cursor];
        // 연결리스트 삭제와 유사 (실제로 배열에서 사라지지는 않음)
        if (prev) list[prev].next = next; 
        if (next) list[next].prev = prev;
        list[cursor].exist = false;
        deleted.push(cursor);
        cursor = next === null ? prev : next;
    } else if (order === &#39;Z&#39;) {
        const repaired = deleted.pop();
        const {prev, next} = list[repaired];
        // 삭제 전으로 돌아가게 만듬
        if (prev) list[prev].next = repaired;
        if (next) list[next].prev = repaired;
        list[repaired].exist = true;
    }
})</code></pre>
<p>이 로직은 잘 돌아가는 것처럼 보이지만 테스트케이스 28번, 효율성케이스 8번에서 런타임 에러가 난다.</p>
<p>며칠을 고민하다가 친구(@dha)의 도움으로 찾을 수 있었는데,</p>
<pre><code class="language-javascript">...
if (prev) list[prev].next = next; // prev에 0이 들어올 수 있음
...
if (prev) list[prev].next = repaired;
...</code></pre>
<p><code>null</code> 을 방지하기 위해 넣은 조건문에 0이 들어오는 경우 조건문을 통과하지 못하기 때문이었다.
(prev, next에 저장되는 것은 인덱스이기 때문에 0이 들어올 수 있다.)</p>
<p><strong>참으로 어이없는 실수다...</strong></p>
<p>올바르게 고친 코드는 다음과 같다.</p>
<pre><code class="language-javascript">const list = [];
const deleted = [];
let cursor = k;
...
cmd.forEach((command) =&gt; {
    const [order, num] = command.split(&#39; &#39;);
    if (order === &#39;U&#39;) {
        let t = parseInt(num);
        while (t--) {
            cursor = list[cursor].prev;
        }
    } else if (order === &#39;D&#39;) {
        let t = parseInt(num);
        while (t--) {
            cursor = list[cursor].next;
        }
    } else if (order === &#39;C&#39;) {
        const {prev, next} = list[cursor];

        if (prev !== null) list[prev].next = next; // null 검사
        if (next !== null) list[next].prev = prev; // null 검사
        list[cursor].exist = false;
        deleted.push(cursor);
        cursor = next === null ? prev : next;
    } else if (order === &#39;Z&#39;) {
        const repaired = deleted.pop();
        const {prev, next} = list[repaired];

        if (prev !== null) list[prev].next = repaired; // null 검사
        if (next !== null) list[next].prev = repaired; // null 검사
        list[repaired].exist = true;
    }
})</code></pre>
<h1 id="마무리">마무리</h1>
<p><code>fasly</code> 값에 대해 처음 알게되었을때 단순하게 if 문을 쓸 때 주의해야지~ 라고만 생각하고 넘어갔었는데 이번 기회로 생각을 바꾸게 되었다.
단순히 코테를 연습할 때도 잘못 쓴 코드 하나를 잡느라 며칠이 걸렸는데, 실제 코딩테스트였다면? <code>falsy</code> 체크 제대로 못한 것 때문에 로직을 다 생각해놓고도 떨어졌을 것이다. 내가 언제든 바보같은 실수를 할 수 있다는 것을 인정하고 <strong>if 문을 쓸 때 정확하게 명시</strong>하는 습관을 가져야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 표현식과 명령문 그리고 값]]></title>
            <link>https://velog.io/@sj_dev_js/JavaScript-%ED%91%9C%ED%98%84%EC%8B%9D%EA%B3%BC-%EB%AA%85%EB%A0%B9%EB%AC%B8-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B0%92</link>
            <guid>https://velog.io/@sj_dev_js/JavaScript-%ED%91%9C%ED%98%84%EC%8B%9D%EA%B3%BC-%EB%AA%85%EB%A0%B9%EB%AC%B8-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B0%92</guid>
            <pubDate>Sat, 09 Apr 2022 05:56:12 GMT</pubDate>
            <description><![CDATA[<h2 id="값">값</h2>
<p>프로그래밍에서 값이란
<strong>표현식을 평가해 생성한 결과</strong>를 말한다.</p>
<pre><code class="language-javascript">x = 30; // 리터럴 30을 평가한 결과인 숫자 30은 값이다.
x = 10 + 20; // 10 + 20 을 평가한 결과인 숫자 30은 값이다.</code></pre>
<p>값은 데이터 타입을 가진다. 
컴퓨터는 2진수로 값을 저장하는데 어떤 데이터 타입인지에 따라서 읽는 방법이 달라진다.
ex) 0100 0001 : 65로 읽을 수도 있고, &#39;A&#39;로 읽을 수도 있다.</p>
<h3 id="리터럴">리터럴</h3>
<p>리터럴이란 사람이 이해할 수 있는 문자나 미리 약속된 기호를 사용하여 값을 생성하는 표기법이다.</p>
<pre><code class="language-javascript">30; // 숫자 30으로 평가되는 리터럴</code></pre>
<h2 id="표현식-expression">표현식 (Expression)</h2>
<p>표현식이란 <strong>값으로 평가될 수 있는 명령문</strong>을 말한다.
표현식이 평가되면 새로운 값을 생성하거나 기존 값을 참조한다.</p>
<pre><code class="language-javascript">30; // 표현식
10 + 20; // 표현식
sum = 10 + 20; // 표현식
sum; // 표현식</code></pre>
<p>리터럴은 평가되어 값을 생성하므로 그 자체로도 표현식이다.</p>
<h2 id="명령문-statement">명령문 (Statement)</h2>
<p>명령문이란 <strong>프로그램을 구성하는 기본 단위이자 최소 실행 단위</strong>이다.
명령문은 토큰으로 이루어져 있다.</p>
<blockquote>
<p><strong>토큰 (token)</strong>
문법적으로 의미를 가지면서 더 나눌 수 없는 최소 단위를 말한다.</p>
</blockquote>
<p>표현식의 정의에서 알 수 있듯이 표현식은 명령문이다.
명령문은 표현식인 문과 표현식이 아닌 문으로 나눌 수 있다.</p>
<pre><code class="language-javascript">var x; // 표현식이 아닌 문
x = 10 + 20; // 표현식인 문</code></pre>
<p>변수의 선언은 값으로 평가될 수 없으므로 표현식이 아닌 문이다.
변수에 할당하는 문은 값으로 평가될 수 있으므로 표현식인 문이다.</p>
<p>명령문이 표현식인지 아닌지 판단할 수 있는 가장 좋은 방법은 변수에 할당하는 것이다.
표현식과 표현식이 평가된 값은 문법적으로 동치이기 때문에 
특정한 값이 있을 수 있는 자리에 그 값으로 평가되는 표현식도 있을 수 있다.</p>
<pre><code class="language-javascript">var foo = var x; // SyntaxError: Unexpected token var
var bar = x = 10 + 20;
console.log(bar); // 30</code></pre>
<h3 id="참고">참고</h3>
<p>이웅모, 『모던 자바스크립트 Deep Dive - 자바스크립트의 기본 개념과 동작 원리』, 위키북스(2020), p50-57</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 2장 운영체제구조]]></title>
            <link>https://velog.io/@sj_dev_js/OS-2%EC%9E%A5-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@sj_dev_js/OS-2%EC%9E%A5-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 08 Apr 2022 04:13:40 GMT</pubDate>
            <description><![CDATA[<h1 id="운영체제에서-제공하는-서비스">운영체제에서 제공하는 서비스</h1>
<p>운영체제에 포함하도록 정해진 서비스는 없으나 공통적으로 제공하는 서비스들이 있다.</p>
<h3 id="사용자-인터페이스">사용자 인터페이스</h3>
<p>거의 모든 운영체제는 사용자 인터페이스를 제공한다. 
인터페이스에는 여러 형태가 존재하는데 명령 인터프리터, 그래픽 사용자 인터페이스(GUI), 터치 스크린 인터페이스가 있다.</p>
<h4 id="명령-인터프리터-command-interpreter">명령 인터프리터 (Command-Interpreter)</h4>
<p>명령 인터프리터는 사용자의 명령을 해석하고 수행한다. 명령의 수행은 두가지 방식으로 이뤄질 수 있다.
한가지 방법은 인터프리터가 사용자의 명령을 수행하는 코드를 가지는 것이다. 예를 들어, 파일을 삭제하는 명령은 명령 인터프리터가 매개변수를 설정하고 적절한 시스템 호출을 수행하는 코드영역으로 가도록 한다. 이 경우 제공할 수 있는 명령의 수가 명령 인터프리터의 크기를 결정한다. 각 명령이 구현 코드를 요구하기 때문이다.
다른 방법은 명령의 구현이 시스템프로그램에 의해 이루어지는 것이다. 이 경우 명령 인터프리터는 전혀 그 명령을 알지 못한다. 단지 파일을 식별하기위해 명령을 사용한다. 
예를 들어 UNIX 에서 파일을 삭제하는 명령을 입력하면,</p>
<blockquote>
<p><code>rm file.txt</code></p>
</blockquote>
<p><code>rm</code> 이라 불리는 파일을 찾아서, 그 파일을 메모리에 적재하고, 그것을 매개변수 <code>file.txt</code>로 수행한다. rm 명령과 관련된 로직은 rm이라는 파일 내의 코드로 수행된다. 새로운 파일을 생성함으로써 시스템에 새로운 명령을 쉽게 추가할 수도 있다. 그로인해 명령 인터프리터 프로그램은 아주 작아질 수 있으며, 새로운 명령을 추가하기 위해 변경될 필요가 없다.</p>
<h4 id="그래픽-기반-사용자-인터페이스-graphical-user-interface-gui">그래픽 기반 사용자 인터페이스 (Graphical User Interface, GUI)</h4>
<p>GUI는 명령 인터프리터처럼 명령어를 직접 입력하는 것이 아닌, 마우스를 기반으로 조작하는 윈도우-메뉴 시스템이다. 우리가 흔히 사용하는 인터페이스이기도 하다. 사용자는 마우스를 움직여 마우스 포인터를 화면상의 이미지(아이콘)에 위치시킨다. 마우스 포인터를 위치시키고 버튼을 누름으로써 프로그램을 호출하거나 파일을 선택하는 등의 여러가지 조작을 할 수 있다.</p>
<h4 id="터치스크린-인터페이스">터치스크린 인터페이스</h4>
<p>모바일 시스템에서는 일반적으로 터치스크린 인터페이스를 사용한다. 
사용자는 터치스크린에서 손가락을 누르거나 스와이프 하는 등의 제스처를 취하여 상호작용한다.</p>
<h3 id="프로그램-수행execution">프로그램 수행(execution)</h3>
<p>시스템은 프로그램을 메모리에 적재해 실행(running)할 수 있어야 한다. 프로그램은 정상적이든, 혹은 비정상적이든(오류를 표시하면서) 실행을 끝낼 수 있어야한다.</p>
<h3 id="입출력-연산">입출력 연산</h3>
<p>실행(running)중인 프로세스는 입출력을 요구할 수 있다. 이런 입출력에는 파일이나 입출력 장치가 연관될 수 있다. 효율성과 보호를 위해 사용자는 입출력 장치를 직접 제어할 수 없다. 운영체제가 입출력 수행의 수단을 제공해야한다.</p>
<h3 id="파일시스템-조작">파일시스템 조작</h3>
<p>운영체제에서 파일시스템은 특히 중요한 분야다. 프로그램은 파일을 읽고 쓸 수 있다. 또한 파일을 생성하고 삭제할 수 있고 지정된 파일을 찾을 수 있으며 파일의 정보를 나열할 수 있어야한다. 몇 몇 프로그램은 권한 관리를 이용하여 파일과 디렉터리의 접근을 허가하거나 거부할 수 있다.</p>
<h3 id="통신">통신</h3>
<p>프로세스 사이에서 정보를 교환해야할 필요가 있다. 이런 통신에는 두가지가 있는데 하나는 동일한 컴퓨터에서 수행 중(execution)인 프로세스들 사이에서 나타나고, 다른 하나는 네트워크로 연결된 서로 다른 컴퓨터 시스템 상에서 수행 중인 프로세스들 사이에서 일어난다. 통신은 공유 메모리를 통해서 구현될 수도 있고, 메시지 전달기법을 사용하여 구현될 수도 있다. 메세지 전달기법에서는 정보 패킷들이 운영체제에 의해 프로세스 사이를 이동한다.</p>
<h3 id="오류탐지">오류탐지</h3>
<p>운영체제는 가능한 모든 오류를 항상 의식하고 있어야한다. 오류는 
CPU, 
메모리 하드웨어 (메모리 오류, 정전 등), 
입출력 장치 (테이프의 패리티오류, 네트워크 접속 실패, 프린터 종이 부족 등), 
또는 사용자 프로그램 (연산의 오버플로우, 잘못된 위치의 메모리에 접근 시도 등)
에서 일어날 수 있다. 운영체제는 올바르고 일관성있는 처리를 보장하기 위해 각 유형의 오류에 대해 조치를 취해야한다.</p>
<h3 id="자원할당">자원할당</h3>
<p>다수의 프로세스가 동시에 실행(running)될 때, 각각의 프로세스에 자원을 할당해 주어야 한다.</p>
<h3 id="기록-작성">기록 작성</h3>
<p>어떤 프로그램이 어떤 종류의 컴퓨터 자원을 얼마나 많이 사용하는지 추적할 수 있다. 이와 같은 기록 관리는 회계 또는 사용 통계를 내기 위해 사용된다. 사용 통계는 서비스를 개선하기 위해 시스템을 재구성하고자 하는 시스템 관리자에게 귀중한 자료가 될 수 있다.</p>
<h3 id="보호와-보안">보호와 보안</h3>
<p>다중 사용자 컴퓨터 시스템 또는 네트워크로 연결된 컴퓨터 시스템에서 저장된 정보의 소유자는 그 정보의 사용을 통제하기를 원한다. 서로 다른 여러 프로세스가 병행하게 수행될 때, 한 프로세스가 다른 프로세스나 운영체제 자체를 방해해서는 안된다. 보호는 시스템 자원에 대한 모든 접근이 통제되도록 보장하는 것이다.
외부로부터의 보안 또한 중요하다. 보안은 각 사용자가 자원에 대한 접근을 원할 때 통상 패스워드를 사용해서 시스템에게 자기 자신을 인증하게한다. 네트워크 어댑터 등과 같은 외부 입출력 장치들을 부적합한 접근 시도로부터 지키고, 침입 탐지를 위해 모든 접속을 기록한다.</p>
<hr>
<h1 id="시스템-콜">시스템 콜</h1>
<p>사용자 프로그램이 잘못된 영역에 접근해서 치명적인 오류를 발생시키는 것을 막기 위해 컴퓨터시스템은 <strong>커널모드</strong> 와 <strong>사용자모드</strong> 라는 이중모드로 나뉘어 있다. 여러 장치들을 작동시키거나 시스템에 설정되어있는 여러 데이터들을 조작하는 권한은 커널모드에서 실행되는 프로그램만 가지고 있다. 사용자모드에서 위와 같은 수행이 필요한 경우 시스템 콜을 통해 커널모드에 요청하여 수행할 수 있다. 시스템콜은 운영체제가 제공하는 서비스에 대한 인터페이스를 제공하는 것이기도 하다.</p>
<h3 id="예제">예제</h3>
<p>시스템 콜이 어떻게 사용되는지 예제를 통해 알아보자.
한 파일로부터 데이터를 읽어서 다른 파일로 복사하는 프로그램을 작성한다고 가정해보자.</p>
<p>입력 파일과 출력 파일의 이름이 필요하므로 파일의 이름을 입력받는 I/O 시스템 콜이 필요하다.
두개의 파일 이름이 얻어지면 입력 파일을 오픈하고 출력 파일을 생성한 후 오픈한다. 파일 오픈에 시스템 콜이 필요하며, 시스템 오류가 발생하면 처리해야한다.</p>
<p>프로그램이 입력 파일을 오픈하려고 할 때, 그 이름을 갖는 파일이 존재하지 않거나 그 파일에 대한 접근이 금지되어있는 경우가 있을 수 있다. 이런 경우 프로그램은 에러메세지를 출력하고 비정상적으로 종료해야하는데 에러메세지 출력과 비정상적인 종료 모두 시스템 콜을 통해 이루어진다.</p>
<p>출력 파일을 생성하는데 동일한 이름을 가진 파일이 이미 존재하는 경우가 있다. 이런 상황에서는 프로그램을 중단하거나 기존 파일을 삭제한 후, 새로운 파일을 생성할 수도 있다. 프로그램 중단, 기존 파일 삭제, 새로운 파일 생성 모두 시스템 콜을 통해 이루어진다.</p>
<p>두 파일이 준비되면 입력 파일로부터 읽어서(시스템 콜), 출력 파일에 기록(시스템 콜)하기를 반복한다. 각 읽기와 쓰기는 가능한 여러가지 오류 상황에 대한 정보를 반환(시스템 콜)해야한다. 읽는 중에 프로그램이 파일의 끝에 도달하거나 하드웨어 오류가 발생할 수 있다. 쓰는 중에 출력 장치에 따라 여러가지 오류들이 발생할 수 있다.</p>
<p>전체 파일이 복사된 후, 프로그램은 두 개의 파일을 닫고(시스템 콜) 콘솔 또는 윈도우에 메세지를 기록(시스템 콜)하고 프로그램을 정상적으로 종료(시슽템 콜)하게 된다.</p>
<p><img src="https://velog.velcdn.com/cloudflare/sj_dev_js/633f2906-c446-4ff0-8101-ade567eb871a/Screen%20Shot%202022-04-08%20at%209.59.17%20AM.png" alt=""></p>
<h3 id="응용프로그래밍-인터페이스">응용프로그래밍 인터페이스</h3>
<p>위 예제에서 보듯이 간단한 프로그램이라도 시스템 콜을 아주 많이 사용하게 된다. 하지만 대부분의 응용 프로그램 개발자들은 시스템 콜을 직접 사용하는 것이 아니라 응용 프로그래밍 인터페이스(API)를 통해 프로그램을 설계한다. API는 응용프로그래머가 사용 가능한 함수의 집합을 명시한다. API를 구성하는 함수들은 응용프로그래머를 대신하여 실제 시스템을 콜을 호출한다. 예를 들면 Windows의 함수 CreateProcess() 는 실제로 Windows 커널의 NTCreateProcess() 시스템콜을 부른다. 왜 실제 시스템 콜을 사용하지 않고 API를 사용할까? 이는 프로그램의 호환성과 관련이 있다. 각각 다른 운영체제는 고유의 시스템 콜을 가지는데 다른 운영체제가 같은 API를 지원한다면 같은 API 함수를 사용하여 프로그램을 작성할 수 있을 것이다. 게다가 실제 시스템 호출은 종종 애플리케이션 프로그래머가 사용할 수 있는 API보다 더 자세하고 작업하기 어렵다.</p>
<p>시스템 콜을 처리하는데 있어서 중요한 또 다른 요소는 <strong>런타임 환경(RTE)</strong> 이다. 런타임 환경이란 특정 프로그래밍 언어로 작성된 응용 프로그램을 실행하는 데 필요한 전체 소프트웨어 모음이다. 런타임 환경은 운영체제가 제공하는 시스템 콜에 대한 연결고리 역할을 하는 <strong>시스템 콜 인터페이스</strong>를 제공한다. 이 시스템 콜 인터페이스는 API 함수의 호출을 가로채어 필요한 운영체제 시스템 콜을 부른다. 각 시스템 콜에는 번호가 할당되고 시스템 콜 인터페이스는 이 번호에 따라 색인화된 테이블을 유지한다. 시스템 콜 인터페이스는 의도하는 시스템 콜을 부록 시스템 콜의 상태와 반환 값을 돌려준다.</p>
<p><img src="https://velog.velcdn.com/cloudflare/sj_dev_js/8204446b-d67d-4680-9e5b-64235fcae56a/Screen%20Shot%202022-04-08%20at%209.59.53%20AM.png" alt=""></p>
<p>호출자는 시스템 콜이 어떻게 구현되고 실행 중 무슨 작업을 하는지 아무것도 알 필요가 없다. 호출자는 단지 API를 준수하고 시스템 콜의 결과로서 운영체제가 무엇을 할 것인지만 이해하면 된다. 운영체제 인터페이스에 대한 대부분의 자세한 내용은 API에 의해 프로그래머로부터 숨겨지고 런타임 환경에 의해 관리된다.</p>
<p>시스템 콜을 통해 운영체제에 매개변수를 전달하기 위한 방법은 세가지가 있다.
가잔 간단한 방법은 매개변수를 레지스터 내에 전달하는 것이다. 그러나 어떤 경우는 레지스터보다 더 많은 매개변수가 있을 수 있다. 여런 경우 매개변수는 메모리 내의 블록이나 테이블에 저장되고, 블록의 주소가 레지스터 내에 매개변수로 전달된다. 혹은 프로그램에 의해 스택에 넣어져서 운영체제에 의해 꺼내진다. 블록 방법이나 스택방법은 전달되는 매개변수들의 개수나 길이를 전달하지 않는다.
<img src="https://velog.velcdn.com/cloudflare/sj_dev_js/d3e6157d-9880-48d4-b8b1-081fef6cd38c/Screen%20Shot%202022-04-08%20at%2010.09.57%20AM.png" alt=""></p>
<hr>
<h1 id="운영체제-구조">운영체제 구조</h1>
<h2 id="모놀리식-구조">모놀리식 구조</h2>
<p>운영체제를 구성하는 가장 간단한 구조는 구조가 아예 없는 것이다. 커널의 모든 기능을 단일 파일에 넣는 것이다. 모놀리식 구조라고 하는 이 방법은 운영체제를 설계하는 일반적인 기술이다. 이 구조를 가진 운영체제의 예로 UNIX가 있다. 모놀리식의 단순성에도 불구하고 이 구조는 구현이나 확장이 어렵다. 그러나 시스템 콜 인터페이스에 오버헤드가 거의 없고 커널 안에서의 통신 속도가 빠르다는 장점이 있다. 모놀리식 커널의 단점에도 불구하고 속도와 효율성 덕분에 이 구조를 여전히 UNIX, Linux, Windows 운영체제에서 발견할 수 있다.</p>
<h4 id="밀접한-결합-vs-느슨한-결합">밀접한 결합 vs 느슨한 결합</h4>
<p>시스템의 한 부분을 변경하면 다른 부분에 광범위한 영향을 줄 수 있으므로 모놀리식 접근법은 밀접하게 결합된 시스템으로 불린다. 모놀리식 구조의 대안으로 느슨하게 결합된 시스템을 설계할 수 있다. 이러한 시스템은 특정 기능을 가진 개별적이며 작은 구성요소로 나뉘고 모든 구성요소가 합쳐져 커널을 구성한다. 모듈 방식의 장점은 한 구성요소의 변경이 해당 구성요소에만 영향을 미치고 다른 구성요소에는 영향을 미치지 않으므로 시스템 구현자가 시스템의 내부를 자유롭게 생성하고 변경할 수 있다는것이다.</p>
<h2 id="계층적-접근">계층적 접근</h2>
<p>시스템은 다양한 방법으로 모듈화 될 수 있는데 그 중 한가지가 계층적 접근 방식이다. 이 방식에서는 운영체제가 여러개의 층으로 나누어진다. 최하위 층(0층)은 하드웨어이고 최상위 층(N층)은 사용자 인터페이스이다. 운영체제 각 층(1층 ~ N-1층)은 데이터와 이를 조작하는 연산으로 구성된다.
각 층은 자료구조와 상위층에서 호출할 수 있는 루틴의 집합으로 구성된다. 해당 층 하위층에 대한 연산을 호출할 수 있다.
계층적 접근 방식의 주된 장점은 구현과 디버깅의 간단함이다. 층들은 단지 자신의 하위층들의 기능들만을 사용할 수 있다. 이러한 접근 방식은 시스템의 검증과 디버깅 작업을 단순화 한다. 운영체제 첫번째 층은 하드웨어만을 사용하여 이 층의 기능을 구현하고 하드웨어는 정확하다고 가정하기 때문에 나머지 층에서 첫번째 층에 대해 아무런 신경을 쓰지 않고 디버깅 할 수 있다. 첫번째 층의 디버깅이 끝나면 두번째 층을 디버깅하는 동안 첫번째 층이 정확하게 동작한다고 가정할 수 있으며 이러한 과정이 반복된다. 만약 디버깅 중 어느 층에서 오류가 발견되면 그 하위의 층은 이미 디버깅 되었기 때문에 오류는 반드시 그 층에 있다. 따라서 시스템을 계층으로 나누면 시스템의 설계나 구현이 간단해진다.
각 층은 하위층으로부터 제공된 연산들만 사용해 구현된다. 한 층은 이러한 연산이 어떻게 구현되는지 알 필요가 없고 다만 이러한 연산들이 무엇을 하는지만 알면된다. 그러므로 각 층은 특정 데이터구조, 연산, 그리고 하드웨어의 존재를 상위층에 숨기게 된다.
이런 시스템의 성능은 각 층을 통과하는 오버헤드로 인해 좋지 못하다. 그러나 어느 정도의 계층화는 현대 운영체제에서 일반적이다.
<img src="https://velog.velcdn.com/cloudflare/sj_dev_js/f6c07a22-d670-4d7e-966e-ab22e73e1dd5/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-04-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.11.32.png" alt=""></p>
<h2 id="마이크로-커널">마이크로 커널</h2>
<p>모놀리식 구조는 확장할 수록 관리하기 힘들어진다. 이에 마이크로커널 접근 방식을 이용한 Mach라 불리는 운영체제가 개발되었다. 이 방식은 덜 중요한 구성요소들을 커널에서 제거하고 사용자 수준 프로그램들로 구현하는 방법이다. 그로 인해 커널은 더욱 작아진다. 어느 서비스가 커널에 있어야할지에 대한 정의는 없다. 그러나 일반적으로 마이크로 커널은 통신 설비와 최소한의 프로세스, 그리고 메모리 관리를 제공한다. 마이크로 커널의 주 기능은 프로세스 간에 통신을 제공하는 것이다. 통신은 메세지 전달에 의해 제공된다. 예를 들면 만일 클라이언트 프로그램이 파일에 접근하기를 윈한다면 파일은 반드시 파일서버와 상호작용해야한다 클라이언트 프로그램과 서비스는 결코 직접 상호작용하지 않는다 오히려 그들은 마이크로커널과 메시지를 교환함으로써 간접적으로 상호작용한다.
마이크로커널 접근법의 장점은 운영체제의 확장이 쉽다는 것이다. 모든 새로운 서비스는 사용자 공간에 추가되며, 따라서 커널을 변경할 필요가 없다. 커널을 꼭 변경해야할 때는 작은 커널이기 때문에 변경할 대상이 비교적 적은 경향이 있다. 결과적으로 만들어진 운영체제는 한 하드웨어로부터 다른 하드웨어로 이식이 쉽다. 마이크로커널은 서비스 대부분이 커널이 아니라 사용자 프로세스로 수행되기 때문에 더욱 높은 보안성과 신뢰성을 제공한다. 만일 한 서비스가 잘못되더라도, 운영체제의 다른 부분은 아무런 영향을 받지 않기 때문이다.</p>
<p><img src="https://velog.velcdn.com/cloudflare/sj_dev_js/986c1ab2-5e80-455c-bb73-c94d206d342f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-04-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.11.57.png" alt=""></p>
<p>마이크로커널은 가중된 오버헤드 때문에 성능이 나쁘다. 두 개의 사용자 서비스가 통신해야 하는 경우 별도의 주소 공간에 서비스가 존재하기 때문에 메시지가 복사되어야한다. 또한 운영체제는 메시지를 교환하기 위해 한 프로세스에서 다른 프로세스로 전환해야한다. 메시지 복사 및 프로세스 전환과 관련된 오버헤드는 마이크로커널 기반 운영체제의 성장에 가장 큰 걸림돌이었다. </p>
<h2 id="모듈">모듈</h2>
<p>운영체제를 설계하는 데 이용되는 최근 기술 중 최선책은 적재가능 커널 모듈(loadable kernel modules, LKM) 기법이다. 이 접근법에서 커널은 핵심적인 구성요소들을 가지고 있고 부팅 또는 실행 중에 부가적인 서비스들을 모듈을 통하여 링크할 수 있다. 이러한 유형의 설계는 Linux, Mac OS X, Solaris, Windows 등의 현대 UNIX를 구현하는 일반적인 방법이다.
설계의 주안점은 커널은 핵심 서비스를 제공하고 다른 서비스들은 커널이 실행되는 동안 동적으로 구현하는 것이다. 서비스를 동적으로 링크하는 것은 새로운 기능을 직접 커널에 추가하는 것보다 바람직하다. 수정 사항이 생길 때마다 커널을 다시 컴파일하지 않아도 되기 때문이다. CPU 스케줄링과 메모리 관리 알고리즘은 커널에 직접 구현하고 다양한 파일 시스템은 적재가능 모듈을 통하여 구현할 수 있다.</p>
<p>커널의 각 부분이 정의되고 보호된 인터페이스를 가진다는 점에서 계층 구조를 닮았다. 그러나 모듈에서 임의의 다른 모듈을 호출할 수 있다는 점에서 계층 구조보다 유연하다. 중심 모듈은 단지 핵심 기능만을 가지고 있고 다른 모듈의 적재 방법과 모듈들과 어떻게 통신하는지 안다는 점에서는 마이크로 커널과 유사하다. 그러나 통신하기 위하여 메세지 전달을 호출할 필요가 없기 때문에 더 효율적이다.</p>
<h2 id="하이브리드">하이브리드</h2>
<p>사실 엄격하게 정의된 하나의 구조를 채택한 운영체제는 거의 존재하지 않는다. 대신 다양한 구조를 결합하여 성능, 보안 및 편리성 문제를 해결하려는 혼용 구조로 구성된다. 예를 들어, Linux는 운영체제 전부가 하나의 주소 공간에 존재하여 효율적인 성능을 제공하기 때문에 모놀리식 구조이다. 그러나 모듈을 사용하기 때문에 새로운 기능을 동적으로 커널에 추가할 수 있다. 역시 성능상의 이유로 Windows도 모놀리식 구조라고 할 수 있다. 그러나 사용자 모드 프로세스로서 실행되는 분리된 서브시스템을 지원하는 등 전형적인 마이크로커널의 형태를 유지하고 있다. Windows 시스템은 또한 동적으로 적재가능 커널 모듈(LKM)도 지원한다.</p>
<hr>
<h1 id="운영체제-부팅">운영체제 부팅</h1>
<p>커널을 적재하여 컴퓨터를 시작하는 과정을 시스템 <strong>부팅</strong> 이라고 한다. 하드웨어는 커널의 위치 그리고 커널을 적재하는 방법을 어떻게 알 수 있을까? 대부분의 시스템에서 부팅과정은 다음과 같다.</p>
<ol>
<li>부트스트랩 프로그램 또는 부트 로더라고 불리는 작은 코드가 커널의 위치를 찾는다. </li>
<li>커널이 메모리에 적재되고 시작된다.</li>
<li>커널이 하드웨어를 초기화 한다. </li>
<li>root 파일 시스템이 마운트된다.</li>
</ol>
<p>부트스트랩 프로그램은 ROM 이라 불리는 비휘발성 저장장치에 저장되어있기 전원이 꺼져도 내용이 사라지지 않으며 전원을 켰을때 가장 먼저 실행된다.
부트스트랩 프로그램은 다양한 작업을 수행한다. 커널 프로그램이 포함된 파일을 메모리에 적재하는 것 외에도 진단을 실시하여 메모리와 CPU를 점검하고 장치 시스템 상태를 확인한다. 진단을 통과하면 프로그램은 부팅 과정을 계속 진행할 수 있다. 부트스트랩은 CPU 레지스터, 장치 컨트롤러 및 메인 메모리를 초기화 할 수 있다. 그 후 운영체제를 시작하고 root 파일 시스템을 마운트 한다. 바로 이 시점에서 시스템이 실행 중이라고 말할 수 있다.</p>
<p>일반적으로 PC와 같은 작은 시스템의 경우 ROM에 있는 부트 로더는 더 단순한 기능을 가지고, 커널을 메모리로 올려줄 부트 프로그램은 디스크에 둔다. 부트 로더가 부트 프로그램을 메모리에 올려 실행시키면 부트 프로그램이 커널을 올려 실행시켜주는 방식을 취한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTML] [JavaScript] defer와 async]]></title>
            <link>https://velog.io/@sj_dev_js/HTML-JavaScript-Script-%ED%83%9C%EA%B7%B8%EC%9D%98-%EC%86%8D%EC%84%B1-defer%EA%B3%BC-async</link>
            <guid>https://velog.io/@sj_dev_js/HTML-JavaScript-Script-%ED%83%9C%EA%B7%B8%EC%9D%98-%EC%86%8D%EC%84%B1-defer%EA%B3%BC-async</guid>
            <pubDate>Wed, 06 Apr 2022 10:28:13 GMT</pubDate>
            <description><![CDATA[<h1 id="script-태그의-문제점">Script 태그의 문제점</h1>
<p>먼저 브라우저의 렌더링 과정 일부를 살펴보자.
서버로부터 받은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 Tree 자료구조 형태(DOM)로 만든다.
그 과정에서 중간에 <code>&lt;script&gt;</code> 태그를 만나게 되면 HTML 문서 파싱을 멈추고 script를 다운받고 실행한다.
이 과정에서 두가지 문제가 발생한다.</p>
<blockquote>
<ol>
<li>스크립트를 다운받고 실행하는 동안 화면이 로딩되지 않고 멈춘다.</li>
<li>스크립트는 아직 파싱되지 않은 DOM요소에 접근할 수 없다.</li>
</ol>
</blockquote>
<p>이 문제 때문에 보통은 script 태그를 HTML 문서 끝 쪽에 배치한다.
하지만 이 방법은 완전한 해결책이 아니다.</p>
<p>script 태그를 만나면 다운로드부터 해야하기 때문에 HTML파일이 과도하게 크거나 네트워크 환경이 열악해서 다운로드가 늦어지는 경우, 화면은 다 로딩이 되었는데 요소들이 제대로 작동하지 않는 상황이 생길 수 있다.</p>
<p><img src="https://velog.velcdn.com/cloudflare/sj_dev_js/06c767c5-3d12-4487-919b-6d6420c5fedf/image.png" alt="script"></p>
<p>이를 해결하기 위한 script 태그의 속성 <strong><code>async</code>, <code>defer</code></strong> 에 대해 알아보자.</p>
<h1 id="async">async</h1>
<p>async 속성은 script 파일을 병렬적으로 다운받게한다. 즉 HTML 문서가 파싱되는 동안 동시에 script를 다운받을 수 있다. 
다운을 받은 즉시 HTML 파싱을 멈추고 script 코드를 실행한다. 이 또한 문제를 야기한다. script 코드가 아직 로딩되지 않은 DOM요소에 접근할 수 없다. 여러 개의 스크립트 파일을 다운받는다면 작성 순서와 상관없이 다운받는 순서대로 실행하기 때문에 스크립트가 작성된 순서대로 실행되는 것을 보장하지 않는다. 스크립트 사이에 의존성이 존재하는 경우 제대로 작동하지 않을 수 있다.</p>
<pre><code class="language-HTML">&lt;script async src=&quot;./first.js&quot;/&gt; &lt;-- 다운로드 5초 !--&gt;
&lt;script async src=&quot;./second.js&quot;/&gt; &lt;-- 다운로드 1초 !--&gt;
&lt;-- first가 먼저 실행되어야하는데 second가 먼저 실행된다. !--&gt;</code></pre>
<p>따라서 DOM요소에 직접 접근하는 스크립트는 async를 사용하지 않는 것이 좋다.
DOM요소에 직접 접근하지 않고, 다른 스트립트와의 의존성이 없는 스크립트에 async 속성을 적용해야한다.
<img src="https://velog.velcdn.com/cloudflare/sj_dev_js/98b21e5d-e449-41d8-82b3-2665bfbc7152/image.png" alt="async"></p>
<h1 id="defer">defer</h1>
<p>defer 속성 또한 script 파일을 병렬적으로 다운받게한다. 하지만 실행은 HTML 문서 파싱이 끝난 후에 일어난다.
DOM요소에 정상적으로 접근할 수 있고 다운로드를 기다리지 않아도 된다. 또한 스크립트 간의 순서를 보장받는다.
따라서 DOM 요소에 직접 접근하는 스크립트는 defer 속성을 사용하는 것이 바람직하다.
<img src="https://velog.velcdn.com/cloudflare/sj_dev_js/18712536-0c35-4d9a-b1c6-7601c4f3eb83/image.png" alt="defer"></p>
<h2 id="참고">참고</h2>
<p><a href="https://javascript.plainenglish.io/async-and-defer-the-complete-guide-to-loading-javascript-properly-ce6edce1e6b5">Async &amp; Defer</a>
<a href="https://www.tutorialexample.com/understand-javascript-async-vs-defer-vs-inline-when-to-use-async-defer-or-inline/">Understand JavaScript async Vs defer Vs inline</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] OSI 7계층을 왜 배울까?]]></title>
            <link>https://velog.io/@sj_dev_js/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-OSI-7%EA%B3%84%EC%B8%B5%EC%9D%84-%EC%99%9C-%EB%B0%B0%EC%9A%B8%EA%B9%8C</link>
            <guid>https://velog.io/@sj_dev_js/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-OSI-7%EA%B3%84%EC%B8%B5%EC%9D%84-%EC%99%9C-%EB%B0%B0%EC%9A%B8%EA%B9%8C</guid>
            <pubDate>Wed, 30 Mar 2022 06:20:13 GMT</pubDate>
            <description><![CDATA[<p>네트워크를 공부할 때 가장 먼저 배우게 되는 것이 TCP/IP 모델 혹은 OSI 모델이다.
오늘날의 네트워크에서 OSI모델은 참조적 모델일 뿐이고 실제로 쓰이는 것은 TCP/IP 모델이라는데 그렇다면 OSI 모델을 왜 배워야하는지 궁금증이 생겼다. 그래서 궁금증을 해결하는 김에 TCP/IP 모델과 OSI 모델이 무엇인지까지 정리해보려고 한다.</p>
<h1 id="osi-모델">OSI 모델</h1>
<p>네트워크에 필요한 프로토콜 기능들을 7계층으로 나누어 복잡성을 줄이고 계층간의 간섭을 최소화 하는 모델이다. </p>
<ul>
<li>응용계층 : 최상위 계층으로 사용자가 네트워크에 접속하는 것을 가능하게 한다.</li>
<li>표현계층 : 송,수신자가 공통으로 이해 할 수 있도록 정보의 데이터 표현방식을 바꾸는 기능을 담당한다.</li>
<li>세션계층 : 세션 계층은 네트워크 대화 제어기로 통신 시스템 간에 상호대화를 설정하고 동기화 한다.</li>
<li>전송계층 : Port를 사용하여 응용 프로그램간 송수신을 담당한다.</li>
<li>네트워크 계층 : IP를 주소로 사용하여 호스트간 전송을 담당한다.</li>
<li>데이터링크 계층 : 네트워크계층에서 정보를 받아 주소와 제어정보를 헤더와 테일에 추가한다.</li>
<li>물리계층 : 데이터를 물리 매체상으로 전송하는 역할을 담당하는 계층이다.</li>
</ul>
<h1 id="tcp--ip-모델">TCP / IP 모델</h1>
<p>OSI와 비슷하게 네트워크에 필요한 기능을 4계층으로 나눈 모델이다. OSI보다 먼저 등장했으며 현재 표준으로 자리잡고 있다. OSI 모델과 유사하나 완전하게 들어맞지는 않으며 대표적으로 계층의 수가 다르다.</p>
<ul>
<li>응용계층</li>
<li>전송계층 </li>
<li>인터넷계층 </li>
<li>네트워크 연결 계층 </li>
</ul>
<h1 id="osi-모델을-왜-배울까">OSI 모델을 왜 배울까?</h1>
<h3 id="두-모델의-공통점">두 모델의 공통점</h3>
<p>두 모델은 두 호스트 사이에서 이루어지는 네트워킹을 계층 구조로 나누는 논리적 관점을 제공한다. 계층을 나눔으로써 각 계층에서 일어나는 일들을 모듈화 시킬 수 있다. 이는 유연성과 확장성이 높은 시스템을 구축할 수 있게 한다. 각 계층의 성능을 업그레이드 시키거나 어디서 문제가 발생했는지 확인하는 것이 쉬워진다.</p>
<h3 id="두-모델의-차이점">두 모델의 차이점</h3>
<p>계층의 수가 다르다. OSI 모델은 TCP/IP 모델에서 한 계층으로 이루어져 있는 응용계층을 3계층으로 나눈다. 위에서 말한 것처럼 계층이 나뉘면 문제해결과 성능개선이 보다 간단해진다. 이런 점에서 호스트간 데이터 교환에 문제가 생겼을 때 OSI 모델이 문제를 하기에 더 유리하다고 할 수 있다.</p>
<p>오늘날에는 TCP/IP 모델이 표준으로 자리잡았는데 그렇다고해서 OSI 모델이 배울 가치가 없는 것은 아니다.
호스트 간의 연결을 계층화한다는 관점에서 OSI 모델은 더 세부적인 관점을 제공하기 때문에 네트워크를 학습하는 사람에게 훌륭한 참조모델이 된다.</p>
<h2 id="참고">참고</h2>
<p><a href="https://www.fortinet.com/resources/cyberglossary/tcp-ip-model-vs-osi-model">TCP/IP Model vs. OSI Model</a>
<a href="https://blog.naver.com/agerio100/221938007939">IT를 공부하는데 큰 도움이 될 [OSI 7계층] 알아보기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[OS] 1장 서론]]></title>
            <link>https://velog.io/@sj_dev_js/OS-1%EC%9E%A5.-%EC%84%9C%EB%A1%A0</link>
            <guid>https://velog.io/@sj_dev_js/OS-1%EC%9E%A5.-%EC%84%9C%EB%A1%A0</guid>
            <pubDate>Tue, 29 Mar 2022 05:42:04 GMT</pubDate>
            <description><![CDATA[<h2 id="시작하기전에">시작하기전에</h2>
<p>운영체제 스터디를 시작하게 되었다. 학교에서 운영체제 수업을 들었지만 한번 배운 것으로는 기억이 잘 나지 않아서 좀 더 깊게 공부하고자 정리하기로 마음먹었다. 책 없이 내가 작성한 글만으로 운영체제를 이해할 수 있게끔 글을 잘 작성하는 것이 목표다.</p>
<h3 id="참고">참고</h3>
<p>OS 교과서로 유명한 운영체제 공룡책 한글판을 주 교재로 사용할 것이고 학교에서 실제 교과서로 썼던 &quot;OS? Oh Yes!&quot;책을 부교재로 사용할 것이다. 공룡책은 다양한 상황에 대한 설명이 깊게 나온다는 장점이 있고 &quot;OS? Oh Yes!&quot; 책은 꼭 필요한 개념을 번역체가 아닌 우리말로 쉽게 설명한다는 장점이 있다.</p>
<h1 id="1장-서론">1장. 서론</h1>
<p>앞으로 운영체제 책에서 다룰 내용을 전반적으로 설명한다. 운영체제를 처음 배우는 분들은 공룡책 1장 몇페이지를 넘기자 마자 당황스러울 것이라고 생각한다. 앞으로의 지식을 전반적으로 설명하고 있어서 그런지 낯선 단어들이 <strong>독자가 알것이라는 전제로</strong> 등장한다. 운영체제를 처음 배우는 분들은 1장을 이해한다는 생각보다는, 앞으로 이런 내용이 나오겠구나 생각하면서 읽기만해도 도움이 될 것이라고 생각한다. 내용을 정리하면서 1장에서 배우기는 어렵다고 생각하는 것들(분산 시스템 등)은 서론 정리에서 제외하였고, 처음 배우는 분들도 접근하기 쉽게 하기 위해 부교재나 다른 자료들을 참고하였다.</p>
<hr>
<h2 id="운영체제가-하는-일">운영체제가 하는 일</h2>
<p><img src="https://images.velog.io/images/sj_dev_js/post/a5f31853-42d7-4aaf-8f4c-eab5fc5932ef/image.png" alt="">
컴퓨터 시스템은 하드웨어, 운영체제, 응용 프로그램, 사용자로 이루어져있다.
하드웨어는 CPU, 메모리, 입출력장치 등으로 구성되어 있으며 <strong>자원을 제공</strong>한다.
응용프로그램인 웹 브라우저, 워드 프로세서 등은 사용자의 계산 문제를 해결하기 위해 <strong>자원을 어떻게 사용할지 정의</strong>한다. 
운영체제는 다양한 사용자를 위해 다양한 응용 프로그램 간의 <strong>자원 사용을 제어하고 조정</strong>한다.</p>
<p>컴퓨터 시스템의 기본 목표는 프로그램을 실행해서 사용자의 계산 문제를 쉽게 해결하는 것이다. 그러나 하드웨어만으로는 컴퓨터의 계산능력을 활용하기 쉽지 않으므로 응용 프로그램이 개발된다. 이러한 응용 프로그램들은 입출력 장치 제어나 CPU 사용 등 자원들을 두고 경쟁하게된다. 경쟁하는 프로그램들 사이에서 자원을 제어하고 할당하는 기능은 운영체제를 통해 실현되는 것이다.</p>
<hr>
<h2 id="컴퓨터-시스템의-구성">컴퓨터 시스템의 구성</h2>
<h3 id="프로세스">프로세스</h3>
<p>프로세스란 수행중인 프로그램(A program in execution)이다. 처리기 작업의 단위이기도 하다.
이는 디스크에 단순히 저장된 프로그램은 프로세스가 아니라는 말과 같다. 프로그램과 데이터를 기본으로 정상적인 실행을 위해 필요한 환경을 시스템으로부터 부여받은 _능동적인 존재_이다.</p>
<blockquote>
<p>번역된 책들은 <code>execute</code> 와 <code>running</code> 모두 <strong>실행</strong>이라고 번역하는데 이는 다른 개념이다.
<code>excute</code> 중인 프로그램을 프로세스라고 한다
<code>running</code> 프로세스는 CPU에 의해 작업 중인 프로세스이다
프로세스라고 해서 항상 <code>running</code>인 것은 아니며 인터럽트나 트랩에 의해 대기상태나 보류상태가 된다.
헷갈릴 여지가 다분하기 때문에 <code>excute</code>를 수행이라고 번역하였다</p>
</blockquote>
<h3 id="커널">커널</h3>
<p>운영체제의 프로그램은 커널인 프로그램과 커널이 아닌 프로그램으로 나뉜다.
커널은 운영체제의 핵심이며 메모리 상주 프로그램이라고 불리기도 한다. 왜 커널을 메모리에 상주시킬까? 폰 노이만 구조에 따라 메모리에 적재된 프로그램만 실행할 수 있는데 이는 운영체제 프로그램도 마찬가지라 운영체제 프로그램 또한 메모리에 적재되어 있어야한다. 운영체제 중에서 빈번히 그리고 빨리 실행되어야할 프로그램을 디스크에 두었을 경우 이들이 실행될 때마다 디스크와 메모리 사이의 입출력이 잦아지게 되어 시스템의 성능이 매우 떨어지게 된다.
하지만 운영체제의 모든 프로그램을 메모리에 적재하면 그만큼 활용할 수 있는 메모리 공간이 작아진다.
메모리를 최대로 활용하기 위해 운영체제 중 빈번하게 쓰이는 프로그램들을 메모리에 상주시키는데 이를 커널이라고 한다.</p>
<h3 id="인터럽트">인터럽트</h3>
<img src=https://images.velog.io/images/sj_dev_js/post/ee36dcb2-a2ca-4d5a-beb4-51b0f8c1b459/image.png width="60%" align="center"/>
인터럽트는 각 자원들이 능동적으로 자신의 상태변화를 CPU에게 알리는 방식이다. CPU가 인터럽트 신호를 받으면 현재 명령어 실행을 마친 후 하던 일을 중단하고 인터럽트를 처리하는 루틴을 실행한다. 이 루틴은 인터럽트 핸들러를 통해 인터럽트가 일어나게한다. 인터럽트가 끝난 후에는 기존에 처리하던 프로그램을 다시 실행해야하기 때문에 인터럽트를 처리하기 전에 기존 프로그램의 상태 및 정보를 시스템 스택에 저장한다. 인터럽트는 마스킹가능 인터럽트와 마스킹불가능 인터럽트로 나뉜다. 중요한 명령들을 실행하는 중에는 마스킹가능 인터럽트가 무시될 수 있다. 또한 인터럽트에 우선순위를 두어 중요한 인터럽트부터 처리할 수 있다.

<h3 id="저장장치-구조">저장장치 구조</h3>
<p><img src="https://images.velog.io/images/sj_dev_js/post/ee2d09ec-4b74-4a5a-a22d-1b685e887664/image.png" alt="저장장치 계층구조"></p>
<ul>
<li><p>레지스터
프로세서 내에서 데이터를 보관하는 아주 빠른 저장장치이다. 일반적으로 현재 계산중인 값을 저장하는데에 쓰인다.</p>
</li>
<li><p>캐시
레지스터와 메인메모리 사이에 존재하는 빠른 저장장치로, 메모리에서 자주 쓰이는 데이터를 복사하여 빠른 접근을 보장한다.</p>
</li>
<li><p>메인 메모리 (RAM, 메모리)
폰 노이만 구조에 따라 프로그램이 실행되기 위해서 올라와야하는 저장장치이다. 
CPU가 접근할수 있는 유일한 대량 메모리다.
휘발성 저장장치이기 때문에 전원이 꺼지면 저장할 수 없다.</p>
</li>
<li><p>보조 저장장치 (2차 저장장치)
메인메모리보다 용량이 크고 비휘발성인 저장장치이다. 하드 디스크 드라이브(HDD)와 비휘발성메모리(NVM)가 있다.</p>
</li>
<li><p>3차 저장장치
2차 저장장치보다 더 용량이 크고 느린 저장장치이다. 자기 테이프, 광학 디스크 등이 있다.</p>
</li>
<li><p>부트스트랩 프로그램
메모리는 휘발성이므로 전원이 꺼져있을 때는 커널 또한 디스크에 저장되어있을 것이다. 그렇다면 누가 커널을 메모리에 올려서 실행시켜줄까? 이때 동원되는 것이 부트스트랩 프로그램이다. 부트스트랩 프로그램은 비휘발성 저장장치인 EEPROM이나 ROM에 저장되어있다. </p>
</li>
</ul>
<p>위 저장장치들은 계층구조에 따라 빠를 수록 비싸고 용량이 작으며 느릴 수록 싸고 용량이 크다.</p>
<h3 id="입출력-구조">입출력 구조</h3>
<p>짧은 입출력 마다 인터럽트가 발생하면 CPU가 입출력 처리에 많은 시간을 할애하게 되어 오버헤드를 유발할 수 있다. 이 문제를 해결하기 위해 직접 메모리 엑세스(DMA)가 사용된다. 장치제어기는 CPU의 개입 없이 메모리로부터 자신의 버퍼로 혹은 버퍼로부터 메모리로 데이터블록 전체를 전송한다. 한 바이트마다 인터럽트가 발생하는 것이 아니라 블록 전송이 완료될 때마다 인터럽트가 발생한다. 장치 컨트롤러가 전송 작업을 수행하고 있는 동안 CPU는 다른 작업을 수행할 수 있다.</p>
<hr>
<h2 id="컴퓨터-시스템-구조">컴퓨터 시스템 구조</h2>
<h3 id="컴퓨터-시스템-구성요소의-정의">컴퓨터 시스템 구성요소의 정의</h3>
<blockquote>
<ul>
<li>CPU - 명령을 실행하는 하드웨어</li>
<li>프로세서(Processor) - 하나 이상의 CPU를 포함하는 물리적 칩</li>
<li>코어(core) - CPU의 기본 계산 단위</li>
<li>다중 코어(multicore) - 동일한 CPU에 여러 코어를 포함함</li>
<li>다중 처리기(multiprocessor) - 여러 프로세서를 포함함</li>
</ul>
</blockquote>
<hr>
<h2 id="운영체제의-작동">운영체제의 작동</h2>
<h3 id="다중-프로그래밍-multiprogramming">다중 프로그래밍 (Multiprogramming)</h3>
<p>수행 중인 프로그램을 프로세스라고 한다. 다중 프로그래밍에서 운영체제는 여러 프로세스들을 메모리에 동시에 유지시킨다. 운영체제는 이 중 하나를 선택하여 CPU가 실행하게 하는데 실행되는 프로그램이 입출력 처리나 시간 초과 등으로 인해 CPU를 사용하지 못하게 되는 경우가 있다. 이때 운영체제는 다른 프로세스를 실행하여 여러 프로그램이 <strong>병행</strong>적(병렬과는 다르다)으로 실행되게 한다. 사용자는 단일 처리기를 사용하더라도 다중 프로그래밍을 통해 여러개의 프로그램들이 동시에 실행되고 있는 것처럼 느끼게 된다.</p>
<blockquote>
<p>다중처리(Multiproccessing)와는 다른 개념이다. 
다중처리는 여러개의 처리기로 <strong>병렬</strong>적으로 프로세스를 실행하는 것을 말한다.</p>
</blockquote>
<h3 id="이중모드와-다중모드">이중모드와 다중모드</h3>
<ul>
<li><p>이중모드
운영체제와 사용자는 하드웨어 및 소프트웨어 자원을 공유한다. 따라서 사용자 프로그램이 실행될 때 잘못된 영역에 접근할 가능성이 있는데, 특히 운영체제가 있는 영역에서 뭔가를 변경시키는 것은 시스템에 치명적이다. 따라서 운영체제는 이런 접근을 막을 수 있는 방법을 제공하는데 이것이 이중모드(Dual Mode)이다. 이중모드는 <strong>커널 모드</strong>와 <strong>사용자 모드</strong>로 나뉜다. 여러 장치들을 작동시키거나 시스템에 설정되어있는 여러가지 데이터들을 조작하는 권한은 커널모드에서 실행되는 프로그램들만 가지도록한다. 유저모드에서 권한이 필요한 수행이 필요한 경우 <strong>시스템 호출</strong>(System Call)을 통해 수행할 수 있다. 즉 유저 모드로 실행 중 커널 모드로 실행해야할 일이 생기면 시스템 호출을 하게 되고 그 일은 운영체제 프로그램이 커널모드에서 실행한 다음 다시 유저모드로 복귀하게 된다.</p>
</li>
<li><p>다중모드
운영체제에서 모드의 개념은 두가지 이상으로 확장될 수 있다. 예를 들어 인텔 프로세서에는 4개의 모드가 있다. </p>
</li>
</ul>
<h3 id="타이머">타이머</h3>
<p>운영체제는 CPU에 대한 제어를 보장받아야한다. 사용자 프로그램이 무한루프에 빠지는 등 제어가 운영체제가 복귀하지 않는 경우가 없도록 방지해야한다. 이를 위해 타이머(timer)가 사용된다. 타이머는 지정된 시간 후 인터럽트하도록 설정할 수 있다. 사용자에게 CPU 제어를 양도하기 전에, 운영체제는 타이머가 인터럽트 할 수 있도록 설정되었는지 확인한다. 타이머가 인터럽트를 발생시키면 CPU 제어는 자동으로 운영체제로 넘어간다.</p>
<hr>
<h2 id="자원관리">자원관리</h2>
<p>위에서 말한 것처럼 하드웨어는 자원이며 응용 프로그램은 사용자를 위해 자원을 어떻게 사용할지 정의한다. 운영체제는 프로그램들의 자원 사용을 제어하고 관리한다. 즉 운영체제는 자원관리자이다. 운영체제가 관리해야할 자원으로는 CPU, 메모리공간, 파일저장공간, I/O 장치가 있다.</p>
<h3 id="프로세스-관리">프로세스 관리</h3>
<p>프로세스들이 정상적으로 실행되기 위해서는 필요한 자원들이 확보되어야한다. 그중 가장 필수적인 자원은 CPU이다. 현대 운영체제는 다중 프로그래밍을 하도록 설계되어있기 때문에 프로세스들이 CPU를 두고 경쟁하게 된다. 운영체제는 프로세스를 관리하기 위해 다음과 같은 활동에 책임을 진다</p>
<ul>
<li>사용자 프로세스와 시스템 프로세스의 생성과 제거</li>
<li>CPU에 프로세스와 스레드 스케쥴하기</li>
<li>프로세스의 일시 중지와 재수행</li>
<li>프로세스 간 동기화를 위한 기법 제공</li>
<li>프로세스 간 통신을 위한 기법 제공</li>
</ul>
<h3 id="메모리-관리">메모리 관리</h3>
<p>메인 메모리는 CPU가 접근할 수 있는 유일한 대량 메모리다. CPU 이용률과 사용자에 대한 응답속도를 높이기 위해 메모리에 여러 프로그램들을 유지해야하며, 이를 위해 운영체제는 메모리 기법을 제공한다.</p>
<ul>
<li>메모리의 어느 부분이 어느 프로세스에 의해 사용중인지 추적</li>
<li>메모리 공간을 할당하고 회수</li>
<li>어떤 프로세스를 메모리에 적재하고 제거할 것인지 결정</li>
</ul>
<h3 id="파일-시스템-관리">파일 시스템 관리</h3>
<p>컴퓨터 시스템의 편리한 사용을 위해 운영체제는 저장장치의 물리적 특성을 추상화하여 논리적인 저장 단위인 파일을 정의하여 제공한다.</p>
<ul>
<li>파일의 생성 및 제거</li>
<li>디렉터리 생성 및 제거</li>
<li>파일과 디렉터리를 조작하기 위한 기본적인 지원</li>
<li>파일을 보조 저장장치로 매핑</li>
<li>안정적인 비휘발성 저장 매체에 파일을 백업</li>
</ul>
<h3 id="대용량-저장장치-관리">대용량 저장장치 관리</h3>
<p>컴퓨터 시스템은 메인 메모리를 백업하기 위해 보조 저장장치를 사용한다. 대부분의 최신 컴퓨터 시스템은 HDD와 NVM 장치를 주요 온라인 저장 매체로 활용한다. 프로그램 대부분은 메모리에 적재될 때까지 이러한 장치에 저장된다. 장치들은 프로세스의 자원이자 목적지(destination)으로 쓰인다. 대용량 저장장치를 적절히 관리하기 위해 운영체제는 다음과 같은 일을 한다.</p>
<ul>
<li>마운팅과 언마운팅</li>
<li>사용 가능 공간의 관리</li>
<li>저장장소 할당</li>
<li>디스크 스케줄링</li>
<li>저장장치 분할</li>
<li>보호</li>
</ul>
<h3 id="캐시-관리">캐시 관리</h3>
<p>메모리와 CPU 사이에 위치하는 캐시에 자주 접근하는 데이터를 두어 더 빨리 접근할 수 있게한다. 캐시는 비싸기 때문에 작은 크기로 설치한다. 그 때문에 한정된 크기로 설치할 수 밖에 없고 그만큼 캐시의 용량도 제한된다. 캐시에 접근했을 때 데이터가 없다면 다시 메모리에 접근해야하기 때문에 캐시가 없을 때보다 오히려 더 오랜 시간이 소요된다. 따라서 캐시의 적중률(hit ratio)를 높이는 것이 중요하다. 이를 위해 운영체제의 <strong>캐시 관리</strong> 기법에 대해 배울 것이다.</p>
<h3 id="입출력-시스템-관리">입출력 시스템 관리</h3>
<p>입출력 장치는 CPU나 메모리 작업에 비해 속도가 훨씬 느린 작업을 수행한다. 기기간 처리속도 차이로 인해 문제가 발생하는데 이를 해결하기 위한 기법으로 버퍼링, 캐싱, 스풀링을 배울 것이다. 또한 장치 하드웨어에 대해 정확하게 알지 않아도 하드웨어의 기능을 사용하게 해주며 커널의 일부인 장치 드라이버에 대해 배울 것이다.</p>
<ul>
<li>버퍼링, 캐싱, 스풀링을 포함한 메모리 관리 구성요소</li>
<li>장치 드라이버 인터페이스</li>
<li>특정 하드웨어 장치들을 위한 드라이버</li>
</ul>
<hr>
<h2 id="마무리하며">마무리하며</h2>
<p>OS를 처음 배우는 사람도 이해할 수 있도록 쉽게 쓰고자 노력했는데 생각보다 페이지가 길어져서 전부 설명할 수 없는 부분도 있었다. 2장부터는 책이 한정된 범위에서 깊게 들어가는 것 같으니 거기서 더 자세하고 깊게 설명해야겠다. </p>
<p><strong>혹시 잘못된 점, 개선할 점을 발견한다면 더 좋은 글로 만들 수 있도록 댓글 부탁 드립니다. :)</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[반성일기 (2022 3/26 라인 코테)]]></title>
            <link>https://velog.io/@sj_dev_js/%EB%B0%98%EC%84%B1%EC%9D%BC%EA%B8%B0-326-%EB%9D%BC%EC%9D%B8-%EC%BD%94%ED%85%8C</link>
            <guid>https://velog.io/@sj_dev_js/%EB%B0%98%EC%84%B1%EC%9D%BC%EA%B8%B0-326-%EB%9D%BC%EC%9D%B8-%EC%BD%94%ED%85%8C</guid>
            <pubDate>Sat, 26 Mar 2022 07:42:10 GMT</pubDate>
            <description><![CDATA[<h3 id="2022년-3월-26일-토요일-비온뒤-맑음-🌦">2022년 3월 26일 토요일 비온뒤 맑음 🌦</h3>
<h2 id="제목--라인-코테를-봤다">제목 : 라인 코테를 봤다</h2>
<p>라인 코테는 제한이 별로 없는 편안한 분위기었다.
프로그래머스를 이용했으며 오픈북, 인터넷 검색, IDE 사용 모두 가능했다.
네트워크에도 딱히 제한이 없어서 원하는 장소에서 시험을 볼 수 있게 해주었다.</p>
<p>본론으로 들어가서 나는 6문제중 4문제를 <strong>제출</strong>했다.
라인 코딩테스트는 환경에는 제한이 없지만, 문제 예제를 제외하고는 테스트 케이스가 주어지지 않는다.
4문제를 제출했지만 그 중 몇개나 맞았는지 알 수가 없다.
개인적인 생각으로는 4문제를 완벽하게 풀었으면 합격일 것이라고 생각한다.
난 특수한 테스트 케이스를 생각하지 않았으니 틀린 문제가 분명 있을 것이라고 생각한다.
즉, 원하는만큼 잘 보지 못했다는 뜻이다.</p>
<p>실패는 아프지만 스스로의 약점을 들여다 볼 수 있는 계기가 되기도한다.
이 참에 개선할 점들을 생각해보았다.</p>
<h3 id="1-자바스크립트를-이용하는-코테에-익숙하지-않았다">1. 자바스크립트를 이용하는 코테에 익숙하지 않았다.</h3>
<p>웹 프론트엔드로 직무를 정하기 전부터 알고리즘 문제를 풀었기 때문에 대부분의 문제를 C++로 풀어왔다.
프론트엔드로 직무를 확실히 정하고도 한동안 익숙한 C++로 문제를 풀어왔는데 최근 자바스크립트로 문제를 풀어보니 문자열을 다루는 측면에서 자바스크립트가 훨씬 쉽다는 것을 느꼈고, 앞으로 계속 사용할 자바스크립트에 익숙해지기 위해서도 자바스크립트로 코테를 풀기로 마음을 정했다. 하지만 그에 비해 준비는 되어있지 않았던 모양이다. 오늘 문제를 풀면서 사고가 정지하는 현상이 평소보다 많이 일어났다. 지금까지 풀었던 백준 문제들을 자바스크립트로 다시 풀어보아야겠다. 또한 시간을 많이 잡아먹는 구현문제들을 시간을 두고 실전처럼 푸는 연습을 할 것이다.</p>
<h3 id="2-코딩테스트-1시간-전에-일어났다">2. 코딩테스트 1시간 전에 일어났다.</h3>
<p>코딩테스트가 오전 10시에 시작인데 오전 9시에 일어났다. 그래서 식사도 빵으로 대충 떼웠다. 코딩테스트는 그날 컨디션에 따라서 한문제를 더 풀기도하고 못 풀기도 하는데 컨디션 관리에 신경쓰지 않은 것은 참 안일했다. 앞으로는 최소 2시간전에 일어나서 밥을 잘 챙겨먹고 짧은 산책으로 두뇌를 깨우고 생각을 정리하는 시간을 가져야겠다.</p>
<h3 id="3-자기확신이-부족했다">3. 자기확신이 부족했다.</h3>
<p>4문제를 풀고 3시간 중 1시간이 남았는데, 두 문제 사이에서 갈팡질팡하다가 둘 중 한 문제도 풀어내지 못했다. 두 문제가 남은 시점에서 불안감이 엄습해서 사고가 정지했던 것 같다. 한 문제는 복잡하지만 구현문제라서 문제대로 코드를 작성하기만 하면 풀 수 있었을 것이라고 생각해 더욱 아쉽다. 여러 시험을 친 경험으로 볼 때 시험은 기세가 중요하다. 같은 실력이어도 스스로에 대한 확신이 얼마나 있냐에 따라서 자신감으로 나타나고, 그 자신감이 한문제라도 더 풀 수 있게 해주는 원동력이 된다. 그럼 자기확신을 어디에서 오는 것일까? 여러 경우가 있는데 절대적인 존재에 대한 믿음으로부터 오기도하고, 주위 사람들의 인정에서 기인하기도 하고, 스스로에 대한 인정이 자신감으로 이어지기도한다. 나는 절대적인 존재에 대한 믿음이 없어서 해당하지 않고, 주위 사람들로부터 인정받지 못했다고 생각하지도 않는다. 다만 나는 열심히 했다는 확신을 할만큼의 믿음을 스스로에게 주지 못했던 것 같다. 요즘 평일 오전 7시에 공부하러 나가고 저녁 10시쯤 집에 돌아오는 생활을 시작했는데, 이 생활을 반복해서 습관으로 만들면 자기 확신도 내것으로 만들 수 있을 것이라고 생각한다. 화이팅!</p>
<hr>
<h2 id="결과">결과</h2>
<p><img src="https://images.velog.io/images/sj_dev_js/post/7af40176-fd26-4693-9676-679ae8439946/Screen%20Shot%202022-03-31%20at%201.03.56%20PM.png" alt="">
예상 외로 합격 통보를 받았다. 하지만 라인은 코딩테스트가 쉽고 필기테스트가 극악으로 어렵다는 이야기를 많이 들었다. 코딩테스트가 끝나자마자 CS 공부를 시작했어서 다행이었다. CS공부를 조금 해보면서 &#39;학교 다닐때 더 열심히 공부할 걸&#39; 이라는 생각도 많이 했지만 이 참에 CS를 진짜 내것으로 만든다는 생각으로 합격 여부와 관련없이 최선을 다해보아야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 변수의 호이스팅]]></title>
            <link>https://velog.io/@sj_dev_js/Javascript-%EB%B3%80%EC%88%98%EC%9D%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85</link>
            <guid>https://velog.io/@sj_dev_js/Javascript-%EB%B3%80%EC%88%98%EC%9D%98-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85</guid>
            <pubDate>Tue, 15 Mar 2022 11:25:20 GMT</pubDate>
            <description><![CDATA[<p>Javascript 에서 호이스팅이란 변수나 함수의 선언이 끌어올려지는 것처럼 보이는 것을 말한다.
(실제로 끌어올려지지는 않는다.)</p>
<p>Javascript 는 문을 한줄 한줄 읽어 실행하는 런타임 이전에 코드 평가 과정을 거치면서 코드를 실행하기 위한 준비를 한다.</p>
<p>이때 자바스크립트 엔진은 모든 선언문을 찾아서 먼저 실행한다. 이 때문에 선언문이 끌어올려져서 실행되는 것처럼 보이는 것이다.</p>
<pre><code class="language-javascript">console.log(a); // undefined
var a;
a = 10;
console.log(a); // 10;</code></pre>
<p>위 예제에서 a를 선언하기 이전에 값을 확인해보면 undefined 인 것을 확인할 수 있다.</p>
<p>var 로 선언된 변수는 선언과 동시에 undefined 로 초기화 되기 때문이다.</p>
<p>하지만 변수를 실행하기도 전에 참조할 수 있는 것은 직관적으로 자연스럽지도 않고, 문제를 일으킬 여지가 상당히 많아보인다.</p>
<p>ES6 이후 등장한 let 과 const 는 선언과 초기화를 나눠서 실행함으로써 호이스팅이 되지 않는 것처럼 보이게한다.</p>
<pre><code class="language-javascript">console.log(b); // Uncaught ReferenceError: b is not defined
let b;
console.log(b); // undefined;
b = 20;
console.log(b); // 20;</code></pre>
<p>위 예제에서 let 으로 선언한 변수 b 또한 호이스팅 되었지만, 선언만 되고 초기화는 되지 않았기 때문에 정의되지 않았다는 에러메세지가 뜬다.</p>
<p>선언문을 만났을 때 비로소 undefined로 초기화를 하고, 이후 재할당을 한 뒤 다시 값을 확인해보면 재할당한 값으로 바뀐 것을 확인할 수 있다.</p>
<pre><code class="language-javascript">console.log(c); // Uncaught ReferenceError: c is not defined
const c = 30;
console.log(c); // 30;</code></pre>
<p>const 로 선언한 변수도 마찬가지로 선언과 초기화가 나눠서 일어난다. </p>
<p>다만 const 로 선언된 변수는 재할당할 수 없기 때문에 코드를 작성할 때는 선언과 동시에 할당을 해주어야한다.</p>
<p>let과 마찬가지로 실제로 변수선언은 호이스팅되어서 런타임 이전에 이루어지지만,  초기화는 런타임에서 const 선언문을 실행하는 시점에 이루어진다. </p>
<p>let 으로 선언한 변수는 (코드 작성시 선언과 함께 초기화하지 않은 경우) undefined로 초기화 될 수도 있지만 const 으로 선언한 변수는 코드 작성시 선언과 초기화를 반드시 같이해주어야 한다는 점이 다르다.</p>
<h1 id="결론">결론</h1>
<p>Javascript는 런타임 이전에 코드평가를 진행하면서 선언문을 미리 실행한다.</p>
<p>ES6 이전에는 변수가 선언됨과 동시에 <code>undefined</code>로 초기화 되었기 때문에 변수선언문 이전에 참조할 수 있었다.</p>
<p>ES6에서 등장한 <code>let</code> 과 <code>const</code>는 선언은 코드평가 과정에서 하지만 초기화는 런타임에서 변수선언문을 만났을때 이뤄지게 한다. </p>
<p>따라서 let과 const로 선언한 변수는 변수선언문 이전에 참조할 수 없고, 호이스팅이 되지 않는 것처럼 보인다.</p>
]]></description>
        </item>
    </channel>
</rss>