<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>string_main.log</title>
        <link>https://velog.io/</link>
        <description>FE developer</description>
        <lastBuildDate>Wed, 04 Sep 2024 14:08:09 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>string_main.log</title>
            <url>https://velog.velcdn.com/images/string_main/profile/ab04c412-b5e9-455a-9272-980adbad2c7a/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. string_main.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/string_main" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[2024 항해 DEV LAB 후기]]></title>
            <link>https://velog.io/@string_main/2024-%ED%95%AD%ED%95%B4-DEV-LAB-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@string_main/2024-%ED%95%AD%ED%95%B4-DEV-LAB-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Wed, 04 Sep 2024 14:08:09 GMT</pubDate>
            <description><![CDATA[<p>최근에 항해 DEV LAB이라는 개발자 행사에 참여할 기회가 생겨서 다녀왔다.
회사 동료분이 항해 출신이신데, 이런 행사가 있다고 알려주셔서 신청했고, 운좋게 200명 안에 선발되었다.
이런 행사에 참여한 적이 처음이라 경험한 것을 기록하기 위해 간단히 정리해보려 한다!</p>
<p><img src="https://velog.velcdn.com/images/string_main/post/8ca42b4b-f205-4f42-b1df-1f7d3e828cbe/image.png" alt=""></p>
<h1 id="행사-일시--타임테이블">행사 일시 &amp; 타임테이블</h1>
<ul>
<li><strong>일시</strong> : 8월 31일 토요일 오후 1시 ~ 6시</li>
<li><strong>장소</strong> : 서울 강남구 테헤란로44길 8, 역삼아이콘 빌딩 지하1층 빅플레이스</li>
</ul>
<p><img src="https://velog.velcdn.com/images/string_main/post/03b44eaf-13b1-41d9-aa07-d0b84ec2309b/image.png" alt=""></p>
<h1 id="발표-내용">발표 내용</h1>
<h2 id="1-ai와-자동화로-주니어-개발자-키우기---인프런-cto-이동욱향로님">1. AI와 자동화로 주니어 개발자 키우기 - 인프런 CTO 이동욱(향로)님</h2>
<p><img src="https://velog.velcdn.com/images/string_main/post/72015e9f-fdf3-40a2-bff7-fdde37d9a2ff/image.jpg" alt=""></p>
<blockquote>
<p>향로님 세션은 인프랩에서 주니어 개발자가 적응 기간을 최소화 하면서 활약할 수 있는 환경을 어떻게 조성할지와 업무 효율을 어떻게 극대화 시킬 수 있을지에 대한 고찰과 실행 과정을 중점으로 진행되었다.</p>
</blockquote>
<h3 id="인프랩이-원하는-시니어의-덕목">인프랩이 원하는 시니어의 덕목</h3>
<ol>
<li>조직과 제품의 비전과 일치</li>
<li>높은 자기 동기부여</li>
<li>리더십과 매니지먼트</li>
<li>기술과 제품 사이 적절한 관점과 결정</li>
<li>적정 수준 이상의 전문성</li>
</ol>
<p>사실 이 모든 것을 충족하는 사람을 찾기는 어렵다.
향로님은 이 체크리스트 중 1, 2번을 제외한 나머지는 훈련이 가능하다 판단하고 인재를 영입했다고 한다.</p>
<h3 id="인프랩에서-ai로-신입-개발자-온보딩-및-업무-효율을-높인-방법들">인프랩에서 AI로 신입 개발자 온보딩 및 업무 효율을 높인 방법들</h3>
<ol>
<li><p><strong>입사 시 개발팀의 미션을 공유</strong></p>
<ul>
<li><a href="https://tech.inflab.com/20231117-devteam-value/">인프랩 개발팀의 미션과 가치</a></li>
</ul>
</li>
<li><p><strong>적응 시간을 줄이고 활약 시간을 늘리기</strong>
 신입이 입사한지 1년 만에 이직을 하거나 그만둔다면? -&gt; 회사에서 투자한 비용 대비 효율 떨어짐
 이런 부분을 개선하기 위해서 적응 시간을 최소화하고 활약할 수 있는 시간을 최대화하는 방법을 고안
 =&gt; AI를 활용하면 어떨까?</p>
</li>
<li><p><strong>AI 코드리뷰 (CodeRabbit.ai)</strong></p>
<ul>
<li>쿼리 최적화 및 누락된 테스트 발견</li>
</ul>
</li>
<li><p><strong>정적 분석 (SonarQube)</strong></p>
<ul>
<li>코드 스멜, 테스트 커버리지, 라이브러리 취약점, 잘못된 패턴 등을 기계적으로 검수해 줌</li>
</ul>
</li>
<li><p><strong>SW 개발 생산성 측정 (DORA Metrics)</strong></p>
<ul>
<li>DORA Metrics는 Jenkins의 빌드 시간 등 개발 생산성을 측정하는 대시보드를 제공하는 툴</li>
<li>개발팀의 생산성을 측정하는 주요 지표</li>
</ul>
</li>
<li><p><strong>AI Slack Bot</strong></p>
<ul>
<li>슬랙특정 채널에서의 질문에 자동으로 답변하는 AI Bot 적용</li>
<li>사내 Wiki, Jira를 참고해서 답변</li>
<li>회사 내에서만 사용되는 특별한 용어들은 스프레드 시트로 정리하고 AI Bot이 학습</li>
</ul>
</li>
<li><p><strong>통합 검색 (MetaSearch)</strong></p>
<ul>
<li>컨플루언스, Github, 구글 드라이브, Jira, Slack 등 파편화된 모든 정보를 검색할 수 있는 환경 제공</li>
</ul>
</li>
</ol>
<blockquote>
<p>인프랩에서는 한번의 문서화가 팀원 전체의 생산성을 개선한다는 것을 팀원 모두가 인지하고 있어서 문서화는 당연히 해야하는 문화가 되었다. 구두로 논의된 내용들도 슬랙에 작성하여 휴가 등으로 부재가 있었던 팀원들도 AI Bot을 이용해 데일리 리포트를 받아볼 수 있게 했다고 한다.</p>
</blockquote>
<h2 id="2-책임-분리의-마법-깔끔한-폴더-구조-만들기---테오의-스프린트-운영자-테오님">2. 책임 분리의 마법: 깔끔한 폴더 구조 만들기 - 테오의 스프린트 운영자 테오님</h2>
<p><img src="https://velog.velcdn.com/images/string_main/post/d13a45c7-7cd0-4e87-b4ca-8479f7f39fac/image.jpg" alt=""></p>
<blockquote>
<p>테오님 세션은 프론트엔드에서의 관심사 분리와 여러 아키텍쳐를 중심으로 진행되었다.</p>
</blockquote>
<p>프론트엔드는 언어를 3개를 배운다.
HTML(구조), CSS(표현), JavaScript(동작)은 관심사 분리의 좋은 예시인데,
각각의 고유한 역할을 담당하면서 개발의 복잡성을 관리할 수 있게 되었다.</p>
<h3 id="관심사-분리soc">관심사 분리(SoC)</h3>
<ul>
<li>정의: 언어, 모듈, 파일, 함수, 클래스 등 특정 계층이 하나의 명확한 역할만 수행하도록 설계함으로써 코드 가독성과 유지보수성을 향상하고자 하는 행위</li>
<li>필요성: 관심사를 분리한다는 것은 인지부하를 최소화하기 위함이다. 명확한 하나의 기준으로 선명하게 분리되는게 중요하다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/string_main/post/72a39e05-5679-4452-b1f3-8cd5f60f05fe/image.png" alt=""></p>
<blockquote>
<p>컴포넌트 희망편 vs 컴포넌트 절망편...</p>
</blockquote>
<p>프론트엔드의 관심사 분리 기준</p>
<ul>
<li>컨텐츠</li>
<li>화면 디자인</li>
<li>사용자 인터렉션</li>
<li>서버 데이터 통신</li>
<li>데이터 변화 자동렌더링</li>
</ul>
<blockquote>
<p>등등... 위와 같이 역할을 중심으로 관심사 분리를 해왔는데, 이제는 UI 요소와 로직을 하나의 단위(컴포넌트)로 개발하다보니 기능 중심의 모듈화가 되었다. 그런데 이것도 문제점이 있었으니..</p>
</blockquote>
<ol>
<li>컴포넌트의 비대화<ul>
<li>하나의 컴포넌트 안에 많은 책임 집중</li>
</ul>
</li>
<li>높은 결합도<ul>
<li>컴포넌트 간 데이터 전달을 위해 props drilling 발생</li>
</ul>
</li>
<li>관리의 어려움<ul>
<li>컴포넌트가 많아지면서 어떻게 보관하고 찾을지 어려워짐</li>
</ul>
</li>
</ol>
<p>이러한 문제들을 해결하기 위해 아래와 같은 방안이 있다.</p>
<ol>
<li>UI 컴포넌트의 계층 구조 만들기 (Atomic Design Pattern)</li>
<li>HTML-CSS 의존성 해결하기 (CSS가 HTML을 따라가도록)</li>
<li>비즈니스 로직과 뷰 로직의 분리</li>
</ol>
<h3 id="클린-아키텍쳐">클린 아키텍쳐</h3>
<ul>
<li>데이터의 흐름을 관심으로 하는 관심사 계층</li>
</ul>
<p><code>구조</code></p>
<ol>
<li>UI Layer</li>
<li>Application Layer</li>
<li>Domain Layer (핵심 비즈니스 로직)</li>
<li>Infrastructure Layer</li>
</ol>
<h3 id="fsdfeature-sliced-design-아키텍쳐">FSD(Feature-Sliced Design) 아키텍쳐</h3>
<ul>
<li>기능 단위로 애플리케이션을 구조화 하는 방식</li>
<li>모듈화, 유지보수성, 확장성을 높이기 위함</li>
</ul>
<p><code>구조</code></p>
<ol>
<li>app (app 전역 설정)</li>
<li>shared (재사용할 공통 컴포넌트)</li>
<li>entities (user, order 등의 도메인 관련)</li>
<li>features (auth, cart 등의 기능 관련)</li>
<li>pages (라우트와 연관된 페이지 컴포넌트)</li>
</ol>
<h3 id="마무리">마무리</h3>
<blockquote>
</blockquote>
<ol>
<li>단일 책임 원칙</li>
<li>의존성과 단방향 데이터 흐름</li>
<li>응집도는 높게, 결합도는 낮게</li>
<li>모듈과 레이어</li>
<li>데이터 흐름과 아키텍쳐</li>
</ol>
<p>이런 요소들과 프로젝트 볼륨을 생각하면서 효율적인 폴더 구조를 생각해야 한다!</p>
<h2 id="3-클린-아키텍처-무한-성장하는-시스템의-비밀---무신사-백엔드-개발자-허재님">3. 클린 아키텍처: 무한 성장하는 시스템의 비밀 - 무신사 백엔드 개발자 허재님</h2>
<ul>
<li>남의 집을 따라하면 그 끝은 남의 집이다. 남의 것을 따르기 보단 규칙을 따르자.</li>
<li>좋은 설계란? -&gt; 미래를 멀리 보지 말고 언제든 변경 가능한 코드를 만드는 것.</li>
<li>각 계층이 하는 일은 서로 몰라야 변경이 용이하다. (책임 분리)</li>
<li>1 Use-Case, 1 Domain</li>
<li>충분히 숙성된 도메인을 내보내야 한다. (ex. 회사에서 도메인이 늘어났을 때를 생각해보기)</li>
<li>하나의 기능을 만들 때 3시간 이상 걸리면 안됨. 어차피 ChatGPT가 개발하니까... 고민 많이 하지 말고 기능을 찢어서 개발해라.</li>
<li>일 두번하는 개발자가 되지 말자.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터 타입에 관한 고찰]]></title>
            <link>https://velog.io/@string_main/%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%97%90-%EA%B4%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</link>
            <guid>https://velog.io/@string_main/%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%97%90-%EA%B4%80%ED%95%9C-%EA%B3%A0%EC%B0%B0</guid>
            <pubDate>Thu, 16 Mar 2023 08:38:24 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-기본형-데이터와-참조형-데이터">🌱 기본형 데이터와 참조형 데이터</h2>
