<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>silverj-kim.log</title>
        <link>https://velog.io/</link>
        <description>Front-end developer</description>
        <lastBuildDate>Wed, 23 Oct 2024 00:51:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>silverj-kim.log</title>
            <url>https://images.velog.io/images/silverj-kim/profile/2a99d1cb-c5c6-4046-b27b-d66c57d9f1c5/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. silverj-kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/silverj-kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React controlled vs uncontrolled]]></title>
            <link>https://velog.io/@silverj-kim/React-controlled-vs-uncontrolled</link>
            <guid>https://velog.io/@silverj-kim/React-controlled-vs-uncontrolled</guid>
            <pubDate>Wed, 23 Oct 2024 00:51:49 GMT</pubDate>
            <description><![CDATA[<h2 id="제어-컴포넌트-controlled-component">제어 컴포넌트 controlled component</h2>
<p>컴포넌트의 state나 props로 주어진 값을 활용하는 컴포넌트
<code>&lt;input&gt;</code>에서 value를 state로 관리하는 경우</p>
<h2 id="비제어-컴포넌트-uncontrolled-component">비제어 컴포넌트 unControlled component</h2>
<p>html 요소 자체적으로 상태를 가져 useState로 상태를 관리하지 않는 컴포넌트다.
<code>&lt;input&gt;</code>에 값을 입력하면 해당 값은 입력 폼 내부의 상태로 관리된다.</p>
<p>ref를 이용하여 요소의 상태에 접근할 수 있으며 상태가 변화하여도 리렌더링이 이루어지지않아 리액트는 변화를 감지하지 못한다.</p>
<p><em>데이터와 UI의 동기가 이루어지지 않는다.</em>
입력이 변경될 때 유효성 검사를 하는 작업 등이 불가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Front End State Management]]></title>
            <link>https://velog.io/@silverj-kim/Front-End-State-Management</link>
            <guid>https://velog.io/@silverj-kim/Front-End-State-Management</guid>
            <pubDate>Sun, 19 May 2024 23:04:05 GMT</pubDate>
            <description><![CDATA[<h2 id="flux-패턴">Flux 패턴</h2>
<p>단방향 데이터 흐름</p>
<pre><code>Action -&gt; Dispatcher -&gt; Store -&gt; View</code></pre><p><strong>Action이 발생하면 Dispatcher 에서 이를 받아와 해석한 후 Store에서 저장된 정보에 변경 가하고 그 결과가 View로 전달되는 데이터 흐름</strong>
action을 통해 상태변화가 일어나고 컴포넌트에서는 selector를 사용해 전역 상태의 일부를 구독(sub)</p>
<h2 id="atomic-패턴">Atomic 패턴</h2>
<p><strong>atoms(공유 상태)에서 selectors(순수 함수)를 거쳐 React 컴포넌트로 내려가는 데이터 흐름</strong>
state와 비슷하게 react tree 안에서 상태를 저장하고 관리하는 방법</p>
<h3 id="atoms">Atoms</h3>
<p>상태의 단위이며 업데이트와 구독이 가능
atom이 업데이트되면 각각 구독된 컴포넌트는 새로운 값을 반영하여 다시 렌더링. 동일한 atom을 여러 컴포넌트에서 사용되는 경우 모든 컴포넌트는 상태를 공유한다.</p>
<h3 id="selectors">Selectors</h3>
<p>atoms나 다른 selectors를 입력으로 받아들이는 pure function
상위의 atom이나 selector가 업데이트되면 하위의 selector도 다시 실행된다. 컴포넌트들은 selectors를 atoms처럼 구독할 수 있으며 selectors가 변경되면 컴포넌트들도 다시 렌더링된다.</p>
<p>최소한의 상태 집합만 atoms에 저장하고 다른 모든 파생되는 데이터는 selectors에 명시한 함수를 통해 효율적으로 계산하면 쓸모없는 상태 보존을 방지할 수 있다.</p>
<h4 id="그리고-지금-알고-싶은-것은--jotai와-zustand">그리고 지금 알고 싶은 것은  jotai와 zustand</h4>
<h2 id="zustand">Zustand</h2>
<p><a href="https://ui.toast.com/posts/ko_20210812">https://ui.toast.com/posts/ko_20210812</a>
<a href="https://github.com/pmndrs/zustand">https://github.com/pmndrs/zustand</a></p>
<ul>
<li>1.2kb</li>
<li>top-down</li>
<li>한 개의 중앙에 집중된 형식의 스토어 구조</li>
<li>상태를 정의하고 사용하는 방법이 단순</li>
<li>Context API를 사용할 때와 달리 상태 변경 시 불필요한 리렌더링 제어 쉬움<ul>
<li>Context의 consumer가 많을 수록 불필요한 리렌더링이 더 많이 일어나는데 이를 개선할 수 있음</li>
</ul>
</li>
<li>자주 바뀌는 상태를 직접 제어할 수 있는 방법 제공 (Trasient Update)</li>
<li>redux devtools</li>
</ul>
<pre><code>//store
const useBearStore = create((set) =&gt; ({
    bears: 0,
    increasePopulation: () =&gt; set((state) =&gt; ({ bears: state.bears + 1 })


//use state
function BearCounter() {
    const bears = useBearStore((state) =&gt; state.bears)
      return {bears}
}

//use action
function Controls() {
    const increase = useBearStore((state) =&gt; state.increasePopulation)
    return &lt;button onClick={increase} /&gt;
}

//useShallow -&gt; select
const {nuts, honey} = useBearStore(
    useShallow(state =&gt; ({ nuts: state.nuts, honey: state.honey }))

//slicing store
export const useBoundStore = create((...a) =&gt; ({
  ...createBearSlice(...a),
  ...createFishSlice(...a),
}))
</code></pre><p><img src="https://velog.velcdn.com/images/silverj-kim/post/5b5b98ee-c5df-4a9d-a2ce-db6a6a851a66/image.png" alt=""></p>
<h2 id="jotai">Jotai</h2>
<p><a href="https://github.com/pmndrs/jotai">https://github.com/pmndrs/jotai</a></p>
<ul>
<li>3.35kb</li>
<li>bottom-up</li>
<li>Context의 리렌더링 문제를 해소하기 위한 접근으로 만든 라이브러리</li>
<li>state,action 모두 atom을 사용하여 만든다. computed state도 atom을 사용한다.</li>
<li>객체의 참조를 WeakMap에 보관해 해당 객체 자체가 변경되지 않는 한 별도의 키가 없어도 객체의 참조를 통해 값을 관리</li>
<li>dev tools <a href="https://codesandbox.io/p/sandbox/peaceful-euclid-k5p12d?file=%2Fsrc%2FApp.tsx&amp;from-embed=">https://codesandbox.io/p/sandbox/peaceful-euclid-k5p12d?file=%2Fsrc%2FApp.tsx&amp;from-embed=</a></li>
</ul>
<pre><code>const countAtom = atom(0)</code></pre><ol>
<li>파생상태를 효과적으로 관리할 수 있으냐</li>
<li>디버깅이 잘 되는냐</li>
<li>쉽냐</li>
<li>가볍냐</li>
<li>확장성을 가지고 있으냐</li>
</ol>
<p><a href="https://medium.com/@ian-white/recoil-vs-jotai-vs-zustand-09d3c8bd5bc0">https://medium.com/@ian-white/recoil-vs-jotai-vs-zustand-09d3c8bd5bc0</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[빅오(Big-O)]]></title>
            <link>https://velog.io/@silverj-kim/%EB%B9%85%EC%98%A4Big-O</link>
            <guid>https://velog.io/@silverj-kim/%EB%B9%85%EC%98%A4Big-O</guid>
            <pubDate>Sat, 06 Jan 2024 10:26:36 GMT</pubDate>
            <description><![CDATA[<h1 id="big-o-빅오-표기법">Big-O 빅오 표기법</h1>
<p>알고리즘의 성능을 나타내는 표기법
시간 복잡도, 공간 복잡도 예측 시 사용
N의 증가에 따른 처리 시간 또는 필요 공간 계산</p>
<p>| 점근적 표현법 중 하나이며, 일반적으로 상수와 계수를 제거하고 알고리즘의 복잡도를 단순화하여 나타낸다.</p>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/927787f8-20b6-4d1e-b22c-9b596571edba/image.png" alt=""></p>
<p>O(1) Constant Time 상수 : input 크기와 상관없이 항상 일정한 시간 소요</p>
<pre><code>arr[0]</code></pre><p>O(logn) Logarithmic 로그 : O(1) 다음으로 빠르 시간 복잡도
<img src="https://velog.velcdn.com/images/silverj-kim/post/6f85c062-7f48-49d7-badc-8118ac7bfa34/image.png" alt=""></p>
<pre><code>function logCounter(n) {
  let loopCount = 0;
  for (let i = 2; i &lt;= n; i*=2) {
      loopCount++;
  }
  return loopCount;
}
logCounter(16) //4</code></pre><p>i가 2, 4, 8, 16
output은 1, 2, 3, 4로 증가하여 4를 반환한다.
n은 16이지만 반복문은 4번만 수행한다.
대표적인 알고리즘: 이진탐색 (binary search)</p>
<p>O(n) Linear 선행 : input의 증가 시 같은 비율로 증가</p>
<pre><code>function countCharacters(str) {
  let count = 0;
  for (let i = 0; i &lt; str.length; i++){
      count++;
  }
  return count;
}</code></pre><p>i는 str.length만큼 증가하고 반복문도 str.length만큼 수행한다.
str.length가 증가하는 만큼 반복횟수가 증가한다.
보통 O(n)보다 느린 알고리즘을 비효율적이라고 한다.</p>
<p>O(n^2) Quadratic 제곱 : input 증가 시 n의 제곱 비율로 증가</p>
<pre><code>function buildMatrix(arr) {
    let matrix = [];
    for (let i = 0; i &lt;= arr.length; i++ ) {
        matrix[i] = [];
        console.log(&quot;inner&quot;);
        for (let j = 0; j &lt; arr.length; j++) {
            matrix[i].push(arr[j]);
                    console.log(&quot;outer&quot;);
        }
    }
    return matrix;
}</code></pre><p>(arr.length + 1) * arr.length 만큼 반복문이 수행한다. 
input이 증가할 수록 시간도 제곱비율로 증가한다.</p>
<p>O(n!) Factorial 팩토리얼 : 가장 느린 속도, input이 늘어남에 따라 기하급수적으로 증가</p>
<pre><code>function factorial(n) {
  let num = n;
  if (n === 0) return 1;
  for (let i = 0; i &lt; n; i++) {
      num = n * factorial(n-1);
  }
  return num;
}</code></pre><h3 id="big-o-의-규칙">Big O 의 규칙</h3>
<ul>
<li>최고차항만 표기한다.</li>
<li>상수항 &amp; 영향력없는 항은 무시한다.</li>
</ul>
<pre><code>// O(1)
function printElement(arr, index) {
  console.log(arr[index]); // O(1)
  console.log(arr[index]); // O(1)
  console.log(arr[index]); // O(1)
}
O(1) + O(1) + O(1) = O(1)

// O(n)
function countCharacters(str) {
  let count = 0; //O(1)
  for(let i = 0; i &lt;= str.length; i++){
    count++; // O(1)
  }
  return count; //O(1)
}
O(1) + n * O(1) * O(1) = O(n)


// O(n^2)
function buildMatrix(arr) {
  let matrix = []; //O(1)
  for (let i = 0; i &lt;= arr.lenth; i++){
      matrix[i] = []; //O(1)
      for (let j = 0; j &lt; arr.length; j++){
        matrix[i].push(arr[j]); //O(1)
    }
  }
  return matrix; //O(1)
}
O(1) + n * O(1) * n * (O(1) + O(1) = O(n^2)</code></pre><p>Big-O는 인풋의 증가에 따른 연산 처리시간의 증가율을 예측하는 척도</p>
<h3 id="자바스크립트에서-유용한-함수들의-시간복잡ㄷ">자바스크립트에서 유용한 함수들의 시간복잡ㄷ</h3>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/b9ac3c8a-1b89-41fa-ac30-db12617fc05a/image.png" alt="">
<img src="https://velog.velcdn.com/images/silverj-kim/post/56ea05f8-c03f-4077-ae45-dc165af5b1eb/image.png" alt=""></p>
<p>참고 <a href="https://www.youtube.com/watch?v=5Ky59iblLBI">https://www.youtube.com/watch?v=5Ky59iblLBI</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[브라우저의 렌더링 과정]]></title>
            <link>https://velog.io/@silverj-kim/%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/@silverj-kim/%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>Sun, 30 Jul 2023 06:44:16 GMT</pubDate>
            <description><![CDATA[<p>모던 자바스크립트 딥 다이브 스터디중!</p>
<p>웹 애플레이션의 클라이언트 사이드 자바스크립트는 브라우저에서 HTML, CSS와 함께 실행한다. 따라서 브라우저 환경을 고려할 때 보다 더 효율적인 클라이언트 사이드 자바스크립트 프로그래밍이 가능하다.</p>
<h2 id="자바스크립트의-기본-개념과-동작원리">자바스크립트의 기본 개념과 동작원리</h2>
<p>브라우저는 HTML, CSS, 자바스크립트로 작성된 텍스트 문서를 어떻게 파싱해서 브라우저에 렌더링 하는 걸까?</p>
<ol>
<li>브라우저는 HTML, CSS, Javascript, Image, Font 파일 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.</li>
<li>브라우저 렌더링 엔진은 서버로부터 응답된 HTML과 CSS를 파싱하여 DOM과 CSSOM을 생성하고 이를 결합하여 Render Tree를 생성한다.</li>
<li>브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 AST를 생성하고 바이트코드로 변환하여 실행한다.</li>
<li>렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅한다.</li>
</ol>
<blockquote>
<p>💡 AST Abstract Syntax Tree
컴퓨터 과학에서 추상 구문 트리(abstract syntax tree, AST), 또는 간단히 구문 트리(syntax tree)는 프로그래밍 언어로 작성된 소스 코드의 추상 구문 구조의 트리이다. 이 트리의 각 노드는 소스 코드에서 발생되는 구조를 나타낸다. 구문이 추상적이라는 의미는 실제 구문에서 나타나는 모든 세세한 정보를 나타내지는 않는다는 것을 의미한다.</p>
</blockquote>
<p>코드 텍스트에서 트리구조의 데이터 스트럭처를 만들어낸다. 코드에 있는 아이템이 각 트리에 있는 노드와 매치된다. 먼저, 렉시컬 분석을 통해 코드의 문자들을 읽어서 정해진 룰에 따라 토큰으로 만들어야 한다. 그런 후 syntax 분석에서는 앞서 나온 토큰 목록을 트리구조로 만든다. </p>
<br>

<h3 id="요청과-응답">요청과 응답</h3>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/07a9e2bd-1a5d-4bc7-abf6-a08a5466bfd6/image.png" alt="by wiki"></p>
<ol>
<li>브라우저 주소창에 위와 같은 URL을 입력한다. 이 때 <code>http://www.example.com</code> 와 같이 루트 요청을 하게 되면 일반적으로 index.html을 응답하도록 기본 설정이 되어 있다.</li>
<li>URL의 host 이름이 DNS를 통해 IP 주소로 변환되고 이 IP 주소를 갖는 서버에게 요청을 전송한다.</li>
</ol>
<blockquote>
<p>💡DNS
DNS는 IP 주소 및 기타 데이터를 저장하고 이름별로 쿼리할 수 있게 해주는 계층형 분산 데이터베이스입니다. 즉, DNS는 컴퓨터가 서로 통신하는 데 사용하는 숫자 IP 주소로 변환되는, 쉽게 읽을 수 있는 도메인 이름의 디렉터리입니다.</p>
</blockquote>
<br>

<h3 id="http-11과-http-20">HTTP 1.1과 HTTP 2.0</h3>
<h4 id="http">HTTP</h4>
<p>HTTP(HyperText Transfer Protocol)는 웹에서 브라우저와 서버가 통신하기 위한 요청/응답 프로토콜이다. 1990년대 초에 설계된 HTTP는 거듭하여 진화해온 <strong>확장 가능한</strong> 프로토콜이다. HTTP는 애플리케이션 계층의 프로노콜로 신뢰 가능한 전송 프로토콜이라면 이론상이로는 무엇이든 사용할 수 있으나 TCP 혹은 TLS를 통해 전송된다.</p>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/cf1c275a-223a-4b1a-870b-e3f63b54927f/image.png" alt=""></p>
<ul>
<li>확장 가능하다.</li>
<li>무상태성(Stateless)</li>
<li>비연결성(Connectionless) , 연결은 전송 계층에서 제어되므로 근본적으로 HTTP 영역 밖이다. </li>
</ul>
<h4 id="http-11">HTTP 1.1</h4>
<p>HTTP1.0과 1.1의 차이</p>
<ol>
<li><p>커넥션 유지 (Persistent Connection)
HTTP 프로토콜은 응용 계층의 프로토콜이다. HTTP를 통한 데이터 전송은 TCP 세션 기반에서 이루어진다.
<img src="https://velog.velcdn.com/images/silverj-kim/post/1951f668-9599-4d79-b929-2abbeb94e0cf/image.png" alt=""></p>
</li>
<li><p>0은 매번 데이터를 요청하고 수신할 때 마다 TCP 세션을 맺어야한다.
반면, 1.1은 한번의 TCP 세션에 여러 개의 요청을 보내고 응답을 수신할 수 있다.
TCP 세션 처리 부하를 줄이고 응답속도를 개선할 수 있다.</p>
</li>
<li><p>파이프라이닝 (Pipelining)
명령어를 순차적으로 실행하는 프로세서에 적용되는 기술로 여러개의 명령어를 실행하는 기법이다.
<img src="https://velog.velcdn.com/images/silverj-kim/post/b9d48aa0-e348-4cb8-9a5e-3f745a7c5aff/image.png" alt="">
HTTP 요청은 순차적으로 이루어진다. 파이프라이닝 기능이 없는 경우에는 요청에 대한 응답이 오고 나서 다음 요청을 할 수 있다. 만약 첫번째 요청이 실패한다면 2,3번째 요청은 진행하지 못한다는 단점이 있다.
파이프라이닝을 통하면 동시에 요청 1,2,3을 보내고 이에 대한 각각의 응답을 받아 처리할 수 있다.</p>
</li>
</ol>
<ol start="3">
<li>호스트 헤더 (Host Header)</li>
<li>0 환경에서는 하나의 IP에 여러 개의 도메인 운영이 불가능 해 도메인 만큼 서버의 개수도 늘어날 수 밖에 없는 구조이다.
<img src="https://velog.velcdn.com/images/silverj-kim/post/0e479bfa-37c7-41b5-bea0-f7dd9ceec0d2/image.png" alt=""></li>
<li>1에서부턴 Host 헤더의 추가를 통해 가상 호스팅(Virtual Hosting)이 가능해졌다.</li>
</ol>
<ol start="4">
<li>강력한 인증 절차 (Improved Authentication Procedure)</li>
<li>1에서 <code>proxy-authentication</code> 과 <code>proxy-authorization</code> 2개의 헤더가 추가되었다.
서버-클라이언트 사이의 인증을 요구하는 헤더는 1.0에도 있었으나 서버-클라 사이에 프록시가 있는 경우 프록시가 사용자의 인증을 요구할 수 있는 방법이 없었다.</li>
</ol>
<h3 id="http-20">HTTP 2.0</h3>
<p>15년만에 등장한 HTTP 2.0
1.1의 문제점을 개선한 2.0의 차이에 대해 알아보자.</p>
<ol>
<li>Multiplexed Streams</li>
<li>0에서 TCP 세션을 맺는 것을 중복해서 수행하는 성능 이슈가 있었고 1.1에서 파이프라이닝과 커넥션 유지로 해당 문제를 일부 해결했었다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/5e3db2cf-a249-494b-8ffb-c66b863b22c3/image.png" alt=""></p>
<p>2.0에서는 더 나아가 multiplexed 라는 기술을 도입해 1개의 세션으로 여러 개의 요청을 <strong>순서 상관없이</strong> Stream으로 받아서 동시다발적으로 처리하고 응답할 수 있다. 이는 1.1의 HOL 블로킹 (Head-Of-Line Blocking) 문제를 해결한다.</p>
<ol start="2">
<li>Stream Priorityzation
HTTP 2.0은 요청을 Stream 형식으로 처리하게 된다. 그리고 각 요청에 대한 Priority를 부여한다.</li>
</ol>
<ol start="3">
<li>Server Push
기존 1.1에서는 HTML 문서를 요청한 후 해당 문서에 필요한 CSS, assets를 추가 요청했었다.</li>
<li>0 부터는 HTML 문서를 요청하면 클라이언트가 추가로 요청을 하지 않아도 된다.</li>
</ol>
<ol start="4">
<li>Header Compression
클라와 서버는 각 Header Table을 관리하고, 이전 요청과 동일한 필드는 table의 index만 보내고 변경되는 값은 Huffman 인코딩 후 보냄으로 Header의 크기를 경량화 하였다.</li>
</ol>
<br>

<h3 id="html-파싱과-dom-생성">HTML 파싱과 DOM 생성</h3>
<p>서버가 응답한 HTML 문서는 문자열로 이루어진 순수한 텍스트이다. 그 문서를 브라우저에서 시각적인 픽셀로 렌더링하려면 HTML 문서를 브라우저가 이해할 수 있는 객체로 변환하여 메모리에 저장해야 한다.</p>
<p><img src="blob:https://velog.io/f5661dd3-9d2d-4458-8570-69b24b793b9c" alt="업로드중.."></p>
<ol>
<li>서버로부터 HTML 파일을 응답받는다. 응답된 바이트 형태의 문서는 meta 태그의 charset 어트리뷰트에 의해 지정된 인코딩 방식(UTF-8)을 기준으로 문자열로 변환된다. 브라우저는 이를 확인하고 문자열로 변환한다.</li>
<li>문자열로 변환된 HTML 문서를 읽어 들여 문법적 의미를 갖는 코드의 최소단위인 토큰으로 분해(lexical analysis) 한다.</li>
<li>각 토큰들을 객체로 변환한여 node를 생성한다. 노드는 이후 DOM을 구성하는 기본 요소가 된다.</li>
<li>HTML 문서는 HTML 요소들의 집합으로 이루어지며 HTML 요소는 중첩관계를 갖는다. 트리 자료구조를 구성하여 DOM을 만든다. (syntax analysis)</li>
</ol>
<br>

<h3 id="css-파싱과-cssom-생성">CSS 파싱과 CSSOM 생성</h3>
<p>렌더링 엔진은 DOM을 한 줄씩 파싱하여 DOM을 생성해가다 CSS를 로드하는 코드를 만나면 DOM생성을 일시 중단한다. CSS를 HTML과 동일한 파싱과정을 거쳐 CSSOM(css object model)을 생성한다.</p>
<br>

<h3 id="렌더-트리-생성">렌더 트리 생성</h3>
<p>HTML, CSS을 각각 파싱하여 DOM과 CSSOM을 생성한 후 렌더링을 위한 렌더 트리 render tree로 결합된다.
렌더 트리는 렌더링을 위한 트리구조의 자료구조로, 화면에 렌더링되지 않는 노드(ex. script tag) 나 css에 의해 비표시 (ex. display:none) 되는 노드들은 포함하지 않는다.</p>
<p>렌더트리는 각 HTML 요소의 레이아웃을 계산하는 데 사용되며 브라우저 화면에 픽셀을 렌더링하는 페인팅 처리에 입력된다.</p>
<pre><code>- 자바스크립트에 의한 노드 추가 또는 삭제
- 브라우저 창의 리사이징에 의한 뷰포트 크기 변경
- HTML 요소의 레이아웃 변경을 발생시키는 스타일 변경</code></pre><p>위와 같은 변경은 리플로우와 리페인팅을 발생시켜 성능에 악영향을 주니 주의해야 한다.</p>
<br>

<h3 id="자바스크립트-파싱과-실행">자바스크립트 파싱과 실행</h3>
<p>HTML 문서를 파싱한 결과물로 생성된 DOM은 문서의 구조와 정보 뿐 아니라 요소를 조작할 수 있는 DOM API도 제공한다. 자바스크립트 코드에서 DOM API를 사용하면 이미 생성된 DOM을 동적으로 조작할 수 있다.
CSS 파싱과 마찬가지로 DOM을 생성해다가 자바스크립트 파일 로드 코드를 마주하면 DOM 생성을 일시 중지한다. script 태그 내 코드를 파싱하기 위해서는 렌더링 엔진 -&gt; 자바스크립트 엔진으로 제어권을 넘긴다. 따라서 다시 렌더링 엔진으로 제어권이 돌아왔을 때 DOM을 이어 생성한다.</p>
<p>자바스크립트 엔진은 자바스크립트 코드를 파싱하여 CPU가 이해할 수 있는 저수준 언어로 변환하고 실행하는 역할을 한다. V8, SpiderMonkey, JavascriptCore 등이 존재하며 모두 ECMAScript를 준수한다. 또, 자바스크립트 엔진은 자바스크립트 코드를 해석하여 AST(Abstract Synctax tree)를 생성하고 그걸 기반으로 인터프리터가 실행할 수 있는 중간코드인 바이트 코드를 생성하여 실행한다.</p>
<pre><code>Javascript &gt; Token &gt; AST &gt; ByteCode &gt; 인터프리터에 의해 실행</code></pre><br>

<h3 id="리플로우와-리페인팅">리플로우와 리페인팅</h3>
<p>한번 생성한 DOM, CSSOM 을 다시 변경시키면 다시 Render tree를 결합하고 그 렌더트리를 기반으로 레이아웃과 페인팅 과정을 거쳐 다시 브라우저 화면에 렌더링한다. 레이아웃계산을 다시 하는 것을 <strong>리플로우</strong>, 재결합된 렌더트리를 다시 페인팅 하는 것은 <strong>리페인팅</strong> 이라고 한다. 
무조건 같이 실행되는 것은 아니고 레이아웃의 영향이 없는 변경은 리페인팅만 실행된다. </p>
<br>

<h3 id="자바스크립트-파싱에-의한-html-파싱-중단">자바스크립트 파싱에 의한 HTML 파싱 중단</h3>
<p>브라우저는 동기적으로 HTML 코드를 읽어 순차적으로 파싱되기 때문에 script태그의 위치에 따라 에러가 발생될 수 있다. DOM이 생성되기 전에 자바스크립트에서 DOM을 조작한다면 에러가 발생할 것이다. 이런 에러를 방지하기 위해 script 코드는 아래에 위치 시키는 것이 좋다.</p>
<br>

<h3 id="script-태그의-asyncdefer">script 태그의 async/defer</h3>
<p>DOM 생성이 중단되는 문제를 근본적으로 해결하기 위해 HTML5부터 script 태그에 async와 defer 어트리뷰트가 추가되었다.</p>
<p>두 어트리뷰트 모두 파일의 로드가 비동기적으로 진행된다는 공통점이 있다. 하지만 자바스크립트의 실행 시점에 차이가 있다.</p>
<pre><code>&lt;script async src=&quot;x.js&quot;/&gt;</code></pre><p>자바스크립트의 파싱과 실행은 자바스크립트 파일의 로드가 완료된 직후 진행되면 이 때 HTML 파싱이 중단된다. 여러 개 사용 시 순서가 보장되지 않는다. 순서 보장이 필요하면 async를 지정하지 않아야 한다.</p>
<pre><code>&lt;script defer src=&quot;x.js&quot;/&gt;</code></pre><p>자바스크립트의 파싱과 실행은 HTML 파싱이 완료된 직후, DOM 생성이 완료된 직후 (DOMContentLoaded event 실행) 진행된다. DOM 생성이 완료된 이후 실행되어야 할 자바스크립트에 유용하다.</p>
<p><a href="https://yceffort.kr/2021/05/ast-for-javascript">https://yceffort.kr/2021/05/ast-for-javascript</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Overview">https://developer.mozilla.org/ko/docs/Web/HTTP/Overview</a>
<a href="https://withbundo.blogspot.com/2021/02/http-http-10-http-11.html">https://withbundo.blogspot.com/2021/02/http-http-10-http-11.html</a>
<a href="https://jaehoney.tistory.com/281">https://jaehoney.tistory.com/281</a>
<a href="https://ko.javascript.info/dom-nodes">https://ko.javascript.info/dom-nodes</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 Business Logic의 분리]]></title>
            <link>https://velog.io/@silverj-kim/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-Business-Logic%EC%9D%98-%EB%B6%84%EB%A6%AC</link>
            <guid>https://velog.io/@silverj-kim/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-Business-Logic%EC%9D%98-%EB%B6%84%EB%A6%AC</guid>
            <pubDate>Sun, 16 Jul 2023 06:09:51 GMT</pubDate>
            <description><![CDATA[<p>프로젝트가 점점 복잡해지고 오래될수록 코드를 유지하는데 비용을 최소화하고 싶은 니즈가 커지게 된다. 따라서 복잡하고 이해가 안되는 코드를 개선하고 싶은 마음이 든다. 
CSR이 핫해지면서 프론트엔드 프로젝트도 점점 복잡해지기 시작했고 잘 설계하기 위해 여러가지 프론트엔드 아키텍처가 나오고 있다. 자바스크립트와 React로 개발을 처음 시작한 나에게는 유명한 아키텍처들도 생소한 패턴이었다. 하지만 직접 React로 2년정도 프로젝트 코드를 작성하다보니 코드가 점점 복잡해지고 비즈니스로직과 뷰로직을 분리하고 싶다는 니즈가 생겨났다.</p>
<h2 id="왜-business-logic를-분리해야-하나">왜 Business Logic를 분리해야 하나</h2>
<p>View와 Business Logic은 맡은 임무, 책임이 다르다. 따라서 각자의 수정 이유가 다르다.
이 로직들이 분리되지 않고 섞여있다면 해당 로직이 어디에 있는 지 찾기 위해 두 로직이 섞여있는 컴포넌트 코드를 모두 살펴봐야 한다. 간단한 변경이어도 이 모든 걸 파악해야 한다.</p>
<h2 id="view-logic">View logic</h2>
<p>우리가 만든 소프트웨어에 사용자가 접근하는 방식을 의미한다. 사용자가 보는 UI, 사용자 인터페이스</p>
<p>View는 어떻게 동작하나? View는 우리가 전달하고 하는 정보를 전달하고 필요하다면 사용자로부터 행동을 입력받고 상호작용한다. 우리는 그 행동을 이벤트를 통해 알 수 있다. 
<img src="https://velog.velcdn.com/images/silverj-kim/post/47dcc1e0-c10c-4dee-ab78-ec00e1fe8c10/image.png" alt=""></p>
<pre><code>function Component() {
  const [showBanner, setShowBanner] = useState(false);

  const changeAgreementHandler = (e) =&gt; {
      const { target: { checked }} = e;
    const lastDateOfEvent = new Date(...);
    const now = new Date();

    setShowBanner(now &lt; lastDateOfEvent &amp;&amp; checked);
  }

  return (
      &lt;div&gt;
        {showBanner &amp;&amp; &lt;Banner /&gt;)
        &lt;input type=&quot;checkbox&quot; onChange={changeAgreementHandler} /&gt;
    &lt;/div&gt;
  )
}</code></pre><p>유저로부터 Event를 전달받고 State를 통해 HTML을 업데이트 하게 된다. 위 코드에서 View logic은?
<strong>View logic</strong></p>
<pre><code>    const changeAgreementHandler = (e) =&gt; {
           ...
      setShowBanner(...);
    }</code></pre><p>사용자로부터 전달받은 이벤트를 통해 UI를 업데이트하는 부분, 배너의 노출여부(showBanner)를 업데이트하는 showBanner의 변경 코드는 뷰로직이라고 할 수 있다.</p>
<pre><code>const lastDateOfEvent = new Date(...);
const now = new Date();
...
now &lt; lastDateOfEvent &amp;&amp; checked</code></pre><p>그럼 여기가 비즈니스 로직인가?</p>
<h2 id="business-logic">Business Logic</h2>
<p>내가 참고한 이문기님의 글에 의하면 <code>Business Logic은 현실 세계의 비지니스 규칙을 프로그램으로 표현한 부분</code> 이라고 정리해주셨다. 우리 프로젝트만의 비지니스 규칙이 들어간 로직이라고 이해하면 좀 더 쉽다.
배너를 노출하고 말지는 비지니스 규칙이 아니지만 이벤트 기간이 아직 끝나지 않았을 때 배너를 노출하는 건 비지니스 규칙이니까!</p>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/43b14037-9769-4b40-a69a-e88bb1429169/image.png" alt=""></p>
<p>두 로직이 섞여 거기서 오는 혼란을 최소화하기 위해서는 View와 Business Logic이 명확하게 구분되는 아키텍처로 코드가 작성되어야 한다.</p>
<h3 id="business-logic을-분리하는-방법들">Business Logic을 분리하는 방법들</h3>
<h4 id="1-business-logic을-위한-함수를-만든다">1. Business Logic을 위한 함수를 만든다.</h4>
<pre><code>function canShowEventBannerIf(agreeWithTerm, lastDateOfEvent) {
  if (agreeWithTerm) {
    const now = new Date();

    return now &lt; lastDateOfEvent;
  }
  return false;
}

const changeTermAgreementHandler = (event) =&gt; {
    const { target: { checked } } = event;
    const lastDateOfEvent = new Date(...);
    const canShow = canShowEventBannerIf(checked, lastDateOfEvent);

    setShowEventBanner(canShow);
  };</code></pre><p>이전보다는 비즈니스 로직 구분이 명확해졌다. 하지만 문제점이 있다.
<code>canShowEventBannerIf</code> 함수만으로는 자신의 역할에 책임을 다 할 수 없기 때문에 책임을 다하려면 값에 대해 외부에 의존적이게 된다. 또는 책임을 다하기 위해 값을 갖게되면 함수 자체가 변화에 유연하지 않다. 결국 외부의 환경이 달라지면 함수는 그 요구에 맞춰 힘겹게 변화해야 한다.</p>
<h4 id="2-class-를-활용한다">2. Class 를 활용한다.</h4>
<pre><code>/** ... */
class EventDate {
  #lastDateOfEvent;
  #offset = 0;

  constructor(lastDateOfEvent, offset = 0) {
    this.lastDateOfEvent = lastDateOfEvent;

    // lastDateOfEvent보다 offset만큼 과거를 계산할 때 사용합니다.
    this.offset = offset;
  }

  /** ... */
  canShowEventBannerIf(agreeWithTerm) {
    if (agreeWithTerm) {
      const now = new Date();
      const lastDateOfEventPastByOffset =
        this.lastDateOfEvent - this.offset;

      return now &lt; lastDateOfEventPastByOffset;
    }

    return false;
  }

  /** ... */
  get() {
    return this.lastDateOfEvent;
  }

  /**
   * @description 값을 비교할 때 사용합니다.
   * @param {EventDate} anotherEventDate
   * @returns {boolean} 
   */
  isEqual(anotherEventDate) {
    ...
  }
}

function Component() {
  const [showEventBanner, setShowEventBanner] = useState(false);
  const [eventDate, setEventDate] = useState(new EventDate(...) /* 이벤트 Date 입니다 */);
  const changeTermAgreementHandler = (event) =&gt; {
    const { target: { checked } } = event;
    const canShow = eventDate.canShowEventBannerIf(checked);

    setShowEventBanner(canShow);
  };
  ...
}</code></pre><p>갑자기 eventDate를 state로 관리하게 된 이유는 <code>Component</code>의 렌더링에 개입하기 위해서다.
비즈니스 로직에 필요한 값을 전역 상태로 관리하는 게 익숙하다보니 값이 바뀌면 자연스레 렌더링이 되길 바랬고 그 때 마다 새 인스턴스를 만들어야 했다. 그 전 값을 유지하기 위해 constructor에 더 많은 파라미터가 필요해졌고 더 복잡한 클래스를 작성하게 되었다. <code>또, 비즈니스 로직을 수정할 때 뷰 로직까지 모두 살펴봐야 했다.</code> (요 부분은 나는 잘 이해가 가지 않는다.) 무튼 그러다 보니 비즈니스로직만 따로 떼어서 테스트하기가 불안해지고, 뷰와 함께 테스트하려니 테스트 비용도 올라갔다.</p>
<p>그 원인은
<img src="https://velog.velcdn.com/images/silverj-kim/post/06dc5733-4881-4e3d-8b63-426e0a8cc0a1/image.png" alt=""></p>
<p>지금까지 한 시도는 비즈니스로직과 뷰로직을 분리한 게 아니고, 비즈니스로직은 뷰 안에서 뷰의 상태를 관리하도록 분리했기 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/63e7d066-22d1-48a6-b4c3-76b0b024c8c4/image.png" alt=""></p>
<p>우리가 원하는 건 View와 API Server 처럼 동작하는 게 아닐까?
API 서버에 요청하고 응답하는 구조를 봤을 때, 그 곳엔 View의 상태가 존재하지 않는다. View에선 응답으로 받은 값을 어떻게 활용할지만 결정한다. API 서버 입장에선 View가 어떤 로직으로 움직이는지 신경쓰지 않는다. 따라서 비즈니스 로직이 이렇게 동작하려면 우선 View의 상태에서 분리할 필요가 있다.</p>
<h3 id="3-useref의-활용">3. useRef의 활용</h3>
<pre><code>  const eventDate = useRef(new EventDate(...) /* 이벤트 Date 입니다 */).current;</code></pre><p>useRef를 활용해 비즈니스 로직이 더이상 상태에 관여하지 않게 작성한다.
비즈니스로직에 요청하는 건 View고 비즈니스 로직의 응답을 활용하는 권한도 View에 있다. 비즈니스 로직은 자신의 책임만 다할 뿐 나머지는 View가 담당한다. 다만 익숙하지않은 패턴임은 분명하다. </p>
<h2 id="분리했을-때의-효과-관심사의-분리">분리했을 때의 효과: 관심사의 분리</h2>
<p>제시한 방법은 방법일 뿐 핵심은 두 로직을 분리하자. 이다. View와 Business logic을 분리하면 각 관심사를 분리할 수 있다.
관심사를 분리하면 책임이 명확해지고 그에 따라 유지보수도 쉬워진다. 또 테스트 작성도 쉬워진다.
View와 Business logic이 결합되어 있다면 간단한 조건 수정을 할 때 View에 잘 반영되는지까지 확인해야하기 때문이다.</p>
<p>뷰 로직과 비즈니스 로직을 분리하고자 하는 생각은 최근에 나온 건 아니다. 이미 한번은 들어봤을 프론트엔드 아키텍처도 존재할 거다. 더 좋은 설계를 하기위한 고민들은 항상 있어왔다.</p>
<h2 id="프론트엔드-아키텍처">프론트엔드 아키텍처</h2>
<h3 id="mvc">MVC</h3>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/a54fb245-9ec9-4ba6-af69-49e2fe62b9d2/image.png" alt=""></p>
<p>Model - View - Controller</p>
<p>Model: Data model, DB에서 받아온 데이터 혹은 API 등으로 받아온 데이터 <code>Ajax로 받아온 데이터</code>
View : HTML과 CSS로 렌더링되는 화면, UI
Controller : Model의 데이터를 받아 View가 화면에 그리고 다시 사용자의 동작을 받아 Model을 변경하게 해주는 것, Model과 View 사이의 중간 역할 <code>서버의 데이터를 받아 화면을 바꾸고 이벤트를 처리하여 서버에 데이터를 전달하는 Javascript</code></p>
<h3 id="mvvm-데이터-바인딩--템플릿">MVVM 데이터 바인딩 + 템플릿</h3>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/43ffa0b5-d6bc-4185-939f-d28206a6da5c/image.png" alt=""></p>
<p>Model - View - View Model</p>
<p>Model : Data Model, 도메인 특화 데이터를 처리
View : UI
View Model : View를 그리는 Model만 다룸, state를 변경하면 즉시 View에 반영</p>
<p>템플릿과 같은 선언적인 방식으로 개발을 할 수 있게 됨
ㄷ</p>
<h3 id="container---presenter">Container - Presenter</h3>
<p>Presenter : 데이터를 받아서 보여주기만 하는 Component
Container : 데이터 조작을 주로 다루는 Component</p>
<p>로직을 한 군데에 모두고 View는 재사용하는 형태의 아키텍처</p>
<h3 id="flux--redux">FLUX : Redux</h3>
<p>컴포넌트의 독립과 재사용성을 위해 컴포넌트를 분리했지만 오히려 상위와 하위 컴포넌트 간의 결합도가 올라가는 Props drilling 문제를 해결하기 위한 방안
비즈니스로직을 굳이 컴포넌트 계층구조로 만들 필요가 없다는 것을 깨닫고 데이터를 조작하는 로직은 별개로 두고 Action이라는 매개체를 통해서 데이터를 변경, 이를 컴포넌트에 직접 연결하는 방법이 나오게 됨
<strong>View와 비즈니스 로직을 분리하고 단방향 데이터 구조를 가지는 FLUX 패턴</strong></p>
<h3 id="hooks--context">hooks &amp; Context</h3>
<p>Redux의 경우 너무나 많은 보일러플레이트가 필요하고 복잡하며 러닝커브가 너무 높다는 등의 문제점이 제기되었다. 간단한 프로젝트의 경우 오버엔지니어링되는 경향이 있었다.
<code>hooks</code>를 통해 외부 비즈니스 로직을 쉽게 연결할 수 있고 <code>Context</code>를 통해 Props Driliing 없이도 상위 props를 하위로 전달할 수 있게 되었따.</p>
<p>더 나아가 전역 상태 관리 라이브러리도 등장 Recoil, Zustands, jotai
Atom이라고 불리는 전역객체를 이용해 데이터를 기록하고 변경감지를 통해 View로 전달하는 방식</p>
<h3 id="서버-api를-통한-global-state-management-react-query">서버 API를 통한 Global state management: React Query</h3>
<p>브라우저의 경우 데이터를 로컬에 잘 보관하지 않기 때문에 프론트엔드 대부분의 전역상태관리가 필요한 이유는 서버 API이다. 비즈니스 로직이 대부분 백엔드에 보관되고 있기 때문이다.</p>
<p>백엔드와 직접 연동하면서 필요한 로딩, 캐싱, 무효화, 업데이트 등 기존 상태관리에 복잡하게 진행되어야했던 로직을 단순하게 만들어주는 방식도 생겨났다.</p>
<h3 id="mvi">MVI</h3>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/52936595-f3de-40d4-a624-dd2629a66e62/image.png" alt=""></p>
<p>위 그림을 통해 비즈니스 로직을 두가지 레이러로 나눌 수 있다.</p>
<p>  1) 사용자가 View를 통해서 전달한 UI Event로 어떠한 데이터 변화를 하게 할 지 전달하는 역할 <strong>=&gt; intent(의도)</strong>
  2) 전달받은 요청에 따라서 적절히 데이터를 변화하는 역할 <strong>=&gt;model(데이터)</strong></p>
<p><img src="https://velog.velcdn.com/images/silverj-kim/post/80f7068f-fe29-40d0-8948-9788f214ff1e/image.png" alt=""></p>
<p>전체적으로 데이터의 방향성이 단방향 이다. 또 데이터가 전역적으로 구성된다.
View 는 Model에 의존적이지만 Business logic은 View와 의존성이 없기 때문에 화면변화에 유연하다. 따라서 유지보수도, 테스트 작성도 쉽다.
뷰는 비즈니스 로직에 의존적이지만 뷰끼리는 느슨하게 결합되어 UI 요구사항에 대응할 수 있다.</p>
<p><code>뷰에서는 의도만 전달</code>하고 <code>의도에 맞는 데이터 변환은 모델</code>에서만 처리할 수 있도록 데이터를 ㅂ녀화하는 코드를 <code>Model 모듈에 모으게 되면 응집도가 높아지고</code>, <code>UI와 비즈니스 로직 간의 결합도를 낮출 수 있다.</code></p>
<p>참고</p>
<p><a href="https://medium.com/@shinbaek89/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-business-logic%EC%9D%98-%EB%B6%84%EB%A6%AC-adc10ae881ab">https://medium.com/@shinbaek89/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-business-logic%EC%9D%98-%EB%B6%84%EB%A6%AC-adc10ae881ab</a></p>
<p><a href="https://medium.com/@shinbaek89/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EC%A7%80%EB%8B%88%EC%8A%A4-%EB%A1%9C%EC%A7%81%EA%B3%BC-%EC%82%AC%EB%A1%80-f09774f53a3b">https://medium.com/@shinbaek89/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EC%A7%80%EB%8B%88%EC%8A%A4-%EB%A1%9C%EC%A7%81%EA%B3%BC-%EC%82%AC%EB%A1%80-f09774f53a3b</a></p>
<p><a href="https://velog.io/@teo/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-MV-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94">https://velog.io/@teo/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-MV-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</a></p>
<p><a href="https://velog.io/@teo/MVI-Architecture?utm_source=oneoneone">https://velog.io/@teo/MVI-Architecture?utm_source=oneoneone</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래밍 인터페이스 디자인하기]]></title>
            <link>https://velog.io/@silverj-kim/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%94%94%EC%9E%90%EC%9D%B8%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@silverj-kim/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%94%94%EC%9E%90%EC%9D%B8%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 29 May 2023 06:04:35 GMT</pubDate>
            <description><![CDATA[<h1 id="rest">REST</h1>
<p>Representational State Transfer</p>
<h2 id="rest-api-호출-분석">REST API 호출 분석</h2>
<p>HTTP 프로토콜을 사용하여 REST API 를 요청해야 한다.</p>
<p>경로: 서버상의 리소스를 식별할 수 있는 주소
HTTP 메서드: 이 리소스를 가지고 무슨 <strong>행위</strong>를 하고 싶은 지 표시해주는 역할
HTTP 상태 코드: 접수된 요청의 처리가 어떻게 되어가는지를 의미
Response body: 요청의 경로로 식별된 리소스의 콘텐츠를 포함</p>
<blockquote>
<p>JSON 데이터 포맷
JSON은 초기엔 Javascript 프로그래밍에서 데이터를 표현하기 위해 등장했던 텍스트 데이터 포맷이지만 그 이름과 달리 지금은 언어와 상관없이 사용할 수 있다.
JSON은 어떤 프로그래밍 언어에서든 처리하기가 용이하고 읽고 쓰기가 쉽다. 이러한 장점 덕에 JSON은 데이터베이스와 설정 파일 등에서 사용되며 당연히 API 에서도 쓰기고 있다.</p>
</blockquote>
<h2 id="http의-기초-사항">HTTP의 기초 사항</h2>
<p>HTTP는 WWW(World Wide Web)의 기초다.
프로그래밍 언어에 구애받지 않는 프로토콜로 애플리케이션 간 문서(리소스)를 인터넷을 통해 주고받을 목적으로 디자인 되었다.</p>
<p>HTTP는 광범위한 애플리케이션에서 사용되고 있지만 가장 유명한 것은 웹 브라우저이다.
웹 브라우저는 HTTP를 이용하여 웹 서버가 호스팅하는 웹 사이트와 의사소통한다. </p>
<p><a href="http://abc.com/about">http://abc.com/about</a> 이라고 주소창에 입력하면
abc.com 을 호스팅하는 서버로 GET /about HTTP request
response로 위 URL에 해당하는 HTML 페이지를 보내준다.</p>
<p>목적이 무엇이든 기본 HTTP 요청에는 HTTP 메서드와 리소스 경로가 꼭 포함된다. HTTP 메서드는 경로로 식별된 자원으로 수행할 작업을 나타낸다.</p>
<h2 id="rest-api">REST API</h2>
<p>REST API는 HTTP 프로토콜을 이용해서 목표를 표현한다.
GET (가져오다), POST (보내다)
리소스는 경로로 식별되며 액션은 HTTP 메서드를 의미한다. </p>
<p>리소스를 프로그래밍적 표현으로 옮기기 전에 우선 기능적 요구사항을 분석해야 한다.
우선 리소스와 리소스 사이의 관계를 식별해야 하고, 리소스별로 가능한 액션과 파라미넡, 무엇이 리턴되는지 식별해야 한다.</p>
<p>리소스들은 다른 리소스들과 관계가 있을 수도, 없을 수도 있다. 또한 일정한 타입의 리소스 여러 개를 포함하는 리소스도 있다.
이런 리소스를 <strong>콜렉션</strong> 이라 부른다.</p>
<p>REST 리소스의 경로는 반드시 <strong>유일</strong>해야 한다. 이 점을 제외하면 REST의 공식적인 규칙은 없다.
ex. /c, /{productId}
{productId} 같은 경로에서 쓰이는 변수들은 경로 파라미터 path parameter라고 부른다.</p>
<p>하지만 c 보다는 명시적으로 경로를 구성하는 편이 더 좋다. c 대신 catalog로 사용하는 게더 좋다.
사또한 리소스를 폴더 같은 계층적 구조로 표현할 수  있다. 즉 상품의 경우 /products/{productId}로 표현할 수 있다.</p>
<p>리소스의 경로는 반드시 사용자 친화적이어야 한다. API는 사용자들이 경로를 해석하기 쉬어야 하기 때문에 경로에서 많은 정보를 제공할수록 더 좋다.</p>
<h4 id="쿼리-파라미터">쿼리 파라미터</h4>
<p>파라미터는 일반적인 경로 뒤 ? 다음에 있게 된다. name=value 형태.
만약 여러개라먼 &amp;(앰퍼샌드) 로 연결해준다.</p>
<h4 id="http-method">HTTP METHOD</h4>
<table>
  <tr>
    <th>Method</th>
    <th>Meaning</th>
    <th>Req parameters</th>
    <th>Return</th>
  </tr>
  <tr>
    <td>POST</td>
    <td>리소스의 생성하기</td>
    <td>리소스 정보</td>
    <td>새로 생성된 리소스의 컨텐츠</td>
  </tr>
  <tr>
    <td>GET</td>
    <td>리소스 가져오기</td>
    <td>X</td>
    <td>리소스에 해당하는 콘텐츠</td>
  </tr>
  <tr>
    <td>DELETE</td>
    <td>리소스 삭제하기</td>
    <td>X</td>
    <td>X</td>
  </tr>
  <tr>
    <td>PATCH</td>
    <td>리소스 일부 수정하기</td>
    <td>수정하고 싶은 정보</td>
    <td>X</td>
  </tr>
  <tr>
    <td>PUT</td>
    <td>리소스 교체, 없는 경우 생성할 수 있음</td>
    <td>교체(또는 생성)하고 싶은 정보</td>
    <td>X (생성된 경우는 생성된 리소스)</td>
  </tr>
</table>

<p>HTTP 메서드의 기본적인 CRUD(Create, Read, Update, Delete) 기능과 매핑 시킬 수 있다.
이 액션들은 컨슈머 관점에서 만들어진 것이기 때문에 DELETE로 요청했다고 해서 실제 데이터베이스에서 해당 리소스를 정말 삭제해야한다는 의미는 아니다.
단순히 상태를 inactive로 변경할 수도 있다.</p>
<h3 id="api-데이터-디자인하기">API 데이터 디자인하기</h3>
<p>API 의 디자인은 데이터베이스, 구조체, 오브젝트와 같은 여타 프로그래밍적인 표현과 똑같이 시작한다. 단순히 속성 property를 나열하고 컨슈머 관점을 고수하는 것이다.
<strong>컨슈머가 반드시 데이터를 이해하도록 만드는 동시에 내부 동작 원리를 노출하지 않는 디자인을 만들어야 한다.</strong></p>
<h4 id="파라미터-디자인">파라미터 디자인</h4>
<p>속성이 필수인지 아닌지 나타내는 것은 컨슈머와 프로바이더 모두에게 매우 중요하다. 컨텍스트에 따라 필수 여부가 다를 수 있기 때문이다. </p>
<p>상품이 생성될 때 상품의 식별자인 참조 정보는 백엔드에서 생성된다. 그래서 컨슈머가 상품을 추가할 때 리퀘스트에 참조 정보를 포함해서 전달할 필요가 없다. createdAt과 같이 백엔드에서 시점을 알아서 생성할 수 있는 속성은 파라미터에 포함할 필요가 없다.</p>
<h4 id="데이터-소스에서-파라미터-확인">데이터 소스에서 파라미터 확인</h4>
<p>컨슈머는 반드시 파라미터로 필요한 데이터를 모두 제공할 수 있어야 한다. 만약 데이터가 제공되지 않았다면 목표를 놓쳤거나 프로바이더 관점이 남아있을 가능성이 크다.</p>
<h4 id="trade-off">Trade off</h4>
<p>REST 리소스의 액션을 HTTP 메서드와 연결짓는 것을 실패할 때, 가장 먼저 해볼 수 있는 선택지는 액션 그 자체를 의미하는 리소스를 만드는 것.
액션 리소스는 명사로 표현되지 않고 <strong>동사</strong>로 표현된다.
ex. POST cart/check-out, POST /check-out-cart</p>
<blockquote>
<p>HTTP 메서드 POST는 유즈케이스에 적합한 다른 메서드가 없을 때 기본으로 택하는 메서드다.</p>
</blockquote>
<p>사용자 편의성과 규칙 준수 사이에서 균형을 잘 잡아야 한다!</p>
<h3 id="api를-디자인할-때-rest가-중요한-이유">API를 디자인할 때 REST가 중요한 이유</h3>
<p>Xerox Courier RPC -&gt; SOAT -&gt; REST -&gt; gRPC, GraphQL
예로부터 지금까지 소프트웨어를 원격에서 커뮤니케이션할 수 있게 해주는 프로그래밍 인터페이스는 늘 존재했으며, 각 각의 명세와 장단점을 가지고 있다.
하지만 그게 무엇이든 간에 API 를 디자인하는 행위는 같은 목표를 가지고 있다. </p>
<h4 id="rest-아키텍처">REST 아키텍처</h4>
<p>REST 아키텍처 스타일의 목표는 효율적이고 확장 가능하며 안정적인 분산시스템을 구축하는 것이다. 분산 시스템은 함께 작동하고 네트워크를 통해 커뮤니케이션하는 서로 다른 컴퓨터에 있는 소프트웨어 조각으로 구성된다.</p>
<p>장점</p>
<ul>
<li>Efficiency 효율성: 반드시 빠른 네트워크를 통한 커뮤니케이션과 리퀘스트 처리 능력이 있어야 한다.</li>
<li>Scalability 확장성: 갈 수록 더 많은 리퀘스트를 처리할 수 있어야 한다.</li>
<li>Reliability 신뢰성: 결함에 대한 내성이 있어야 한다.</li>
<li>Reusability 재사용성: 컴포넌트의 이식성</li>
<li>Simplicity 단순성</li>
<li>Modifiability 변경 용이성</li>
</ul>
<p>위 모든 것들을 충족하기 위해서는 소프트웨어 아키텍처가 아래의 제약사항을 충족해야한다.</p>
<h3 id="restful">RESTFul</h3>
<ul>
<li><p>클라이언트/서버 분리</p>
</li>
<li><p>스테이트리스 stateless : request를 처리하는데 필요한 모든 정보는 해당 request에 포함되어 있어야 한다. 클라이언트는 요청을 처리하는데 필요한 그 어떤 컨텍스트도 서버의 세션에 담지 않는다.</p>
</li>
<li><p>캐시 가능성 Cacheability : request에 대한 response는 저장 가능 여부(재요청을 하지 않고 재사용할 수 있는) 및 기간을 표시해야 한다.</p>
</li>
<li><p>레이어드 시스템 Layered system : 클라이언트가 서버와 상호작용 할 때, 오직 서버만을 알고 있어야 한다. 인프라는 뒷단에 숨겨져 있어야 하며 하나의 레이어만 볼 수 있어야 한다.</p>
</li>
<li><p>코드 온 디멘드 Code on demand : 서버는 필요하다면 클라이언트에 실행간으한 코드를 전송할 수 있어야 한다. (ex. javascript)</p>
</li>
<li><p>유니폼 인터페이스 Uniform interface : 모든 상호작용은 식별된 리소스의 개념에 따라 이루어져야 한다. 또한 상호작용은 리소스의 표현이 무엇을 의미하는 지와 이 리소스들로 무엇을 할 수 있는지 알려줄 수 있는 모든 메타데이터를 제공해야 한다.</p>
<p><strong>REST 인터페이스를 사용하는 것은 리소스 상태의 표현을 전송하는 것</strong>으로 구성된다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 SOLID]]></title>
            <link>https://velog.io/@silverj-kim/%EB%A6%AC%EC%95%A1%ED%8A%B8-SOLID</link>
            <guid>https://velog.io/@silverj-kim/%EB%A6%AC%EC%95%A1%ED%8A%B8-SOLID</guid>
            <pubDate>Sun, 04 Dec 2022 07:15:17 GMT</pubDate>
            <description><![CDATA[<h1 id="solid-principles">SOLID principles</h1>
<p>객체 지향 프로그래밍 (OOP) 에서 자주 나오는 설계 원칙 5개 S.O.L.I.D</p>
<h2 id="s-single-responsibility">S Single Responsibility</h2>
<p>단일 책임 원칙
&quot;every class should have only one responsibility&quot;
클래스는 단일 책임을 가져야 한다. 한 클래스가 많은 책임이 있는 경우 책임 중 하나를 변경하면 사용자도 모르게 사이드이펙이 나올 수 있는 가능성이 많아진다.</p>
<pre><code>export function Good() {
  const { products } = useProducts();

  //data filter는 hook에서
  const { filterRate, handleRating } = useRateFilter();

  return (
    &lt;div className=&quot;flex flex-col h-full&quot;&gt;
      //필터 View 로직은 Filter 컴포넌트에서
      &lt;Filter
        filterRate={filterRate as number}
        handleRating={handleRating}
      /&gt;
      &lt;div className=&quot;h-full flex flex-wrap justify-center&quot;&gt;
        {filterProducts(products, filterRate).map((product: any) =&gt; (
          //Product View 로직은 Product 컴포넌트에서
          &lt;Product product={product} /&gt;
        ))}
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><h2 id="o-open-closed">O Open Closed</h2>
<p>개방-폐쇄 원칙
&quot;software entities should be open for extension but closed for modification&quot;
클래스는 확장에는 열려있어야 하지만 수정에는 닫혀있어야 한다.
클래스의 현재 동작을 변경하면 해당 클래스를 사용하는 모든 시스템에 영향을 미친다. 이미 존재하는 기능을 변경하지 않고 추가하는 것이 중요하다.</p>
<pre><code>
interface IButtonProps
  extends React.ButtonHTMLAttributes&lt;HTMLButtonElement&gt; {
  text: string;
  // role?: &quot;back&quot; | &quot;forward&quot; | &quot;main&quot; | &quot;not-found&quot;; //bad
  icon?: React.ReactNode; //good
}

export function Button(props: IButtonProps) {
  const { text, role, icon } = props;

  return (
    &lt;button
      className=&quot;flex items-center font-bold outline-none pt-4 pb-4 pl-8 pr-8 rounded-xl bg-gray-200 text-black&quot;
      {...props}
    &gt;
      {text}
      &lt;div className=&quot;m-2&quot;&gt;
        {/* bad
          {role === &quot;forward&quot; &amp;&amp; &lt;HiOutlineArrowNarrowRight /&gt;}
          {role === &quot;back&quot; &amp;&amp; &lt;HiOutlineArrowNarrowLeft /&gt;}
        */}
        {/* good */}
        {icon}
      &lt;/div&gt;
    &lt;/button&gt;
  );</code></pre><h2 id="l-liskov-substitution">L Liskov Substitution</h2>
<p>리스코프 치환 원칙
&quot;subtype object shoul d be substitutable for subtype objects&quot;
S가 T의 자식 타입인 경우, T 타입 개체는 속성변경 없이 S 개체로 대체 될 수 있다.
하위 클래스가 상위 클래스와 동일한 작업을 수행할 수 없는 경우 버그가 발생할 가능성이 높다.
하위 클래스는 상위 클래스와 동일한 결과를 제공하거나 동일한 타입의 결과를 제공할 수 있어야 한다.</p>
<pre><code>
interface ISearchInputProps
  extends React.InputHTMLAttributes&lt;HTMLInputElement&gt; {
  isLarge?: boolean;
}

export function SearchInput(props: ISearchInputProps) {
  const { value, onChange, isLarge, ...restProps } = props;

  return (
    &lt;div className=&quot;flex w-10/12&quot;&gt;
      ...
        &lt;input
          type=&quot;search&quot;
          id=&quot;default-search&quot;
          className={cx(
            &quot;block p-4 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 outline-none&quot;,
            isLarge &amp;&amp; &quot;text-3xl&quot;
          )}
          placeholder=&quot;Search for the right one...&quot;
          required
          value={value}
          onChange={onChange}
          {...restProps}
        /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}</code></pre><p>InputElement 를 상속받아 만든 컴포넌트인 SearchInput은 isLarge를 제외한 super type component(Input)의 속성을 그대로 전달해야한다.</p>
<h2 id="i-interface-segregation">I Interface Segregation</h2>
<p>인터페이스 분리 원칙
&quot;client should not depend upon interfaces that they don&#39;t use&quot;
클라이언트가 사용하지 않는 인터페이스에 의존해선 안된다.
클래스는 역할을 수행하는 데 필요한 작업만 수행하도록 해야한다.</p>
<pre><code>
interface IThumbnailProps {
  // product: IProduct;
  imageUrl: string;
}

export function Thumbnail(props: IThumbnailProps) {
  // const { product } = props;
  const { imageUrl } = props;

  return (
    &lt;img
      className=&quot;p-8 rounded-t-lg h-48&quot;
      src={imageUrl}
      alt=&quot;product image&quot;
    /&gt;
  );
}</code></pre><h2 id="d-dependency-inversion">D Dependency Inversion</h2>
<p>의존성 역전 원칙
&quot;one entity should depend upon abstractions not concretions&quot;
추상화는 구체화에 의존해서는 안되며 세부 사항은 추상화에 의해 달라진다.
high level 모듈은 low level 모듈에 의존해서는 안된다. 둘 다 추상화에 의존해야 한다.</p>
<pre><code>High-level Module : 도구로 액션을 수행하는 클래스
Low-level Module: 작업을 실행하는 데 필요한 도구
Abstraction: 두 클래스를 연결하는 인터페이스
Concretion: 도구 작동 방식</code></pre><p>DIP 에 따르면 클래스는 작업을 실행하는 데 사용하는 도구와 융합되어선 안된다. 오히려 도구가 클래스에 연결할 수 있도록 Interface에 융합되어야 한다.
클래스와 인터페이스 모두 도구가 작동하는 방식을 몰라야 한다. 그러나 도구는 인터페이스의 사양을 충족해야 한다. 하위 클래스에 대한 상위 클래스의 종속성을 줄이는 것을 목표로 작성해야 한다.</p>
<pre><code>
export function Form(props: IFormProps) {
  const [email, setEmail] = useState(&quot;&quot;);
  const [password, setPassword] = useState(&quot;&quot;);

  const { onSubmit } = props;

  // const handleSubmit = async (e: React.FormEvent) =&gt; {
  //   e.preventDefault();

  //   await axios.post(&quot;https://localhost:3000/login&quot;, {
  //     email,
  //     password,
  //   });
  // };

  const handleSubmit2 = (e: React.FormEvent) =&gt; {
    onSubmit(email, password);
  };

  return (
    &lt;div&gt;
    ...
    &lt;/div&gt;
  );
</code></pre><p>High-level Module : Form 작성하는 View 로직이 있는 컴포넌트
Low-level Module: Submit 시 로그인 요청을 하는 비즈니스 로직이 있는 컴포넌트
Abstraction: IFormProps (prop: onSubmit)
Concretion: 제출 버튼 클릭 이벤트 헨들러</p>
<p>참고 영상: <a href="https://www.youtube.com/watch?v=MSq_DCRxOxw">https://www.youtube.com/watch?v=MSq_DCRxOxw</a>
참고 블로그: <a href="https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898">https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[A Complete Guide to useEffect]]></title>
            <link>https://velog.io/@silverj-kim/A-Complete-Guide-to-useEffect</link>
            <guid>https://velog.io/@silverj-kim/A-Complete-Guide-to-useEffect</guid>
            <pubDate>Wed, 22 Jun 2022 15:17:58 GMT</pubDate>
            <description><![CDATA[<h3 id="useeffect-로-componentdidmount-동작을-흉내내려면"><code>useEffect</code> 로 <code>componentDidMount</code> 동작을 흉내내려면?</h3>
<p><code>useEffect(fn, [])</code> 으로 흉내낼 순 있지만 완전히 같지는 않다. 더 생산적으로 접근하기 위해 이펙트 기준으로 생각해야 한다.(thinking in effects)</p>
<h3 id="이펙트를-일으키는-의존성-배열에-함수를-명시해도-될까">이펙트를 일으키는 의존성 배열에 함수를 명시해도 될까?</h3>
<p>추천하는 방법은 prop이나 state를 반드시 요구하지 않는 함수는 컴포넌트 바깥에 선언해서 호이스팅하고 이펙트 안에서만 사용되는 함수는 이펙트 함수 내부에 선언하는 것.
렌더 범위 안에 있는 함수를 이펙트가 사용하고 있다면 구현부를 <code>useCallback</code> 으로 감싸라.</p>
<h3 id="왜-가끔씩-이펙트-안에서-이전-state-나-props-값을-참조할까">왜 가끔씩 이펙트 안에서 이전 <code>state</code> 나 <code>props</code> 값을 참조할까?</h3>
<p>아마도 의존성 배열에 지정하는 걸 깜빡했을 것.</p>
<h3 id="모든-렌더링은-고유의-prop과-state가-있다">모든 렌더링은 고유의 <code>prop</code>과 <code>state</code>가 있다.</h3>
<p><code>setState</code>를 호출하여 state를 업데이트 할 때 마다 리액트는 컴포넌트를 호출한다.
특정 랜더링 시 그 안에 있는 <code>state</code> 는 <strong>상수</strong>고, 상수는 시간이 지난다고 바뀌는 것이 아니다. 컴포넌트가 다시 호출되고 각각 랜더링 마다 격리된 고유의 <code>state</code> 값을 <strong>보는</strong> 것이다. 👀</p>
<h3 id="모든-랜더링은-고유의-이벤트-핸들러를-가진다">모든 랜더링은 고유의 이벤트 핸들러를 가진다.</h3>
<p>우리의 함수는 여러번 호출되지만(랜더링 마다 한 번씩), 각각의 랜더링에서 함수 안의 <code>state</code> 값은 상수이자 독립적인 값(특정 랜더링 시의 state) 으로 존재한다.</p>
<p>특정 랜더링 시 그 내부에서 props와 state는 영원히 같은 상태로 유지된다. 이를 사용하는 어떠한 값(이벤트 핸들러 포함)도 분리되어 있다.</p>
<h3 id="모든-랜더링은-고유의-이팩트를-가진다">모든 랜더링은 고유의 이팩트를 가진다</h3>
<p>변화하지 않는 effect 안에서 state가 임의로 바뀌는 것이 아니라 effect 함수 자체가 매 랜더링 마다 별도로 존재한다.</p>
<p>리액트는 우리가 제공한 이펙트 함수를 기억해놨다가 DOM 의 변화를 처리하고 브라우저가 스크린에 그리고 난 뒤 실행한다.
사실 매 랜더링 마다 이펙트 함수는 다른 함수라고 이해하면 쉽다.</p>
<h3 id="모든-랜더링은-고유의--모든-것을-가지고-있다">모든 랜더링은 고유의 ... 모든 것을 가지고 있다.</h3>
<pre><code class="language-javascript">  useEffect(() =&gt; {
    setTimeout(() =&gt; {
      console.log(`You clicked ${count} times`);
    }, 3000);
  });</code></pre>
<pre><code class="language-javascript">componentDidUpdate() {
  setTimeout(() =&gt; {
     console.log(`You clicked ${this.state.count}   times`);
  }, 3000);
}</code></pre>
<p>useEffect 훅과 클래스 컴포넌트의 componentDidUpdate() 가 다르게 동작하는 걸 위 예제로 확인할 수 있다.</p>
<h3 id="흐름을-거슬러-올라가기">흐름을 거슬러 올라가기</h3>
<p>이펙트 안에 정의해둔 콜백에서 사전에 잡아둔 값을 쓰는 것이 아니라 최신의 값을 사용하고 싶을 때는 어떻게 해야할까?
제일 쉬운 방법은 <code>ref</code> 를 사용하는 것. 하지만 이런 방식은 흐름을 거슬러 올라가는 일이기 때문에 신중하게 사용해야 한다.</p>
<h3 id="클린업cleanup은-뭐지">클린업(cleanup)은 뭐지?</h3>
<p>클린업의 목적은 이펙트를 되돌리는 것.
리액트는 브라우저가 페인트를 하고 난 뒤에 이펙트를 실행한다. 그리하여 대부분의 이펙트가 스크린 업데이트를 가로막지 않아 앱을 빠르게 만들어 준다. <strong>이전 이펙트는 새 prop과 함께 리랜더링 되고 난 뒤에 클린업된다.</strong></p>
<h3 id="라이프사이클이-아니라-동기화">라이프사이클이 아니라 동기화</h3>
<p>useEffect는 리액트 트리 밖에 있는 것들을 prop과 state에 따라 동기화할 수 있다.</p>
<h3 id="리액트에게-이펙트를-비교하는-법-가르치기">리액트에게 이펙트를 비교하는 법 가르치기</h3>
<p>의존성 배열(Deps)에 값을 추가하는 것은 우리가 리액트에게 &quot;랜더링 스코프에서 <code>name</code>(추가된 값)외의 값은 쓰지 않는다고 약속할게.&quot; 라고 하는 것과 같다.
리액트는 함수 안을 살펴볼 순 없지만 deps를 비교할 수 있기 때문에 deps가 같으면 새 이펙트 실행을 스킵한다.</p>
<h3 id="액션을-업데이트로-부터-분리하기">액션을 업데이트로 부터 분리하기</h3>
<p>어떤 상태 변수가 다른 상태 변수의 현재 값에 연관되도록 설정하려고 한다면, 두 상태 변수 모두 <code>useReducer</code> 로 교체해야 한다.
리튜서는 컴포넌트 안에서 일어나는 <strong>액션</strong>의 표현과 그 반응으로 상태가 어떻게 업데이트되어야 할지를 분리한다.</p>
<h4 id="before">before</h4>
<pre><code class="language-javascript"> const [count, setCount] = useState(0);
  const [step, setStep] = useState(1);
  useEffect(() =&gt; {
    const id = setInterval(() =&gt; {
      setCount(c =&gt; c + step);
    }, 1000);
    return () =&gt; clearInterval(id);
  }, [step]);</code></pre>
<h4 id="after">after</h4>
<pre><code class="language-javascript"> const [state, dispatch] = useReducer(reducer, initialState);
const { count, step } = state;
useEffect(() =&gt; {
  const id = setInterval(() =&gt; {
    dispatch({ type: &#39;tick&#39; }); // setCount(c =&gt; c + step) 대신에
  }, 1000);
  return () =&gt; clearInterval(id);
}, [dispatch]);</code></pre>
<p>리액트는 컴포넌트가 유지되는 한 <code>dispatch</code> 함수가 항상 같다는 것을 보장한다. step이 바뀔 때 마다 인터벌을 다시 셋팅할 필요 없다.</p>
<h3 id="왜-usereducer가-hooks의-치트-모드인가">왜 useReducer가 hooks의 치트 모드인가</h3>
<p>그렇다. 
useReducer를 사용하면 업데이트 로직과 그로 인해 무엇이 일어나는 지 서술하는 것을 분리할 수 있다. 불필요한 의존성을 제거하여 필요할 때보다 더 자주 실행되는 것을 피할 수 있도록 도와준다.</p>
<h3 id="함수를-이펙트-안으로-옮기기">함수를 이펙트 안으로 옮기기</h3>
<p>흔한 실수 중 하나가 함수는 의존성에 포함하면 안된다는 것. 함수를 이펙트 안으로 옮겨라.</p>
<h3 id="저는-이-함수를-이펙트-안에-넣을-수-없어요">저는 이 함수를 이펙트 안에 넣을 수 없어요</h3>
<p>컴포넌트 안에 정의된 함수는 매 랜더링 마다 바뀐다.</p>
<ul>
<li>함수가 컴포넌트 스코프 안의 어떤 것도 사용하지 않는다면 컴포넌트 외부로 빼라.</li>
<li><code>useCallback</code> 훅으로 감싸라</li>
</ul>
<h3 id="경쟁상태-race-condition에-대하여">경쟁상태 race condition에 대하여</h3>
<p>데이터 요청 순서롤 보장할 수 없기 때문에 먼저 시작된 요청이 더 늦게 끝나서 잘못된 상태를 덮어씌우는 경우가 있는데 이를 경쟁상태라 한다.
보통 비동기 호출 결과도 돌아올 때까지 기다린다고 여기며 위에서 아래로 데이터가 흐르면서 async/await이 섞여있는 코드에 자주 나타난다.
boolean 값을 사용하여 타이밍을 조절할 수 있다.</p>
<h3 id="진입장벽-더-높이기">진입장벽 더 높이기</h3>
<p>useEffect를 클래스 컴포넌트의 라이프 사이클 개념으로 생각하면 사이드 이펙트는 랜더링 결과물과 다르게 동작한다. UI를 랜더링하는 것은 props, state을 통해 이루어지며 이들의 일관성에 따라 보장받는다. 하지만 사이드이펙트는 아니다.
useEffect 의 개념으로 생각하면 <strong>모든 것들은 기본적으로 동기화된다.</strong> 사이드 이펙트는 리액트 데이터 흐름의 일부이다.</p>
<p>Suspense가 나오면서 데이터를 불러오는 경우를 더 많이 커버하게 되면 (이미 나왔지만) 미래에 useEffect는 더욱 로우 레벨로 내려가 파워유저들이 진정으로 사이드 이펙트를 통해 props, state를 동기화 하고자 할 때 사용하는 도구가 될 것이다.</p>
<p>참고: <a href="https://www.rinae.dev/posts/a-complete-guide-to-useeffect-ko">https://www.rinae.dev/posts/a-complete-guide-to-useeffect-ko</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 재조정(Reconciliation)]]></title>
            <link>https://velog.io/@silverj-kim/React-%EC%9E%AC%EC%A1%B0%EC%A0%95Reconciliation</link>
            <guid>https://velog.io/@silverj-kim/React-%EC%9E%AC%EC%A1%B0%EC%A0%95Reconciliation</guid>
            <pubDate>Sat, 14 May 2022 16:35:04 GMT</pubDate>
            <description><![CDATA[<p>하나의 트리를 가지고 다른 트리로 변환하기 위한 최소한의 연산 수를 구하는 알고리즘의 복잡도는 O(n^3) 를 갖는다.
리액트에 이 알고리즘을 적용하면 1000개의 엘리먼트를 그리기 위해 1000^3 = 10억번의 비교 연산을 수행해야 한다. 
따라서 리액트는 O(n) 복잡도의 휴리스틱 알고리즘을 구현했다.
    1. 서로 다른 타입의 두 엘리먼트는 서로 다른 트리를 만들어 낸다.
    2. 개발자가 <code>key</code> prop을 통해 여러 렌더링 사이에서 어떤 자식 엘리먼트가 변경되지 않아야 할 지 표시할 수 있다.</p>
<br>

<h2 id="비교-알고리즘-diffing-algorithm">비교 알고리즘 Diffing Algorithm</h2>
<p>두 개의 트리를 비교할 때 React는 두 엘리먼트의 root 엘리먼트 부터 비교한다.</p>
<h3 id="엘리먼트의-타입이-다른-경우">엘리먼트의 타입이 다른 경우</h3>
<p>두 root 엘리먼트 타입이 다르면 React는 이전 트리를 버리고 완전히 새로운 트리를 구축한다. 트리를 버릴 때 이 전 DOM 노드들은 모두 파괴된다. 루트 엘리먼트 아래의 모든 컴포넌트도 언마운트되고 그 state도 사라진다.</p>
<br>

<h3 id="같은-타입의-컴포넌트-엘리먼트">같은 타입의 컴포넌트 엘리먼트</h3>
<p>컴포넌트가 갱신되면 인스턴스는 동일하게 유지되어 렌더링 간 state 유지, props 갱신한다.</p>
<br>

<h3 id="자식에-대한-재귀적-처리">자식에 대한 재귀적 처리</h3>
<p>DOM 노드의 자식들을 재귀적으로 처리할 때 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성한다.
자식의 끝에 엘리먼트를 추가하면 두 트리 사이의 변경은 잘 작동한다.
<em>그러나 리스트 맨 앞에 엘리먼트를 추가하는 경우엔 성능이 좋지 않다.</em></p>
<pre><code>&lt;ul&gt;
  &lt;li&gt;Duke&lt;/li&gt;
  &lt;li&gt;Villanova&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;Connecticut&lt;/li&gt;
  &lt;li&gt;Duke&lt;/li&gt;
  &lt;li&gt;Villanova&lt;/li&gt;
&lt;/ul&gt;</code></pre><p>위와 같이 맨 위에 엘리먼트를 추가하는 경우 모든 자식을 변경한다. 이러한 비효율은 문제가 될 수 있다.</p>
<br>

<h3 id="keys">Keys</h3>
<p>자식들이 <code>key</code>를 가지고 있다면 React는 Key를 통해 기존 트리와 이후 트리의 자식들이 일치하는 지 확인한다.</p>
<pre><code>&lt;ul&gt;
  &lt;li key=&quot;2015&quot;&gt;Duke&lt;/li&gt;
  &lt;li key=&quot;2016&quot;&gt;Villanova&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li key=&quot;2014&quot;&gt;Connecticut&lt;/li&gt;
  &lt;li key=&quot;2015&quot;&gt;Duke&lt;/li&gt;
  &lt;li key=&quot;2016&quot;&gt;Villanova&lt;/li&gt;
&lt;/ul&gt;</code></pre><p>2014 key를 가진 엘리먼트가 새로 추가되었고 2015, 2016 key를 가진 엘리먼트는 이동만 하기 때문에 효율적이게 수행된다.
해당 key는 오로지 형제 사이에서만 유일하면 되고, 전역에서 유일할 필요는 없다.</p>
<p>최후의 수단으로 배열의 인덱스를 key로 사용할 수 있다. 항목들이 재배열되지 않는다면 문제없지만 재배열 되는 경우엔 비효율적으로 동작할 것이다. 또 항목의 순서가 바뀌면 key도 바뀌기 때문에 컴포넌트가 의도하지 않은 방식으로 바뀔 수 있다.</p>
<br>

<h3 id="고려-사항">고려 사항</h3>
<p>리액트가 말하는 재렌더링은 모든 컴포넌트의 <code>render</code>를 호출하는 것이지 컴포넌트를 엄마운트 시키고 다시 마운트하는 것은 아니다. 렌더링 전후에 변경된 부분만을 적용할 것이다.</p>
<ol>
<li>알고리즘은 다른 컴포넌트 타입을 갖는 종속 트리들의 일치 여부를 확인하지 않는다. 비슷한 결과물을 출력하는 두 컴포넌트를 교체한다면 그 둘을 <strong>같은 타입</strong>으로 만드는 것을 추천한다.</li>
<li>key는 반드시 변하지 않고 예쌍 가능하며 유일해야 한다. 변하는 key를 사용한다면 key를 사용하는 이유가 없다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[우아한 테크 세미나 - 지속가능한 SW 개발을 위한 코드리뷰]]></title>
            <link>https://velog.io/@silverj-kim/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%85%8C%ED%81%AC-%EC%84%B8%EB%AF%B8%EB%82%98-%EC%A7%80%EC%86%8D%EA%B0%80%EB%8A%A5%ED%95%9C-SW-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@silverj-kim/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%85%8C%ED%81%AC-%EC%84%B8%EB%AF%B8%EB%82%98-%EC%A7%80%EC%86%8D%EA%B0%80%EB%8A%A5%ED%95%9C-SW-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Sun, 01 May 2022 09:17:59 GMT</pubDate>
            <description><![CDATA[<p><a href="https://youtu.be/ssDMIcPBqUE?t=1167">우아한 테크 세미나</a></p>
<p>지속가능한 SW 개발을 위한 코드리뷰에 관련된 세미나를 보고 개인적으로 정리해보았습니다.</p>
<h2 id="코드리뷰--지속가능한-sw-개발">코드리뷰 : 지속가능한 SW 개발</h2>
<h3 id="왜-코드-리뷰를-해야하나">왜 코드 리뷰를 해야하나?</h3>
<ul>
<li><h2 id="vuca란">VUCA란?</h2>
</li>
<li>우리가 살고 있는 시대는 변동성이 많은 시대기 때문에 혼자만이 알고 있는 방법으로 해결하기 보단 빠르게 변하는 문제들을 모두와 함께 해결해야한다.</li>
<li>개발 조직의 성능(생산성)이 중요해지고 있다.</li>
<li>클린코드의 중요성<ul>
<li>SW의 진정한 비용 ~= 유지보수 비용</li>
<li>작성보다 이해에 10배 이상의 노력 소요</li>
</ul>
</li>
<li><strong>&quot;The only way to go fast, is to go well&quot; - Robert C. Martin</strong></li>
<li>코드리뷰 목적<ul>
<li>품질 문제 검수 (버그, 장애)</li>
<li>더 나은 코드 품질 -&gt; 향후 변경 비용 개선</li>
<li>학습 및 지식 전달, 동기 부여</li>
<li>상호 책임감 증대</li>
<li>설계 개선 제안</li>
<li>개발 문화 개선</li>
</ul>
</li>
</ul>
<h2 id="왜-코드리뷰가-어려운가">왜 코드리뷰가 어려운가?</h2>
<p>코드에 대한 비판을 자신에 대한 비판으로 이해하기 때문</p>
<h2 id="기법들">기법들</h2>
<h3 id="효율적인-pr-방법">효율적인 PR 방법</h3>
<p>기계가 더 잘할 수 있는 일은 기계에게 넘기자.
Formatting 은 별도의 커밋/PR로 분리하자.
스타일에 대한 논쟁은 리뷰에서 시간 낭비다. -&gt; 합의를 하고 그것을 지키자.
<strong>PR을 올릴 때 Author가 먼저 주석을 달자</strong>
빨리 리뷰를 하라. -&gt; 우선순위 높은 업무로 1일 내 리뷰
PR에 포함된 변경이 적도록 노력하라.
<strong>하나의 라운드에 20~50개 정도의 의견은 위험의 시작</strong>
  초기 라운드에서는 고수준 피드백으로 제한 -&gt; 그 이후에 저수준 이슈 처리
<strong>예제 코드 제공에 관대하라</strong>
<strong>리뷰의 범위를 존중하라</strong>
  PR에 포함된 리뷰만 진행하라.
<strong>1~2등급만 코드레벨을 올리는 것을 목표로</strong>
  F등급인 경우만 승인을 보류하는 유일한 이유여야 한다.
  완전하지 않아도 충분히 기분 좋은 코드가 되도록만.
~하는 것을 제안합니다. ~하는 게 어떨까요? 추천
진정한 칭찬을 해라. 좋은 코멘트를 남겨라.
<strong>교착상태를 적극적으로 처리해라</strong>
  ㅋㅋㅋㅋㅋㅋㅋ텍스트 기반 의사소통은 상대가 인간이라는 것을 잊게 함</p>
<h3 id="필요한-기술들">필요한 기술들</h3>
<p>TDD, 리팩터링, 레거시 코드 다루기, Clean Code</p>
<h3 id="faq">FAQ</h3>
<p>개발생산성 vs 개발 품질의 트레이드 오프
  버그 수정 비용은 개발 라이프 싸이클에서 후반으로 갈 수록 기하급수적으로 커짐
  품질이 좋으면 후반으로 갈 수록 시간이 절약됨</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Javascript 의 Event loop ]]></title>
            <link>https://velog.io/@silverj-kim/Javascript-%EC%9D%98-Event-loop</link>
            <guid>https://velog.io/@silverj-kim/Javascript-%EC%9D%98-Event-loop</guid>
            <pubDate>Sun, 01 May 2022 07:45:37 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트의 <strong>호출 스택과 이벤트 루프.</strong>
자바스크립트 코드 동작을 이해하려면 필수적으로 알아야 하기 때문에 정리를 해두려고 한다.</p>
<p>우선 호출스택과 이벤트 루프를 알기 전에 <strong>실행 컨텍스트 Excution Context</strong>를 알아보자.</p>
<h3 id="execution-context-실행-컨텍스트">Execution Context 실행 컨텍스트</h3>
<p>실행 컨텍스트는 아마 많이 들어봤을 것 같은데 scope, hoisting, this, function 등의 동작 원리를 담고 있는 <strong>자바스크립트의 핵심 원리</strong>다.</p>
<p>context를 한국어로 번역하면 <strong>문맥</strong> 이다. 코드의 실행환경 이라고 이해하면 쉽다.</p>
<p>우선 제일 먼저 <strong>전역 컨텍스트</strong> 가 존재한다. 처음 스크립트를 실행해서 종료될 때 까지 유지 된다. 그 다음은 <strong>함수 컨텍스트</strong>, 함수를 호출할 때 마다 함수 컨텍스트가 하나씩 더 생긴다.</p>
<p><em>컨텍스트 생성 시 컨텍스트 안에 <strong>변수 객체(arguments, variables), scope chain, this</strong> 가 생성된다.</em>
컨텍스트 생성 후 해당 컨텍스트에 변수가 없다면 스코프 체인을 따라 올라가며 찾게 된다.</p>
<h3 id="global-context-전역-컨텍스트">global context 전역 컨텍스트</h3>
<p>전역 컨텍스트는 함수의 인자인 arguments가 없고 variables만 있다.
scope chain은 원래 자신과 상위 스코프의 변수 객체를 의미하는데 전역 컨텍스트는 상위 스코프가 없기 때문에 자기 자신의 전역 변수객체만 있다.
<em>this 는 따로 설정되어 있지 않다면 window이다</em></p>
<p>그 다음은</p>
<h3 id="호출-스택-call-stack">호출 스택 Call Stack</h3>
<p>함수를 실행하려면 스택에 함수를 집어넣게 되고 함수에서 리턴이 일어나면 스택의 가장 위쪼겡서 해당 함수를 꺼내게 된다. 이것이 전부!</p>
<pre><code>function first() {
  second();
}

function second() {
  third();
}

function third() {
}

first();
third();</code></pre><p><img src="https://images.velog.io/images/silverj-kim/post/d6ebfbe0-9f94-4b26-a173-3c96d2e9e2c6/%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%202021-05-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.21.46.png" alt="콜스택 예제"></p>
<p style="color:red";>Uncaught RangeError: Maximum call stack size exceeded</p>

<p>호출 스택이 가득 찼을 때 위와 같은 에러가 발생한다.
재귀함수 recursive funtion 를 사용할 때 주로 발생한다.</p>
<h3 id="이벤트-루프-event-loop">이벤트 루프 Event loop</h3>
<p>자바스크립트와 노드에서 사용되는 이벤트 루프. 이 또한 아주 중요!!</p>
<h5 id="스레드-thread">스레드 thread?</h5>
<p>스레드는 어떤 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 의미한다.
일반적으로 한 프로그램은 하나의 스레드를 가지고 있다. (싱글스레드) 그러나 프로그램 환경에 따라 여러 개의 스레드를 실행할 수 있다. (멀티스레드)</p>
<h5 id="동시성-concurrency">동시성 concurrency?</h5>
<p>여러 작업이 마치 동시에 일어나는 것처럼 보이는 것</p>
<h4 id="자바스크립트는-싱글스레드">자바스크립트는 싱글스레드?</h4>
<p>자바스크립트를 싱글스레드라고 부르는 이유는 자바스크립트의 메인 스레드인 이벤트 루프가 싱글스레드이기 때문이다.
싱글스레드는 프로그램이 작동되는 동안 한번에 하나의 작업만을 수행할 수 있다.
그러나 이벤트 루프만 독립적으로 실행되지 않고 웹 브라우저나 Nodejs같은 자바스크립트 런타임 환경은 멀티 스레드이다. 따라서 자바스크립트는 비동기 코드가 동작한다. (대표적인 예로 3초 후에 로그를 찍을 때 프로그램이 멈추지 않고 동작하다가 로그가 찍힌다) </p>
<h4 id="자바스크립트의-작동-원리">자바스크립트의 작동 원리</h4>
<p>자바스크립트의 런타임은 메모리 힙(Memory Heap)과 콜스택(Call Stack) 으로 구성되어 있다.
메모리 힙은 <strong>메모리 할당을 담당</strong>, 콜스택은 <strong>코드가 호출될 때 스택으로 쌓이는 곳</strong>
메인 스레드에서 호출되는 함수들은 콜스택에 쌓이게 되고 이 함수들은 LIFO 방식으로 실행된다.</p>
<p>기본적인 작업들은 위에 콜스택 설명할 때 말했듯이 함수 실행 -&gt; 실행 종료 후 콜스택에서 제거 가 반복 된다.
그러나 비동기 작업은 다르다.</p>
<h4 id="동시성과-이벤트-루프">동시성과 이벤트 루프</h4>
<p>자바스크립트는 한번에 하나밖에 할 수 없다. 다른 코드를 실행시키는 동안 Ajax 요청, setTimeout 역시 할 수 없다.
우리가 이걸 동시에 할 수 있는 이유는 브라우저가 단순 런타임 이상을 의미하기 때문이다. 브라우저는 Web API 를 통해 자바스크립트에서 호출할 수 있는 스레드를 제공해준다. <strong>여기에 동시성이 들어온다.</strong> (Node는 C++ API) </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Python 기본]]></title>
            <link>https://velog.io/@silverj-kim/Python-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@silverj-kim/Python-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Sun, 17 Apr 2022 02:38:48 GMT</pubDate>
            <description><![CDATA[<h2 id="문자열-다루기">문자열 다루기</h2>
<pre><code>text = input() //입력받기
text.split(&quot;:&quot;) //문자열 나누기
text[0:4] //문자열 슬라이싱

// multiline
multiline = &#39;&#39;&#39;
Life is good
I&#39;m happy
&#39;&#39;&#39;

len(text) //문자열 길이

//문자열 인덱싱
a = &quot;Life is good&quot;
a[0] //L
a[-1] //d


//문자열 포맷팅
&quot;I eat %d apples.&quot; % 3
&quot;I eat %s apples.&quot; % &quot;three&quot;
&quot;I eat %x apples.&quot; % 98 

//format 함수를 사용한 포맷팅
&quot;I eat {0} apples.&quot;.format(3)
&quot;I ate {number} apples. I was sick for {day} days&quot;.format(number = 10, day = 3)


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[무한스크롤, intersection observer]]></title>
            <link>https://velog.io/@silverj-kim/%EB%AC%B4%ED%95%9C%EC%8A%A4%ED%81%AC%EB%A1%A4-intersection-observer</link>
            <guid>https://velog.io/@silverj-kim/%EB%AC%B4%ED%95%9C%EC%8A%A4%ED%81%AC%EB%A1%A4-intersection-observer</guid>
            <pubDate>Sun, 10 Apr 2022 12:17:53 GMT</pubDate>
            <description><![CDATA[<p>최근 무한스크롤을 구현하다가 intersection observer에 대해 알게 되어 오랜만에 정리합니다.</p>
<h2 id="과거에는">과거에는...</h2>
<p>대부분 <code>scroll event</code>를 사용하여 무한스크롤을 구현했습니다.
<code>window.innerHeight + document.documentElement.scrollTop &gt;= document.documentElement.offsetHeight)</code>
윈도우 높이 + 스크롤 된 Top 좌표 &gt;= 스크롤을 포함한 전체 페이지 길이를 계산하여 아래까지 스크롤 했을 때 데이터를 더 요청하도록 구현하는 방법입니다.
<br />
해당 방법은 스크롤할 때 마다 scoll event가 너무 많이 발생합니다. 따라서 여러 개의 스크롤 이벤트 리스너가 있다면 메인스레드에 과부하를 줄 수도 있습니다. 
스크롤 이벤트에서 현재 스크롤된 Top 좌표를 알기 위해 <code>offsetTop</code> 을 사용하는데 이 값을 정확하게 가져오기 위해서는 매번 layout을 새로 그려야합니다. layout을 새로 그리려면 render tree를 새로 생성하여 reflow가 매번 발생합니다. 또, 스크롤 이벤트가 많이 발생함에 따라 데이터 요청도 많이 발생하게 됩니다.
따라서 스크롤 이벤트 핸들러가 호출되는 수를 줄일 수 있는 최적화 방법으로 쓰로틀링<code>throttling</code> 이라는 이벤트 제어 방법을 사용하곤 했습니다. </p>
<blockquote>
<p>throttle
이벤트를 일정한 주기마다 발생하도록 하는 기술, 설정 시간 동안 최대 1번만 발생하게 하는 기술로 무한스크롤에 자주 사용됩니다.</p>
</blockquote>
<h1 id="intersection-observer">Intersection Observer</h1>
<p>타겟 요소와 상위 요소 또는 최상위 document의 viewport 사이의 intersection 내의 변화를 비동기적으로 관찰하는 방법</p>
<br/>

<p>Intersection Observer, 말그대로 교차부분 관찰자.
그들이 감시하고자 하는 요소가 다른 요소(viewport)에 들어가거나 나갈 때 또는 요청한 부분만큼 두 요소의 교차부분이 변경될 때 마다 실행될 콜백함수를을 등록할 수 있게 합니다. 요소의 교차를 지켜보기 위해 <strong>메인 스레드를 사용할 필요 없이</strong> 브라우저는 원하는대로 교차 영역 관리를 최적화할 수 있습니다.</p>
<h3 id="컨셉과-사용">컨셉과 사용</h3>
<ol>
<li>target으로 칭하는 요소가 기기 뷰포트나 특정요소(root)와 교차</li>
<li>observer가 최초로 타겟을 관측하도록 요청받을 때 마다
일반적으로, 요소의 교차성이 가장 가까운 scollable 조상에 의해 변경되길 원할 것입니다. 도큐먼트의 루트 요소를 기준으로 해당 요소를 관찰하기 위해서는 <code>null</code>을 사용하면 됩니다.</li>
</ol>
<br/>

<p>뷰포트 혹은 다른 요소를 root로 사용하건 간에 이 API는 같은 방식으로 동작합니다.
대상 요소의 가시성이 변경될 때 마다 콜백 함수를 실행하며 그것이 원하는 만큼 root 요소와 교차합니다.
간단히 설명해 target이 화면에 노출되었는 지 여부를 간단하게 구독할 수 있는 API 입니다.</p>
<br/>

<pre><code>const options = { threshold: 1.0 };

const callback = (entires, observer) =&gt; {
  entries.forEach((entry) =&gt; {
    if(entry.isIntersection) {
      observer.unobserve(entry.target);
      // 화면에 노출
    } else {
      // 화면에서 제외
    }
  });
}</code></pre><ol>
<li>먼저 <code>IntersectionObserver</code> 객체를 생성하면서 <code>callback</code>과 <code>option</code>을 전달합니다.</li>
<li><code>IntersectionObserver</code>에서 <code>observe</code>로 <code>target</code>을 추가합니다.</li>
<li><code>target</code>에 <code>options.threshold</code> 로 정의한 % 만큼 해당 요소가 화면에 노출 또는 제외되면 <code>entires</code>에 추가하고 <code>callback</code>을 호출합니다.</li>
<li>더이상 <code>target</code>을 구독할 필요가 없으면 <code>unobserve</code> 합니다.</li>
</ol>
<p><code>entry.isIntersecting</code>는 노출 여부를 나타내며
<code>entry.intersectionRatio</code>는 노출 비율, <code>entry.intersectionRect</code>는 노출 영역으로 정의되어 있습니다.</p>
<br />


<p>간단하게 구현해본 예제 <a href="https://stackblitz.com/edit/react-wghtbk?file=src%2FApp.js">https://stackblitz.com/edit/react-wghtbk?file=src%2FApp.js</a></p>
<h2 id="장점">장점</h2>
<ul>
<li>offsetTop 값이 필요없어 reflow가 발생하지 않습니다.</li>
<li>동기적으로 너무 많이 발생하는 스크롤 이벤트를 사용하지 않아도 됩니다.</li>
</ul>
<p>참고 
<a href="https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API">mdn - intersection observer</a>
<a href="https://pks2974.medium.com/intersection-observer-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-fc24789799a3">IntersectionObserver 간단정리</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 1000 javascript 입력받기]]></title>
            <link>https://velog.io/@silverj-kim/%EB%B0%B1%EC%A4%80-1000-javascript-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@silverj-kim/%EB%B0%B1%EC%A4%80-1000-javascript-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Sun, 04 Jul 2021 07:39:24 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-두-정수-a와-b를-입력받은-다음-ab를-출력하는-프로그램을-작성하시오">문제: 두 정수 A와 B를 입력받은 다음, A+B를 출력하는 프로그램을 작성하시오.</h3>
<p>문제를 풀다보면 입력을 받아야 하는 경우가 발생하는데
언어가 node.js 라면 아래와 같이 해결하면 된다.</p>
<pre><code>const fs = require(&#39;fs&#39;);
const input = fs.readFileSync(&#39;/dev/stdin&#39;).toString().split(&#39; &#39;);
const a = parseInt(input[0]);
const b = parseInt(input[1]);
console.log(a+b);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[정규표현식 정리]]></title>
            <link>https://velog.io/@silverj-kim/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@silverj-kim/%EC%A0%95%EA%B7%9C%ED%91%9C%ED%98%84%EC%8B%9D-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 04 Jul 2021 06:49:46 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/dream-ellie/regex">드림코딩 정규표현식 정리</a>
<a href="https://regexr.com/5ml92">정규표현식 연습용 사이트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[노마드 코더 간단 알고리즘 정리]]></title>
            <link>https://velog.io/@silverj-kim/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EA%B0%84%EB%8B%A8-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@silverj-kim/%EB%85%B8%EB%A7%88%EB%93%9C-%EC%BD%94%EB%8D%94-%EA%B0%84%EB%8B%A8-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 22 Jun 2021 15:02:36 GMT</pubDate>
            <description><![CDATA[<p>요새 노마드 코더 채널에서 니꼴라스가 10분씩 알고리즘 및 자료구조를 정리해주는데
간단하게 정리할 겸 적어보려 한다.</p>
<h2 id="array-배열">Array 배열</h2>
<p><a href="https://www.youtube.com/watch?v=NFETSCJON2M">youtube</a></p>
<h4 id="time-complexity시간복잡도">Time Complexity(시간복잡도)</h4>
<p>데이터 구조의 오퍼레이션 혹은 알고리즘이 얼마나 빠르고 느린지 측정하는 방법
실제 시간을 측정하는 것이 아니라 얼마나 많은 <strong>단계 steps</strong>가 있는 지로 측정
단계가 적을 수록 좋다 :)</p>
<h4 id="2가지-종류의-메모리">2가지 종류의 메모리</h4>
<p>volatile(휘발성) vs non-volatile(비휘발성)
메모리 RAM vs 컴퓨터를 껐다 켜도 데이터가 남아있는 하드 드라이브</p>
<p>프로그램이 돌아가고 변수를 생성할 때 등 모든 건 RAM(Ramdom Access Memory) 에 저장
하드메모리의 데이터를 읽는 것 보다 RAM에 있는 데이터를 읽는 게 빠르다</p>
<p>RAM을 박스 그룹이라고 가정한다.
그 박스들은 데이터를 저장할 수 있고 박스의 이름이 memory address 다.
프로그램이 RAM 메모리에게 memory address로 가고싶다고 하면 바로 접근이 가능하다. 
바로 해당 어드레스로 이동할 수 있다.</p>
<h4 id="메모리-관점에서의-배열">메모리 관점에서의 배열</h4>
<p>배열을 만들 때 컴퓨터에게 배열의 길이만큼 공간을 미리 예약/할당 해야한다.
메모리 안에 박스들이 나란히 자리할 수 있도록.
JS, python 은 배열을 선언할 때 length 를 직접 정하지 않지만 백그라운드에서 이 과정을 다 해주고 있는 것이다.</p>
<h4 id="reading">Reading</h4>
<p>배열은 0부터 인덱싱을 한다. 위치만 알면 배열의 데이터에 접근할 수 있다.
컴퓨터는 배열이 어디서 시작하는 지 알고 있기 때문에 read 가 빠르다.
길이와 상관없이 인덱스에서 요소를 읽어내는 속도는 동일하기 때문에 많은 양의 자료를 읽을 때 유리하다.</p>
<h4 id="searching">searching</h4>
<p>reading과 searching 은 다르다.
찾고 싶은 값이 배열에 있는지, 없는지, 어디에 있는지 모른다.
배열의 요소를 하나씩 체크해야 한다. one by one
최선의 경우: 찾는 값이 첫번째 인덱스에 있는 것
평균의 경우는 중간에 있는 것
최악의 경우는 맨 마지막 인덱스에 있는 것, 진짜 최악은 없는 것...
배열에서 searcing은 빠르지 않다.
<em>선형 검색 Linear searching: 순서대로 0부터 끝까지 찾는 것</em></p>
<h4 id="insertadd">insert(add)</h4>
<p>배열을 만들 때 메모리 공간을 미리 확보해야 한다.
&quot;어디에&quot; 새 값을 추가할 것인가.
최고의 경우 : 그 값을 배열 맨 끝에 추가하는 경우, 컴퓨터는 배열이 어디서 시작하고 얼마나 긴 지 알고 있기 때문에 배열의 맨 끝으로 이동하여 새 값을 추가하는 건 빠르다.
평균의 경우 : 배열 중간에 추가하는 경우
최악의 경우 : 배열의 맨 앞에 추가하는 경우, 모든 요소를 한 칸 씩 움직여야 한다. 
따라서 배열의 크기가 크면 클 수록 위치에 따라 insert 가 오래걸릴 수 있다.
또 다른 경우는 이미 공간이 꽉찼는데 값을 추가하려고 하는 경우이다. 이런 경우는 새 배열을 만들어서 이전 배열을 복사하고 추가해야하기에 시간이 오래 걸린다.</p>
<h4 id="delete">delete</h4>
<p>삭제는 삽입과 비슷하다.
최고의 경우 : 마지막 값을 삭제할 때
평균의 경우 : 중간 값을 삭제할 때
최악의 경우 : 맨 앞의 값을 삭제할 때, 맨 앞의 공백을 없애기 위해 모든 요소가 한 칸 씩 움직여야 한다.
삽입과 마찬가지로 배열이 길면 길 수록 오래 걸리게 된다.</p>
<p>배열은 read가 빠르고 searcing, adding, deleting 이 느리다.
추가, 삭제를 하고 싶을 경우에는 배열 맨 끝에서 작업하는 것을 추천한다.</p>
<h2 id="검색-알고리즘">검색 알고리즘</h2>
<p><a href="https://www.youtube.com/watch?v=WjIlVlmmNqs">youtube</a></p>
<p>배열 안에 잇는 숫자를 어떻게 찾을 수 있는 지
어떤 알고리즘을 선택하느냐에 따라 스피드가 어떻게 달라지는지를 알아보자</p>
<p>완벽한 자료구조, 알고리즘 조합을 찾아내면 코드의 스피드 자체가 달라진다.</p>
<p>알고리즘에도 Time Complexity (시간 복잡도) 가 존재한다</p>
<h3 id="linear-search-선형검색-알고리즘">Linear Search (선형검색 알고리즘)</h3>
<p>가장 자연스러운 방법
순서대로 처음부터 끝까지 검색하는 방법</p>
<p>최악의 경우 : 배열 맨 마지막에 있거나 아예 없는 경우
배열이 길어질 수록 검색 시간도 오래걸린다 = Linear Time Complexity</p>
<h3 id="sorted-array">Sorted Array</h3>
<p>정렬이 안된 배열에 요소를 추가하는 건 쉬우나 정렬된 배열에 요소를 추가하는 건 오래걸린다.
이유는 해당 배열에서 요소보다 큰 값을 찾은 후 값을 다 한 칸 씩 이동한 후에 큰 값 왼쪽에 삽입해야하기 때문</p>
<h3 id="binary-search-이진검색-알고리즘">Binary Search (이진검색 알고리즘)</h3>
<p>정렬된 배열(Sorted Array) 에서만 사용가능</p>
<p>이진 =&gt; 반으로 쪼개다
인덱스 0 부터 검색하지 않고 middle(중간) 부터 검색을 시작한다.</p>
<pre><code>1. 가운데 숫자가 target 보다 큰 지, 작은 지 비교
2. n &gt; target : target은 n의 왼쪽에 위치, n &lt; target : target은 n의 오른쪽에 위치
3. 왼쪽 또는 오른쪽 배열의 중간값과 target을 다시 비교
4. 반복 하다가 target을 찾는다!</code></pre><p>이진 검색은 매 스텝마다 절반의 아이템을 없애기 때문에 배열의 길이가 길어져도 작업을 수행하는데 필요한 스텝이 선형적으로 늘어나지 않는다.</p>
<p>따라서 이진검색은 거대한 배열을 다룰 때 효과적이다.
그러나 이진검색을 하고싶다면 배열을 정렬해야 한다. 이는 새 요소를 추가에 시간이 오래걸린다.
<em>이러한 상충관계를 잘 알고 적절한 자료구조, 알고리즘을 사용해야 한다.</em></p>
<h2 id="big-o">Big O</h2>
<p><a href="https://www.youtube.com/watch?v=BEVnxbxBqi8">youtube</a></p>
<p>빠른 알고리즘은 느린 알고리즘보다 우수하다.</p>
<p>알고리즘의 스피드를 나타내는 방법 : 완료까지 걸리는 절차의 수 =&gt; <strong>Big O</strong></p>
<h4 id="상수-시간-시간복잡도">상수 시간 시간복잡도</h4>
<pre><code>def print_first(arr):
    print(arr[0]);</code></pre><p>input size 에 상관없이 1step이면 끝난다.
이 함수의 시간복자도는 constant time (상수시간)이다.
=&gt; <strong>O(1)</strong>
프린트를 두번 한다면 O(2) 인가?
=&gt; NO. <strong>O(1)</strong></p>
<p><em>BigO는 함수의 디테일엔 관심이 없고 인풋사이즈에 따라 함수가 어떻게 동작하는지만 관심이 있기 때문에 여전히 O(1)이다. 상수 시간인 경우에는 그 step이 200이든 5이든 O(1)이다. 그래프가 같기 때문에 러프하게 O(1)로 표시한다.</em></p>
<h4 id="on">O(n)</h4>
<ul>
<li><p>선형 검색 알고리즘의 경우
input size = <strong>n</strong>
algorithm steps = <strong>n</strong> steps
=&gt; complexity : <strong>O(n)</strong></p>
</li>
<li><p>반복문</p>
<pre><code>def print_all(arr):
for n in arr :
  print(n)</code></pre><p>=&gt; <strong>O(n)</strong>
반복문이 두개라면? O(2n)?
=&gt; No. <strong>O(n)</strong></p>
</li>
</ul>
<h4 id="on2">O(n^2)</h4>
<p>시간복잡도의 Quadratic time(2차 시간)
2차 시간은 Nested Loop(중첩 루프)에서 발생</p>
<h4 id="olog-n">O(log n)</h4>
<p>로그(logarithm) &lt;-&gt; 지수(exponent)
<img src="https://images.velog.io/images/silverj-kim/post/1579ffa7-22c3-49f7-b1fb-5d13b2344942/%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%202021-07-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.55.18.png" width=50%/>
<img src="https://images.velog.io/images/silverj-kim/post/205640b7-b0ee-457f-bcaa-62e046fb7184/%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%202021-07-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.56.15.png" width=50%/>
<img src="https://images.velog.io/images/silverj-kim/post/d967f1f7-0d9c-4e4b-9c92-f6297ee460a3/%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%202021-07-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.56.20.png" width=50%/>
n을 구하는 방법은 32를 2로 나눴을 때 1이 나오기 까지의 step 을 구하는 방법과 동일하다
32/2 = 16
16/2 = 8
8/2 = 4
4/2 = 2
2/2 = 1
총 5번 이기 때문에 n = 5 가 된다.
이 방법은 이진검색 방법과 매우 비슷하다.
따라서 정렬된 배열의 이진검색의 시간복잡도는 O(log n)이다.</p>
<p><img src="https://images.velog.io/images/silverj-kim/post/217a14ee-9c94-4ff1-89c3-ba0179dc1195/%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%202021-07-03%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.01.33.png" alt=""></p>
<h2 id="sorting-정렬-알고리즘">Sorting 정렬 알고리즘</h2>
<p>항상 BigO가 모든 알고리즘을 완벽하게 설명하는 것은 아니다.
같은 BigO를 가지고 있어도 각각의 퍼포먼스가 다를 수 있다.</p>
<p>sorting 이란
무언가를 정리하는 것, 정렬하는 것.</p>
<h3 id="버블-정렬-bubble-sort">버블 정렬 Bubble Sort</h3>
<p>배열의 2개의 아이템을 선택하고 비교 -&gt; 값이 큰 쪽을 오른쪽으로 가도록 교환, 이를 반복한다.</p>
<p>버블정렬의 시간복잡도는?
사이클마다 n-1 번 비교, 최악의 경우 모든 사이클을 n-1 번 비교해야한다.
따라서 O(n^2), 좋은 알고리즘이 아니다.</p>
<h3 id="선택-정렬-selection-sort">선택 정렬 Selection Sort</h3>
<p>전체 아이템 중 가장 작은 아이템의 위치를 변수에 저장한다.
그 다음 첫번째 아이템과 가장 작은 아이템의 위치를 교환한다.
그러면 제일 첫번째 아이템은 정렬된 부분이고 정렬되지 않은 부분 중 가장 작은 아이템을 찾고 위의 과정을 반복한다.</p>
<p>선택정렬의 시간 복잡도는?
정렬되지 않은 전체 배열에서 가장 작은 숫자를 찾으므로 n-1 비교를 한다.
하지만 버블정렬과 다르게 최악의 경우에도 n번의 스왑을 하지않는다.
한 사이클에서 1 번의 스왑만 하면된다. (제일 작은 수만 앞으로 옮기면 됨)
따라서 <strong>시간은 버블정렬 &gt; 선택정렬</strong> 버블정렬이 훨씬 많이 걸린다.
그러나 시간복잡도는 동일하게 O(n^2)</p>
<h3 id="삽입-정렬-insertion-sort">삽입 정렬 Insertion Sort</h3>
<p>index 0 자리에 가장 작은 값을 넣어야 한다고 선택하면 그 왼쪽의 아이템부터 비교를 시작하여 작은 값을 발견하면 index 0 과 swap 한다.
index 0 의 왼쪽은 없으니까 index 1 부터 시작하고 key 값은 1이다.
삽입 정렬은 필요한 아이템만 스캔하여 비교하기 때문에 선택 정렬보다 빠르다.</p>
<p>그렇지만 시간복잡도는 동일하게 O(n^2)이다.</p>
<p>이 경우에는 최악의 시나리오만을 보지않고 <strong>평균 시나리오</strong>를 봐야한다.
insertion sort 는 Best scenario 가 O(n) 이고 나머지는 O(n^2)이다.</p>
<h2 id="hash-table">Hash Table</h2>
<p>베리베리베리 임포턴트!</p>
<h3 id="hash-table-과-array-를-비교">Hash table 과 Array 를 비교</h3>
<p>array의 경우 요소를 찾기 위해서는 선형검색을 해야한다. 시간이 오래걸림. O(n)</p>
<p>hash table의 경우 key를 사용하여 value 를 바로 가져올 수 있다. 시간이 빠름. O(1)
검색 및 추가, 삭제도 O(1)</p>
<h3 id="array-대신-hash-table을-사용하기">Array 대신 Hash Table을 사용하기</h3>
<pre><code>//array
fruits = [&#39;사과&#39;, &#39;배&#39;, &#39;참외&#39;, &#39;딸기&#39;]

//hash table
fruits = {
    &#39;사과&#39; : true,
    &#39;배&#39; : true,
    &#39;참외&#39; : true,
    &#39;딸기&#39; : true
}</code></pre><p>array를 사용해서 참외가 fruits 에 있는 지 확인하려면 하나씩 검색해서 찾아야 한다.
하지만 hash table을 사용하면
<code>fruits[&#39;사과&#39;] === true ? &quot;있다&quot; : &quot;없다</code>
이렇게 바로 검색하여 찾을 수 있다. 시간이 훨씬 빠르다.</p>
<h4 id="hash-table은-내부에-array가-있다">Hash Table은 내부에 array가 있다.</h4>
<p>하지만 array보다 빠르다. 그 이유는 hash function 때문이다!</p>
<h3 id="hash-function">Hash Function</h3>
<p>Hash Function 이 key를 숫자로 바꿔버린다. 그 key 가 index가 되고 그 value에 내가 저장한 value 가 저장되는 것이다.</p>
<p>즉, hash function으로 hash table을 만든다고 하면 key를 해시함수에 넣고 반환된 숫자(index)에 value를 저장하면 된다.</p>
<h5 id="hash-function에-다른-key를-넣었는데-같은-숫자를-반환하면-어떻게-될까">hash function에 다른 key를 넣었는데 같은 숫자를 반환하면 어떻게 될까?</h5>
<p>이를 해시 충돌(hash collision) 이라고 한다.
대처 방법. 리스트의 같은 숫자 공간에 또 다른 배열을 넣는다.
    key 를 사용해서 value를 찾을 때 해시 함수에서 반환된 index 에 있는 요소에 배열이 있다면 그 곳에서 선형 검색을 하게 되는 것이다.
    이 이유 때문에 언제나 해시 테이블의 검색 시간 복잡도가 O(1)이 아니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[What is Javascript?]]></title>
            <link>https://velog.io/@silverj-kim/What-is-Javascript</link>
            <guid>https://velog.io/@silverj-kim/What-is-Javascript</guid>
            <pubDate>Sun, 25 Apr 2021 01:42:48 GMT</pubDate>
            <description><![CDATA[<h1 id="자바스크립트란">자바스크립트란?</h1>
<p>자바스크립트로 작성한 프로그램: 스크립트(script)
스크립트는 웹 페이지의 HTML 안에 작성이 가능, 웹 페이지를 불러올 때 스크립트가 자동으로 실행
자바스크립트는 컴파일 없이 보통의 문자 형태로 작성, 실행이 가능 = 인터프리터(interpreter) 언어</p>
<blockquote>
<p>interpreter vs compiler
프로그램 언어를 해석하고 실행시키는 대표적인 방법 2가지: Compile, Interpret
Compile 컴파일 : 프로그래밍 언어를 런타임 이전에 기계어로 해석하는 작업 방식
런타임 이전에 어셈블리 언어로 변환하기 때문에 구동 시간이 오래걸리지만 구동된 이후에 하나의 패키지로 매우 빠르게 작동됨. 대표적인 언어 : C / C++, Java 등
Interpret 인터프리트 : 런타임 이후에 Row 단위로 해석하여 프로그램을 구동시키는 방식
컴파일 방식에 비해 낮은 퍼포먼스, 그러나 런타임에 실시간 디버깅 및 코드 수정이 가능
인터프리트 언어는 해석을 위한 Virtual Machine 을 두고 머신 위에서 인터프리트를 수행하게 됨. 대표적인 언어 : Javascript(JVM 머신 또는 Analyzer 머신)</p>
</blockquote>
<p>자바스크립트는 브라우저뿐 아니라 서버에서도 실행 가능하며 그 외에도 자바스크립트 엔진이 들어있는 모든 디바이스에서 동작이 가능
브라우저ㄴ에는 자바스크립트 가상 머신이 들어가 있으며 대표적인 예는 아래에</p>
<ul>
<li><strong>V8</strong> Chrome, Opera 사용</li>
<li><strong>SpiderMonkey</strong> Firefox 사용<blockquote>
<p>엔진은 어떻게 동작하나요?</p>
<ol>
<li>엔진이 스크립트를 읽는다 (파싱)</li>
<li>읽어들인 스크립트를 기계어로 전환한다 (컴파일)</li>
<li>기계어로 전환된 코드가 실행된다</li>
</ol>
</blockquote>
</li>
</ul>
<h5 id="브라우저가-보안-상-할-수-없게-막아논-일-중-대표적인-예">브라우저가 보안 상 할 수 없게 막아논 일 중 대표적인 예</h5>
<h6 id="same-origin-policy-동일-출처-정책">Same Origin Policy (동일 출처 정책)</h6>
<p>브라우저는 같은 도메인, 프로토콜, 포트여야만 해당 페이지에 접근이 가능하다.
어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한한다.
타 사이트나 도메인에서 데이터를 받아오는 것은 원칙상 불가능하다.
<em>Same Origin Policy 는 사용자의 보안을 위해 만들어졌다. A에서 받아온 페이지가 B에서 받아온 페이지 상의 정보에 접근해 중요한 개인정보를 훔치는 걸 막기 위함</em></p>
<h6 id="cors-corss-origin-resource-sharing">CORS (Corss-Origin Resource Sharing)</h6>
<p>교차 출처 리소스 공유 CORS는 HTTP 헤더를 사용하여 한 출처에서 실행중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제
Same Origin 정책을 지키기 어려운 경우(<code>https://a.com</code> 에서 <code>https://b.com/flower.jpg</code> 에 접근하거나 <code>https://b.com/data.json</code>에 사용 요청을 하는 경우)가 많기 때문에 리소스의 Origin이 다를 때 Cross-Origin HTTP 요청을 실행하게 된다.</p>
<p>보안상의 이유로 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한 (스크립트에서 보내는 요청 헤더는 언제든 수정이 가능하기 때문?)
Cross Origin 리소스를 불러오려면 그 Origin 에서 올바른 CORS 헤더를 포함한 응답을 반환해야 함 (서버에서 response header에 cors 허용을 함께 보내줘야 함)</p>
<h5 id="자바스크립트를-위한-언어들">자바스크립트를 위한 언어들</h5>
<p>브라우저에서 실행도기 전 자바스크립트로 트랜스파일(transpile, 변환) 할 수 있는 언어들</p>
<ul>
<li>CoffeeScript: javascript&#39;s syntactic suger </li>
<li>TypeScfript: 타입 체크가 없는 자바스크립트를 위한 데이터 타이핑을 집중해 만든 언어</li>
<li>Flow: 타입을 강조하는 언어, made by facebook</li>
<li>Dart: 크로스플랫폼 앱 프레임워크인 Flutter가 사용하는 언어, made by Google</li>
</ul>
<h5 id="inline-script-vs-external-script">inline script vs external script</h5>
<p><strong>인라인 스크립트</strong></p>
<ul>
<li>스크립트 코드가 동일한 페이지에 로드되기 때문에 다른 요청이 필요 없음, HTTP 요청 수가 줄어 성능이 좋음</li>
<li><em>외부 스크립트*</em></li>
<li>외부 스크립트 파일이 다운로드되면 브라우저는 이를 캐시에 저장하므로 다른 페이지에서 참조하는 경우 추가 다운로드가 필요하지 않음, 다운로드 시간이 단축<blockquote>
<p>HTML 파일은 캐싱이 안되나요?
HTML 코드도 캐싱을 할 수 있으나 스크립트로 HTML 코드는 동적으로 변경되는 경우가 많기 때문에 보통 정적인 코드인 javascript, css, 또는 정적인 파일을 캐싱한다. </p>
</blockquote>
</li>
</ul>
<blockquote>
<p>캐시 Cache
캐시(고속완충기)는 데이터나 값을 미리 복사해놓은 임시 저장소이다
캐시에 데이터를 미리 복사해 놓으면 계산이나 접근시간 없이 더 빠른 속도로 데이터에 접근 가능</p>
</blockquote>
<blockquote>
<p>브라우저 캐시, 웹 캐시
서버 지연을 줄이기 위해 웹 페이징, 이미지 등을 임시 저장하기 위한 정보 기술
동일한 서버에 다시 접근할 때 프록시 서버의 웹 캐시에 저장된 정보를 불러오므로 더 빠르게 열람이 가능
브라우저 캐시는 웹 캐시의 일종이며 일반적으로 static assets을 캐싱한다</p>
</blockquote>
<h5 id="다른-형을-가진-값-간의-비교">다른 형을 가진 값 간의 비교</h5>
<pre><code>0 == &quot;0&quot; //true
0 === &quot;0&quot; //false
Boolean(0) //false
Boolean(&quot;0&quot;) //true</code></pre><p>동등 비교 연산자 <code>==</code> 는 0과 false를 구별하지 못함
동등연산자는 형이 다른 피연산자를 비교할 때 피연산자를 숫자형으로 바꾸기 때문에 0도 false가 되고 따라서 0 == false 는 true가 나온다
그러나 일치 연산자 <code>===</code> 를 사용하면 형 변환 없이 값을 비교할 수 있다
일치연산사즌 엄격한 동등연산자라 자료형의 동등 여부까지 검사하기 때문에 형이 다를 경우 <code>===</code>는 즉시 false를 반환한다</p>
<h5 id="논리연산자">논리연산자</h5>
<p><strong>OR ||</strong>
첫번째 truthy 를 찾는 OR
가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 평가
각 피연산자를 불린형으로 변호나하며 변환 후 그 값이 true면 <strong>연산을 멈추고 해당 피연산자의 변환전 원래 값을 반환</strong>
<strong>AND &amp;&amp;</strong>
첫번째 falsy를 찾는 AND
각 피연산자를 불린형으로 변호나하며 변환 후 그 값이 false이면 <strong>연산을 멈추고 해당 피연산자의 변환전 원래 값을 반환</strong></p>
<h6 id="단락평가-short-circuit-evaluation">단락평가 short circuit evaluation</h6>
<p>OR : truthy를 만나면 나머지 값은 더이상 평가하지 않는 것을 단락평가라 부른다</p>
<pre><code>true || alert(&quot;not printed&quot;);
false || alert(&quot;printed&quot;);</code></pre><blockquote>
<p>&amp;&amp; 의 우선순위가 || 보다 높습니다</p>
</blockquote>
<h5 id="폴리필-polyfill">폴리필 polyfill</h5>
<p>트랜스파일러는 명세서에 추가된 새로운 문법이나 내장함수를 사용한 코드를 구 표준을 준수하는 코드로 변경해준다
이렇게 변경된 표준을 준수할 수 있게 기존 함수의 동작 방식을 수정하거나 새롭게 구현한 함수의 스크립트를 <strong>폴리필(polyfill)</strong> 이라 부른다</p>
<h5 id="바벨">바벨</h5>
<p>바벨(Babel)은 트랜스파일러(transpiler)로 모던 자바스크립트 코드를 구 표준을 준수하는 코드로 바꿔준다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[믹스인 Mixin]]></title>
            <link>https://velog.io/@silverj-kim/%EB%AF%B9%EC%8A%A4%EC%9D%B8-Mixin</link>
            <guid>https://velog.io/@silverj-kim/%EB%AF%B9%EC%8A%A4%EC%9D%B8-Mixin</guid>
            <pubDate>Sat, 30 Jan 2021 13:27:09 GMT</pubDate>
            <description><![CDATA[<h1 id="믹스인">믹스인</h1>
<p>자바스크립트는 단일상속만 허용하는 언어
객체엔 단 하나의 [[Prototype]]만 있을 수 있고, 클래스는 클래스 하나만 상속받을 수 있음</p>
<p><strong>믹스인</strong>은 다른 클래스를 상속받을 필요없이 이들 클래스에 구현되어있는 메서드를 담고 있는 클래스
믹스인은 다른 클래스에 행동을 더해주는 용도로 사용
자바스크립트는 다중상속을 지원하지 않는데 믹스인을 사용하면 메서드를 복사해 프로토타입에 구현할 수 있기 때문에 클래스를 확장하는 용도로 사용 가능</p>
<h3 id="믹스인-예시">믹스인 예시</h3>
<p>자바스크립트에서 믹스인을 구현할 수 있는 가장 쉬운 방법은 유용한 메서드 여러개가 담긴 객체를 하나 만드는 것</p>
<pre><code>let satHiMixin = {
  sayHi() {
    alert(`Hello ${this.name}`);
  }
}

class User {
  constructor(name) {
    this.same = name;
  }
}

//메서드 복사
Object.assign(User.prototype, sayHiMixin);
new User(&quot;Dude&quot;).sayHi(); //Hello Dude</code></pre><p>클래스 상속과 믹스인에 구현된 추가 메서드 사용도 가능,
믹스인 안에서 믹스인 상속을 사용하는 것도 가능</p>
<blockquote>
<p><code>__proto__</code> 는 <code>[[Prototype]]</code> 용 getter, setter</p>
</blockquote>
<pre><code>const animal = { eats : true };
const rabbit = { jumps : jumps };
rabbit.__proto__ = animal;
rabbit.eats //true;</code></pre><p><code>rabbit</code>의 프로토타입은 <code>animal</code>이다.
<code>rabbit</code>은 <code>animal</code>을 상속받는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Effective TypeScript]]></title>
            <link>https://velog.io/@silverj-kim/Effective-TypeScript-qgsrj1ea</link>
            <guid>https://velog.io/@silverj-kim/Effective-TypeScript-qgsrj1ea</guid>
            <pubDate>Mon, 18 Jan 2021 05:48:32 GMT</pubDate>
            <description><![CDATA[<h1 id="ch1">Ch1.</h1>
<h2 id="item-5-any-타입의-사용을-제한하라">item 5. any 타입의 사용을 제한하라</h2>
<p>TypeScript&#39;s type system is gradual and optional. 이것의 핵심은 any 타입이다.</p>
<p>There&#39;s No Type Safety with any Types.
any 타입과 함께인 타입 안전함은 없다.</p>
<pre><code>let age: number;
age = &#39;12&#39;;
age = &#39;12&#39; as any;</code></pre><p>age 를 number로 선언했지만 any 타입은 string을 할당하는 것을 허락한다.
타입 체커는 그것이 number라고 믿을 것이다. 혼란이 생길 것 이다.</p>
<p>any Lets You Break Contracts.
any는 contract를 깨게 한다.</p>
<pre><code>function calculateAge(birthDate: Date) : number {
//...
}
let birthDate: any = &quot;1990-01-19&quot;;
calculateAge(birthDate); //OK</code></pre><p>function 을 생성할 때 타입을 명시해주는데 만약에 any type을 사용하면 그 타입을 지키지 않더라도 에러가 발생하지 않는다. 자바스크립트가 종종 암묵적으로 타입들 사이를 변환하려고 하기 때문에 특히 문제가 될 수 있다. </p>
<p>There are No Language Services for any Types.
any 타입을 위한 언어 서비스는 없다.</p>
<pre><code>interface Person {
  first: string;
  last: string;
}

const formatName = (p: Person) =&gt; `${p.first} ${p.last}`;
const formatNameAny = (p: any) =&gt; `${p.first} ${p.last}`;</code></pre><p>타입스크립트는 원래 자동완성 기능을 제공해주는데 any 타입과 함께라면 제공해주지 않는다. 타입스크립트의 모토는 확장된 자바스크립트. </p>
<p>any Types mask bugs when you refactor code
any 타입은 너가 리팩토링할 때 버그를 숨긴다</p>
<p>타입을 작성하는 것은 귀찮을 수 있고 너는 단지 any를 쓰면 된다.
하지만 좀 더 자세한 타입을 사용했다면 type checker에 잡힐 것이고 any를 사용한다면 type checker에 안걸리고 런타임 exception이 발생할 수 있다.</p>
<pre><code>interface ComponentProps {
  onSelectItem: (item: any) =&gt; void;
}
function renderSelector(props: ComponentProps) { /* ... */ }

let selectedId: number = 0;
function handleSelectItem(item: any) { //하지만 여기가 any
  selectedId = item.id;
}

renderSelector({onSelectItem: handleSelectItem});

//아래와 같이 item의 타입을 number로 변경
interface ComponentProps {
  onSelectItem: (id: number) =&gt; void;
}</code></pre><p>any hides your type design.
any 타입은 너의 타입 디자인을 숨긴다.</p>
<p>수십가지의 프로퍼티에 대한 타입을 쓰는 것 보다 너는 단지 any 타입을 쓰는 게 더 쉬워보일 수 있다. 좋은 디자인은 clean, correct and understandable 코드를 작성하는 것이 필수적이다. 하지만 any 타입은 암묵적이다. <em>Better to write it out for everyone to see.</em> 이부분이 any type을 썻다는 걸 적으라는 건지 아니면 타입을 적으라는 건지?</p>
<p>any type undermine confidence in the type system.
any 타입은 타입시스템의 신뢰를 훼손한다.</p>
<p>타입스크립트는 나의 실수를 많이 잡아주는데 any 타입을 쓰면 잡히지 않을 때가 있어서 타입스크립트의 신뢰를 떨어뜨린다. </p>
<p>정리!!
사용하지마라!!!</p>
<h2 id="chapter-2-typescripts-type-system">Chapter 2. TypeScript&#39;s Type System.</h2>
<p>타입스크립트의 타입 시스템</p>
<p>타입스크립트는 코드를 생성하지만 타입 시스템이 메인 이벤트다. 이것이 너가 이 언어를 사용하는 이유다.단단한 기초를 배울 수 있는 챕터</p>
<h2 id="item-6-use-your-editor-to-interrogate-and-explore-the-type-system">Item 6. Use Your editor to interrogate and explore the type system.</h2>
<p>타입시스템의 탐색하고 조사하기 위해 에디터를 사용해라</p>
<p>너가 타입스크립트를 설치할 때 너는 2가지 실행파일을 얻는다.</p>
<ol>
<li>tsc, 타입스크립트 컴파일러</li>
<li>tsserver, 타입스크립트 독립형 서버</li>
</ol>
<p>너는 타입스크립 컴파일러를 직접적으로 실행할 가능성이 높지만 서버는 언어 서비스를 제공하기 때문에 모든 부분이 매우 중요하다.? 
자동완성, 조사, navigation, refactoring을 제공하도록 구성되어있지 않다면 너는 놓칠 것이다. 자동완성은 타입스크립트의 좋은 점 중 하나.</p>
<p>조건식의 분기에서 타입의 변화를 보는 것은 타입 시스템의 신뢰를 쌓을 수 있는 엄청난 방법이다.</p>
<pre><code>function logMessage(messgae: string | null) {
  if(message) {
    message //(parameter) message: string)
  }
}</code></pre><p>분기 외부에 null, 내부에 string</p>
<pre><code>function getElement(elOrId: string|HTMLElement|null): HTMLElement {
  if (typeof elOrId === &#39;object&#39;) {
    return elOrId;
 // ~~~~~~~~~~~~~~ &#39;HTMLElement | null&#39; is not assignable to &#39;HTMLElement&#39;
  } else if (elOrId === null) {
    return document.body;
  } else {
    const el = document.getElementById(elOrId);
    return el;
 // ~~~~~~~~~~ &#39;HTMLElement | null&#39; is not assignable to &#39;HTMLElement&#39;
  }
}</code></pre><p>javascript의 typeof null은 &quot;object&quot;다. 그래서 elOrId는 여전히 null일 수 있다 따라서 먼저 null을 체크하도록 수정해야 한다. 그리고 2번째 에러는 getElementById 는 null을 반환할 수 있기 때문에 발생한다. 따라서 추가 헨들링이 필요하다.</p>
<p>&quot;Go to Definition&quot; 그 타입을 선언한 파일로 이동한다. </p>
<p>타입 선언은 처음에 읽기 어려울 수 있지만 타입스크립트로 할 수 있는 것, 사용중인 라이브러리의 모델링 방법 및 오류를 디버깅하는 방법을 확인할 수 있는 훌륭향 방법이다. </p>
<p>정리!!</p>
<ul>
<li>에디터를 써서 타입스크립트를 이용해라</li>
<li>타입 시스템이 어떻게 작동하고 타입스크립트가 타입을 어떻게 추론하는지에 대한 감을 얻기위해서 에디터를 사용해라</li>
<li>타입 선언 파일로 점프하는 방법</li>
</ul>
<h2 id="item-7-think-of-types-as-sets-of-values어렵">item 7. Think of types as Sets of Values.어렵..</h2>
<p>값의 세트로서 타입을 생각</p>
<p>런타임에서 모든 변수는 자바스크립트의 값 범위 중 하나를 선택한다. 많은 값들이 있다.
그러나 코드를 실행하기 전에 타입스크립트는 에러를 체크할 때 변수는 타입을 가진다.
가능한 값들의 세트로서 생각하는 것이 최고다. 이 세트는 그 타입의 도메인(범위)으로 알려져있다. 
가장 작은 세트는 아무런 값도 포함하고 있지 않은 empty set. 그것은 타입스크립트의 never 타입에 해당한다. 그것의 도메인은 비어져 있기 때문에 아무런 값이 할당될 수 없다.
다음으로 작은 세트는 단일 값이 포함된 것이이다. 이것들은 타입스크립트의 유닛 타입으로 알려진 또는 <em>리터럴타입</em>  에 해당된다. </p>
<blockquote>
<p>리터럴 : 데이터 그 자체, 값을 할당할 때 사용된다.
javascript&#39;s literal : string, number, boolean, null, undefined, Symbol, object</p>
</blockquote>
<p>너는 유닛 타입들을 union 할  수 있다. (합칠 수 있다?)
Union types correspond to unions sets of values.</p>
<p>type checker가 하는 거의 모든 작업은 한 세트가 다른 세트의 하위 집합(subset)인지 테스트하는 것</p>
<p>유한한 집합은 추론하기 쉽다. 그러나 무한 도메인이 있고 그 추론은 더 어렵다.</p>
<p>타입스크립트의 구조 입력 룰은 값이 다른 속성을 가질 수도 있음을 의미한다. 심지어 호출할 수도 있다. 이 사실은 가끔씩 과도한 프로퍼티 검사에 의해 가려질 수 있다.</p>
<pre><code>interface Person {
  name: string;
}
interface Lifespan {
  birth: Date;
  death?: Date;
}
type PersonSpan = Person &amp; Lifespan;
const ps : PersonSpan = {
  name: &quot;Alan Turing&quot;,
  birth: new Date(&quot;1923/12/11&quot;),
  death: new Date(&quot;1955/12/11&quot;)
} //OK
type K = keyof (Person | Lifespan); //Type is never</code></pre><p>&amp; 연산자는 두 가지 타입의 교차점을 계산한다.
Person과 Lifespan에 공통 속성이 없어서 empty set(never type)이라고 생각할 수 있다. 하지만 type operations는 인터페이스의 속성이 아닌 값 집합에 적용된다.
3가지 이상의 속성을 가져도 여전히 PersonSpan 타입에 속한다. 일반적인 규칙은 intersection(교차점) 타입의 값에는 속성의 합(union) 을 포함한다.
그러나 두 인터페이스의 union의 타입은 never다.</p>
<pre><code>keyof (A&amp;B) = (keyof A) | (keyof B)
keyof (A|B) = (keyof A) &amp; (keyof B)</code></pre><blockquote>
<p>keyof
타입 값에 존재하는 모든 프로퍼티의 키값을 union 형태로 리턴받는다
ex. type LifeKeys = keyof LifeSpan; //birth, death</p>
</blockquote>
<pre><code>interface Person {
  name: string;
}
interface PersonSpan extends Person {
  birth: Date;
  death?: Date;
}</code></pre><p>값의 세트로 타입을 생각할 때 extends의 의미는 무엇인가? 
단지 &quot;할당가능&quot; &quot;하위 집합&quot;
PersonSpan의 모든 값은 string 타입의 name 속성을 무조건 가져야 한다. 그리고 birth도.</p>
<pre><code>interface Vector1D {x: number}
interface Vector2D extends Vector1D {y: number}
interface Vector3D extends Vector2D {z: number}</code></pre><p>1차원, 2차원, 차원 벡터의 관점에서 subtype을 설명한다면
Vector3D는 Vertor1D의 subset인 Vertor2D의 subset(하위 집합).
보통 계층구조(하이어라키)로 그려지지만 값의 집합으로 생각하면 <strong>밴다이어그램이 낫다.</strong></p>
<p>extends 키워드는 또한 generic 타입에서도 제약 조건으로 나타날 수 있다. subset of 를 의미하기도 한다.
집합의 관점에서 생각해보면, 어떤 종류의 도메인이라도 string의 subset이면 된다.</p>
<p>Union 타입은 계층구조로는 맞지 않을 수 있지만 sets of value의 관점에서는 생각할 수 있다. </p>
<blockquote>
<p>Tuple
const nameAndHeight: [string, number] = [&#39;aaa&#39;, 177];
튜플 타입을 이용해 원소의 수와 타입을 지정된 배열의 타입을 정의할 수 있다.</p>
</blockquote>
<pre><code>const list = [1,2]; //Type is number[]
const tuple: [number, number] = list; //error </code></pre><p>number[]은 [number,number]의 하위집합이 아니기 때문에 할당할 수 없다. (역할당은 가능하다). 예를들어 [], [1]은 number[]은 맞지만 [number, number]는 아니기 때문.
속성의 길이가 다르기 때문에 triple을 pair에 할당하는 것도 안된다. 타입스트립트는 {0: number, 1: number}를 {0: number, 1: number, length: 2}로 모델링하기 때문. </p>
<p>모든 sets of values(값의 세트)가 타입스크립트 타입에 해당하는 것은 아니다.
Exclude 를 이용하여 유형을 뺄수 있으나 적절한 Typescript type이 될 경우에만 제외된다. (??)</p>
<blockquote>
<p>Exclude&lt;T,U&gt;
T타입들 중 U타입과 겹치는 타입을 제외한다.
type Exclude&lt;T, U&gt; = T extends U ? never : T;
예시: tyep T0 = Exclude&lt;&quot;a&quot; | &quot;b&quot;, &quot;a&quot;&gt; //&quot;b&quot;</p>
</blockquote>
<p>정리!!</p>
<ul>
<li>sets of values(타입의 도메인)으로 타입을 생각하라.</li>
<li>타입스크립트 유형은 엄격한 하이어라키 보다 교차집합(밴다이어그램)을 형성한다. 두 가지 유형은 다른 유형의 하위 유형없이 겹칠 수 있다.</li>
<li>추가적인 속성을 가지더라도 오브젝트는 여전히 타입에 속할 수 있다.</li>
<li>타입 연산은 세트의 도메인을 적용된다. A와 B의 교차점은 A의 도메인과 B의 도메인의 교차점이다. 오브텍트 타입의 경우, A&amp;B는 A와 B 모두의 속성을 갖는 것을 의미한다.</li>
<li>&quot;extends&quot;는 &quot;assignable to&quot; , &quot;subtype of&quot;는 &quot;subset of&quot;와 동의어</li>
</ul>
<h2 id="item8-know-how-to-tell-wheteher-a-symbol-is-in-the-type-space-or-value-space">Item8. Know how to tell wheteher a Symbol is in the type space or value space</h2>
<p>타입 공간 또는 값 공간에 Symbol이 있는지 확인하는 방법에 대해 알아보자</p>
<p>타입스크립트의 Symbol은 2가지 space(공간)가 존재한다.</p>
<ul>
<li>Type space</li>
<li>Value space</li>
</ul>
<p>동일한 이름이 어떤 공간에 있느냐에 따라 다른 것을 참조할 수 있기때문에 혼란을 줄 수 있다.</p>
<pre><code>interface Cylinder {
  radius: number;
  height: number;
}
const Cylinder = (radius: number, height: number) =&gt; ({radius, height});</code></pre><p><code>interface Cylinder</code>는 type space 안에 있는 심볼이다.
<code>const Cylinder</code>는 value space 안에 있는 동일한 이름의 심볼이다.
서로 아무런 관계가 없다. </p>
<p><code>instanceof</code> 는 자바스크립트의 런타임 연산자이며 그것은 값으로 작동한다.
그래서 <code>instanceof Cylinder</code>는 타입이 아니라 function 이다.</p>
<p>type sapce인지 value space인지 한눈에 알 수 있는 것은 아니다. symbol이 발생하는 컨텍스트를 통해 알 수 있다. </p>
<p><strong>일반적으로 type or interface 뒤에 있는 symbol은 type space,
const or let 선언에 도입된 symbol은 value</strong></p>
<p>컴파일 하면서 Type은 지워지기 때문에 생성된 자바스크립트를 보면 type space인지 value space인지 명확하게 알 수 있다.</p>
<p>타입스크립트에서는 type space와 value space을 번갈아 사용할 수 있다. 
<code>:</code> 또는 <code>as</code> 뒤에 오는 심볼은 type space, <code>=</code> 뒤에 있는 심볼은 value space</p>
<pre><code>interface Person {
  first: string;
  last: string;
}
const p: Person = { first: &quot;Jane&quot;, last: &quot;Jacobs&quot; };</code></pre><p>Person은 타입, { first: &quot;Jane&quot;, last: &quot;Jacobs&quot; } 은 값.</p>
<p>클래스에서 도입한 타입스크립트의 Type은 그것의 shape(속성과 메서드)을 기반으로 한다.</p>
<pre><code>type T1 = typeof p;  // Type is Person
type T2 = typeof email;
    // Type is (p: Person, subject: string, body: string) =&gt; Response

const v1 = typeof p;  // Value is &quot;object&quot;
const v2 = typeof email;  // Value is &quot;function&quot;</code></pre><p><code>typeof</code>는 자바스크립트의 런타임 연산자고 그것은 string을 리턴한다.
그것은 Typescript type과 같지않다.
자바스크립트에는 6가지 런타임 타입이 있다 : string, number, boolean, undefined, object, function</p>
<p><code>class</code> 키워드는 value와 type을 둘다 가지고 있기 때문에 컨텍스트에 달려있다.</p>
<pre><code>const v = typeof Cylinder;  // Value is &quot;function&quot;
type T = typeof Cylinder;  // Type is typeof Cylinder
declare let fn: T;
const c = new fn();  // Type is Cylinder</code></pre><p>declare let fn: T; ???????</p>
<p><code>InstanceType</code> generic을 사용하여 instance type과 constructor type 사이를 이동할 수 있다.
<code>type C = InstanceType&lt;typeof Cylinder&gt;;</code></p>
<p><code>obj[field]</code>와 <code>obj.field</code>는 값 공간에서는 동일하지만 타입공간에서는 동일하지 않다. 다른 타입의 속성의 타입을 얻으려면 []를 사용해야 한다.</p>
<p>이해가 안가는 부분 ??</p>
<pre><code>type PersonEl = Person[&#39;first&#39; | &#39;last&#39;];  // Type is string
type Tuple = [string, number, Date];
type TupleEl = Tuple[number];  // Type is string | number | Date
</code></pre><p>아 Tuple[number] index 에 number를 넣으면 그 값이 타입이 된다는 건가?
ex. Tuple[1] type is number</p>
<p>두 공간에서 서로 다른 의미를 갖는 다른 많은 구성요소가 있다.</p>
<ul>
<li>javascript의 <code>this</code> 키워드는 value space의 this, type으로의 <code>this</code>는 this의 타입스크립트 타입, &quot;다형성 polymorphic this&quot; 하위클래스가 있는 메서드 체인을 구현하는데 유용</li>
</ul>
<blockquote>
<p>다형성</p>
</blockquote>
<ul>
<li>in value space, &amp; and | 는 AND and OR, in type space, union 연산자 와 교차점이다.</li>
<li><code>const</code>는 새로운 변수를 소개하지만 <code>as const</code>는 리터럴 또는 리터럴 표현식의 추론된 타입을 변경한다. </li>
<li><code>extends</code> 는 subclass 또는 subtype 또는 제네릭의 제약을 를 정의할 수 있다.</li>
<li><code>in</code> </li>
</ul>
<p>destructuring 하려면</p>
<pre><code>function email({person, subject, body}: {person: Person, subject: string, body: string}) {...}</code></pre><p>정리!!</p>
<ul>
<li>type space, value space 어디에 있는지 확인하는 방법에 대해 알아보자</li>
<li>모든 값은 타입을 가지고 있다. 그러나 타입은 값을 가지고 있지 않다. type 과 interface는 타입 스페이스에만 존재한다</li>
<li>class 또는 enum은 유형과 값을 모두 도입한다.</li>
<li>&quot;foo&quot;는 string 리터럴 일 수도 있고 string 리터럴 타입일 수도 있다. </li>
<li><code>typeof</code> 및 많은 키워드와 연산자는 타입 스페이스와 값 스페이스에서 다른 의미를 가진다.</li>
</ul>
<h2 id="item-9-prefer-type-declarations-to-type-assertions">Item 9. Prefer Type Declarations to Type Assertions.</h2>
<p>타입 단언보다 타입 선언 선호하라.</p>
<p>타입스크립트에서 변수에 값을 할당하고 값을 지정하는 두가지 방법이 있다.</p>
<pre><code>interface Person { name: string };

const alice: Person = { name: &quot;Alice&quot; };
const bob = { name: &quot;Bob&quot; }  as Person;</code></pre><ol>
<li>변수에 타입 선언을 추가하고 값이 타입을 준수하는지 확인한다.</li>
<li>타입 단언(주장, assertion). 타입스크립트에서 추론한 타입에도 불구하고 타입이 Person이라고 말한다.</li>
</ol>
<p>타입 선언을 선호하는 이유는 값이 인터페이스를 준수하는지 varify하기 때문이다. 반면에 type assertion은 type checker에게 타입을 알려주기 때문에 에러를 침묵시킨다. </p>
<p><code>&lt;Person&gt;{} = {} as Person</code></p>
<p>이해가 잘?? 
 But (name: Person) would specify the type of name as Person and allow the return type to be inferred, which would produce an error.</p>
<pre><code>const people = [&#39;alice&#39;, &#39;bob&#39;, &#39;jan&#39;].map(
  (name): Person =&gt; ({name})
); // Type is Person[]</code></pre><p>언제 type assertion을 사용해야하나? type checker를 사용할수 없는 context에서</p>
<p>prefix !는 boolean negation(부정)
suffix !는 값이 non-null이라는 assertion(주장)으로 해석된다.</p>
<p>타입 주장에는 제한이 있다 : 임의 타입간에 변환할 수 없다. 하위타입 간에 변환은 가능하나 하위 타입이 아닌 경우 불가능하다.</p>
<p><code>Every type is a subtype of unknown, so assertions involving unknown are always OK.</code>
unknown 을 포함함녀 임의의 타입 사이에 변환이 가능해진다. </p>
<p>정리!!</p>
<ul>
<li>타입 선언을 더 선호하라</li>
<li>arrow function 의 반환 타입에 주석을 다는 방법</li>
<li>타입스크립트에 없는 타입에 대해 알고 있을 때 non-null assertions과 type assertion을 사용해라</li>
</ul>
<h2 id="item-10-avoid-object-wrapper-types-string-number-boolean-symbol-bigint">item 10. Avoid Object Wrapper Types (String, Number, Boolean, Symbol, BigInt)</h2>
<p>자바스크립트는 object를 제외하고 <strong>string, number, booleans, null, undefined, symbol, bigint</strong> primitive value(원시 값)을 가지고 있다.</p>
<p>Primitives는 불변이고 메서드가 없기 때문에 object와 구별된다. 
stirng primitive 은 메소드가 없지만 자바스크립트는 메소드가 있는 string object type 또한 정의한다. Javascript는 이런 유형 간 서로 자유롭게 변환이 된다. string primitive에서 charAt과 같은 메서드에 접근하는 경우 자바스크립트는  해당 메서드를 string 오브젝트로 감싸고 메서드를 호출한 다음 object를 버린다.</p>
<p>null과 undefined는 object wrapper가 없다</p>
<p>wrapper type은 원시값에 대한 메서드와 정적 메서드를 제공하지만 일반적으로는 인스턴스화 할 이유가 없다.</p>
<p>Typescript는 원시 요소와 오브젝트 래퍼에 대해 고유한 타입을 사용하여 이러한 차이를 모델링한다.</p>
<p><code>string</code>은 <code>String</code>에 할당할 수 있지만 <code>String</code>은 <code>string</code>에 할당할 수 없다.</p>
<p>물론 런타임의 값은 object가 아니라 primitive다.
그러나 primitive type을 object wrapper에 할당할 수 있기 때문에 타입스크립트는 이러한 선언을 허용한다. <code>primitive type</code>을 사용하는 게 좋다.</p>
<p>BigIng와 Symbol values가 있다. type이 아니다. (??)</p>
<p>정리!!</p>
<ul>
<li>원시값에 대한 메서드를 제공하기 위해 오브젝트 래퍼 타입을 사용하는 법을 이해한다.
인스턴스화 하거나 직접 사용하지 않도록 한다.</li>
<li>타입스크립트 오브젝트 래퍼 타입을 피해라. 대신에 원시 타입을 사용해라. </li>
</ul>
<h2 id="item-11-recognize-the-limits-of-excess-property-checking">Item 11. Recognize the Limits of excess property checking</h2>
<p>속성 확인 초과의 제한을 알아보다.</p>
<p>선언된 타입의 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 프로퍼티를 가지고 있고 다른 속성은 없는지 확인한다.</p>
<pre><code>interface Room {
  numDoors: number;
  ceilingHeightFt: number;
}
const r: Room = {
  numDoors: 1,
  ceilingHeightFt: 10,
  elephant: &#39;present&#39;,
// ~~~~~~~~~~~~~~~~~~ Object literal may only specify known properties,
//                    and &#39;elephant&#39; does not exist in type &#39;Room&#39;
};
const obj = {
  numDoors: 1,
  ceilingHeightFt: 10,
  elephant: &#39;present&#39;,
};
const r: Room = obj;  // OK</code></pre><p>선언된 타입의 프로퍼티를 제외하고 다른 프로퍼티가 있을 경우 에러를 뱉지만
중간 변수를 사용하면 에러가 없어진다.</p>
<p><em>type assertion을 사용할 때 초과 프로퍼티 검사는 발생하지 않는다.</em>
이것은 assertion보다 declaration을 더 선호하는 이유 중 하나다.</p>
<p>index signature를 사용하여 추가 프로퍼티를 기대하도록 지시할 수도 있다.</p>
<pre><code>interface Options {
  darkMode?: boolean;
  [otherOptions: string]: unknown;
}
const o: Options = { darkmode: true };  // OK</code></pre><p>이건 적합하지 않은 방법이다.</p>
<p><strong>weak type</strong> 오직 옵션 필드만 가지고 있는 weak 타입
weak type의 경우 타입스크립트는 값 타입과 선언된 타입에 하나 이상의 공통 속성이 있는지 확인하기 위해 다른 검사를 추가한다.
모든 할당 가능성 검사 중에 발생하며 이 검사는 중간 변수를 사용해도 무시되지 않는다. </p>
<p><code>excess property checking</code>은 오타를 잡고 실수를 잡는 데 효과적이다. 특히 옵션 필드가 포함된 타입의 경우. 그러나 범위가 매우 제한적이다. 객체 리터럴에서만 적용된다.</p>
<p>정리!!</p>
<ul>
<li>object literal을 변수에 할당하거나 인수로 전달하면 excess property checking을 받는다.</li>
<li>과도한 프로퍼티 검사는 에러를 찾는데 효과적인 방법이다. 그러나 일반적인 구조적 할당 가능성 검사와는 다르다. 서로 충돌하면 할당 가능성의 모델을 구축하기가 더 어렵다.</li>
<li>과도한 프로퍼티 검사의 한계를 알고 있어야 한다. 중간 변수를 도입하면 에러가 없어진다.</li>
</ul>
<h2 id="item-12-apply-types-to-entire-function-expressions-when-possible">item 12. Apply Types to Entire Function Expressions when possible</h2>
<p>가능한 전체 함수 표현식에 타입을 적용하라</p>
<p>자바스크립트와 타입스크립트는 함수문과 함수식을 구별한다.</p>
<p>TS에서 함수 표현식의 장점은 매개변수의 타입과 반환 타입을 개별적으로 지정하는 대신 한번에 전체 함수에 타입 선언을 할 수 있다는 것이다.</p>
<p>적은 annotation, function 구현과 분리되어 있고 logic을 더 명백하게 만든다. 반환 타입도 체크한다.</p>
<p>라이브러리 작성자의 경우 , 일반적인 콜백에 대한 타입 선언을 제공하는 것을 고려해라.
ex. 리액트의 MouseEventHandler type</p>
<p>노이해 ??</p>
<pre><code>const checkedFetch: typeof fetch = async (input, init) =&gt; {
  const response = await fetch(input, init);
  if (!response.ok) {
    throw new Error(&#39;Request failed: &#39; + response.status);
  }
  return response;
}</code></pre><p>fetch 함수 를 타입으로 적용하면 타입스크립트는 fetch 함수 타입을 통해 input과 init parameter의 타입을 추론할 수 있다.
또 checkedFetch의 반환 타입이 fetch와 동일하다는 걸 보장할 수 있다. </p>
<p>간결 + 안정성이 향상, 타입 선언을 전체 함수에 적용할 수 있는지 여부를 고려하라.</p>
<p>정리!!</p>
<ul>
<li>매개변수와 리턴 타입이 아닌 전체 함수식에 타입 annotation을 적용하는 것을 고려하라</li>
<li>같은 타입 시그니처가 반복된다면 function type을 고려하라</li>
<li>다른 함수의 시그니처를 일치시킬 때 <code>typeof fn</code>을 사용하라</li>
</ul>
<h2 id="item-13-know-the-differences-between-type-and-interface">Item 13: Know the Differences Between type and interface</h2>
<p>타입과 인터페이스의 차이점</p>
<p>타입스크립트에서 named type을 선언하길 원한다면 너는 두가지 옵션을 가진다.
type 또는 interface</p>
<pre><code>type TState = {
  name: string;
  capital: string;
}
interface IState {
  name: string;
  capital: string;
}</code></pre><p>클래스도 사용할 수 있지만 자바스크립트 런타임에서 값으로 생각한다</p>
<p>type과 interface 중 어떤 걸 써야하나?</p>
<p><em>접두사의 예는 이름이 I 또는 T인 타입 이름만 사용하여 정의되는 방법을 나타낸다. 그러나 요즘엔 불필요하고 나쁜 스타일로 여겨지고 있다.</em></p>
<p>먼저 State type은 거의 구별할 수 없다. </p>
<p>?? (x: number): number; 이거 머지?</p>
<pre><code>type TFnWithProperties = {
  (x: number): number;
  prop: string;
}</code></pre><p>class는 인터페이스와 간단한 타입으로 구현할 수 있다.</p>
<p>차이점 
인터페이스는 union type처럼 복잡한 타입을 확장할 수 앖다. 그렇게 하려면 type과 &amp; 을 써야한다.
union type은 있고 union interface는 없다.</p>
<p>일반적으로 타입이 인터페이스보다 좋다. union할 수 있으며 매핑된 기능이나 조건부 타입같은 확장된 기능을 이용할 수 있다.
튜플 및 어레이 타입을 보다 쉽게 표현.</p>
<p>그러나, 타입에는 없는 기능을 인터페이스는 몇가지 가지고 있다.
인터페이스는 augmented 증강될 수 있다. 같은 이름의 interface를 선언하여 필드를 추가할 수 있다. 이것을 &quot;declaration merging&quot;이라고 한다.
타입스크립트는 병합을 이용해 다른 버전의 자바스크립트 표준 라이브러리에 대한 타입을 가져온다. es5 + es2015 </p>
<p>만약 아무도 너의 타입을 늘리지 않는 것이 중요할 땐 type을 써라.</p>
<p>복잡한 타입의 경우 타입을 사용해아한다. 하지만 단순한 오브젝트 타입은? 일관성과 확대를 고려하여 알아서 사용해라?
확립된 스타일이 없을 땐 augmentation 증가에 대해 생각해라.</p>
<p>정리!!</p>
<ul>
<li>타입과 인터페이스 차이와 유사성 이해</li>
</ul>
<h2 id="item-14use-type-operations-and-generics-to-avoid-repeating-yourself">item 14.Use type operations and Generics to Avoid repeating yourself</h2>
<p>반복을 피하기 위해 타입 연산 및 제네릭을 사용하라 </p>
<p>DRY principle (원칙) : Don&#39;y repeat yourslef (DRY) 반복하지마라.
타입 간 매핑 방법을 학습하여 DRY의 이점을 타입 정의에 적용할 수 있따.</p>
<p>반복을 줄이는 가장 간단한 방법은 타입을 지정하는 것.</p>
<pre><code>interface Point2D {
  x: number;
  y: number;
}
function distance(a: Point2D, b: Point2D) {}

type HTTPFunction = (url: string, opts: Options) =&gt; Promise&lt;Respons&gt;;
const get: HTTPFunction = (url, opts) =&gt; {}
const post : HTTPFunction = (url, opts) =&gt; {}</code></pre><p>또한 교차 연산차(&amp;)를 이용하여 기존 타입을 확장할 수 있다. 하지만 다음과 같은 경우는 흔하지 않다.</p>
<pre><code>type PersonWithBirthday = Pesron &amp; {birth: Date};</code></pre><p>TopNavState를 확장하여 State를 구축하는 대신 TopNavState를 State 필드의 하위 집합으로 정의하려고 한다. 이렇게 하면 전체 앱의 상태를 정의하는 단일 인터페이스를 유지할 수 있다. 중복되는 프로퍼티의 타입을 제거할 수 있다.</p>
<pre><code>interface State {
  userId: string;
  pageTitle: string;
  recentFiles: string[];
  pageContents: string;
}
type TopNavState = {
  userId: State[&#39;userId&#39;];
  pageTitle: State[&#39;pageTitle&#39;];
  recentFiles: State[&#39;recentFiles&#39;];
};

//better
type TopNavState = {
  [k in &quot;userId&quot; | &quot;pageTitle&quot; | &quot;recentFiles&quot; ]: State[k]  
};

type Pick&lt;T, K&gt; = { [k in K]: T[k] };

//최종
type TopNavState = Pick&lt;State, &#39;userId&#39; | &#39;pageTitle&#39; | &#39;recentFiles&#39;&gt;;</code></pre><p>반복문도 쓸 수 있네
이해 제대로 한거임?
<code>Pick</code>은 제네릭의 예. PICK은 T(State)와 K(userId | pageTitle | recentFiles) 두가지 타입을 사용하며 함수가 2개의 값을 사용하고 세가지를 반환할 수 있기 때문에 세가지 타입을 반환한다.</p>
<pre><code>type ActionType = &#39;save&#39; | &#39;load&#39;;
//better
type ActionType = Action[&#39;type&#39;];</code></pre><p>타입이 반복되어 각 속성을 ? 옵셔널로 설정하는 경우는 일반적이여서 표준 라이브러리에 
<code>Partial</code> 로 포함되어있다.
<code>typeof</code>를 이용하여 값의 shape도 일치하는 타입을 정의할 수 있다 
<code>type Options = typeof INIT_OPTIONS</code></p>
<p>조건부 타입(conditional types) : <code>ReternType</code> 제네릭
<code>type UserInfo = ReturnType&lt;typeof getUserInfo&gt;;</code>
함수의 값인 getUserInfo가 아닌 함수 타입인 getUserInfo의 타입에 따라 작동한다. 신중하게 사용하라..</p>
<p>제네릭 타입은 타입에 대한 함수와 동일하다.그리고 함수들은 DRY의 열쇠이다.
따라서 제네릭이 타입의 DRY 핵심인건 놀라운 일이 아니다.
타입 시스템을 사용하여 매핑할 수 있는 값을 제한할 수 있다. </p>
<p>제네릭 타입의 파라미터는 어떻게 제한하냐? <code>extends</code>를 사용한다. 제네릭 매개변수가 타입을 확장한다고 선언할 수 있다.</p>
<p><em>note 현재 타입스크립트는 선언데 항상 generic 파라미터를 쓰길 요구한다. Typescript가 제네릭 매개변수의 타입을 추론하도록 하려면 신중하게 타입이 정의된 함수를 사용할 수 있다.</em></p>
<p>extends 를 subset of 로 읽는게 도움이 된다.</p>
<p>정리!!</p>
<ul>
<li>DRY 원칙 적용</li>
<li>타입을 반복하지 않고 이름을 정하라.인터페이스의 필드를 반복하지 마라. extends를 사용하라.</li>
<li>타입 간에 매핑을 위해 Typescript에서 제공하는 tool 이해를 구축하라. keyof typeof indexing, and mapped types.</li>
<li>제네릭 타입은 타입에 대한 함수와 동일하다. extends 를 사용하여 제네릭 타입을 제약하라</li>
<li>Partial, ReturnType, Pick 에 대해 숙지</li>
</ul>
<h2 id="item-15-use-index-signatures-for-dynamic-data">item 15. Use index signatures for dynamic data</h2>
<p>동적 데이터에는 index signature를 사용하라</p>
<p>Javascript 의 가장 좋은 기능 중 하나는 객체를 만드는 편리한 구문</p>
<p>인덱스 서명(index signature)을 이용하여 유연한 매핑을 할 수 있다.</p>
<pre><code>type Rocket = {[property: string]: string};
// string is the index signature.</code></pre><ul>
<li>a name for keys : 단순히 문서화용, 타입 검사기에 어떤 방식으로도 사용되지 않음</li>
<li>a type for the key : string, number or symbol 을 조합해야 하지만 일반적으로 문자열만 사용</li>
<li>a type for the value: 무엇이든 될 수 있다.</li>
</ul>
<p>index signature는 그다지 정확하지 않다. 이 경우 로켓은 인터페이스여야 한다</p>
<p>인덱스 서명을 사용하는 곳은 동적 데이터.
인덱스 서명을 사용하는 데 있어 문제가 있는 경우 string이 너무 광범위 하면 다른 방법들이 있다.</p>
<p>그 중 하나는 <code>Record</code>를 사용하는 것.
이것은 키 타입의 유연성을 높여주는 제네릭 타입니다. 특히 string의 하위 집합을 전달할 수 있다.</p>
<pre><code>type Vec3D = Record&lt;&#39;x&#39; | &#39;y&#39; | &#39;z&#39;, number&gt;;
// Type Vec3D = {
//   x: number;
//   y: number;
//   z: number;
// }</code></pre><p>또 다른 하나는 매핑된 타입을 쓰는 것이다. 이렇게 하면 키마다 다른 타입을 사용할 수 있다.</p>
<pre><code>type Vec3D = {[k in &#39;x&#39; | &#39;y&#39; | &#39;z&#39;]: number};
// Same as above
type ABC = {[k in &#39;a&#39; | &#39;b&#39; | &#39;c&#39;]: k extends &#39;b&#39; ? string : number};
// Type ABC = {
//   a: number;
//   b: string;
//   c: number;
// }</code></pre><h2 id="item-16-prefer-arrays-tuples-and-arraylike-to-number-index-signatures">item 16. Prefer arrays, tuples and arraylike to number index signatures</h2>
<p>number index signature보다 array tuple arrylike를 더 선호하라</p>
<p>자바스크립트는 유별난 언어. 암묵적인 타입의 강압을 포함한다</p>
<pre><code>&quot;0&quot; == 0 //true</code></pre><p>위 와 같은 기능은 === 으로 방지할 수 있다.</p>
<p>object는 무엇인가? 키/값 쌍의 모음
키는 보통 문자열이고 값은 무엇이든 될 수 있음</p>
<blockquote>
<p>해시
해시 함수? 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수.
해시 함수를 이용하여 고정된 길이의 암호화된 문자열로 바꿔버리는 것</p>
</blockquote>
<p>자바스크립트는 &quot;hashable&quot; object에 대한 개념이 없다. 보다 복잡한 키를 사용하려는 경우 해당 오브젝트는 그것을 toString 을 호출하여 stirng으로 변환한다.
특히 숫자는 키로 사용할 수 없다. 런타임에서 문자열로 변환된다.</p>
<p>array는 무엇인가? 이것은 object다.
그러나 숫자 인덱스를 함께 사용하는 것은 매우 일반적.
object.keys를 사용해서 array의 키를 조회해보면 string이 반환된다.</p>
<h2 id="item17-변화와-관련된-오류를-방지하기-위해-readonly-사용">item17. 변화와 관련된 오류를 방지하기 위해 readonly 사용</h2>
<h1 id="chapter3-type-inference">Chapter3. Type Inference</h1>
<p>프로그래밍언어에서 “statically typed”와 ‘explicitly typed” 는 동의어로 사용되어 왔다. </p>
<h2 id="item19-avoid-cluttering-your-code-with-inferable-types">item19. Avoid cluttering your code with inferable types.</h2>
<p>추론 가능한 타입과 함께 너의 코드를 어지럽히지마라.</p>
<p>모든 변수에 타입 선언을 하는 것은 비생산적. The explicit type annotation is redundant. 
타입스크립트는 너가 기대하는 것보다 더 정교한 타입 추론이 가능</p>
<p>추론된 타입을 쓰는 것은 리팩토링에 좀 더 좋을 수 있다.</p>
<p>destructuring 은 타입 추론이 된다.</p>
<p>차입스크립에서 변수의 타입은 보통 생성될 때 결정된다. 
이상적인 타입스크립트 코드는 함수와 메소드에 대한 타입 선언을 포함하고 그 안에 있는 로컬변수에는 포함되어있지 않다. </p>
<p>파라미터에 타입 선언을 안하는 경우</p>
<ol>
<li>default value</li>
<li>callback 함수로 사용될 때 (ex. express 라이브러리)</li>
</ol>
<p>타입 선언을 원하는 경우 =&gt; 정확한 장소에 에러를 알 수 있다</p>
<ol>
<li>오브젝트 리터럴을 선언할 . 프로퍼티 타입 체크를 하는 게 안전</li>
<li>함수의 반환 타입</li>
</ol>
<p>린트 룰 no-inferrable-types 타입 선언이 필수</p>
<p>요약</p>
<ul>
<li>타입 추론이 가능할 땐 타입 선언을 피하라</li>
<li>이상적인 타입스크립트 코드는 함수와 메소드에 대한 타입 선언을 포함하고 그 안에 있는 로컬변수에는 포함되어있지 않다</li>
<li>오브젝트 리터럴과 함수 리턴 타입에는 선언을 사용해라</li>
</ul>
<h2 id="item20-use-different-variables-for-different-types">item20. use different variables for different types.</h2>
<p>다른 타입에 다른 변수를 사용해라.</p>
<p>변수의 값은 변할 수 있지만 그것의 타입은 보통 변하지 않는다.</p>
<p>타입을 바꾸지않고 두 개의 변수를 선언하면 좋은 이유</p>
<ul>
<li>두가지의 연관되어있지않은 컨셉이 얽히지 않는다</li>
<li>너가 좀 더 특정한 변수 이름을 사용할 수 있게 한다.</li>
<li>타입 추론을 향상시킨다.(?)</li>
<li>간단한 타입</li>
<li>const 로 변수를 선언하게 한다. 그건 사람에게나 타입 검사기에게나 좋다</li>
</ul>
<p>다른 컨셉의 변수는 다른 이름을 사용하는 게 좋다.
릴트 룰로 shadowing하는 걸 허락하지않는다.</p>
<h2 id="item21-understand-type-widening">item21. understand type widening</h2>
<p>타입 확장을 이해하라</p>
<p>런타임에서 모든 변수는 single value다.
타입스크립트가 너의 코드를 체크하는 정적 분석타임(?)에서는 변수는 가능한 value의 세트(=type)를 가진다.</p>
<p>타입스크립트는 똑똑하지만 내 마음을 읽을 수는 없다</p>
<p>변수의 타입은 선언 후에 변경될 수 없는 게 기본 룰</p>
<p>‘TypeScript is trying to strike a balance between specificity and flexibility.’
타입스크립트는 특수성과 유연성 사이에서 발란스를 맞추려고 애쓴다</p>
<p>타입스크립트의 확장을 컨트롤하는 몇가지 방법</p>
<ul>
<li>const는 만병통치약
  그러나 오브젝트와 어레이에서는 노 해결책 : object에서 타입스크립트의 확장 알고리즘은 각각의 요소를 let으로 할당한 것처럼 처리함. 처음 할당된 값으로 타입을 추론하고 다른 타입으로 할당 안됨.</li>
<li>타입스크립트의 default behavior를 오버라이드한다. 타입 선언을 하거나 타입 검사이에 부가적인 컨텍스트를 제공한다, 또 const assertion(as const)을 사용하는 방법이 있다. as const를 하면 타입스크립트는 가장 좁은 타입 중에서 타입을 추론함. no widening</li>
</ul>
<h2 id="item22-understand-type-narrowing">item22. understand Type Narrowing</h2>
<p>타입 축소를 이해하라</p>
<p>타입 확장의 반대
타입스크립트가 넓은 타입에서 좁은 타입으로 가는 과정.</p>
<ul>
<li>null checking</li>
<li><code>instanceof</code> </li>
<li>Array.isArray 같은 함수 사용</li>
<li>tag : tagged union or discriminated union</li>
</ul>
<p>타입을 좁히는 방법을 이해하라
tagged, discriminated(차별화된) 유니온과 사용자 정의 타입 가드를 쓰는거는 타입을 좁히는데 도움을 준다</p>
<h2 id="item23-create-object-all-at-once">item23. create object all at once.</h2>
<p>object를 한번에 생성하다.</p>
<p>빈 오브젝트를 선언한 후에 프로퍼티를 할당할 수 없다.</p>
<pre><code>const pt = {}
pt.x = 1; //error

interface Point { x: number; y: number; };
const pt: Point = {}; //error
const pt = {x: 3, y: 4}; //ok</code></pre><p>as (type assertion) 으로 에러를 없앨 순 있지만 한번에 생성하는 방법이 더 좋다.
...(object spread operator)를 통해 large object도 한번에 선언 가능.</p>
<p>요약</p>
<ul>
<li>조금씩 보단 한번에 object를 만드는 걸 선호해라, ...는 안전한 방법</li>
<li>조건적으로 프로퍼티를 추가하는 방법을 알아라</li>
</ul>
<h2 id="item24-be-consistent-in-your-use-of-aliases">item24. be consistent in your use of aliases</h2>
<p>별칭 사용에 일관성을 가져라</p>
<p>alias
alias를 도입했으면 일관성있게 사용하라</p>
<p>타입스크립트의 control flow는 로컬변수에는 좋고 프로퍼티에는 안전하지 않다</p>
<p>요약</p>
<ul>
<li>aliasing은 타입스크립트가 narrowing types하는 것을 막다. alias를 사용하면 일관적으로 써라.</li>
<li>destructuring을 사용해라</li>
<li>함수호출이 프로퍼티의 타입 세분화(refinements)를 어떻게 무효화시킬 수 있는지, 프로퍼티보다 로컬변수의 refinement를 믿어라 </li>
</ul>
<h2 id="item-33-prefer-more-precise-alternatives-to-string-types">item 33. Prefer More Precise Alternatives to String Types.</h2>
<p>문자열보다 보다 정확한 대안을 선호하라</p>
<p>그냥 string type을 사용하는 것 보단 더 좁은 타입을 정해주는게 좋다
엄격한 타입 검사 말고도 장점이 또 있다</p>
<ol>
<li>의미가 손상되지 않는다
 그냥 string으로 넘기면 Album의 정의가 숨겨져있음</li>
<li>타입에 documentation (설명)을 첨부할 수 있다.</li>
</ol>
<p>또 다른 string의 잘못된 사용은 함수 파라미터에 있다.
any[] 로 파라미터 타입 정하면 문제가 많다. 특히 return 값에서
string은 any와 같은 문제를 몇가지 가지고있다.
invalid 한 값을 허용하고 타입 간의 관계를 숨긴다. </p>
<p>1.generic type 사용
2.subset of string 을 정의하는 것</p>
<p>명확한 타입 선언은 에러를 잡고 가독성을 향상하는 데 좋<del>다</del></p>
<h2 id="item-34-prefer-incomplete-type-of-inaccurate-type">item 34. Prefer incomplete type of inaccurate type</h2>
<p>부정확한 타입의 불완전한 타입을 선호하라</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TypeScript ]]></title>
            <link>https://velog.io/@silverj-kim/TypeScript</link>
            <guid>https://velog.io/@silverj-kim/TypeScript</guid>
            <pubDate>Mon, 11 Jan 2021 04:43:25 GMT</pubDate>
            <description><![CDATA[<h1 id="시작하기">시작하기</h1>
<p><a href="https://typescript-kr.github.io/">https://typescript-kr.github.io/</a></p>
<h2 id="ts-for-the-new-programmer">TS for the New Programmer</h2>
<p>Typescript is Javascript&#39;s flavor or variant.</p>
<h3 id="javascript의-짧은-역사">Javascript의 짧은 역사</h3>
<p>자바스크립트는 처음에 브라우저를 위한 스크립트 언어로 만들어졌다.
웹 브라우저 개발자들은 JS 사용량이 늘어나면서 실행 엔진(동적 컴파일)을 최적화시키고 최적화된 것을 이용해 할 수 있는 일(API 추가)을 확장하여 JS를 더 인기있게 만들었다.</p>
<p>하지만 Javascript에는 문제들이 존재한다.</p>
<ul>
<li><p>JS의 동일 연산자(==)는 인수를 강제로 변환하여 예기치 않은 동작을 유발한다.</p>
<pre><code>&quot;&quot; == 0 //true
1 &lt; x &lt; 3 //x가 어떤 값이던 true</code></pre></li>
<li><p>JS는 존재하지 않는 프로퍼티의 접근을 허용한다.</p>
<pre><code>const obj = { width: 10, height: 15 };
const area = obj.width * obj.h; //NaN</code></pre><p>대부분의 프로그래밍 언어는 이런 종료의 오류가 발생하면 오류를 보여주고 일부는 코드가 실행되기 전인 컴파일 중에 오류를 표출한다. </p>
</li>
</ul>
<h3 id="typescript-정적-타입-검사자-typescript-a-static-type-checker">TypeScript 정적 타입 검사자 (TypeScript: A Static Type Checker)</h3>
<p>프로그램을 실행시키지 않으면서 코드의 오류를 검출하는 것을 정적 검사 라고 한다.
어떤 것이 오류인지와 어떤 것이 연산되는 값에 기인하지 않음을 정하는 것이 정적 타입 검사.</p>
<blockquote>
<p>정적타입 vs 동적타입
<strong>정적타입</strong>
컴파일 시 변수의 타입이 결정되는 언어, 따라서 변수에 들어갈 값의 타입을 명시해주어야 한다. 타입이 맞지 않는 값이 있을 경우 컴파일 에러가 발생!
<strong>동적타입</strong>
런타임 시 변수의 타입이 결정되는 언어, 타입없이 변수를 선언하여 값을 지정할 수 있다. 단점으로는 런타임에 예상치 못한 타입 에러가 발생할 수 있음!</p>
</blockquote>
<p>정적 타입 검사자인 TypeScript는 프로그램을 실행시키기 전에 값의 종류를 기반으로 프로그램의 오류를 찾는다.</p>
<pre><code>// @errors: 2551
const obj = { width: 10, height: 15 };
const area = obj.width * obj.h;</code></pre><h3 id="타입이-있는-javascript의-상위-집합a-typed-superset-of-javascript">타입이 있는 Javascript의 상위 집합(A Typed Superset of Javascript)</h3>
<p><strong>구문(syntax)</strong>
타입스크립트는 자바스크립트의 구문이 허용되는 자바스크립트의 상위 집합 언어이다. 구문은 프로그램을 만들기 위해 코드를 작성하는 방법을 의미한다.
<strong>타입(types)</strong>
타입스크립트는 다른 종류의 값들을 사용할 수 있는 방법이 추가된, <strong>타입이 있는 상위 집합</strong>이다. <code>obj.h</code>의 오류는 구문 오류가 아닌 타입 오류이다.
타입스크립트의 타입 검사자는 일반적인 오류를 최대한 많이 검출하면서 올바른 프로그램을 만들 수 있게 설계되어있다. 
<strong>런타임 특성(runtime behavior)</strong>
타입스크립트는 자바스크립트의 런타임 특성을 가진 프로그래밍 언어이다.</p>
<blockquote>
<p>런타임과 컴파일타임
프로그램을 생성하기 위해 개발자는 소스코드를 작성하고 코드는 컴파일을 통해 기계어 코드로 변환되어 실행 가능한 프로그램이 되며 이러한 과정을 컴파일타임이라고 한다.
컴파일과정을 마친 프로그램은 사용자에 의해 실행되어 지며, 프로그램이 실행되고 있는 동안을 런타임이라고 부른다.</p>
</blockquote>
<p>타입스크립트는 자바스크립트 코드의 런타임 특성을 <strong>절대</strong> 변화시키지 않는다!
즉 타입스크립트가 코드에 타입 오류가 있음을 알아도 자바스크립트 코드를 타입스크립트로 이동시키는 것은 같은 방식으로 실행시킬 것을 보장한다.
두 언어 간에 쉽게 전환할 수 있도록 하기 위한 타입스크립트의 기본적인 약속.
<strong>삭제된 타입(Erased Tyeps)</strong>
타입스크립트의 컴파일러가 코드 검사를 마치면 타입을 삭제해서 결과적으로 <strong><em>컴파일 된 코드</em></strong> 를 만든다. 즉 코드가 컴파일 되면 결과로 나온 js코드에는 타입 정보가 없다.
타입 정보가 없는 것은 타입스크립트가 추론한 타입에 따라 프로그램의 특성을 변화시키지 않는다는 의미로, 컴파일 도중에는 타입에러가 발생할 수 있지만 프로그램이 실행될 때와는 관련이 없다.
타입스크립트는 추가 런타임 라이브러리가 없다. 자바스크립트와 같은 표준 라이브러리를 사용한다.</p>
<h2 id="ts-for-js-programmers">TS for JS Programmers</h2>
<p>Typescript는 Javascript위에 레이어로서 자리잡고 있으며 Jaavascript의 기능들을 제공하면서 그 위에 자체 레이어를 추가한다. 그 레이어가 <strong>Typescript의 타입 시스템</strong></p>
<blockquote>
<p>javascript의 리터럴타입
Boolean, null, undefined, Number, BigInt, String, Symbol, Object</p>
</blockquote>
<p>Typescript의 타입 검사기는 사용자가 생각한 일과 Javascript가 시렞로 하는 일 사이의 불일치를 강조할 수 있다.</p>
<h3 id="타입-추론-types-by-inference">타입 추론 (Types by Inference)</h3>
<p>Typescript는 변수를 생성하면서 동시에 특정 값에 할당하는 경우 그 값을 해당 변수의 타입으로 사용한다.
Javascript가 동작하는 방식을 이해함으로써 TS는 JS를 받아들이면서 타입을 가지는 타입 시스템을 구축할 수 있다. </p>
<h3 id="타입-정의-defining-types">타입 정의 (Defining Types)</h3>
<p>Javascript 는 다양한 디자인 패턴을 가능하게 하는 동적 언어이다.
Typescript는 타입이 무엇인지 명시 가능한 Javascript 언어의 확장을 지원.</p>
<p>name: string과 id: numver 를 포함하는 추론 타입을 가진 객체 </p>
<pre><code>const user = {
  name: &quot;Silver&quot;,
  id: 0
}</code></pre><p>이 객체의 형태를 명시적으로 나타내기 위해서 <code>interface</code> 로 선언하고
변수 선언 뒤에 <code>: TypeName</code> 의 구문을 사용해 Javascript 객체가 새로운 interface 형태를 따르고 있음을 선언할 수 있다.</p>
<pre><code>interface User {
  name: string;
  id: number
}

const user: User = {
  name: &quot;Silver&quot;,
  id: 0
}</code></pre><p>Javascript는 클래스와 객체 지향 프로그래밍을 지원하기 때문데 Typescript 또한 동일하며 인터페이스는 클래스로 선언할 수 있다.</p>
<pre><code>interface User {
  name: string;
  id: number;
}

class UserAccount {
  name: string;
  id: number;

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

const user: User = new UserAccount(&quot;Dong&quot;, 1);</code></pre><blockquote>
<p>객체지향에서의 Interface
클래스에서 구현부가 빠진 설계도. 어떠한 객체가 어떤 프로퍼티 혹은 메소드를 가지늕지 설계하고 선언하는 역할. 추상메서드와 상수를 멤버로 가진다. 실질적인 구현은 이를 구현한다고 선언하는 클래스가 한다. 클래스는 인터페이스에 있는 프로퍼티 및 메소드를 모두 가지고 구현해야한다.</p>
</blockquote>
<p>Javascript에서 사용할 수 있는 리터럴 타입이 이미 있다. Typescript    는 몇 가지를 추가해 목록을 확장한다. 
<code>any</code> (무엇이든 허용)
<code>unknown</code> (이 타입을 사용하는 사람이 타입이 무엇인지 확인)
<code>never</code> (이 타입은 발생될 수 없음)
<code>void</code> (undefined를 리턴하거나 리턴값이 없는 함수)</p>
<h2 id="타입-구성-composing-types">타입 구성 (Composing Types)</h2>
<p>객체들을 조합하여 더 크고 복잡한 객체를 만드는 방법과 유사하게 TS에 타입으로 이를 수행하는 도구가 있다.</p>
<h3 id="유니언unions">유니언(Unions)</h3>
<p>타입이 여러 타입 중 하나일 수 있음을 선언하는 방법</p>
<pre><code>type MyBool = true | false;
function getLength(obj : string | string[]) {
  return obj.length;
}</code></pre><h3 id="제네릭generics">제네릭(Generics)</h3>
<p>타입에 변수를 제공하는 방법, &lt;타입으로 사용되는 식별자&gt;
제네릭이 있는 배열은 배열안의 값을 설명할 수 있다.</p>
<pre><code>type StringArray = Array&lt;string&gt;;
type ObjectWithNameArray = Array&lt;{name: string}&gt;;

interface Backpack&lt;Type&gt; {
  add: (obj: Tyepe) =&gt; void;
}

declare const backpack: Backpack&lt;string&gt;;
backpack.add(23) //error, backpack 변수가 string이므로 number를 전달할 수 없음</code></pre><blockquote>
<p>객체지향에서의 제네릭
제네릭은 어떠한 클래스 혹은 함수에서 사용할 타입을 그 함수나 클래스를 사용할 때 결정하는 프로그래밍 기법</p>
</blockquote>
<h3 id="구조적-타입-시스템-structural-type-system">구조적 타입 시스템 (Structural Type System)</h3>
<p>타입스크립트의 핵심 원칙 중 하나는 타입 검사가 값이 있는 형태에 집중한다는 것.
= 덕 타이핑(duck typing) = 구조적 타이핑</p>
<pre><code>interface Point {
  x: number;
  y: number;
}

function printPoint (p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

const point = { x: 12, y: 26 };
printPoint(point);
const rect = { x:33, y:3, width: 30, height: 80};
printPoint(rect);</code></pre><p>여기서 <code>point</code> 변수는 <code>Point</code> 타입으로 선언된 적이 없지만 타입스크립트의 타입 검사해서 둘 다 같은 형태기 때문에 패스한다.
형태 일치는 일치시킬 객체의 필드의 하위 집합만 필요하다.</p>
<h1 id="ts-for-oop-programmers">TS for OOP Programmers</h1>
<p>Typescript는 정적 타이핑을 사용하는 언어에 익숙한 프로그래머들에게 인기있는 선택이다.</p>
<h2 id="javascript와-함께-배우기">Javascript와 함께 배우기</h2>
<p>Javascript의 런타임 동작을 이해하기 위해 우선적으로 타입을 제외한 Javascript의 일부분을 배우는 것이 좋다. Typescript는 Javascript와 동일한 런타임을 사용하믐로 특정한 런타임 동작을 구현하려는 리소스는 항상 타입스크립트 프로그램에 똑같이 잘 적용되다는 점을 기억하는 것은 매우 중요하다.</p>
<blockquote>
<p>자바스크립트의 런타임
런타임(runtime)이란 프로그래밍 언어가 구동되는 환경을 의미
Node.js나 크롬 등의 여러 브라우저들은 자바스크립트가 구동되는 환경이기 때문에 node.js나 브라우저가 자바스크립트의 런타임
자바스크립트는 싱글스레드, 논-블로킹 언어 : 하나의 힙 영역과 하나의 콜 스택(함수가 실행되는 순서를 기억하고 있다)을 가지며 그 의미는 한번에 한가지 일밖에 못한다는 의미이다. 
<a href="https://beomy.github.io/tech/javascript/javascript-runtime/">참고링크</a></p>
</blockquote>
<h2 id="클래스-다시-생각하기">클래스 다시 생각하기</h2>
<h3 id="자유로운-함수와-데이터">자유로운 함수와 데이터</h3>
<p>js에서 함수는 어디에나 있을 수 있고 미리 정의된 class나 struct에 속하지 않고 자유롭게 전달할 수 있다.  자유로운 함수는 프로그램을 자바스크립트로 작성하는 모델로 선호된다.</p>
<h3 id="정적-클래스">정적 클래스</h3>
<p>싱글턴과 같은 정적 클래스 같은 특정 구조는 필요없다.</p>
<blockquote>
<p>싱글턴
인스턴스를 하나만 만들어 사용하기 위한 패턴
유일한 단일 객체를 반환할 수 있도록 정적 메소드를 지원해야 한다.</p>
</blockquote>
<h2 id="타입스크립트의-oop-object-oriented-programming">타입스크립트의 OOP (Object Oriented Programming)</h2>
<p>타입스크립트는 인터페이스, 상속, 정적(static) 메서드 구현과 같은 일반적인 패턴을 지원한다.</p>
<blockquote>
<p>static 
변수 선언 시 static 키워드를 붙이면 자바의 경우 메모리 할당을 한번만 하게 되어 메모리 사용에 이점이 있다.</p>
</blockquote>
<h2 id="타입-다시-생각하기">타입 다시 생각하기</h2>
<h3 id="이름으로-구체화된-타입시스템-nominal-reified-type-systems">이름으로 구체화된 타입시스템 (Nominal Reified Type Systems)</h3>
<h3 id="집합으로서의-타입-types-as-sets">집합으로서의 타입 (Types as Sets)</h3>
<p>C#또는 자바에서 런타임 타입과 해당 컴파일 타입 선언 사이의 일대일 대응 관계는 중요하다.
타입스크립트에서 타입은 공통의 무언가를 공유하는 값의 집합으로 생각하는 것이 좋다. 타입은 집합에 불과하기 때문에 특정한 값은 동시에 여러 집합에 속할 수 없다.</p>
<h3 id="삭제된-구조적-타입-erased-structural-types">삭제된 구조적 타입 (Erased Structural Types)</h3>
<p>객체는 정확히 단일 타입이 아니다.
예를 들어 인터페이스를 만족하는 객체를 생성할 때 둘 사이의 선언적인 관계가 없더라도 해당 인터페이스가 예상되는 곳에 해당 객체를 사용할 수 있다.
타입스크립트의 타입 시스템은 구조적이고 구체화되지 않았다. 타입은 런타임에 어떤 형태로도 존재하지 않는다.</p>
<h3 id="구조적-타입화의-결과-consequences-of-structural-typing">구조적 타입화의 결과 (Consequences of Structural Typing)</h3>
<p><strong>빈타입 (Empty Types)</strong></p>
<pre><code>class Empty {}
function fn(arg: Empty) {}
fn({k: 10});</code></pre><p>타입스크립트는 주어진 인수가 유효한 Empty인지를 확인하여 fn의 호출이 유효한지를 검사한다. {k:10}과 Empty의 구조를 확인하여 유효서을 검사한다. Empty에 프로퍼티가 없으므로 유효한 호출이다. 
<strong>동일한 타입(Identical Types)</strong></p>
<pre><code>class Car {
  drive() {}
}
class Golfer {
  drive() {}
}
let w: Car = new Golfer();</code></pre><p>두 클래스의 구조가 동일하기 때문에 에러가 발생하지 않는다.</p>
<h3 id="반영-reflection">반영 (Reflection)</h3>
<p>객체지향은 제네릭을 포함하여 어떤 값의 유형이라도 다룰 수 있음에 익숙하다.
자바스크립트에는 <code>typeof</code>와 <code>instanceof</code> 와 같은 제한된 원시요소가 있지만 이러한 연산자는 타입이 지워진 코드의 출력에 존재하므로 여전히 작동함을 알아야 한다. typeof(new Car()) 는 Car가 아닌 object다.</p>
<h1 id="핸드북">핸드북</h1>
<h2 id="핸드북에-대해서-about-this-handbook">핸드북에 대해서 (About this Handbook)</h2>
<p>자바스크립트는 프로그래밍 커뮤티티에 도입된지 20년이 지난 지금, 가장 널리 퍼진 cross-platform 언어 중 하나다.
프로그래머들이 작성하는 가장 흔한 오류는 <em>타입오류</em> 이다. TypeScript의 목표는 JavaScript 프로그램의 정적 타입 검사자이다. 즉, 코드가 실행되기 전에 실행하고(정적), 프로그램 타입이 정확한지 확인하는 도구(타입 검사)이다.</p>
<p>자바스크립트의 핵심 개념을 전부 소개하지는 않는다.
핸드북은 언어 명세를 대체하기 위함이 아니다.</p>
<h2 id="기본-타입">기본 타입</h2>
<p>프로그램이 유용하려면 숫자, 문자열, 구조체, 불리언과 같은 간단한 데이터 단위가 필요하다. 타입스크립트는 자바스크립트와 거의 비슷하며 열거 타입을 사용할 수 있다.</p>
<h3 id="boolean">Boolean</h3>
<p><code>let isDone: boolean = true;</code>
참/거짓 (true/false)</p>
<h3 id="number">Number</h3>
<p>자바스크립트처럼 타입스크립트의 모든숫자는 부동 소수 값.
TypeScript는 16진수, 10진수 리터럴에 더불어 2진수, 8진수 리터럴도 지원한다.
<code>let decimal: number = 6;</code>
<code>let hex: number = 0xf00d;</code></p>
<h3 id="문자열-string">문자열 string</h3>
<p>텍스트 데이터 타입을 string으로 표현한다. 큰타옴표(&quot;) 나 작은따옴표(&#39;)를 문자열 데이터를 감싸는데 사용한다.
<code>let color: string = &quot;blue&quot;;</code></p>
<h3 id="배열-array">배열 Array</h3>
<p>배열 타입을 두가지 방법으로 쓸 수 있다.
타입 뒤에 []를 쓰는 방법
<code>let list: number[] = [1,2,3];</code>
제네릭 배열 타입을 쓰는 것 <code>Array&lt;elemType&gt;</code>
<code>let list: Array&lt;number&gt; = [1,2,3];</code></p>
<h3 id="튜플-tuple">튜플 Tuple</h3>
<p>튜플 타입을 사용하면 요소의 타입과 개수가 고정된 배열을 표현할 수 있다.
단 요소들의 타입이 모두 같을 필요는 없다.</p>
<pre><code>//튜플 타입으로 선언
let x: [string,number];

x = [&quot;hello&quot;, 10]; //성공
x = [10, &quot;hello&quot;]; //에러
console.log(x[1].substring(1)); //에러 number에는 substring이 없음
x[3] = 에러&quot;world&quot;; // 프로퍼티 3이 없음
console.log(x[5].toString()); //에러 프로퍼티 5가 없음</code></pre><h3 id="열어-enum">열어 Enum</h3>
<p>Jvascript의 표준 자료형 집합과 사용하면 도움이 될만한 데이터 형은 <code>enum</code>
enum은 값의 집합에 더 나은 이름을 붙여줄 수 있다.</p>
<pre><code>enum Color {Red = 1, Green, Blue};
let c: Color = Color.Green;
let colorName: string = Color[2];
console.log(colorName); //Green</code></pre><p>기본적으로 enum은 0부터 시작하여 멤버들의 번호를 메기며 수동으로 설정하여 위처럼 값을 변경할 수 있다.
유요한 기능 중 하나는 매겨진 값을 이용해 enum의 멤버의 이름을 알아낼 수 있다.</p>
]]></description>
        </item>
    </channel>
</rss>