<hr>
<ul>
<li><p>객체의 프로퍼티를 변경했을 때</p>
<pre><code class="language-jsx">  var a = 10;
  var b = a;
  var obj1 = { c: 10, d: &#39;ddd&#39; };
  var obj2 = obj1;

  b = 15;
  obj2.c = 20;</code></pre>
<p>  기본형 데이터를 복사한 변수 b의 값을 바꿨을 때, 해당 데이터 참조 값(주소) 자체가 변경되는 반면, 참조형 데이터를 복사한 변수 obj2의 프로퍼티를 바꾸면 참조 값이 가리키는 객체의 프로퍼티가 저장된 곳의 참조 값이 바뀔 뿐, 변수의 참조 값 자체가 바뀌지 않는다.</p>
<p>  즉, 변수 a와 b는 서로 다른 주소를 바라보게 됐으나, 변수 obj1와 obj2는 여전히 같은 객체를 바라보고 있는 상태이다. 이를 코드로 표현하면 아래와 같다.</p>
<pre><code class="language-jsx">  a !== b
  obj1 === obj2</code></pre>
<p>  이 결과가 기본형 데이터와 참조형 데이터의 가장 큰 차이점이다. 대부분의 자바스크립트 책에서 기본형은 값을 복사하고 참조형은 주솟값을 복사한다고 설명하고 있지만, 실은 어떤 데이터 타입이든 변수에 할당하기 위해서는 주솟값을 복사해야 한다. 엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수밖에 없다.</p>
<p>  다만, 기본형은 주솟값 복사 과정이 한 번만 이뤄지고, 참조형은 한 단계를 더 거치게 된다는 차이가 있을 뿐이다.</p>
</li>
<li><p>객체 자체를 변경했을 때</p>
<pre><code class="language-jsx">  var a = 10;
  var b = a;
  var obj1 = { c: 10, d: &#39;ddd&#39; };
  var obj2 = obj1;

  b = 15;
  obj2 = { c: 20, d: &#39;ddd&#39; };</code></pre>
<pre><code class="language-jsx">  a !== b
  obj1 !== obj2</code></pre>
<p>  이 경우에는 값을 직접 변경했기 때문에 객체에 대한 변경임에도 값이 달라졌다. 즉, 참조형 데이터가 가변값이라고 설명할 때는 참조형 데이터 자체를 변경할 때가 아니라 객체 내부의 프로퍼티를 변경할 때만 성립한다.</p>
</li>
</ul>
<h2 id="🌱-불변-객체">🌱 불변 객체</h2>
<hr>
<ul>
<li><p>객체의 내부 프로퍼티를 변경할 일이 있을 때마다 새로운 객체를 만들어 재할당하기로 하거나 자동으로 새로운 객체를 만드는 도구(라이브러리, Spread 연산자, Object.assign 메서드 등)를 활용하면 객체의 불변성을 확보할 수 있다.</p>
</li>
<li><p>객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우에 불변 객체가 필요하다.</p>
<pre><code class="language-jsx">  // 객체의 가변성에 따른 문제점

  var user = {
    name: &#39;Jaenam&#39;,
    gender: &#39;male&#39;,
  };

  var changeName = function(user, newName) {
    var newUser = user;
    newUser.name = newName;
    return newUser;
  };

  var user2 = changeName(user, &#39;Jung&#39;);

  if (user !== user2) {
    console.log(&#39;유저 정보가 변경되었습니다.&#39;); // 출력되지 않는 문제 발생
  }
  console.log(user.name, user2.name); // Jung Jung
  console.log(user === user2); // true</code></pre>
<pre><code class="language-jsx">  // 해결된 코드

  var user = {
    name: &#39;Jaenam&#39;,
    gender: &#39;male&#39;,
  };

  var changeName = function(user, newName) {
    return {
      name: newName,
      gender: user.gender, // 변경할 필요없는 기존 정보가 하드 코딩된 문제점
    };
  };

  var user2 = changeName(user, &#39;Jung&#39;);

  if (user !== user2) {
    console.log(&#39;유저 정보가 변경되었습니다.&#39;); // 유저 정보가 변경되었습니다.
  }
  console.log(user.name, user2.name); // Jaenam Jung
  console.log(user === user2); // false</code></pre>
<pre><code class="language-jsx">  // 좀 더 개선된 코드 (얕은 복사)

  var copyObject = function(target) {
    var result = {};
    for (var prop in target) {
      result[prop] = target[prop];
    }
    return result;
  };

  var user = {
    name: &#39;Jaenam&#39;,
    gender: &#39;male&#39;,
  };

  var user2 = copyObject(user);
  user2.name = &#39;Jung&#39;;

  if (user !== user2) {
    console.log(&#39;유저 정보가 변경되었습니다.&#39;); // 유저 정보가 변경되었습니다.
  }
  console.log(user.name, user2.name); // Jaenam Jung
  console.log(user === user2); // false
  1-14</code></pre>
</li>
</ul>
<h2 id="🌱--undefined와-null">🌱  undefined와 null</h2>
<hr>
<ul>
<li><p><code>undefined</code> : 사용자가 명시적으로 지정할 수도 있지만, 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여할 때도 있다. (사용자가 어떤 값을 지정할 것이라 예상되는 상황임에도 실제로는 그렇게 하지 않았을 때) ‘비어있음’을 의미하는 순회 가능한 하나의 값이다.</p>
<ul>
<li><p>값을 대입하지 않은 변수, 데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때</p>
<ul>
<li><p>배열에 대해서는 다소 특이한 동작을 확인할 수 있다.</p>
<pre><code class="language-jsx">  // 비어있는 요소와 undefined를 할당한 요소는 다르다.
  // 비어있는 요소는 순회 대상에서 제외된다.

  var arr1 = [];
  arr1.length = 3;
  console.log(arr1); // [empty x 3]

  var arr2 = new Array(3);
  console.log(arr2); // [empty x 3]

  var arr3 = [undefined, undefined, undefined];
  console.log(arr3); // [undefined, undefined, undefined]</code></pre>
</li>
</ul>
</li>
<li><p>객체 내부의 존재하지 않는 프로퍼티에 접근하려 할 때</p>
</li>
<li><p>return 문이 없거나 호출되지 않는 함수의 실행 결과</p>
<aside>
💡 값으로써 할당된 undefined는 실존하는 데이터인 반면, 자바스크립트 엔진이 반환해주는 undefined는 문자 그대로 값이 없음을 나타낸다. 이러한 혼란을 방지하기 위해 undefined는 오직 자바스크립트 엔진이 반환하는 경우로 한정되게 하면 된다. 즉, 같은 의미를 가진 null을 사용해 직접 undefined를 할당하지 않게 해주면 된다.

</aside>
</li>
</ul>
</li>
<li><p><code>null</code> : 사용자가 명시적으로 ‘없음’을 표현하기 위해 대입한 값.</p>
<pre><code class="language-jsx">  // 일치 연산자(===)를 사용해야만 null을 정확히 판별할 수 있다.

  var n = null;
  console.log(typeof n); // object

  console.log(n == undefined); // true
  console.log(n == null); // true

  console.log(n === undefined); // false
  console.log(n === null); // true</code></pre>
  <aside>
  💡 typeof 명령어는 null에 대해서 object를 반환하는 버그가 있다.

  </aside>


</li>
</ul>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터라는 것과 기본형 데이터와 참조형 데이터가 메모리에 할당되는 과정이 다르기 때문에 동작 방식에서 차이가 나타나는 것이라는 사실을 알게되었고, 참조형 데이터가 가변값이라고 설명할 때는 참조형 데이터 자체를 변경할 때가 아니라 객체 내부의 프로퍼티를 변경할 때만 성립한다는 부분과 객체의 불변성을 유지해야 하는 상황이 어떤 상황인지 알게 되었다.</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>코어 자바스크립트</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[얕은 복사와 깊은 복사 1분 만에 이해하기]]></title>
            <link>https://velog.io/@string_main/%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%99%80-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC-1%EB%B6%84-%EB%A7%8C%EC%97%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@string_main/%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%99%80-%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC-1%EB%B6%84-%EB%A7%8C%EC%97%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 25 Jan 2023 14:36:26 GMT</pubDate>
            <description><![CDATA[<h3 id="얕은-복사-vs-깊은-복사">얕은 복사 vs 깊은 복사</h3>
<ul>
<li><p><code>얕은 복사(shallow copy)</code> : 객체의 참조(주소) 값을 복사하는 것. 1 depth까지만 복사하며, 객체에 중첩되어 있는 객체의 경우 참조 값을 복사한다.</p>
<pre><code class="language-jsx"> const obj1 = { a: 1, b: 2 };
  const obj2 = obj1; // 참조에 의한 할당 (같은 데이터 주소)

  console.log(obj1 === obj2); // true

  obj2.a = 3; // 같은 주소를 참조하고 있어서 obj2의 프로퍼티를 수정하면 obj1의 프로퍼티도 수정된다.
  console.log(obj1.a); // 3</code></pre>
</li>
<li><p><code>깊은 복사(deep copy)</code> : 객체의 실제 값을 복사하는 것. 객체에 중첩된 객체까지 모두 복사한다.</p>
<ul>
<li><p>spread 연산자를 통한 깊은 복사 (단, 1 depth 까지만 깊은 복사 가능)</p>
<pre><code class="language-jsx">  const obj1 = { a: 1, b: 2 };
  const obj2 = { ...obj1 };

  obj2.a = 3;

  console.log(obj1 === obj2) // false
  console.log(obj1.a) // 1</code></pre>
</li>
<li><p>Object.assign() 메서드를 통한 복사 (단, 1 depth 까지만 깊은 복사 가능)</p>
<pre><code class="language-jsx">  const obj1 = { a: 1, b: 2 };
  const obj2 = Object.assign({}, obj1);

  obj2.a = 3;

  console.log(obj1 === obj2); // false
  console.log(obj1.a) // 1</code></pre>
</li>
<li><p>완벽한 깊은 복사 방법</p>
<ul>
<li><p>JSON.parse() &amp; JSON.stringify() 사용하기</p>
<pre><code class="language-jsx">  const obj1 = { a: 1, b: 2, c: {d: 3} };
  // 객체 순환이 아닌 문자열로 변경 후 그것을 다시 원본 객체로 변경하는 방식
  // 문자열은 원시 타입으로 불변성을 가지기 때문에 깊은 복사가 가능하다!
  const obj2 = JSON.parse(JSON.stringify(obj1));

  obj2.c = 3;

  console.log(obj1 === obj2); // false
  console.log(obj1.c) // {d: 3}</code></pre>
</li>
<li><p>Lodash 라이브러리의 cloneDeep 함수 사용하기</p>
</li>
<li><p>재귀적으로 깊은 복사하기</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="느낀-점">느낀 점</h3>
<p>헷갈려하던 얕은 복사와 깊은 복사를 코드 예제를 직접 작성해보면서 다시 상기하게 되었다. 원시 값과 객체의 특성이 다르기 때문에 항상 이를 내부적으로 고려해서 코드를 작성해야겠다고 느꼈다.</p>
<blockquote>
<p><strong>참고 자료</strong></p>
</blockquote>
<ul>
<li>모던 자바스크립트 Deep Dive</li>
<li><a href="https://hanamon.kr/javascript-shallow-copy-deep-copy/">얕은 복사(shallow copy) vs 깊은 복사(deep copy)</a></li>
<li><a href="https://medium.com/watcha/%EA%B9%8A%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%99%80-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EC%8B%AC%EB%8F%84%EC%9E%88%EB%8A%94-%EC%9D%B4%EC%95%BC%EA%B8%B0-2f7d797e008a">깊은 복사와 얕은 복사에 대한 심도있는 이야기</a><blockquote>
</blockquote>
<em>잘못된 점이나 궁금한 점이 있으시면 댓글로 남겨주시면 감사하겠습니다!</em></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TypeScript] 타입]]></title>
            <link>https://velog.io/@string_main/TypeScript-%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@string_main/TypeScript-%ED%83%80%EC%9E%85</guid>
            <pubDate>Mon, 23 Jan 2023 11:13:07 GMT</pubDate>
            <description><![CDATA[<h2 id="typescript의-타입">TypeScript의 타입</h2>
<hr>
<table>
<thead>
<tr>
<th>타입</th>
<th>예시</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>number</strong></td>
<td>1, 5.3, -10</td>
<td>모든 숫자들, 정수와 실수형 간 차이 없음</td>
</tr>
<tr>
<td><strong>string</strong></td>
<td>‘Hi’, “Hi”, `Hi`</td>
<td>모든 문자 값</td>
</tr>
<tr>
<td><strong>boolean</strong></td>
<td>true, false</td>
<td>오직 참과 거짓 두 가지 값</td>
</tr>
<tr>
<td><strong>object</strong></td>
<td>{age: 30}</td>
<td>모든 자바스크립트 객체, 객체의 타입 지정을 구체적으로 명시할 수 있음</td>
</tr>
<tr>
<td><strong>array</strong></td>
<td>[1, 2, 3]</td>
<td>모든 자바스크립트 배열, 타입은 요소의 타입에 따라 유연하거나 엄격할 수 있음</td>
</tr>
<tr>
<td><strong>tuple</strong></td>
<td>[1, 2]</td>
<td>타입스크립트에 의해 추가된 타입: 정해진 길이의 배열</td>
</tr>
<tr>
<td><strong>enum</strong></td>
<td>enum {NEW, OLD}</td>
<td>타입스크립트에 의해 추가된 타입: 자동적으로 열거된 전역 상수 식별자</td>
</tr>
<tr>
<td><strong>any</strong></td>
<td>*</td>
<td>모든 종류의 값, 타입 배정이 필요하지 않음</td>
</tr>
<tr>
<td><strong>unknown</strong></td>
<td>*</td>
<td>모든 종류의 값, any와 유사하지만, unknown 타입에 어떤 것을 대입하는 것이 유효하지 않아 더 안전함</td>
</tr>
<tr>
<td><strong>function</strong></td>
<td>function a(n1: number, n2: number) : number</td>
<td>매개변수 타입과 반환 타입 표기가 가능함</td>
</tr>
<tr>
<td><strong>void</strong></td>
<td>function noop(): void { return; }</td>
<td>값을 반환하지 않는 함수의 반환 값을 의미함</td>
</tr>
<tr>
<td><strong>union</strong></td>
<td>number</td>
<td>string</td>
</tr>
<tr>
<td><strong>intersection</strong></td>
<td>Person &amp; Developer</td>
<td>union이 or이라면 intersection은 and, 자주 사용되는 방법은 아님</td>
</tr>
<tr>
<td><strong>literal</strong></td>
<td>&#39;as-number&#39;</td>
<td>&#39;as-text&#39;</td>
</tr>
<tr>
<td><strong>null</strong></td>
<td>null</td>
<td>명시적으로 빈 값을 나타냄</td>
</tr>
<tr>
<td><strong>undefined</strong></td>
<td>undefined</td>
<td>선언 후 아무 값도 할당받지 않은 초기 상태</td>
</tr>
<tr>
<td><strong>never</strong></td>
<td>function fail(msg: string): never { throw new Error(msg); }</td>
<td>절대 관측될 수 없는 값을 의미, 함수가 예외를 발생시키거나, 프로그램 실행을 종료함을 의미함</td>
</tr>
</tbody></table>
<h2 id="typescript의-장점-및-tips">TypeScript의 장점 및 Tips</h2>
<hr>
<pre><code class="language-jsx">function add(n1, n2) {
  return n1 + n2;
}

const number1 = &#39;5&#39;;
const number2 = 2.8;

const result = add(number1, number2);
console.log(result); // 52.8</code></pre>
<blockquote>
<p>위의 예시는 수학적 계산 결과가 아니라 문자열과 숫자가 연결되어 반환된다.
이러한 부분은 에러를 찾기 어렵게 만들고 버그로 이어질 가능성이 있다.</p>
</blockquote>
<ul>
<li><p>타입스크립트를 사용하면 타입 에러를 개발 단계에서 발견할 수 있다.</p>
</li>
<li><p>타입스크립트는 컴파일을 차단하지 않고 실수를 알려준다.</p>
</li>
<li><p>동일한 이름의 js 파일과 ts 파일을 동시에 열어두면 Duplicate function implementation 오류가 발생하니 주의하자.</p>
</li>
<li><p>타입스크립트 기능은 자바스크립트 엔진에 내장되어 있지 않기 때문에 개발 단계에서만 지원을 받을 수 있다. 그래서 타입스크립트는 브라우저에서 실행할 수 없으며 개발 단계에서 컴파일 할 때만 실행 가능하다.</p>
</li>
<li><p>타입스크립트의 주요 원시 타입은 모두 소문자이다.</p>
</li>
</ul>
<h2 id="타입-추론-type-inference">타입 추론 (Type Inference)</h2>
<hr>
<pre><code class="language-tsx">let number1: number = 5;</code></pre>
<ul>
<li>타입스크립트는 위와 같이 타입 배정을 하지 않아도 타입 추론이라는 내장 기능을 활용해 추론한다.</li>
</ul>
<pre><code class="language-tsx">let str = &quot;test&quot;;
str = 0; // 에러 발생</code></pre>
<ul>
<li>숫자형이 할당되어 타입 추론을 알아서 해주기 때문에 굳이 타입을 명시할 필요가 없다. 명시적인 타입 지정은 좋은 방식이 아니다.</li>
</ul>
<h2 id="객체-object">객체 (Object)</h2>
<hr>
<pre><code class="language-tsx">const person: {
    name: string;
    age: number;
}</code></pre>
<ul>
<li>타입스크립트의 객체 타입 정의는 쉼표가 아닌 세미 콜론으로 마무리 된다.</li>
</ul>
<h3 id="javascript-객체">JavaScript 객체</h3>
<pre><code class="language-jsx">const product = {
  id: &#39;abc1&#39;,
  price: 12.99,
  tags: [&#39;great-offer&#39;, &#39;hot-and-new&#39;],
  details: {
    title: &#39;Red Carpet&#39;,
    description: &#39;A great carpet - almost brand-new!&#39;
  }
}</code></pre>
<h3 id="typescript-타입">TypeScript 타입</h3>
<pre><code class="language-tsx">{
  id: string;
  price: number;
  tags: string[];
  details: {
    title: string;
    description: string;
  }
}</code></pre>
<h2 id="배열-array과-튜플-tuple">배열 (Array)과 튜플 (Tuple)</h2>
<hr>
<ul>
<li>any는 유연하지만 타입 등의 좋은 기능들을 활용하지 못하게 된다.</li>
</ul>
<pre><code class="language-tsx">const person = {
  name: &#39;Maximilian&#39;,
  age: 30,
  hobbies: [&#39;Sports&#39;, &#39;Cooking&#39;],
  role: [2, &#39;author&#39;]
};

person.role.push(&#39;admin&#39;);
person.role[1] = 10;</code></pre>
<ul>
<li>role 속성은 배열의 첫번째 요소가 숫자여야 하고 두번째 요소가 문자열이어야 하는데, 공용 타입(union)으로는 구조를 명시할 수 없다. 순서에 상관없이 두 타입 모두 가능하기 때문이다. 이러한 경우에 튜플(tuple)이 적합하다.</li>
</ul>
<pre><code class="language-tsx">const person: {
  name: string;
  age: number;
  hobbies: string[];
  role: [number, string];
} = {
  name: &quot;Maximilian&quot;,
  age: 30,
  hobbies: [&quot;Sports&quot;, &quot;Cooking&quot;],
  role: [2, &quot;author&quot;],
};

person.role.push(&#39;admin&#39;);
person.role[1] = 10; // 에러 발생</code></pre>
<ul>
<li>push는 예외적으로 튜플에서 허용되어서 에러를 걸러낼 순 없지만, 적어도 잘못된 값을 할당하지는 않는다.</li>
</ul>
<h2 id="열거형-enum">열거형 (Enum)</h2>
<hr>
<pre><code class="language-tsx">const person = {
  name: &quot;Maximilian&quot;,
  age: 30,
  hobbies: [&quot;Sports&quot;, &quot;Cooking&quot;],
  role: 2,
};

// role 2가 admin 권한인지 read only인지..</code></pre>
<ul>
<li>role 등을 설정할 때 숫자로만 설정한다면 사람이 바로 알기 어려워서 사람이 이해하기 쉬운 식별자로 설정하는 것이 효율적이다.</li>
</ul>
<pre><code class="language-tsx">const person = {
  name: &quot;Maximilian&quot;,
  age: 30,
  hobbies: [&quot;Sports&quot;, &quot;Cooking&quot;],
  role: &#39;READ ONLY USER&#39;,
};

if(person.role === &#39;READ-ONLY-USER&#39;) {
  console.log(&#39;is read only&#39;);
}</code></pre>
<ul>
<li>그렇다고 또 문자열로 식별자를 설정하게 되면, 정확한 문자열을 알고있어야 하는 단점이 존재한다.</li>
</ul>
<pre><code class="language-tsx">const ADMIN = 0;
const READ_ONLY = 1;
const AUTHOR = 2;

const person = {
  name: &quot;Maximilian&quot;,
  age: 30,
  hobbies: [&quot;Sports&quot;, &quot;Cooking&quot;],
  role: ADMIN,
};

if (person.role === ADMIN) {
  console.log(&quot;is admin&quot;);
}</code></pre>
<ul>
<li>이 방법도 나쁘지 않지만, 모든 상수를 정의하고 관리해야 하는 문제점이 존재한다.</li>
</ul>
<pre><code class="language-tsx">enum Role { ADMIN, READ_ONLY, AUTHOR };

const person = {
  name: &quot;Maximilian&quot;,
  age: 30,
  hobbies: [&quot;Sports&quot;, &quot;Cooking&quot;],
  role: Role.ADMIN,
};

if (person.role === Role.AUTHOR) {
  console.log(&quot;is author&quot;);
}</code></pre>
<ul>
<li>enum이 각 lable을 숫자로 할당하게 해주어 편리하다.</li>
</ul>
<pre><code class="language-tsx">var Role;
(function (Role) {
    Role[Role[&quot;ADMIN&quot;] = 0] = &quot;ADMIN&quot;;
    Role[Role[&quot;READ_ONLY&quot;] = 1] = &quot;READ_ONLY&quot;;
    Role[Role[&quot;AUTHOR&quot;] = 2] = &quot;AUTHOR&quot;;
})(Role || (Role = {}));
;</code></pre>
<ul>
<li>컴파일 하면 enum이 구현된 자바스크립트 코드를 확인할 수 있다.</li>
</ul>
<pre><code class="language-tsx">enum Role { ADMIN=&#39;admin&#39;, READ_ONLY=1, AUTHOR };</code></pre>
<ul>
<li>초기값 지정도 가능하다.</li>
</ul>
<h2 id="any">Any</h2>
<hr>
<ul>
<li>유연한 타입이라 편할 것 같지만?… 사용하면 자바스크립트 쓰는거랑 진배없다^^</li>
<li>어떤 값도 저장하지 않아서 타입스크립트 컴파일러가 작동하지 않음.</li>
<li>어떤 값이나 종류의 데이터가 어디에 저장될지 알 수 없는 경우에 대비하거나 런타임 검사 수행 시 작업의 범위를 좁히기 위해 사용하는 것 이외의 경우에는 사용하지 않는 것이 좋다.</li>
</ul>
<pre><code class="language-tsx">// 런타임 검사 예시
if(typeof n1 !== &#39;number&#39; || typeof n2 !== &#39;number&#39;) {
    throw new Error(&#39;Incorrect input&#39;);
}</code></pre>
<h2 id="조합-union">조합 (Union)</h2>
<hr>
<pre><code class="language-tsx">function combine(input1: number | string, input2: number | string) { // Union Type
  const result = input1 + input2; // Error: Operator &#39;+&#39; cannot be applied to types &#39;string | number&#39; and &#39;string | number&#39;.

  return result;
}

const combinedAges = combine(30, 26);
console.log(combinedAges);

const combinedNames = combine(&#39;Max&#39;, &#39;Anna&#39;);
console.log(combinedNames);</code></pre>
<ul>
<li>더하기 연산자는 숫자와 문자열 모두 사용할 수 있어서 문제가 없어야 하지만, 타입스크립트는 유니언 타입만 이해할 뿐 유니언 타입 내에 무엇이 있는지는 분석하지 못해서 더하기 연산자를 사용할 수 없다고 판단해 오류가 발생한다.</li>
</ul>
<pre><code class="language-tsx">function combine(input1: number | string, input2: number | string) {
  let result;

  if(typeof input1 === &#39;number&#39; &amp;&amp; typeof input2 === &#39;number&#39;) {
    result = input1 + input2;
  }else {
    result = input1.toString() + input2.toString();
  }

  return result;
}

const combinedAges = combine(30, 26);
console.log(combinedAges);

const combinedNames = combine(&#39;Max&#39;, &#39;Anna&#39;);
console.log(combinedNames);</code></pre>
<ul>
<li><p>런타임 타입 검사를 추가해 해결할 수 있다.</p>
</li>
<li><p>Union 타입을 사용하면 매개변수를 보다 유연하게 사용할 수 있다.</p>
</li>
</ul>
<h2 id="리터럴-literal">리터럴 (Literal)</h2>
<hr>
<pre><code class="language-tsx">function combine(
  input1: number | string,
  input2: number | string,
  resultConversion: string
) {
  let result;

  if (typeof input1 === &quot;number&quot; &amp;&amp; typeof input2 === &quot;number&quot; || resultConversion === &#39;as-number&#39;) {
    result = +input1 + +input2;
  } else {
    result = input1.toString() + input2.toString();
  }

  return result;
}

const combinedAges = combine(30, 26, &quot;as-number&quot;);
console.log(combinedAges);

const combinedStringAges = combine(&#39;30&#39;, &quot;26&quot;, &quot;as-number&quot;);
console.log(combinedStringAges);

const combinedNames = combine(&quot;Max&quot;, &quot;Anna&quot;, &quot;as-text&quot;);
console.log(combinedNames);</code></pre>
<ul>
<li>이 방법의 단점은 개발자가 문자열을 기억해야 한다는 점, 실수가 발생할 수 있다.</li>
</ul>
<pre><code class="language-tsx">function combine(
  input1: number | string,
  input2: number | string,
  resultConversion: &#39;as-number&#39; | &#39;as-text&#39; // Literal Type
) {
  let result;

  if (typeof input1 === &quot;number&quot; &amp;&amp; typeof input2 === &quot;number&quot; || resultConversion === &#39;as-number&#39;) {
    result = +input1 + +input2;
  } else {
    result = input1.toString() + input2.toString();
  }

  return result;
}

const combinedAges = combine(30, 26, &quot;as-number&quot;);
console.log(combinedAges);

const combinedStringAges = combine(&#39;30&#39;, &quot;26&quot;, &quot;as-number&quot;);
console.log(combinedStringAges);

const combinedNames = combine(&quot;Max&quot;, &quot;Anna&quot;, &quot;as-text&quot;);
console.log(combinedNames);</code></pre>
<ul>
<li>리터럴 타입으로 개선 가능, 오타 시 Error 발생</li>
</ul>
<h2 id="별칭-alias">별칭 (Alias)</h2>
<hr>
<ul>
<li><p>유니언 타입으로 작업을 수행할 때 매번 반복하는 것은 유지보수에 번거롭다. → 타입에 별칭을 지정해 해결!</p>
<pre><code class="language-tsx">  // Type Alias
  type Combinable = number | string;
  type ConversionDescriptor = &quot;as-number&quot; | &quot;as-text&quot;;

  function combine(
    input1: Combinable,
    input2: Combinable,
    resultConversion: ConversionDescriptor
  ) {
    let result;

    if (
      (typeof input1 === &quot;number&quot; &amp;&amp; typeof input2 === &quot;number&quot;) ||
      resultConversion === &quot;as-number&quot;
    ) {
      result = +input1 + +input2;
    } else {
      result = input1.toString() + input2.toString();
    }

    return result;
  }

  const combinedAges = combine(30, 26, &quot;as-number&quot;);
  console.log(combinedAges);

  const combinedStringAges = combine(&#39;30&#39;, &quot;26&quot;, &quot;as-number&quot;);
  console.log(combinedStringAges);

  const combinedNames = combine(&quot;Max&quot;, &quot;Anna&quot;, &quot;as-text&quot;);
  console.log(combinedNames);</code></pre>
</li>
</ul>
<ul>
<li><p>객체에도 별칭 지정 가능</p>
<pre><code class="language-tsx">  type User = { name: string; age: number };
  const u1: User = { name: &#39;Max&#39;, age: 30 };</code></pre>
</li>
<li><p>아래와 같이 사용할 수도 있다.</p>
<pre><code class="language-tsx">  type User = { name: string } | string;
  let u1: User = {name: &#39;Max&#39;};
  u1 = &#39;Michael&#39;;</code></pre>
</li>
</ul>
<h2 id="함수-반환-타입과-void">함수 반환 타입과 void</h2>
<hr>
<pre><code class="language-tsx">function add(n1: number, n2: number): string {
  return n1 + n2; // Error!
}</code></pre>
<ul>
<li>리턴 타입도 명시할 수 있지만, 타입스크립트가 추론하게 하는 것이 바람직함.</li>
</ul>
<pre><code class="language-tsx">function add(n1: number, n2: number) {
  return n1 + n2;
}

function printResult(num: number): void {
  console.log(&#39;Result: &#39; + num);
}

printResult(add(5, 12)); // Result: 17
console.log(printResult(add(5, 12))); // undefined</code></pre>
<ul>
<li>함수가 아무것도 반환하지 않으면 void 타입을 가진다.</li>
</ul>
<pre><code class="language-tsx">function add(n1: number, n2: number) {
  return n1 + n2;
}

function printResult(num: number): undefined { // Error: A function whose declared type is neither &#39;void&#39; nor &#39;any&#39; must return a value.
  console.log(&#39;Result: &#39; + num);
    // return; // return을 추가하면 에러가 발생하지 않음
}

printResult(add(5, 12));
console.log(printResult(add(5, 12))); // undefined</code></pre>
<ul>
<li>리턴 값이 없는 함수를 찍어보면 undefined가 나오는데, 그렇다고 함수 반환 타입을 undefined로 하게 되면 에러가 발생한다. 타입스크립트에서는 의도적으로 함수의 반환문이 없다는 것을 void로 명시해주어야 한다.</li>
</ul>
<pre><code class="language-tsx">function add(n1: number, n2: number) {
  return n1 + n2;
}

let combineValues; // any

combineValues = add;
combineValues = 5; // Runtime Error

console.log(combineValues(8, 8));</code></pre>
<ul>
<li>함수를 변수에 할당한 후, 타입 지정을 해주지 않으면 any로 지정됨 → 런타임 에러 발생</li>
</ul>
<pre><code class="language-tsx">function add(n1: number, n2: number) {
  return n1 + n2;
}

function printResult(num: number): void {
  console.log(&#39;Result: &#39; + num);
}

let combineValues: Function;

combineValues = add;
combineValues = 5; // Compile Time Error
combineValues = printResult; // Runtime Error

console.log(combineValues(8, 8));</code></pre>
<ul>
<li>이 방법도 괜찮지만, 매개변수가 다른 함수가 할당될 수 있기 때문에 완벽하지 않은 방법이다.</li>
</ul>
<pre><code class="language-tsx">let combineValues: (a: number, b: number) =&gt; number;</code></pre>
<ul>
<li><p>함수 타입을 사용하여 이와 같이 개선할 수 있다.</p>
</li>
<li><p>콜백과 함수 타입은 거의 같은 방식으로 생성된다.</p>
</li>
</ul>
<pre><code class="language-tsx">function addAndHandle(n1: number, n2: number, cb: (num: number) =&gt; void) {
  const result = n1 + n2;
  cb(result);
}

addAndHandle(10, 20, (result) =&gt; {
  console.log(result);
  return result; // void라 정의해도 에러가 안남
});</code></pre>
<ul>
<li>버그가 아니라 기본적으로 callback이 반환하는 값으로는 어떤 작업도 수행하지 않는다는 것을 명시하는 용도. 콜백 함수는 자신이 전달되는 인수가 반환 값을 기대하지 않는 경우에도 값을 반환할 수 있다.</li>
</ul>
<h2 id="알-수-없는-unknown-타입">알 수 없는 (Unknown) 타입</h2>
<hr>
<ul>
<li>어떤 사용자가 무엇을 입력할지 알 수 없을 때 사용하는 타입.</li>
</ul>
<pre><code class="language-tsx">let userInput: unknown; // any일 경우 에러 안 남
let userName: string;

userInput = 5;
userInput = &#39;Max&#39;;
userName = userInput; // Error: Type &#39;unknown&#39; is not assignable to type &#39;string&#39;.</code></pre>
<pre><code class="language-tsx">let userInput: unknown;
let userName: string;

userInput = 5;
userInput = &quot;Max&quot;;

if (typeof userInput === &quot;string&quot;) {
  userName = userInput;
}</code></pre>
<ul>
<li>추가적인 타입 검사를 해 주면 에러 해결.</li>
<li>unknown이 any보다 좀 더 제한적이기 때문에 더 나은 선택이다.</li>
</ul>
<h2 id="절대-never-타입">절대 (Never) 타입</h2>
<hr>
<ul>
<li>void와 다르게 함수가 반환할 수 있고, 아무것도 반환하지 않는다는 것을 명시하는 타입이다.</li>
<li>관찰되지 않는 값을 나타내며, 리턴 타입에서 함수가 예외를 throw 하거나 프로그램 실행을 종료함을 의미한다. union에 남은 것이 없다고 판단할 때도 never가 나타난다.</li>
</ul>
<pre><code class="language-tsx">function generateError(message: string, code: number) {
  throw { message: message, errorCode: code };
}

const result = generateError(&quot;An error occurred!&quot;, 500);
console.log(result); // 콘솔에 찍히지 않음</code></pre>
<ul>
<li>generateError 함수는 never를 반환함. throw 에러가 스크립트와 충돌해 스크립트가 취소된다.</li>
<li>함수에 커서를 올리면 반환값이 void로 나오는데, never가 타입스크립트의 초기 버전부터 사용되진 않았기 때문에 반영이 되지 않은 것.</li>
<li>장점 :<ul>
<li>코드 품질 관점에서 의도를 분명히 할 수 있다.</li>
<li>스크립트 충돌을 일으켜 무한루프를 차단하려는 개발자 간 의도를 알 수 있게 한다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>이 글은 Udemy - Typescript :기초부터 실전형 프로젝트까지 with React + NodeJS 강의를 보고 정리한 내용입니다.
잘못된 부분이 있다면 댓글로 피드백 주시면 감사하겠습니다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[기업 코딩테스트를 보고 나서]]></title>
            <link>https://velog.io/@string_main/%EA%B8%B0%EC%97%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EB%B3%B4%EA%B3%A0-%EB%82%98%EC%84%9C</link>
            <guid>https://velog.io/@string_main/%EA%B8%B0%EC%97%85-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EB%B3%B4%EA%B3%A0-%EB%82%98%EC%84%9C</guid>
            <pubDate>Sun, 15 Jan 2023 13:45:42 GMT</pubDate>
            <description><![CDATA[<p>2년차 이상 뽑는 기업에 이력서를 넣었는데, 운좋게 서류 합격이 되어서 코테를 볼 기회가 생겼다.
저번에 신입 뽑는 기업의 코테를 봤었을때는 비교적 쉬운 문제들로 구성이 되었음을 느꼈는데, (그럼에도 5문제 중 2.5문제 밖에 못풀긴 했지만...) 이번에 본 코테는 구현 문제가 많아서 그런지 1번 문제 빼고는 감이 잘 안왔다.</p>
<p>사실 1번 문제는 그냥 거저 주는 문제라 생각했는데, 결국 테케 절반만 통과된 채로 제출했다.
문제를 먼저 확실하고 빠르게 이해하고 나서 어떻게 작성할 것인지와 엣지 케이스 등을 먼저 고민하고 짜면 좋았을 텐데, 빨리 풀어야 한다는 생각에 처음부터 무작정 코드를 작성해나가서 코드가 매우 더러워졌고... 나중에는 어느 부분의 코드를 어떻게 고쳐야 통과될지 감도 못잡게 되었던 것이 가장 큰 문제였던 것 같다.
공개된 테케 자체가 적어서 그 이외의 반례를 생각하는 것도 꽤 어려웠다. </p>
<h3 id="깨달은-것">깨달은 것</h3>
<ul>
<li>긴 시간을 투자하더라도 일단 구현 전에 이해하고 설계하는 게 더 중요하다.</li>
<li>코드 모듈화를 해놔야 나중에 수정하기도 용이하다.</li>
<li>아직 코테 문제 푼 경험 자체가 많이 적어서 문제 유형 파악도 잘 안되는게 느껴졌다. 문제 글씨 수가 많아서 마치 비문학을 읽는 느낌..</li>
</ul>
<p>나의 부족한 점들을 알 수 있는 좋은 경험이었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘 문제 해결 접근법과 여러 패턴들]]></title>
            <link>https://velog.io/@string_main/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0-%EC%A0%91%EA%B7%BC%EB%B2%95%EA%B3%BC-%EC%97%AC%EB%9F%AC-%ED%8C%A8%ED%84%B4%EB%93%A4</link>
            <guid>https://velog.io/@string_main/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0-%EC%A0%91%EA%B7%BC%EB%B2%95%EA%B3%BC-%EC%97%AC%EB%9F%AC-%ED%8C%A8%ED%84%B4%EB%93%A4</guid>
            <pubDate>Thu, 12 Jan 2023 11:27:27 GMT</pubDate>
            <description><![CDATA[<h2 id="알고리즘의-정의">알고리즘의 정의</h2>
<hr>
<ul>
<li><p><strong>정의</strong> : 특정 작업을 달성하기 위한 과정이나 일련의 단계를 의미, 문제를 해결하기 위한 일련의 수학적 단계 (ex. 유튜브 알고리즘)</p>
</li>
<li><p><strong>필요성</strong> :</p>
<ul>
<li>프로그래밍에서 수행하는 거의 모든 작업에는 일종의 알고리즘이 포함됨</li>
<li>성공적인 문제 해결 및 개발자가 되기 위한 기반</li>
<li>면접에 필요함</li>
</ul>
</li>
</ul>
<blockquote>
<p>어떻게 해야 알고리즘을 더 잘 이해할 수 있을까?
→ 타고난 문제 해결 능력도 있겠지만, 노력하면서 향상될 수 있음.</p>
</blockquote>
<ol>
<li>문제 해결을 위한 계획을 수립한다.</li>
<li>일반적인 문제 해결 패턴을 파악한다. → 카테고리화</li>
</ol>
<h2 id="문제-해결-접근법">문제 해결 접근법</h2>
<hr>
<ol>
<li><strong>문제를 이해</strong>한다. (<strong>Understand the Problem</strong>)<ul>
<li>코드를 바로 작성하기 전에 한 걸음 물러서서 직면한 과제를 확실히 이해하는 것이 중요함.</li>
<li>Check List<ul>
<li>문제를 나만의 방식으로 다시 생각할 수 있습니까?</li>
<li>문제는 어떤 형태의 입출력값을 가집니까?</li>
<li>문제를 해결하기에 충분한 정보를 가지고 있습니까?</li>
<li>데이터의 중요한 부분에 라벨을 지정할 수 있습니까?</li>
</ul>
</li>
</ul>
</li>
<li><strong>구체적인 예시</strong>를 알아본다. (<strong>Explore Concrete Examples</strong>)<ul>
<li>예시를 생각하면 문제를 더 잘 이해하는 데 도움이 되며, 최종 솔루션이 정상적으로 작동하는지 확인하는 기능을 제공한다.</li>
<li>Check List<ul>
<li>간단한 예시부터 시작</li>
<li>더 복잡한 예시로 나아가기</li>
<li>빈 입력이 있는 예시 및 유효하지 않은 입력값이 주어진 예시 탐색 (엣지 케이스)</li>
</ul>
</li>
</ul>
</li>
<li><strong>문제를 세분화</strong>한다. (<strong>Break It Down</strong>)<ul>
<li>필요한 단계들을 명확하게 의사 코드로 작성하기 (가이드라인 작성) → 면접에서 문제를 모두 풀지 못하더라도 문제 접근 방법은 알고 있다는 것을 보여줄 수 있음.</li>
</ul>
</li>
<li><strong>문제를 해결</strong>하고 <strong>단순화</strong>한다. (<strong>Solve / Simplify</strong>)<ul>
<li>문제를 해결할 수 있다면 해결하고, 당장 해결할 수 없다면 해결 가능한 단순한 문제부터 해결하기 → 분할 정복</li>
<li>어려운 부분에 막혔을 때<ul>
<li>문제의 핵심적인 어려움을 찾기</li>
<li>잠시 어려운 부분을 무시하기</li>
<li>단순화 된 솔루션 작성하기</li>
<li>다시 어려운 부분을 통합시키기</li>
</ul>
</li>
</ul>
</li>
<li><strong>문제를 복습</strong>하고 <strong>재구성(리팩토링)</strong>한다. (<strong>Look Back and Refactor</strong>)<ul>
<li>문제를 풀고나면 끝? ㄴㄴ 일어나…리팩토링 해야지…</li>
<li>그냥 작동만 하도록 작성한 코드로 끝나지 않고 코드를 분석, 성찰하며 되돌아보는 것이 중요함.</li>
<li>Check List<ul>
<li>결과를 확인할 수 있습니까?</li>
<li>결과를 다르게 도출할 수 있습니까?</li>
<li>한눈에 이해가 되시나요? → 직관력</li>
<li>결과나 방법을 다른 문제에 사용할 수 있습니까?</li>
<li>솔루션의 성능을 향상시킬 수 있습니까? → 시간 복잡도, 공간 복잡도로 평가</li>
<li>리팩토링할 다른 방법을 생각할 수 있습니까? → 가독성, 성능 등을 위해 리팩토링</li>
<li>다른 사람들은 이 문제를 어떻게 해결했습니까?</li>
</ul>
</li>
</ul>
</li>
</ol>
<blockquote>
<p>Q. 문자열을 입력받아 각 문자의 개수를 반환하는 함수를 작성하시오.</p>
</blockquote>
<ul>
<li>1단계 : 의사코드를 보고 가장 단순한 문법으로 구현한다.</li>
</ul>
<pre><code class="language-jsx">function charCount(str) {
    let result = {};

    for(let i = 0; i &lt; str.length; i++) {
        let char = str[i].toLowerCase();

        if(result[char] &gt; 0) { // value가 0보다 크면 이미 해당 문자가 존재한다
            result[char]++; // 1 증가
        }
        else {
            result[char] = 1; // 1로 설정
        }
    }
    return result;
}</code></pre>
<ul>
<li>2단계 : 1차 리팩토링</li>
</ul>
<pre><code class="language-jsx">function charCount(str) {
    let obj = {};

    for(let char of str) {
        char = char.toLowerCase();
        if(/[a-z0-9]/.test(char)){ // 문자가 영숫자인지 test하는 정규 표현식 (특수문자 제외)
            obj[char] = ++obj[char] || 1; // ||을 기준으로 truthy면 값 증가, falsy면 1로 설정
        }
    }
    return obj;
}</code></pre>
<ul>
<li>3단계 : 2차 리팩토링 (정규 표현식보다 빠른 방법)</li>
</ul>
<pre><code class="language-jsx">function charCount(str) {
    let obj = {};

    for(let char of str) {
        if(isAlphaNumeric(char)) {
            char = char.toLowerCase();
            obj[char] = ++obj[char] || 1;
        }
    }
    return obj;
}

function isAlphaNumeric(char){
    let code = char.charCodeAt(0); // 첫번째 문자를 할당
    if(!(code &gt; 47 &amp;&amp; code &lt; 58) &amp;&amp; // 숫자 (0-9)
        !(code &gt; 64 &amp;&amp; code &lt; 91) &amp;&amp; // 대문자 (A-Z)
        !(code &gt; 96 &amp;&amp; code &lt; 123)) { // 소문자 (a-z)
        return false;
    }
    return false;
}

charCodeAt(0)</code></pre>
<h2 id="문제-해결-패턴">문제 해결 패턴</h2>
<hr>
<ul>
<li>문제 해결 패턴은 프로그래밍 매커니즘이자 청사진이다.</li>
<li>문제 해결 패턴<ul>
<li>Frequency Counter</li>
<li>Multiple Pointers</li>
<li>Sliding Window</li>
<li>Divide and Conquer</li>
<li>Dynamic Programming</li>
<li>Greedy Algorithms</li>
<li>Backtracking</li>
</ul>
</li>
</ul>
<h3 id="빈도-카운터-frequency-counter">빈도 카운터 (Frequency Counter)</h3>
<hr>
<ul>
<li>이 패턴은 객체 또는 집합을 사용하여 값의 빈도를 수집하는 패턴이다.</li>
<li>배열과 문자열을 사용하여 중첩 루프 또는 O(n^2) 작업의 필요성을 피할 수 있다.</li>
</ul>
<blockquote>
<p>Q. 배열 2개를 입력받아 첫번째 배열의 모든 값의 제곱이 두번째 배열에 포함되면 참을 반환하는 same 함수를 작성해라. (순서 상관없음)</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">same([1,2,3], [4,1,9]) // true
same([1,2,3], [1,9]) // false
same([1,2,1], [4,4,1]) // false (must be same frequency)</code></pre>
<ul>
<li>naive solution - 시간 복잡도 : O(n²)</li>
</ul>
<pre><code class="language-jsx">function same(arr1, arr2){
    if(arr1.length !== arr2.length){
        return false;
    }
    for(let i = 0; i &lt; arr1.length; i++){
        let correctIndex = arr2.indexOf(arr1[i] ** 2)
        if(correctIndex === -1) {
            return false;
        }
        console.log(arr2);
        arr2.splice(correctIndex,1)
    }
    return true;
}

same([1,2,3,2], [9,1,4,4]) // true</code></pre>
<ul>
<li>Frequency Counter solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function same(arr1, arr2){
    if(arr1.length !== arr2.length){ 
        return false;
    }
    let frequencyCounter1 = {}
    let frequencyCounter2 = {}
    for(let val of arr1){
        frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1
    }
    for(let val of arr2){
        frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1        
    }
    console.log(frequencyCounter1);
    console.log(frequencyCounter2);
    for(let key in frequencyCounter1){
        if(!(key ** 2 in frequencyCounter2)){
            return false
        }
        if(frequencyCounter2[key ** 2] !== frequencyCounter1[key]){
            return false
        }
    }
    return true
}

same([1,2,3,2,5], [9,1,4,4,11]) // false</code></pre>
<blockquote>
<p>Q. 두 개의 문자열이 주어지면 두 번째 문자열이 첫 번째 문자열의 애너그램인지 확인하는 함수를 작성해라. 애너그램은 단어의 문자를 재배열해 다른 뜻을 가진 단어로 바꾸는 것을 말한다. (ex. <em>iceman</em> → c<em>inema</em>)</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">validAnagram(&#39;&#39;, &#39;&#39;) // true
validAnagram(&#39;aaz&#39;, &#39;zza&#39;) // false
validAnagram(&#39;anagram&#39;, &#39;nagaram&#39;) // true
validAnagram(&quot;rat&quot;,&quot;car&quot;) // false) // false
validAnagram(&#39;awesome&#39;, &#39;awesom&#39;) // false
validAnagram(&#39;amanaplanacanalpanama&#39;, &#39;acanalmanplanpamana&#39;) // false
validAnagram(&#39;qwerty&#39;, &#39;qeywrt&#39;) // true
validAnagram(&#39;texttwisttime&#39;, &#39;timetwisttext&#39;) // true</code></pre>
<ul>
<li>Frequency Counter solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function validAnagram(first, second) {
    if(first.length !== second.length) {
        return false;
    }

    const lookup = {};

    for(let i = 0; i &lt; first.length; i++) {
        let letter = first[i];
        lookup[letter] ? lookup[letter] += 1 : lookup[letter] = 1;
    }

    for(let i = 0; i &lt; second.length; i++) {
        let letter = second[i];
        if(!lookup[letter]) {
            return false;
        } else {
            lookup[letter] -= 1;
        }
    }

    return true;
}</code></pre>
<ul>
<li>내가 쓴 답</li>
</ul>
<pre><code class="language-jsx">function validAnagram(str1, str2){
  // add whatever parameters you deem necessary - good luck!

  let obj1 = {};
  let obj2 = {};

  if(str1.length !== str2.length) {
      return false;
  }

  for(let val of str1) {
      obj1[val] = (obj1[val] || 0) + 1;
  }

  for(let val of str2) {
      obj2[val] = (obj2[val] || 0) + 1;
  }

  for(let key in obj1) {
      if(obj1[key] !== obj2[key]) {
          return false;
      }
  }

  return true;
}</code></pre>
<h3 id="다중-포인터-multiple-pointers">다중 포인터 (Multiple Pointers)</h3>
<hr>
<ul>
<li>인덱스나 위치에 해당하는 포인터나 값을 만든 다음 특정 조건에 따라 시작, 끝 또는 중간으로 이동하는 포인터 또는 값을 생성하는 패턴. 두 개 또는 그 이상의 포인터를 두고 값들을 비교한다.</li>
<li>최소한의 공간 복잡성으로 문제를 해결하는 데 매우 효율적.</li>
</ul>
<blockquote>
<p>Q. 정렬된 배열을 받는 sumZero 함수를 작성해라. 함수는 합계가 0인 첫 번째 쌍을 찾아야 하며, 합계가 0이거나 쌍이 존재하지 않는 경우 정의되지 않은 두 값을 모두 포함하는 배열을 반환한다. (양 끝에서 시작하여 중간으로 이동하는 경우)</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">sumZero([-3,-2,-1,0,1,2,3]) // [-3, 3] 
sumZero([-2,0,1,3]) // undefined
sumZero([1,2,3]) // undefined</code></pre>
<ul>
<li>naive solution - 시간 복잡도 : O(n²)</li>
</ul>
<pre><code class="language-jsx">function sumZero(arr){
    for(let i = 0; i &lt; arr.length; i++){
        for(let j = i+1; j &lt; arr.length; j++){
            if(arr[i] + arr[j] === 0){
                return [arr[i], arr[j]];
            }
        }
    }
}

sumZero([-4,-3,-2,-1,0,1,2,5])</code></pre>
<ul>
<li>Multiple Pointers solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function sumZero(arr){
    let left = 0;
    let right = arr.length - 1;
    while(left &lt; right){
        let sum = arr[left] + arr[right];
        if(sum === 0){
            return [arr[left], arr[right]];
        } else if(sum &gt; 0){
            right--;
        } else {
            left++;
        }
    }
}

sumZero([-4,-3,-2,-1,0,1,2,5]) // [-2, 2]</code></pre>
<blockquote>
<p>Q. 정렬된 배열을 받아 배열의 고유한 값을 계산하는 countUniqueValues라는 함수를 구현해라. 배열에 음수가 있을 수 있지만 항상 정렬된다.</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">countUniqueValues([1,1,1,1,1,2]) // 2개
countUniqueValues([1,2,3,4,4,4,7,7,12,12,13]) // 7개
countUniqueValues([]) // 0개
countUniqueValues([-2,-1,-1,0,1]) // 4개</code></pre>
<ul>
<li>Multiple Pointers solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function countUniqueValues(arr){
    if(arr.length === 0) return 0;
    var i = 0;
    for(var j = 1; j &lt; arr.length; j++){
        if(arr[i] !== arr[j]){
            i++;
            arr[i] = arr[j]
        }
    }
    return i + 1;
}
countUniqueValues([1,2,2,5,7,7,99])</code></pre>
<ul>
<li>내가 쓴 답</li>
</ul>
<pre><code class="language-jsx">function countUniqueValues(arr){
  let i = 0;
  let j = 1;

  if(arr.length === 0) return 0;

  while(arr.length &gt; j) {
      if(arr[i] === arr[j]) {
          j++;
      } else {
          i++;
          arr[i] = arr[j];
      }
  }

  return i + 1;
}</code></pre>
<h3 id="슬라이딩-윈도우-sliding-window">슬라이딩 윈도우 (Sliding Window)</h3>
<hr>
<ul>
<li>고정 사이즈의 윈도우가 이동하면서 윈도우 내에 있는 데이터를 이용해 문제를 풀이하는 알고리즘.</li>
<li>배열이나 문자열 등의 일련의 데이터를 입력하거나 특정 방식으로 해당 데이터의 하위 집합을 찾는 경우에 유용.</li>
</ul>
<blockquote>
<p>Q. 정수 배열과 n이라는 숫자를 받아들이는 maxSubarraySum이라는 함수를 작성해라. 함수는 배열에서 n개의 연속된 요소의 최대 합을 계산해야 한다.</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">maxSubarraySum([1,2,5,2,8,1,5],2) // 2 + 8 = 10
maxSubarraySum([1,2,5,2,8,1,5],4) // 2 + 5 + 2 + 8 = 17
maxSubarraySum([4,2,1,6],1) // 6
maxSubarraySum([4,2,1,6,2],4) // 4 + 2 + 1 + 6 = 13
maxSubarraySum([],4) // null</code></pre>
<ul>
<li>naive solution - 시간 복잡도 : O(n²)</li>
</ul>
<pre><code class="language-jsx">function maxSubarraySum(arr, num) {
    if (num &gt; arr.length){ // 주어진 수가 배열의 길이보다 크면 null 반환
    return null;
  }
    var max = -Infinity; // 배열이 모두 음수일 경우 가장 큰 합은 여전히 음수이므로 음수로 최댓값 지정

    for (let i = 0; i &lt; arr.length - num + 1; i ++){
    temp = 0; // 각 루프의 합계가 저장되는 변수
    for (let j = 0; j &lt; num; j++){ // i를 기준으로 num개씩 더함
      temp += arr[i + j];
    }
    if (temp &gt; max) {
      max = temp;
    }
  }
  return max;
}

maxSubarraySum([2,6,9,2,1,8,5,6,3],3)</code></pre>
<ul>
<li>Sliding Window solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function maxSubarraySum(arr, num){
  let maxSum = 0;
  let tempSum = 0;

  if (arr.length &lt; num) return null; // 주어진 수가 배열의 길이보다 크면 null 반환

  for (let i = 0; i &lt; num; i++) { // num 개수 만큼 합산
    maxSum += arr[i];
  }
  tempSum = maxSum;

  for (let i = num; i &lt; arr.length; i++) {
    tempSum = tempSum - arr[i - num] + arr[i]; // 윈도우의 첫번째 요소 제거 후 다음 요소를 추가해서 합산
    maxSum = Math.max(maxSum, tempSum); // 최댓값 비교 후 재할당
  }
  return maxSum;
}

maxSubarraySum([2,6,9,2,1,8,5,6,3],3)</code></pre>
<h3 id="분할-정복-divide-and-conquer">분할 정복 (Divide and Conquer)</h3>
<hr>
<ul>
<li>분할 정복 알고리즘은 주로 배열이나 문자열 같은 큰 규모의 데이터 세트를 더 작은 조각으로 나눈 다음 데이터 하위 집합으로 프로세스를 반복하는 것을 포함한다.</li>
<li>이 패턴은 시간 복잡성을 크게 줄일 수 있다.</li>
</ul>
<blockquote>
<p>Q. 정렬된 정수 배열이 주어지면 값을 받아 함수에 전달된 값이 있는 인덱스를 반환하는 search라는 함수를 작성해라. 값을 찾을 수 없으면 -1을 반환한다.</p>
</blockquote>
<ul>
<li>example</li>
</ul>
<pre><code class="language-jsx">search([1,2,3,4,5,6],4) // 3
search([1,2,3,4,5,6],6) // 5
search([1,2,3,4,5,6],11) // -1</code></pre>
<ul>
<li>naive solution - 시간 복잡도 : O(n)</li>
</ul>
<pre><code class="language-jsx">function search(arr, val){
    for(let i = 0; i &lt; arr.length; i++){
        if(arr[i] === val){
            return i;
        }
    }
    return -1;
}</code></pre>
<ul>
<li>Divide and Conquer solution (이진 탐색) - 시간 복잡도 : O(log n)</li>
</ul>
<pre><code class="language-jsx">function search(array, val) {

    let min = 0;
    let max = array.length - 1;

    while (min &lt;= max) {
        let middle = Math.floor((min + max) / 2); // 반복적으로 절반을 나누어 중간 지점을 찾는다
        let currentElement = array[middle];

        if (array[middle] &lt; val) {
            min = middle + 1;
        }
        else if (array[middle] &gt; val) {
            max = middle - 1;
        }
        else {
            return middle;
        }
    }

    return -1;
}</code></pre>
<blockquote>
<p>Udemy의 JavaScript 알고리즘 &amp; 자료구조 마스터클래스를 학습하고 정리한 내용입니다.
잘못된 부분이 있다면 댓글로 피드백 부탁드립니다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[내가 프론트엔드 개발자를 선택한 이유]]></title>
            <link>https://velog.io/@string_main/%EB%82%B4%EA%B0%80-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%95%9C-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@string_main/%EB%82%B4%EA%B0%80-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%95%9C-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Tue, 27 Dec 2022 10:43:43 GMT</pubDate>
            <description><![CDATA[<h3 id="어렸을-때의-나는">어렸을 때의 나는...</h3>
<p>어렸을 때는 꿈이 참 많았다.
부모님이 아플 때는 간호사, 노래 부를 때는 가수, 피아노 학원을 다닐 때는 피아니스트, 그림을 그릴 때는 화가, 신문부일 때는 기자, 레고를 조립할 때는 건축가가 되고 싶었다. (꿈도 참 많았다...)</p>
<p>그런데 어느 순간 부터는 내가 진정으로 하고싶은 것이 뭔지 모르게 되었다.
당장에 이룰 목표가 없으니 공부를 해야할 이유도 없었고 흥미도 없었다.
그 와중에 그나마 꾸준히 했던 한 가지 취미가 있다면 그건 게임이었다.</p>
<h3 id="컴퓨터-공학부를-선택한-이유">컴퓨터 공학부를 선택한 이유</h3>
<p>다양한 게임을 해보면서 게임 취향이 생겨났다.
나는 로스트아크나 오버워치, 메이플스토리 같은 세계관이 방대한 게임을 좋아하는데,
내가 진짜로 그 세계에 들어간 것처럼 몰입하게 되었다.
내 캐릭터가 성장하면 덩달아 내가 성장한 것 같고..ㅋㅋㅋㅋ</p>
<p>그리고 나는 극한의 P인간이었다.
대학교 원서를 넣기 직전에 과를 정할 정도로..
다른 친구들은 다들 원하는 과가 있는데 나는 뭐가 좋을까 생각하다가.
그 당시에 유튜브에서 오버워치 시네마틱 영상을 보고 너무 감명을 받아서
게임을 만들어야겠다! 하고 컴퓨터 공학, 게임 학부 쪽으로 원서를 썼다.
지금 생각하면 진짜 무모한 선택이었는데, 운좋게도 나름 적성에 맞아서 졸업은 무사히 했다.</p>
<h3 id="학부에서-느낀-것">학부에서 느낀 것</h3>
<p>학부 때 필수 과목은 아니었지만, 웹프로그래밍 강의를 듣고 싶어져서 신청했었다.
중고 서적 웹 사이트를 제작하는 팀플을 했었는데, 나는 백엔 포지션이었지만, 프론트 맡은 동기가 이쁘게 만들어줘서 친구들에게 자랑할 맛이 났었다. 남들이 웹을 사용할 때 나는 직접 만드는 창작자가 된다는 점이 멋졌다.</p>
<p>그리고 기업들을 찾아보다가 한 웹 에이전시의 사이트를 보게 되었는데,
뭔가 말로 다 할 수 없는 감동... 너무너무 인터랙티브하고 멋져서 나도 만들어보고 싶다는 생각이 들었다.</p>
<h3 id="개발자가-되고-싶은-이유">개발자가 되고 싶은 이유</h3>
<p>그렇게 어느 순간 프론트엔드 개발자가 되고 싶어졌다.
사실 거창한 이유는 아니었지만, 그냥 지금 당장 해보고 싶으니까!</p>
<p>나는 성장하는 게 좋은가보다. 아직 이유는 모르겠지만, 나는 안정적인 것 보다 도전적인게 좋다.
내가 할 수 있는 한 경험을 많이 쌓아서 지금의 나보다 나은 사람이 되고싶다.
그런 맥락에서 개발자는 참으로 매력적인 직업이다.
끊임없이 새로운 것을 배우고 익혀야해서 나를 고여있지 않게 하는 점이 좋다.
쉽지 않은 길이 되겠지만, 개발자의 삶을 살아보고 싶다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2022년을 보내며]]></title>
            <link>https://velog.io/@string_main/%EC%8A%A4%ED%84%B0%EB%94%94%EB%A5%BC-%EC%9A%B4%EC%98%81%ED%95%98%EB%A9%B0-%EB%8A%90%EA%BC%88%EB%8D%98-%EC%A0%90</link>
            <guid>https://velog.io/@string_main/%EC%8A%A4%ED%84%B0%EB%94%94%EB%A5%BC-%EC%9A%B4%EC%98%81%ED%95%98%EB%A9%B0-%EB%8A%90%EA%BC%88%EB%8D%98-%EC%A0%90</guid>
            <pubDate>Tue, 27 Dec 2022 10:43:11 GMT</pubDate>
            <description><![CDATA[<h3 id="새로운-시작과-도전의-해-2022">새로운 시작과 도전의 해, 2022</h3>
<hr>
<p>1년이 또 금방 지나갔다. 연말이 되어 22년을 돌아보니 뭐 한거 별로 없지 않았나? 라고 생각했는데, 생각보다 많이 돌아다니고, 새로운 것도 많이 시도하고 많은 output을 낸 한 해였다. 생전 하지 않던 운동을 꾸준히 해보기도 하고, 알바도 하고, 2주 동안 웹 만드는 챌린지도 도전해보고, 처음으로 공모전에 참가해서 상도 타보고, 정처기 실기를 준비하면서 부트캠프도 병행하고, 여행도 여기저기 다니고...(이하 생략)
다 적기엔 너무 많지만, 여하튼 생각보다 바삐 살았더라..ㅋㅋㅋ
그래서 나에게 2022년을 새로운 시작과 도전의 해라고 이름 붙이고 싶었다.</p>
<h3 id="마지막-등교">마지막 등교</h3>
<hr>
<p>4년 동안 다니던 대학을 졸업했을 때는 시원하기도 했지만, 아쉬운 마음이 더 컸다. (코로나 때문에 2년 동안은 사이버 대학이었기 때문..) 그래도 다행히 졸업식은 갈 수 있었는데, 가족, 친구들과 사진도 찍고 즐겁게 축하받은 하루 끝에 집 가려고 친구 차 얻어타고 가는데 갑자기 눈물이 왈칵했다. 고등학교 졸업 때도 울진 않았는데ㅋㅋㅋㅋ 많이 아쉬웠나보다. 그리고 집에 와서 내가 눈물이 났던 이유를 노트에 적어나갔다. 이것이 나의 제대로 된 회고의 첫 시작이 아닐까 싶다. 이유의 가장 큰 범주는 후회였다. 통학이 아니라 학교 근처에 살았더라면, 연구실도 들어가보고, 동아리 활동같은 좀 더 많은 경험의 기회가 있었지 않았을까? 하고. 자립을 대학생 때 경험해보지 못해서 인격적 성장이 더뎌진 것에 대한 아쉬움도 들었다. 하지만 이미 지나간 시간을 후회해봤자 돌아오지 않는다는 사실. 그게 나를 더 우울하게 만들었지만... 어쩌겠나. 이를 반면교사 삼아 앞으로 후회하는 일을 줄이려면, 좀 더 내가 원하는 것, 좋아하는 것, 하고 싶은 것이 무엇인지 내면의 소리에 귀기울일 필요성을 뼈저리게 느꼈다.</p>
<h3 id="내가-좋아하는-것들">내가 좋아하는 것들</h3>
<hr>
<p>나는 아무래도 새로운 것을 좋아한다. 새로운 장소, 새로운 사람들, 아직 겪어보지 않은 모든 경험..
후회를 겪고 나서는 새로운 경험을 시도하는 횟수가 많아졌다. 그러다보니 자연스럽게 함께하는 동료들이 많이 생겼다. 동료들이 많이 생기니 새로운 경험을 더 많이 할 수 있게 되었다. 일단 시도하고 나니, 내가 좋아하는 것들이 줄줄이 소세지처럼 따라왔다. 웹 메이킹 챌린지, 부트캠프에서는 페어프로그래밍과 팀 프로젝트, 스터디도 하면서 멋진 사람들을 너무 많이 만났다. 동료들과 멘토님들께 많은 도움을 받아서 감사하고, 나중에는 내가 도움을 드릴 수 있는 개발자로 성장하고 싶어졌다. 그러기 위해서는 과거나 미래가 아닌 현재에 집중해야 한다는 것을 한 해 동안 많이 깨달았다. 내가 하고 싶은 일을 도전하면, 그 곳에는 도전을 함께 하는 좋은 사람들이 있고, 그 사람들과 밥도 먹고 술 한잔 하는 것. 그것이 행복 아닐까 ^.^</p>
<p>취업도 하고 좀 더 성장하는 내년이 되길 기약하며...!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 프로미스]]></title>
            <link>https://velog.io/@string_main/JS-%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4</link>
            <guid>https://velog.io/@string_main/JS-%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4</guid>
            <pubDate>Tue, 20 Dec 2022 15:00:35 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-콜백-패턴의-단점">🌱 콜백 패턴의 단점</h2>
<hr>
<blockquote>
<p>자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용하는데, 전통적인 콜백 패턴은 아래와 같은 몇가지 단점이 존재한다.</p>
</blockquote>
<ol>
<li><p><strong>콜백 헬</strong>로 인해 가독성이 나쁘다.</p>
<pre><code class="language-jsx"> get(&#39;/step1&#39;, a =&gt; {
   get(`/step2/${a}`, b =&gt; {
     get(`/step3/${b}`, c =&gt; {
       get(`/step4/${c}`, d =&gt; {
         console.log(d);
       });
     });
   });
 });</code></pre>
<p> 비동기 함수를 호출하면 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다 해도 기다리지 않고 즉시 종료된다. 즉, 비동기 함수 내부의 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다.</p>
<pre><code class="language-jsx"> let g = 0;

 // 비동기 함수인 setTimeout 함수는 콜백 함수의 처리 결과를 외부로 반환하거나
 // 상위 스코프의 변수에 할당하지 못한다.
 setTimeout(() =&gt; { g = 100; }, 0);
 console.log(g); // 0</code></pre>
<blockquote>
<p>✔️ 비동기 함수는 처리 결과를 외부에 반환할 수 없고, 상위 스코프의 변수에 할당할 수도 없기 때문에 비동기 함수의 처리 결과(서버 응답 등)에 대한 후속 처리는 비동기 함수 내부에서 수행해야 한다.</p>
</blockquote>
</li>
<li><p>비동기 처리 중 발생한 <strong>에러의 처리가 곤란</strong>하다.</p>
<pre><code class="language-jsx"> try {
   setTimeout(() =&gt; { throw new Error(&#39;Error!&#39;); }, 1000);
 } catch (e) {
   // 에러를 캐치하지 못한다
   console.error(&#39;캐치한 에러&#39;, e);
 }</code></pre>
<blockquote>
<p>✔️ setTimeout 함수의 콜백 함수가 실행될 때 setTimeout 함수는 이미 콜 스택에서 제거된 상태이고, 이는 setTimeout 함수의 콜백 함수를 호출한 것이 setTimeout 함수가 아니라는 의미이다. <strong>에러는 호출자(caller) 방향으로 전파</strong>되기 때문에 setTimeout 함수의 콜백 함수가 발생시킨 에러는 catch 블록에서 캐치되지 않는다.</p>
</blockquote>
</li>
<li><p><strong>여러 개의 비동기 처리</strong>를 한번에 처리하는 데 <strong>한계</strong>가 있다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 비동기 프로그래밍]]></title>
            <link>https://velog.io/@string_main/JS-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@string_main/JS-%EB%B9%84%EB%8F%99%EA%B8%B0-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Mon, 19 Dec 2022 14:55:14 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-동기-처리와-비동기-처리">🌱 동기 처리와 비동기 처리</h2>
<hr>
<p>자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 가지고, 한 번에 하나의 태스크만 실행할 수 있는 싱글 스레드 방식으로 동작한다. 그렇기 때문에 처리에 시간이 걸리는 태스크를 실행하는 경우 <strong>블로킹(blocking)</strong>이 발생한다.</p>
<ul>
<li><p><code>동기 처리</code> : 현재 실행 중인 태스크가 종료할 때 까지 다음에 실행될 태스크가 대기하는 방식. 실행 순서가 보장된다는 장점이 있지만, 앞선 태스크가 종료될 때 까지 이후 태스크들이 블로킹되는 단점이 있다.</p>
<pre><code class="language-jsx">  // 일정 시간 경과 후 콜백 함수를 호출하는 함수
  function sleep(func, delay) {
      const delayUntil = Date.now() + delay;

      while(Date.now() &lt; delayUntil);
      // 일정 시간 경과 후 콜백 함수 func 호출
      func();
  }

  function foo() {
      console.log(&#39;foo&#39;);
  }

  function bar() {
      console.log(&#39;bar&#39;);
  }

  // sleep 함수는 3초 이상 실행
  sleep(foo, 3 * 1000);
  // bar 함수는 3초 이상 블로킹
  bar();</code></pre>
</li>
</ul>
<ul>
<li><p><code>비동기 처리</code> : 현재 실행 중인 태스크가 종료되지 않은 상태여도 다음 태스크를 곧바로 실행하는 방식. 블로킹이 발생하지 않는 장점이 있지만, 태스크의 실행 순서가 보장되지 않는 단점이 있다.</p>
<pre><code class="language-jsx">  function foo() {
      console.log(&#39;foo&#39;);
  }

  function bar() {
      console.log(&#39;bar&#39;);
  }

  // 타이머 함수 setTimeout은 일정 시간 경과 후 foo 함수를 호출하며 bar 함수를 블로킹하지 않는다.
  setTimeout(foo, 3 * 1000);
  bar();</code></pre>
<blockquote>
<p>✔️ 타이머 함수인 setTimeout과 setInterval, HTTP 요청, 이벤트 핸들러는 비동기 처리 방식으로 동작한다.</p>
</blockquote>
</li>
</ul>
<h2 id="🌱-이벤트-루프와-태스크-큐">🌱 이벤트 루프와 태스크 큐</h2>
<hr>
<ul>
<li><code>이벤트 루프</code> : 자바스크립트의 동시성(concurrency)을 지원하는 것으로, 브라우저에 내장된 기능이다. (ex. HTTP 요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링 하는 작업)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/string_main/post/f3ffdb32-c852-4c19-b44a-cb7a9184609b/image.png" alt=""></p>
<blockquote>
<p>대부분의 자바스크립트 엔진은 크게 2가지 영역으로 구분할 수 있다.</p>
</blockquote>
<ul>
<li><code>콜 스택(call stack)</code> : 소스코드 평가 과정에서 생성된 실행 컨텍스트가 추가되고 제거되는 스택 자료구조인 실행 컨텍스트 스택이다.</li>
<li><code>힙(heap)</code> : 객체가 저장되는 메모리 공간이다. 콜 스택의 요소인 실행 컨텍스트는 힙에 저장된 객체를 참조한다. 객체는 원시 값과 달리 크기가 정해져 있지 않으므로 할당할 메모리 공간의 크기를 런타임에 결정(동적 할당)해야 한다. 따라서 힙은 구조화 되어 있지 않다는 특징이 있다.</li>
</ul>
<blockquote>
<p>✔️ 비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 Node.js가 담당한다.</p>
</blockquote>
<p>예를 들어, setTimeout의 콜백 함수의 평가와 실행은 자바스크립트 엔진이 담당하지만 호출 스케줄링을 위한 타이머 설정과 콜백 함수의 등록은 브라우저 또는 Node.js가 담당한다. 이를 위해서 브라우저 환경은 태스크 큐와 이벤트 루프를 제공한다.</p>
<blockquote>
</blockquote>
<ul>
<li><code>태스크 큐(task queue/event queue/callback queue)</code> : 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역. 프로미스의 후속 처리 메서드의 콜백 함수가 일시적으로 보관되는 마이크로 태스크 큐도 존재한다.</li>
<li><code>이벤트 루프(event loop)</code> : 이벤트 루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 태스크 큐에 대기중인 함수가 있는지 반복해서 확인한다. 만약 콜스택이 비어 있고 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시킨다. 즉, 태스크 큐에 일시 보관된 함수들은 비동기 처리 방식으로 동작한다.</li>
</ul>
<pre><code class="language-jsx">function foo() {
    console.log(&#39;foo&#39;);
}

function bar() {
    console.log(&#39;bar&#39;);
}

setTimeout(foo, 0); // 0초(실제는 4ms) 후에 foo 함수가 호출됨
bar();</code></pre>
<blockquote>
<p>✔️ 자바스크립트는 싱글 스레드 방식으로 동작한다. 싱글 스레드 방식으로 동작하는 것은 브라우저가 아니라 브라우저에 내장된 자바스크립트 엔진이다. 모든 자바스크립트 코드가 자바스크립트 엔진에서 싱글 스레드 방식으로 동작한다면 자바스크립트는 비동기로 동작할 수 없다. 즉, 자바스크립트 엔진은 싱글 스레드로 동작하지만, 브라우저는 멀티 스레드로 동작한다.</p>
</blockquote>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>자바스크립트의 비동기 처리 작동 원리에 대해 정리할 수 있었던 시간이었다. 자바스크립트 엔진은 싱글 스레드로 동작하지만 브라우저는 멀티 스레드로 동작한다는 것을 유념하자.</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 이벤트]]></title>
            <link>https://velog.io/@string_main/JS-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@string_main/JS-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Fri, 16 Dec 2022 15:30:28 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-이벤트-드리븐-프로그래밍">🌱 이벤트 드리븐 프로그래밍</h2>
<hr>
<ul>
<li><code>이벤트 핸들러</code> : 이벤트가 발생했을 때 호출될 함수</li>
<li><code>이벤트 핸들러 등록</code> : 이벤트 발생 시 브라우저에게 이벤트 핸들러의 호출을 위임하는 것</li>
</ul>
<blockquote>
<p>사용자가 언제 이벤트를 발생시킬 지 알 수 없는데 그렇다면 언제 함수를 호출해야 할까?</p>
</blockquote>
<p>✔️ 브라우저는 사용자의 이벤트를 감지하고 특정 함수(이벤트 핸들러)를 호출하도록 위임(이벤트 핸들러 등록)할 수 있다. 개발자가 명시적으로 함수를 호출하는 것이 아니라 브라우저에게 함수 호출을 위임하는 것이다.</p>
<blockquote>
</blockquote>
<pre><code class="language-jsx">const $button = document.querySelector(&#39;button&#39;);
$button.onclick = () =&gt; { alert(&#39;button click&#39;); };</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] DOM]]></title>
            <link>https://velog.io/@string_main/JS-DOM</link>
            <guid>https://velog.io/@string_main/JS-DOM</guid>
            <pubDate>Thu, 15 Dec 2022 14:56:25 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-dom">🌱 DOM</h2>
<hr>
<ul>
<li><strong>정의</strong> : Document Object Model의 약자로, HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 노드 객체들로 구성된 트리 자료구조.</li>
</ul>
<blockquote>
<p>✔️ DOM은 HTML 문서의 계층적 구조와 정보를 표현하고, 노드 객체의 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공한다. 이 DOM API를 통해 HTML의 구조나 내용, 스타일 등을 동적으로 조작할 수 있다.</p>
</blockquote>
<h2 id="🌱-노드">🌱 노드</h2>
<hr>
<ul>
<li><p><code>HTML 요소</code> : HTML 문서를 구성하는 개별적인 요소.</p>
<pre><code class="language-html">  &lt;!-- &lt;시작태그 어트리뷰트 이름=&quot;어트리뷰트 값&quot;&gt; 콘텐츠 &lt;/종료 태그&gt; --&gt;
  &lt;div class=&quot;greeting&quot;&gt; Hello &lt;/div&gt;</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/string_main/post/70c52e7d-837e-4ffe-9970-94459e3f397d/image.png" alt=""></p>
<blockquote>
<p>✔️ HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다. HTML 요소의 어트리뷰트는 <strong>어트리뷰트 노드</strong>로, 텍스트 콘텐츠는 <strong>텍스트 노드</strong>로 변환된다.
HTML 요소 간에는 중첩 관계에 의해 계층적인 부자 관계가 형성되는데, 이를 객체화한 모든 노드 객체들을 <strong>트리 자료구조</strong>로 구성한다.</p>
</blockquote>
<h3 id="🍀-노드-객체의-타입">🍀 노드 객체의 타입</h3>
<p><img src="https://velog.velcdn.com/images/string_main/post/0fa7b0c5-4b50-4073-be59-b6f03acd07f8/image.png" alt=""></p>
<blockquote>
<p>노드 객체는 총 12개의 타입이 있는데, 이 중 중요한 타입은 4가지가 있다.</p>
</blockquote>
<ul>
<li><code>문서 노드</code> : DOM 트리의 최상위에 존재하는 루트 노드로 document 객체를 가리킨다. document 객체는 전역 객체 window의 document 프로퍼티에 바인딩되어 있고, 다른 노드들에 접근하기 위한 진입점 역할을 담당한다.</li>
<li><code>요소 노드</code> : HTML 요소를 가리키는 객체이다. HTML 요소 간 중첩에 의해 부자 관계를 가지고, 이를 통해 문서의 구조를 표현한다.</li>
<li><code>어트리뷰트 노드</code> : HTML 요소의 어트리뷰트를 가리키는 객체이다. 요소 노드와 연결되어 있지만, 부모 노드가 없으므로 요소 노드의 형제 노드는 아니다.</li>
<li><code>텍스트 노드</code> : HTML 요소의 텍스트를 가리키는 객체이다. 요소 노드가 문서의 구조를 표현한다면 텍스트 노드는 문서의 정보를 표현한다고 할 수 있다. 텍스트 노드는 DOM 트리의 최종단인 리프 노드이다.</li>
</ul>
<h3 id="🍀-노드-객체의-상속-구조">🍀 노드 객체의 상속 구조</h3>
<p><img src="https://velog.velcdn.com/images/string_main/post/53b1b601-79f1-4eed-a6c4-c8e581cb82e3/image.png" alt=""></p>
<blockquote>
<p>✔️ DOM을 구성하는 노드 객체는 표준 빌트인 객체가 아닌 브라우저 환경에서 추가적으로 제공하는 호스트 객체이다. 하지만 노드 객체도 자바스크립트 객체이므로 프로토타입에 의한 상속 구조를 갖는다.</p>
</blockquote>
<p>모든 노드 객체는 Object, EventTarget, Node 인터페이스를 상속받고, 문서 노드는 Document, HTMLDocument 인터페이스를 상속받고 어트리뷰트 노드는 Attr, 텍스트 노드는 CharacterData, 요소 노드는 Element, HTMLElement와 종류별로 세분화된 인터페이스들을 상속받는다.</p>
<blockquote>
</blockquote>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
  &lt;input type=&quot;text&quot;&gt;
  &lt;script&gt;
    // input 요소 노드 객체를 선택
    const $input = document.querySelector(&#39;input&#39;);

    // input 요소 노드 객체의 프로토타입 체인
    console.log(
      Object.getPrototypeOf($input) === HTMLInputElement.prototype,
      Object.getPrototypeOf(HTMLInputElement.prototype) === HTMLElement.prototype,
      Object.getPrototypeOf(HTMLElement.prototype) === Element.prototype,
      Object.getPrototypeOf(Element.prototype) === Node.prototype,
      Object.getPrototypeOf(Node.prototype) === EventTarget.prototype,
      Object.getPrototypeOf(EventTarget.prototype) === Object.prototype
    ); // 모두 true
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<blockquote>
<p>✔️ 노드 객체의 상속 구조는 개발자 도구의 Elements 패널 우측의 Properties 패널에서 확인할 수 있다.</p>
</blockquote>
<h2 id="🌱-요소-노드-취득-방법">🌱 요소 노드 취득 방법</h2>
<hr>
<ul>
<li>getElementById : 아이디</li>
<li>getElementByTagName : 태그 명</li>
<li>getElementByClassName : 클래스 명</li>
<li>querySelector / querySelectorAll : CSS 선택자</li>
</ul>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 브라우저의 렌더링 과정]]></title>
            <link>https://velog.io/@string_main/JS-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@string_main/JS-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Wed, 14 Dec 2022 14:45:01 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-파싱과-렌더링">🌱 파싱과 렌더링</h2>
<hr>
<ul>
<li><code>파싱(parsing)</code> : 프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 문자열을 토큰으로 분해(어휘 분석)하고, 토큰에 문법적 의미와 구조를 반영해 파스 트리를 생성하는 과정이다. 파싱이 완료된 이후에는 중간 언어인 바이트코드를 생성하고 실행한다.</li>
<li><code>렌더링(rendering)</code> : HTML, CSS, JavaScript로 작성된 문서를 파싱해 브라우저에 시각적으로 출력하는 것.</li>
</ul>
<h2 id="🌱-브라우저의-렌더링-과정">🌱 브라우저의 렌더링 과정</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/string_main/post/e930aeac-0093-48bd-a828-9bd490b84b19/image.png" alt=""></p>
<ol>
<li><strong>브라우저</strong>는 HTML, CSS, JavaScript, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.</li>
<li>브라우저의 <strong>렌더링 엔진</strong>은 서버로부터 응답된 HTML과 CSS를 파싱해 DOM과 CSSOM을 생성하고 이들을 결합해 렌더 트리를 생성한다.</li>
<li>브라우저의 <strong>자바스크립트 엔진</strong>은 서버로부터 응답된 JavaScript를 파싱해 AST(Abstract Syntax Tree)를 생성하고 바이트코드로 변환해 실행한다. 이때 JavaScript는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있고, 변경된 이후 다시 렌더 트리로 결합된다.</li>
<li>렌더 트리를 기반으로 HTML 요소의 레이아웃을 계산하고 브라우저 화면에 HTML 요소를 <strong>페인팅</strong> 한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 클로저]]></title>
            <link>https://velog.io/@string_main/JS-%ED%81%B4%EB%A1%9C%EC%A0%80</link>
            <guid>https://velog.io/@string_main/JS-%ED%81%B4%EB%A1%9C%EC%A0%80</guid>
            <pubDate>Fri, 09 Dec 2022 15:00:35 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-클로저">🌱 클로저</h2>
<hr>
<blockquote>
<p>클로저는 자바스크립트 고유의 개념이 아니므로 클로저의 정의가 ECMAScript 사양에 등장하지 않는다.</p>
</blockquote>
<ul>
<li><p><strong>MDN 정의</strong> :</p>
<blockquote>
<p>A <strong>closure</strong> is the combination of a function bundled together (enclosed) with references to its surrounding state (the <strong>lexical environment</strong>). In other words, a closure gives you access to an outer function&#39;s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.</p>
</blockquote>
<p>  클로저는 주변 상태(어휘적 환경)에 대한 참조와 함께 번들로 묶인(묶음) 기능의 조합이다. 즉, 클로저를 사용하면 내부 함수에서 외부 함수의 범위에 액세스할 수 있다. JavaScript에서는 함수가 생성될 때마다 함수가 생성될 때마다 클로저가 생성된다.</p>
<blockquote>
</blockquote>
</li>
</ul>
<pre><code class="language-jsx">const x = 1;

function outerFunc() {
    const x = 10;

    function innerFunc() {
        console.log(x); // 10
    }

    innerFunc();
}

outerFunc();</code></pre>
<pre><code class="language-jsx">const x = 1;

function outerFunc() {
    const x = 10;
    innerFunc();
}

function innerFunc() {
    console.log(x); // 1
}

outerFunc();</code></pre>
<blockquote>
<p>✔️ innerFunc 함수가 outerFunc 내부에 정의된 중첩 함수가 아니라면 innerFunc 함수를 outerFunc 함수의 내부에서 호출해도 outerFunc 함수의 변수에 접근할 수 없다. 이런 현상이 발생하는 이유는 자바스크립트가 <strong>렉시컬 스코프</strong>를 따르는 언어이기 때문이다.</p>
</blockquote>
<h2 id="🌱-렉시컬정적-스코프">🌱 렉시컬(정적) 스코프</h2>
<hr>
<ul>
<li><strong>정의</strong> : 자바스크립트 엔진이 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지 그 환경에 따라 상위 스코프를 결정하는 것.</li>
</ul>
<blockquote>
<p>✔️ 스코프의 실체는 실행 컨텍스트의 렉시컬 환경이다. 렉시컬 환경은 자신의 OuterLexicalEnvironmentReference를 통해 상위 렉시컬 환경과 연결되는데 이것이 바로 <strong>스코프 체인</strong>이다.</p>
</blockquote>
<h2 id="🌱-함수-객체의-내부-슬롯-environment">🌱 함수 객체의 내부 슬롯 [[Environment]]</h2>
<hr>
<ul>
<li><p><strong>정의 :</strong> 렉시컬 스코프가 가능하려면 함수는 자신이 정의된 환경인 상위 스코프를 기억해야 한다. 이를 위해 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경인 상위 스코프의 참조를 저장한다.</p>
</li>
<li><p><strong>함수 코드 평가 순서</strong> :</p>
<p>  <img src="blob:https://velog.io/405ef070-3137-4186-b917-1cc0ae569eec" alt="업로드중.."></p>
<ol>
<li><p>함수 실행 컨텍스트 생성</p>
</li>
<li><p>함수 렉시컬 환경 생성</p>
<p> 2.1 함수 환경 레코드 생성</p>
<p> 2.2 this 바인딩</p>
<p> 2.3 외부 렉시컬 환경에 대한 참조 결정</p>
</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 실행 컨텍스트]]></title>
            <link>https://velog.io/@string_main/JS-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@string_main/JS-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 08 Dec 2022 15:00:11 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-소스코드의-타입">🌱 소스코드의 타입</h2>
<hr>
<ul>
<li><code>전역 코드</code> : 전역에 존재하는 소스코드로, 전역 스코프를 생성하고 전역 객체와 연결되기 위해 코드 평가 시 <strong>전역 실행 컨텍스트</strong>가 생성된다. (함수, 클래스 등 내부 코드는 포함되지 않음.)</li>
<li><code>함수 코드</code> : 함수 내부에 존재하는 소스코드로, 지역 스코프를 생성 후 전역 스코프의 스코프 체인의 일원으로 연결해야 해서 코드 평가 시 <strong>함수 실행 컨텍스트</strong>가 생성된다. (내부에 중첩된 함수, 클래스 등의 내부 코드는 포함되지 않음.)</li>
<li><code>eval 코드</code> : 빌트인 전역 함수인 eval 함수에 인수로 전달되어 실행되는 소스코드로, strict mode에서 자신만의 독자적인 스코프를 생성한다. 코드 평가 시 <strong>eval 실행 컨텍스트</strong>가 생성된다.</li>
<li><code>모듈 코드</code> : 모듈 내부에 존재하는 소스코드로, 모듈 스코프를 생성하고 코드 평가 시 <strong>모듈 실행 컨텍스트</strong>가 생성된다. (모듈 내부의 함수, 클래스 등 내부 코드는 포함되지 않음.)</li>
</ul>
<blockquote>
<p>✔️ 소스코드에 따라 실행 컨텍스트를 생성하는 과정과 관리 내용이 다르다!</p>
</blockquote>
<h2 id="🌱-소스코드의-평가와-실행">🌱 소스코드의 평가와 실행</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/string_main/post/7a80c12a-808d-4748-a8d6-1578dee94136/image.png" alt=""></p>
<ol>
<li>소스코드 평가 과정<ul>
<li>실행 컨텍스트 생성</li>
<li>변수, 함수 등 선언문 먼저 실행</li>
<li>변수, 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(환경 레코드)에 등록</li>
</ul>
</li>
<li>소스코드 실행 과정<ul>
<li>평가 종료 후 런타임 시작 (소스코드 순차적 실행)</li>
<li>변수 할당문 실행하기 위해 스코프에 등록된 변수인지 확인</li>
<li>선언된 변수라면 값을 할당 후 결과를 실행 컨텍스트에 등록하여 관리</li>
</ul>
</li>
</ol>
<h2 id="🌱-실행-컨텍스트의-정의와-역할">🌱 실행 컨텍스트의 정의와 역할</h2>
<hr>
<ul>
<li><strong>정의</strong> : 실행 컨텍스트는 소스코드를 실행하는 데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역이다. 즉, 식별자를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘으로, 모든 코드는 실행 컨텍스트를 통해 실행되고 관리된다.<ul>
<li>식별자와 스코프는 실행 컨텍스트의 렉시컬 환경으로 관리하고 코드 실행 순서는 실행 컨텍스트 스택으로 관리한다.</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">// 전역 변수 선언
const x = 1;
const y = 2;

// 함수 정의
function foo(a) {
    // 지역 변수 선언
    const x = 10;
    const y = 20;

    // 메서드 호출
    console.log(a + x + y); // 130
}

// 함수 호출
foo(100);

// 메서드 호출
console.log(x + y); // 3</code></pre>
<ol>
<li><p><strong>전역 코드 평가</strong> : </p>
<blockquote>
<p>전역 코드를 실행하기 전 코드 평가 과정에서 변수 선언문과 함수 선언문이 먼저 실행되고, 실행 컨텍스트가 관리하는 전역 스코프에 등록된다. 이 때, var 키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 프로퍼티와 메서드가 된다.</p>
</blockquote>
</li>
<li><p><strong>전역 코드 실행</strong> : </p>
<blockquote>
<p>전역 코드 평가 과정 이후 런타임이 시작되어 전역 코드가 순차적으로 실행된다. 전역 변수에 값이 할당되고 함수가 호출된다. 함수 호출 시 전역 코드의 실행을 일시 중단하고 코드 실행 순서를 변경해 함수 내부로 진입한다.</p>
</blockquote>
</li>
<li><p><strong>함수 코드 평가</strong> : </p>
<blockquote>
<p>함수 호출에 의해 함수 내부로 진입하면 함수 코드 평가 과정을 거쳐 매개변수와 지역 변수 선언문이 먼저 실행되고, 이후 실행 컨텍스트가 관리하는 지역 스코프에 등록된다. 또한, 함수 내부에서 지역 변수처럼 사용할 수 있는 arguments 객체가 생성되어 지역 스코프에 등록되고 this 바인딩도 결정된다.</p>
</blockquote>
</li>
<li><p><strong>함수 코드 실행</strong> : </p>
<blockquote>
<p>함수 코드 평가 과정 이후 런타임이 시작되어 함수 코드가 순차적으로 실행된다. 매개변수와 지역 변수에 값이 할당되고 console.log 메서드가 호출된다. 코드가 실행되려면 스코프를 구분해 식별자와 바인딩 된 값이 관리되어야 한다. 중첩 관계에 의해 스코프 체인을 형성해 식별자를 검색할 수 있어야 하고, 전역 객체의 프로퍼티도 전역 변수처럼 검색이 가능해야 한다. 또한, 함수 호출 종료 시 이전으로 돌아가기 위해 현재 실행 중인 코드와 이전 코드를 구분해 관리해야 한다.</p>
</blockquote>
</li>
</ol>
<h2 id="🌱-실행-컨텍스트-스택">🌱 실행 컨텍스트 스택</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/string_main/post/3b0de14e-c85e-47c9-aa7a-bc5403ddba5b/image.png" alt=""></p>
<ul>
<li><strong>정의</strong> : 스택 자료구조로 관리되는 실행 컨텍스트. 코드의 실행 순서를 관리한다. 실행 컨텍스트 스택의 최상위에 존재하는 실행 컨텍스트는 언제나 현재 실행 중인 코드의 실행 컨텍스트이다.</li>
</ul>
<ol>
<li><strong>전역 코드 평가와 실행</strong></li>
<li><strong>함수 코드 평가와 실행</strong> </li>
<li><strong>내부 함수 코드 평가와 실행</strong></li>
<li><strong>전역 코드로 복귀</strong></li>
</ol>
<blockquote>
<p>코드 평가 → 실행 컨텍스트 생성 → 실행 컨텍스트 스택에 푸시 → 실행 컨텍스트에 변수와 함수 등록 → 코드 실행 시작 → 변수 값 할당 및 함수 호출</p>
</blockquote>
<h2 id="🌱-렉시컬-환경">🌱 렉시컬 환경</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/string_main/post/56f2368c-17b9-4e66-bb65-d35b95865b0a/image.png" alt=""></p>
<ul>
<li><strong>정의</strong> : 식별자와 식별자에 바인딩 된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트이다. 스코프와 식별자를 관리하는 저장소의 역할을 한다.<ul>
<li>실행 컨텍스트는 LexicalEnvironment 컴포넌트와 VariableEnvironment 컴포넌트로 구성된다.</li>
<li>렉시컬 환경은 식별자를 등록하고 바인딩된 값을 관리하는 저장소인 EnvironmentRecord 컴포넌트와 상위 스코프를 가리키는 OuterLexicalEnvironmentReference 컴포넌트로 구성된다.</li>
</ul>
</li>
</ul>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>실행 컨텍스트 파트를 정독하고 나니 스코프 관리 방식, 호이스팅 발생 이유, 클로저의 동작 방식 등 자바스크립트의 전반적인 코어 개념들을 더욱 깊이있게 이해할 수 있게 되었다. 상쾌한 기분!</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] this]]></title>
            <link>https://velog.io/@string_main/JS-this</link>
            <guid>https://velog.io/@string_main/JS-this</guid>
            <pubDate>Wed, 07 Dec 2022 14:57:30 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-this-키워드">🌱 this 키워드</h2>
<hr>
<ul>
<li><strong>정의</strong> : 자신이 속한 객체 또는 자신이 생성할 인터페이스를 가리키는 자기 참조 변수이다.</li>
<li><strong>필요성</strong> : 동작을 나타내는 메서드는 자신이 속한 객체의 상태(프로퍼티)를 참조하고 변경할 수 있어야 하는데, 그러기 위해서는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.</li>
</ul>
<h2 id="🌱">🌱</h2>
<hr>
<ul>
<li><h2 id="🌱-1">🌱</h2>
</li>
</ul>
<hr>
<ul>
<li><h2 id="🌱-2">🌱</h2>
</li>
</ul>
<hr>
<ul>
<li><h3 id="예제">예제)</h3>
</li>
</ul>
<pre><code class="language-jsx"></code></pre>
<blockquote>
</blockquote>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] var, let, const]]></title>
            <link>https://velog.io/@string_main/JS-var-let-const</link>
            <guid>https://velog.io/@string_main/JS-var-let-const</guid>
            <pubDate>Tue, 06 Dec 2022 14:59:26 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-var-키워드의-문제점">🌱 var 키워드의 문제점</h2>
<hr>
<ol>
<li><p><strong>변수 중복 선언 허용</strong> : var 키워드로 선언한 변수는 같은 스코프 내에서 중복 선언이 가능하다.</p>
<pre><code class="language-jsx"> var x = 1;
 var y = 1;

 var x = 100;
 var y; // 초기화문이 없는 변수 선언문은 무시된다.

 console.log(x); // 100
 console.log(y); // 1</code></pre>
</li>
<li><p><strong>함수 레벨 스코프</strong> : var 키워드로 선언한 변수는 함수의 코드 블록만을 지역 스코프로 인정한다. 함수 외부에서 선언한 변수는 코드 블록 내에서 선언해도 모두 전역 변수가 된다.</p>
<pre><code class="language-jsx"> var x = 1;

 if(true) {
     var x = 10;
 }

 console.log(x); // 10</code></pre>
<pre><code class="language-jsx"> var i = 10;

 for(var i = 0; i &lt; 5; i++) {
     console.log(i); // 0 1 2 3 4
 }

 console.log(i); // 5</code></pre>
</li>
<li><p><strong>변수 호이스팅</strong> : var 키워드로 변수를 선언하면 변수 호이스팅에 의해 변수 선언문이 스코프의 선두로 끌어 올려진 것 처럼 동작한다. 이는 프로그램의 흐름상 맞지 않고, 오류를 발생시킬 여지를 남긴다.</p>
<pre><code class="language-jsx"> console.log(foo); // 2. foo는 undefined로 초기화 된다.

 foo = 123; // 3. 변수에 값을 할당한다.

 console.log(foo); // 123

 var foo; // 1. 변수 선언은 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 실행된다.</code></pre>
</li>
</ol>
<h2 id="🌱-let-키워드">🌱 let 키워드</h2>
<hr>
<ol>
<li><p><strong>변수 중복 선언 금지</strong> : let 키워드로 이름이 같은 변수를 중복 선언하면 문법 에러가 발생한다.</p>
<pre><code class="language-jsx"> let bar = 123;
 let bar = 456; // SyntaxError: Identifier &#39;bar&#39; has already been declared</code></pre>
</li>
<li><p><strong>블록 레벨 스코프</strong> : let 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프를 따른다.</p>
<pre><code class="language-jsx"> let foo = 1;

 {
     let foo = 2;
     let bar = 3;
 }

 console.log(foo); // 1
 console.log(bar); // ReferenceError: bar is not defined</code></pre>
</li>
<li><p><strong>변수 호이스팅</strong> : let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것 처럼 동작한다. var 키워드로 선언한 변수는 선언 단계와 초기화 단계가 한번에 진행되는 반면, let 키워드로 선언한 변수는 선언 단계와 초기화 단계가 분리되어 진행된다.</p>
<pre><code class="language-jsx"> console.log(foo); // ReferenceError: foo is not defined
 let foo;</code></pre>
<blockquote>
<p>스코프의 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 일시적 사각지대(TDZ)라고 부른다.</p>
</blockquote>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 전역 변수의 문제점]]></title>
            <link>https://velog.io/@string_main/JS-%EC%A0%84%EC%97%AD-%EB%B3%80%EC%88%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</link>
            <guid>https://velog.io/@string_main/JS-%EC%A0%84%EC%97%AD-%EB%B3%80%EC%88%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</guid>
            <pubDate>Mon, 05 Dec 2022 14:50:02 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-변수의-생명-주기">🌱 변수의 생명 주기</h2>
<hr>
<ul>
<li><strong>정의</strong> : 메모리 공간이 확보(allocate)된 시점부터 메모리 공간이 해제(release)되어 가용 메모리 풀에 반환되는 시점까지를 변수의 생명주기라고 한다.</li>
<li><strong>필요성</strong> : 변수에 생명주기가 없다면 한번 선언된 변수는 프로그램을 종료하지 않는 한 영원히 메모리 공간을 점유하게 된다.</li>
</ul>
<h3 id="🌿-지역-변수의-생명-주기">🌿 지역 변수의 생명 주기</h3>
<pre><code class="language-jsx">function foo() {
    var x = &#39;local&#39;; // 지역 변수 X 생성 및 할당
    console.log(x); // local
    return x; // 지역 변수 X 소멸
}

foo();
console.log(); // ReferenceError: x is not defined</code></pre>
<blockquote>
<p>지역 변수의 생명 주기는 함수의 생명 주기와 일치한다.</p>
</blockquote>
<pre><code class="language-jsx">var x = &#39;global&#39;;

function foo() {
    console.log(x); // undefined
    var x = &#39;local&#39;;
}

foo();
console.log(x); // global</code></pre>
<blockquote>
<p>지역 변수는 함수 전체에서 유효하며, 호이스팅은 스코프 단위로 동작한다.</p>
</blockquote>
<h3 id="🌿-전역-변수의-생명-주기">🌿 전역 변수의 생명 주기</h3>
<pre><code class="language-jsx">var x = &#39;global&#39;; // 전역 변수 x 생성 및 할당

function foo() {
    console.log(x);
    return x;
}

foo();
console.log(x); // 전역 변수 x 소멸</code></pre>
<blockquote>
<p>전역 변수는 진입점이 없어서 코드가 로드 되자마자 바로 해석되고 실행된다. var 키워드로 선언한 전역 변수는 <strong>전역 객체</strong>의 프로퍼티가 되고, 생명 주기는 전역 객체의 생명 주기와 일치한다.</p>
</blockquote>
<p>✔️ <strong>전역 객체</strong>란, 클라이언트 사이드(브라우저)에서는 window, 서버 사이드(Node.js)에서는 global 객체를 의미한다.</p>
<h2 id="🌱-전역-변수의-문제점">🌱 전역 변수의 문제점</h2>
<hr>
<ol>
<li><code>암묵적 결합(implicit coupling)</code> : 전역 변수는 코드 어디서든 참조하고 변경할 수 있다. 이는 암묵적 결합을 허용하는 것이다. 변수의 유효 범위가 크면 클수록 코드 가독성이 나빠지고 의도치 않게 상태가 변경될 위험성이 높아진다.</li>
<li><code>긴 생명 주기</code> : 전역 변수는 생명 주기가 길어 메모리 리소스도 오랜 기간 소비한다. 즉, 전역 변수의 상태를 변경할 수 있는 시간과 기회가 많아 오류가 발생할 확률이 높아진다.</li>
<li><code>스코프 체인 상에서 종점에 존재</code> : 전역 변수는 스코프 체인 상에서 종점에 위치하기 때문에 가장 마지막에 검색되어 검색 속도가 느리다.</li>
<li><code>네임스페이스 오염</code> : 자바스크립트는 파일이 분리되어 있어도 하나의 전역 스코프를 공유하는 문제점이 있어서 다른 파일 내 동일 이름으로 된 전역 변수나 함수가 같은 스코프 내에 존재할 경우 예상치 못한 결과가 생길 수 있다.</li>
</ol>
<h2 id="🌱-전역-변수의-사용을-억제하는-방법">🌱 전역 변수의 사용을 억제하는 방법</h2>
<hr>
<blockquote>
<p>전역 변수를 반드시 사용해야 할 이유를 찾지 못한다면 지역 변수를 사용해야 한다.
변수의 스코프는 좁을수록 좋다.</p>
</blockquote>
<ol>
<li><p><code>즉시 실행 함수</code> : 모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다.</p>
<pre><code class="language-jsx"> (function () {
     var foo = 10;
     // ...
 }());

 console.log(foo); // ReferenceError: foo is not defined</code></pre>
</li>
<li><p><code>네임스페이스 객체</code> : 전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법이다. (식별자 충돌을 방지하는 효과는 있으나 네임스페이스 객체 자체가 전역 변수에 할당되므로 그다지 유용하진 않아 보인다.)</p>
<pre><code class="language-jsx"> var MYAPP = {}; // 전역 네임스페이스 객체
 MYAPP.name = &quot;Lee&quot;;
 console.log(MYAPP.name); // Lee</code></pre>
</li>
<li><p><code>모듈 패턴</code> : 모듈 패턴은 클로저를 기반으로 동작하며 <strong>캡슐화</strong>를 구현할 수 있다.</p>
<pre><code class="language-jsx"> var Counter = (function () {
     // private 변수
     var num = 0;

     return {
         increase() {
             return ++num;
         },
         decrease() {
             return --num;
         }
     };
 }());

 // private 변수는 외부로 노출되지 않는다.
 console.log(Counter.num); // undefined

 console.log(Counter.increase()); // 1
 console.log(Counter.increase()); // 2
 console.log(Counter.decrease()); // 1
 console.log(Counter.decrease()); // 0</code></pre>
<blockquote>
<p>자바스크립트는 접근 제한자를 제공하지 않아서 한정적이긴 하지만 정보 은닉을 구현하기 위해 사용된다.</p>
</blockquote>
</li>
</ol>
<pre><code>✔️ **캡슐화**란, 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것을 말한다.</code></pre><ol start="4">
<li><p><code>ES6 모듈</code> : ES6 모듈은 독자적인 모듈 스코프를 제공한다. 모듈 내에서 var 키워드로 선언한 변수는 더는 전역 변수가 아니다. script 태그에 type=&quot;module” 어트리뷰트를 추가하면 자바스크립트 파일은 모듈로서 동작한다.</p>
<pre><code class="language-html"> &lt;script type=&quot;module&quot; src=&quot;lib.mjs&quot;&gt;&lt;/script&gt;
 &lt;script type=&quot;module&quot; src=&quot;app.mjs&quot;&gt;&lt;/script&gt;</code></pre>
<blockquote>
<p>브라우저의 ES6 모듈 기능을 사용하더라도 트랜스파일링이나 번들링이 필요하기 때문에 아직까지는 Webpack 등의 모듈 번들러를 사용하는 것이 일반적이다.</p>
</blockquote>
</li>
</ol>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>무심코 사용하던 전역 변수의 무시무시한 문제점을 알게 되었다. 앞으로는 전역 변수 사용에 주의해서 코드를 작성해야겠다.</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 스코프란?]]></title>
            <link>https://velog.io/@string_main/JS-%EC%8A%A4%EC%BD%94%ED%94%84%EB%9E%80</link>
            <guid>https://velog.io/@string_main/JS-%EC%8A%A4%EC%BD%94%ED%94%84%EB%9E%80</guid>
            <pubDate>Fri, 02 Dec 2022 12:11:35 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-스코프란">🌱 스코프란?</h2>
<hr>
<p><img src="https://velog.velcdn.com/images/string_main/post/55d9b522-a58d-4e73-ac8b-ed0b6d3cf38e/image.png" alt=""></p>
<ul>
<li><strong>정의</strong> : 모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 자신을 참조할 수 있는 유효 범위가 결정되는데, 즉, 식별자가 유효한 범위를 스코프라고 한다.</li>
<li><strong>필요성</strong> : 스코프라는 개념이 없다면, 같은 이름을 갖는 변수는 충돌을 일으키므로 프로그램 전체에서 하나밖에 사용할 수 없다.</li>
</ul>
<pre><code class="language-jsx">function add(x, y) {
    // 매개변수의 스코프는 함수 몸체 내부다.
    console.log(x, y); // 2, 5
    return x + y;
}

add(2, 5);

console.log(x, y); // ReferenceError: x is not defined</code></pre>
<h2 id="🌱-스코프의-종류">🌱 스코프의 종류</h2>
<hr>
<ul>
<li><code>전역(global)</code> : 코드의 가장 바깥 영역으로, 전역에 선언한 변수는 전역 스코프를 가져 어디서든지 참조할 수 있다.</li>
<li><code>지역(local)</code> : 함수 몸체 내부 영역으로, 지역에 선언한 변수는 지역 스코프를 가져 자신이 선언된 지역과 하위 지역(중첩 함수)에서만 참조할 수 있다.</li>
</ul>
<h2 id="🌱-스코프-체인scope-chain">🌱 스코프 체인(scope chain)</h2>
<hr>
<ul>
<li><strong>정의</strong> : 스코프가 계층적으로 연결된 것. 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작해 상위 스코프 방향으로 이동하며 선언된 변수를 검색(identifier resolution)한다. (스코프 체인은 실행 컨텍스트의 렉시컬 환경을 단방향으로 연결한 것이다.)</li>
</ul>
<h2 id="🌱-함수-레벨-스코프--블록-레벨-스코프">🌱 함수 레벨 스코프 &amp; 블록 레벨 스코프</h2>
<hr>
<ul>
<li><p><code>함수 레벨 스코프</code> : var 키워드로 선언된 변수는 함수의 코드 블록만을 지역 스코프로 인정한다. (코드 블록이 아닌 함수에 의해서만 지역 스코프가 생성된다.)</p>
<pre><code class="language-jsx">  var x = 1;

  if (true) {
      // 함수 밖에서 var 키워드로 선언된 변수는 코드 블록 내에 선언되었어도 전역 변수이다.
      // 이는 의도치 않게 변수 값이 변경되는 부작용이 있다.
      var x = 10;
  }

  console.log(x); // 10</code></pre>
</li>
<li><p><code>블록 레벨 스코프</code> : C나 Java등 대부분의 프로그래밍 언어는 함수 몸체만이 아니라 모든 코드 블록이 지역 스코프를 만든다. (ES6에서 도입된 let, const 키워드는 블록 레벨 스코프를 지원한다.)</p>
</li>
</ul>
<h2 id="🌱-다이나믹-스코프--렉시컬-스코프">🌱 다이나믹 스코프 &amp; 렉시컬 스코프</h2>
<hr>
<ul>
<li><p><code>다이나믹(동적) 스코프</code> : 함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정하는 방식.</p>
</li>
<li><p><code>렉시컬(정적) 스코프</code> : 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정하는 방식.</p>
<pre><code class="language-jsx">  var x = 1;

  function foo() {
      var x = 10;
      bar();
  }

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

  foo(); // 1
  bar(); // 1</code></pre>
</li>
</ul>
<blockquote>
<p>자바스크립트를 비롯한 대부분의 프로그래밍 언어는 렉시컬 스코프를 따른다. 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주지 않는다. 함수의 상위 스코프는 언제나 자신이 정의된 스코프이다.</p>
</blockquote>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>바로 위의 예제에서 10과 1이 출력될 것이라고 예상했는데, 함수가 호출된 위치는 상위 스코프 결정에 아무런 영향이 없다는 것을 깨달았다. 함수 선언문으로 정의된 함수들은 런타임 전에 먼저 평가되어 함수 객체를 생성하고, 자신이 정의된 스코프(전역 스코프)를 기억해서 상위 스코프로 사용한다는 점을 잊지말자!</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 함수란?]]></title>
            <link>https://velog.io/@string_main/JS-%ED%95%A8%EC%88%98%EB%9E%80</link>
            <guid>https://velog.io/@string_main/JS-%ED%95%A8%EC%88%98%EB%9E%80</guid>
            <pubDate>Thu, 01 Dec 2022 14:42:24 GMT</pubDate>
            <description><![CDATA[<h2 id="🌱-함수란">🌱 함수란?</h2>
<hr>
<ul>
<li><strong>정의</strong> : 일련의 과정을 문(statement)으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것</li>
<li><strong>필요성</strong> :<ol>
<li>코드의 재사용성 : 필요할 때 여러 번 호출할 수 있고, 실행 시점을 개발자가 결정할 수 있다.</li>
<li>유지보수의 편의성 : 코드의 중복을 제거하여 유지보수에 편리하다.</li>
<li>코드의 신뢰성 : 코드의 중복을 제거하여 코드 수정 시 실수를 줄일 수 있다.</li>
<li>코드의 가독성 : 적절한 함수명은 내부 코드를 이해하지 않고도 코드의 역할을 파악할 수 있다.</li>
</ol>
</li>
</ul>
<h2 id="🌱-용어-정리">🌱 용어 정리</h2>
<hr>
<ul>
<li><code>매개변수(parameter)</code> : 함수 내부로 입력을 전달 받는 변수</li>
<li><code>인수(argument)</code> : 입력</li>
<li><code>반환값(return value)</code> : 출력</li>
</ul>
<pre><code class="language-jsx">// 함수 정의
function add(x, y) { // 매개변수
    return x + y; // 반환값
}

// 함수 호출
add(2, 5); // 인수</code></pre>
<h2 id="🌱-함수-정의-방식">🌱 함수 정의 방식</h2>
<hr>
<ul>
<li><p><strong>함수 선언문</strong> : 함수 리터럴과 형태가 동일하나, 함수 선언문은 함수 이름을 생략할 수 없다. 표현식이 아닌 문이므로 변수에 할당할 수 없다.</p>
<pre><code class="language-jsx">  function add(x, y) {
      return x + y;
  }</code></pre>
</li>
<li><p><strong>함수 표현식</strong> : 자바스크립트에서 함수는 객체 타입의 값이기 때문에 함수 리터럴로 생성할 수 있다. 함수 선언문이 변수에 할당되는 것 처럼 보이지만, 자바스크립트 엔진이 코드의 문맥에 따라 함수 표현식으로 해석한다.</p>
<pre><code class="language-jsx">  var f = function add(x, y) { // 함수 이름 생략 가능 (익명 함수)
      return x + y;
  };</code></pre>
<blockquote>
<p>함수는 함수 이름으로 호출하는 것이 아니라 함수 객체를 가리키는 식별자로 호출한다.
  즉, 함수 선언문으로 생성한 함수를 호출한 것은 함수 이름이 아니라 자바스크립트 엔진이 암묵적으로 생성한 식별자 add이다. 결론적으로 자바스크립트 엔진은 함수 선언문을 함수 표현식으로 변환해 생성한다고 생각할 수 있다. 단, 선언문과 표현식이 정확히 동일하게 동작하는 것은 아님에 유의하자.</p>
</blockquote>
</li>
<li><p><strong>Function 생성자 함수</strong> : 자바스크립트가 기본으로 제공하는 빌트인 함수인 Function 생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면 함수 객체를 생성해서 반환한다. new 연산자 없이 호출해도 결과는 동일하다.</p>
<pre><code class="language-jsx">  var add = new Function(&#39;x&#39;, &#39;y&#39;, &#39;return x + y&#39;);</code></pre>
<blockquote>
<p>Function 생성자 함수로 생성한 함수는 클로저를 생성하지 않는 등 일반적인 함수와 다르게 동작하므로 바람직하지 않다.</p>
</blockquote>
</li>
<li><p><strong>화살표 함수</strong> : ES6에서 도입된 방식으로 function 키워드 대신 화살표(⇒) 를 사용해 함수를 간략히 선언할 수 있다.</p>
<pre><code class="language-jsx">  var add = (x, y) =&gt; x + y;</code></pre>
<blockquote>
<p>화살표 함수는 생성자 함수로 사용할 수 없으며, 기존 함수와 this 바인딩 방식이 다르고, prototype 프로퍼티가 없으며 arguments 객체를 생성하지 않는다는 차이점이 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="🌱-함수-호이스팅">🌱 함수 호이스팅</h2>
<hr>
<pre><code class="language-jsx">// 함수 참조
console.dir(add); // f add(x, y)
console.dir(sub); // undefined

// 함수 호출
console.log(add(2, 5)); // 7
console.log(sub(2, 5)); // TypeError: sub is not a function

// 함수 선언문
function add(x, y) {
    return x + y;
}

// 함수 표현식
var sub = function (x, y) {
    return x - y;
}</code></pre>
<blockquote>
<p>모든 선언문이 그렇듯 함수 선언문도 런타임 이전에 자바스크립트 엔진에 의해 먼저 실행되어 함수 호이스팅이 일어난다. 변수 호이스팅과 함수 호이스팅은 초기화에서 미묘한 차이가 있다. var 키워드로 선언된 변수는 <strong>undefined</strong>로 초기화되고, 함수 선언문을 통해 암묵적으로 생성된 식별자는 <strong>함수 객체</strong>로 초기화된다.</p>
</blockquote>
<p>변수 할당문의 값은 런타임에 평가되므로 함수 표현식으로 정의할 경우에는 함수 호이스팅이 아닌 변수 호이스팅이 발생한다.</p>
<blockquote>
</blockquote>
<p>✅ 함수 선언 이전에 호출이 가능한 문제점 때문에 함수 선언문 대신 함수 표현식을 사용할 것이 권장된다!</p>
<h2 id="🌱-함수의-종류">🌱 함수의 종류</h2>
<hr>
<ul>
<li><p><code>즉시 실행 함수</code> : 함수 정의와 동시에 즉시 호출되는 함수로, 단 한 번만 호출되며 다시 호출할 수 없다.</p>
<pre><code class="language-jsx">  (function () {
      var a = 3;
      var b = 5;
      return a * b;
  }());</code></pre>
<blockquote>
<p>그룹 연산자(...)로 감싸지 않으면 문법 에러가 발생한다. 그룹 연산자의 피연산자는 값으로 평가되므로 함수 리터럴로 평가되어 함수 객체가 된다.</p>
</blockquote>
</li>
<li><p><code>재귀 함수</code> : 자기 자신을 호출(재귀 호출)하는 함수.</p>
<pre><code class="language-jsx">  function factorial(n) {
      if(n &lt;= 1) return 1; // 탈출 조건
      return n * factorial(n - 1);
  }

  console.log(factorial(5)); // 5! = 120</code></pre>
<blockquote>
<p>탈출 조건이 없으면 함수가 무한 호출되어 스택 오버플로 에러가 발생한다. 재귀 함수는 반복문을 사용하는 것 보다 재귀 함수를 사용하는 것이 직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직하다.</p>
</blockquote>
</li>
<li><p><code>중첩(내부) 함수</code> : 함수 내부에 정의된 함수로, 일반적으로 외부 함수를 돕는 헬퍼 함수의 역할을 한다.</p>
<pre><code class="language-jsx">  function outer() {
      var x = 1;

      function inner() {
          var y = 2;
          // 외부 함수의 변수 참조 가능
          console.log(x + y); // 3
      }

      inner();
  }

  outer();</code></pre>
</li>
<li><p><code>콜백 함수</code> : 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수.</p>
</li>
<li><p><code>고차 함수</code> : 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수.</p>
<pre><code class="language-jsx">  function repeat(n, f) { // 고차 함수 (HOF)
      for(var i = 0; i &lt; n; i++ {
          f(i);
      }
  }

  var logAll = function (i) {
      console.log(i);
  };

  // 반복 호출할 함수를 인수로 전달
  repeat(5, logAll); // 0 1 2 3 4

  var logOdds = function (i) {
      if (i % 2) console.log(i);
  };

  // 반복 호출할 함수를 인수로 전달
  repeat(5, logOdds); // 1 3</code></pre>
<blockquote>
<p>함수에서 공통 로직 이외에 경우에 따라 변경되는 일부분의 로직은 매번 함수를 새롭게 정의할 필요 없이 함수의 합성으로 해결할 수 있다. (경우에 따라 변경되는 함수를 추상화 해서 함수 외부에서 함수 내부로 전달)</p>
</blockquote>
</li>
<li><p><code>순수 함수</code> : 외부 상태에 의존하지도 않고 변경하지도 않는, 부수 효과가 없는 함수. 동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수.</p>
<pre><code class="language-jsx">  var count = 0;

  // 순수 함수
  function increase(n) {
      return ++n;
  }

  // 순수 함수가 반환한 결과값을 변수에 재할당해서 상태 변경
  count = increase(count);
  console.log(count); // 1

  count = increase(count);
  console.log(count); // 2</code></pre>
</li>
<li><p><code>비순수 함수</code> : 외부 상태에 의존하거나 외부 상태를 변경하는, 부수 효과가 있는 함수.</p>
<pre><code class="language-jsx">  var count = 0;

  // 비순수 함수
  function increase(n) {
      return ++count; // 외부 상태에 의존하여 외부 상태 변경
  }

  // 비순수 함수는 외부 상태를 변경하여 상태 변화 추적이 어렵다.
  increase();
  console.log(count); // 1

  increase();
  console.log(count); // 2</code></pre>
<blockquote>
<p>함수가 외부 상태를 변경하면 상태 변화 추적이 어려워지기 때문에 순수 함수를 사용하는 것이 좋다. (+ 함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 불변성을 지향하는 프로그래밍 패러다임이다.)</p>
</blockquote>
</li>
</ul>
<h3 id="🌿-알게된-점--느낀-점">🌿 알게된 점 &amp; 느낀 점</h3>
<hr>
<blockquote>
<p>내가 당연하게 알고 있었다고 생각했던 개념들이었는데, 책을 정독해보니 새로 알게 된 사실들이 많았다.
특히, 함수는 함수 이름으로 호출하는 것이 아니라 자바스크립트 엔진이 암묵적으로 생성한 함수 객체를 가리키는 식별자로 호출한다는 점이 가장 흥미로운 사실이었다. 앞으로도 당연시 여기는 것이 없이 내가 정확히 알고 있는지를 끊임없이 의심하자.</p>
</blockquote>
<p><strong>| 참고자료 |</strong></p>
<blockquote>
<p>모던 자바스크립트 Deep Dive</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>