<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>isabel_noh.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 28 Dec 2023 04:21:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>isabel_noh.log</title>
            <url>https://images.velog.io/images/isabel_noh/profile/c07865e9-2b58-49b7-aaf9-38e91867151b/80C9BF75-B6E9-4677-A7D7-532EB3AB7289.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. isabel_noh.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/isabel_noh" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[iOS] 신뢰할 수 없는 기업용 앱 Untrusted Enterprise Developer ]]></title>
            <link>https://velog.io/@isabel_noh/iOS-%EC%8B%A0%EB%A2%B0%ED%95%A0-%EC%88%98-%EC%97%86%EB%8A%94-%EA%B8%B0%EC%97%85%EC%9A%A9-%EC%95%B1-Untrusted-Enterprise-Developer</link>
            <guid>https://velog.io/@isabel_noh/iOS-%EC%8B%A0%EB%A2%B0%ED%95%A0-%EC%88%98-%EC%97%86%EB%8A%94-%EA%B8%B0%EC%97%85%EC%9A%A9-%EC%95%B1-Untrusted-Enterprise-Developer</guid>
            <pubDate>Thu, 28 Dec 2023 04:21:01 GMT</pubDate>
            <description><![CDATA[<p>Iphone에서 App Store을 통하지 않고, 기업이나 공공기관을 통해 직접적으로 어플을 설치받았을 때 발생하는 에러를 해결하는 방법을 공유하고자 한다. </p>
<hr>
<p>어느 업체를 통해 어플을 다운 받을 일이 생겼고, 사용하려고 하니 <code>Untrusted Enterprise Developer</code> 이라며 어플이 작동되지 않았다. </p>
<blockquote>
<p>왱? 난 이 업체를 신뢰하는데 왜 니가 안 신뢰를 해 ???? </p>
</blockquote>
<p>App Store을 통해서 설치받은 것이 아니라 따로 외부 링크를 통해 어플을 설치했을 경우, 어플의 인증서에 문제가 있을 경우 등의 상황에서 이러한 에러 메시지가 뜬다고 한다. </p>
<blockquote>
<p>그렇지만 난 이 어플을 써야 하는 걸? </p>
</blockquote>
<hr>
<h2 id="해결-방법">해결 방법</h2>
<ol>
<li><p>아이폰의 <code>설정(Settings)</code>에 들어간다. </p>
</li>
<li><p><code>일반(General)</code>로 들어간다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/20719d6f-31e8-459f-9227-5ad17d3596b4/image.png" alt="SettingsPage"></p>
</li>
<li><p><code>일반(General)</code>에서 <code>기기 관리(Device Management)</code>에 들어간다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/4db04e69-49d8-49c9-8556-4c3b8a6106b5/image.png" alt="GeneralPage"></p>
</li>
<li><p>화면을 보면 <code>신뢰할 수 없는 App</code>의 리스트를 확인할 수 있다. 클릭하여 들어간다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/0e51b94b-2aab-41f3-8e45-0f7dfbf137c9/image.png" alt="VPNandDeviceManagementPage"></p>
</li>
<li><p>신뢰(Trust this App)을 클릭한다. 해결! 
지금 내 핸드폰에서는 이미 신뢰 버튼을 클릭해서 Delete App만 나오지만 원래는 Trust this App인가로 쓰여 있었다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/d99b94d7-51fe-49e8-96f8-2e0a788d23d1/image.png" alt=""></p>
</li>
</ol>
<blockquote>
<p>주의 ! 정말정말정말정말로 신뢰할 수 있는 어플만 신뢰하기!!! </p>
</blockquote>
<p>잘 못 신뢰했다가 해킹 당할 수도 있기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] Heap (feat. 프로그래머스 - 더 맵게)]]></title>
            <link>https://velog.io/@isabel_noh/Algorithm-Heap</link>
            <guid>https://velog.io/@isabel_noh/Algorithm-Heap</guid>
            <pubDate>Wed, 27 Sep 2023 07:45:59 GMT</pubDate>
            <description><![CDATA[<p>프로그래머스에서 힙 문제를 풀다가 헷갈려 정리차원에서 이 글을 작성하게 되었다. </p>
<h1 id="heap">Heap</h1>
<p>힙은 일종의 완전 이진 트리이다.<br>주로 우선순위 큐를 구현하는데 밑받침이 되는 자료구조로 쓰인다.<br>트리 구조이기 때문에 삽입과 삭제에 <code>O(logN)</code>의 시간이 소요된다.</p>
<p>최소 힙, 최대 힙<br>빠른 시간 안에 최대값과 최소값을 찾아낼 수 있다.</p>
<blockquote>
<p>파이선 -&gt; heapq heapify 등 라이브러리에서 함수와 구조를 제공</p>
</blockquote>
<h3 id="힙에서의-부모-자식-관계">힙에서의 부모-자식 관계</h3>
<p>힙은 완전 이진 트리 base 이기 때문에, 노드들 간의 부모-자식 관계가 성립하게 된다. 힙의 경우엔 보통의 완전 이진 트리와는 다르게 반정렬 상태(느슨한 정렬 상태)를 유지한다. <code>최대힙이라면 큰 값이 부모 노드쪽에, 최소힙이라면 작은 값이 부모 노드 쪽에 배치되는 것만 유지</code>하고 왼쪽 자식과 오른쪽 자식은 부모 노드보다 작은 값을 유지하기만 하면 된다.</p>
<h3 id="구현---max-heap">구현 - Max Heap</h3>
<pre><code class="language-js">// 기본 세팅
class Heap {
  constructor() {
    this.heap = [null]; // 첫 원소는 사용 X
  }
}</code></pre>
<p>배열의 첫 원소는 사용하지 않으므로 부모와 자식 간 다음의 관계가 성립한다.</p>
<blockquote>
<p>완전 이진 트리의 일종이기 때문에 Binary Search tree에서의 부모-자식 간 관계와 유사하다.</p>
</blockquote>
<ul>
<li>왼쪽 자식의 index = <code>부모 index * 2</code>;</li>
<li>오른쪽 자식의 index = <code>(부모 index * 2) + 1</code>;</li>
<li>부모의 index = <code>Math.floor(자식의 인덱스 / 2)</code>;</li>
</ul>
<pre><code class="language-js">getParentIndex(i){
    return Math.floor(i / 2);
}

getLeftChildIndex(i){
    return i * 2;
}

getRightChildIndex(i){
    return i * 2 + 1;
}</code></pre>
<h2 id="삽입">삽입</h2>
<p>마지막 노드에 들어온 값을 <code>push()</code>하여 배열의 맨 마지막에 삽입한다. 이 때 부모노드를 확인하면서 들어온 값이 부모노드보다 작은지 큰지를 확인하면서 위치를 교환 <code>swap()</code>해주며 정렬 <code>heapifyUp()</code>한다.</p>
<pre><code class="language-js">swap(idx1, idx2){
    const temp = this.heap[idx1];
    this.heap[idx1] = this.heap[idx2];
    this.heap[idx2] = temp;
}

push(value){
    this.heap[this.heap.length] = value; // 배열의 맨 마지막에 값 넣기
    this.heapifyUp();
}

// 최대 힙에 맞게 제일 큰 노드를 최상단으로 맞춰주기 위해 가장 마지막에 들어온 노드의 인덱스를 변수로 둔다.
heapifyUp(){
    let curIndex = this.heap.length - 1;
    // 확인 중의 인덱스의 값이 부모 인덱스의 값보다 크면, swap하고, 현재 인덱스에 부모 인덱스를 재할당하여 while문에서 부모 인덱스를 확인
    while(this.heap[curIndex] &gt; this.heap[this.getParentIndex(curIndex)]){
        this.swap(curIndex, this.getParentIndex(curIndex));
        curIndex = this.getParentIndex(curIndex);
    }
}</code></pre>
<h2 id="삭제추출">삭제/추출</h2>
<p>힙에서 루트 노드가 가장 먼저 추출된다. 그 빈 자리는 트리의 맨 마지막에 있는 값을 가져와 채우고, 맨 마지막 노드를 삭제한다. 그리고 다시 트리를 정렬한다. 힙의 원칙에 맞게 정렬이 다 끝나면 처음에 추출했던 루트노드값을 리턴한다.</p>
<ol>
<li>maxVal: 배열의 최상위 노드를 꺼낸다.</li>
<li>루트 노드와 맨 끝에 있는 값을 교체한다.</li>
<li>맨 마지막 노드를 삭제한다.</li>
<li>변경된 노드와 자식 노드들을 비교하면서 정렬한다.</li>
<li>자식 노드 둘보다 부모 노드가 크거나 가장 마지막 바닥까지 도달하지 않을 때까지 과정을 반복한다.</li>
<li>2에서 제거한 루트 노드 값을 return 한다.</li>
</ol>
<pre><code class="language-js">poll(){
    let maxVal = this.heap[1];
    this.heap[1] = this.heap[this.heap.length - 1];
    this.heap.length--;

    this.heapifyDown();

    return maxVal;
}

// 최소 힙에 맞게 제일 작은  노드를 최상단으로 맞춰주기 위해 가장 마지막에 들어온 노드의 인덱스를 변수로 둔다.
heapifyDown(){
    let curIndex = 1;
    // curIndex가 마지막 노드가 아닐 때까지 반복
    while(this.heap[this.getLeftChildIndex(curIndex)] !== undefined){
        let biggerChildIndex = this.getLeftChildIndex(curIndex);

        if(this.heap[this.getRightChildIndex(curIndex)] !== undefined &amp;&amp; this.heap[this.getRightChildIndex(curIndex)] &gt; this.heap[this.getLeftChildIndex(curIndex)]
        ){
            biggerChildIndex = this.getRightChildIndex(curIndex);
        }
        // 자식 노드가 있다면 자식 노드 중에서 제일 큰 자식 노드의 값과 현재 노드의 값을 비교
        // 자식 노드 값이 더 크다면 swap하는 식으로 전체 트리를 heap의 구조에 맞게 정렬
        if(this.heap[curIndex] &lt; this.heap[biggerChildIndex]){
            this.swap(curIndex, biggerChildIndex);
            curIndex = biggerChildIndex;
        } else {
            return;
        }

    }
}</code></pre>
<h2 id="전체-코드">전체 코드</h2>
<pre><code class="language-js">class Heap {
  constructor() {
    this.heap = [];
  }

  getParentIndex(i) {
    return Math.floor(i / 2);
  }

  getLeftChildIndex(i) {
    return i * 2;
  }

  getRightChildIndex(i) {
    return i * 2 + 1;
  }

  swap(idx1, idx2) {
    const temp = this.heap[idx1];
    this.heap[idx1] = this.heap[idx2];
    this.heap[idx2] = temp;
  }

  push(val) {
    this.heap[this.heap.length] = val;
    this.heapifyUp();
  }

  heapifyUp() {
    let curIdx = this.heap.length - 1;
    // min Heap 은 반대로 될 것
    while (this.heap[curIdx] &gt; this.heap[this.getParentIndex(curIdx)]) {
      this.swap(curIdx, this.getParentIndex(curIdx));
      curIdx = this.getParentIndex(curIdx);
    }
  }

  poll() {
    // min Heap 은 반대로 될 것
    let maxVal = this.heap[0];
    if (maxVal === 12 || maxVal === 10 || maxVal === 8) {
      console.log(&quot;g&quot;, this.heap);
    }
    this.heap[0] = this.heap[this.heap.length - 1];
    this.heap.length--;
    this.heapifyDown();
    return maxVal;
  }

  heapifyDown() {
    let curIdx = 0;
    while (this.heap[this.getLeftChildIndex(curIdx)] !== undefined) {
      let biggerChild = this.getLeftChildIndex(curIdx);
      if (
        this.heap[this.getLeftChildIndex(curIdx)] &lt;
        this.heap[this.getRightChildIndex(curIdx)]
      ) {
        biggerChild = this.getRightChildIndex(curIdx);
      }
      if (this.heap[curIdx] &lt; this.heap[biggerChild]) {
        this.swap(curIdx, biggerChild);
        curIdx = biggerChild;
      } else {
        return;
      }
    }
  }
}</code></pre>
<h4 id="힙-사용-예제">힙 사용 예제</h4>
<ul>
<li>우선순위 큐를 구현하는데 사용한다.</li>
<li>게임엔진에서 각 액터의 우선순위를 정한다.</li>
<li>서버에서 많은 트래픽을 처리할 때 우선 처리해야 할 트래픽을 정한다.</li>
<li>시뮬레이션 시스템</li>
<li>네트워크 트래픽 제어</li>
<li>운영 체제에서의 작업 스케쥴링 (우선 순위가 높은 일을 바로 조회)</li>
<li>수치 해석적인 계산</li>
</ul>
<h3 id="관련-문제">관련 문제</h3>
<h4 id="프로그래머스---더-맵게"><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42626">프로그래머스 - 더 맵게</a></h4>
<h5 id="문제-설명">문제 설명</h5>
<p>매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.</p>
<p>섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)
Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.
Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.</p>
<h5 id="제한-사항">제한 사항</h5>
<p>scoville의 길이는 2 이상 1,000,000 이하입니다.
K는 0 이상 1,000,000,000 이하입니다.
scoville의 원소는 각각 0 이상 1,000,000 이하입니다.
모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.</p>
<h4 id="문제풀이">문제풀이</h4>
<p>MinHeap을 직접 구현하여야 풀이할 수 있는 문제이다.
최소힙은 오른쪽 왼쪽 상관없이 부모노드가 자식노드보다 크기만 하면 된다. (처음에 오른쪽이 왼쪽보다 커야하는 줄 알고 헷갈렸음 )</p>
<p>먼저, 전체 입력값을 Heap에 push해준다. heap에 push할 때에는 값을 배열의 맨 마지막 부분에 넣어주고, 마지막 index의 값을 기준으로 부모 노드와 비교하면서 부모노드보다 더 큰 상황이 올 때까지 부모와 자식을 swap하면서 올라간다. 부모 노드가 현재 비교대상인 자식노드보다 더 크다면 값을 swap하고 비교대상을 그 부모노드의 index로 변경한다. 그렇지 않다면 멈춘다.</p>
<p>Heap의 첫 번째로 작은 값과 두번째로 작은 값 * 2를 구하기 위해, heap에서 pop을 두 번하여, 제일 작은 값과 두번째 작은 값을 구한다. (매 pop마다 minHeap은 정렬된다.) 그 다음 그 값들의 합을 Push하고, heap을 재정렬한다. 이런식으로 반복하다가 heap의 길이가 1, 즉 제일 작은 값만 있고, 두 번째 값이 없는 경우가 되거나, heap의 [0]값이 K보다 커지면 위 동작을 멈춘다. 위 두 경우에서, heap[0]이 K보다 크다면 answer을, 그렇지 않다면 조건을 충족시키지 못한 경우이므로 -1을 리턴한다. (<code>missing point</code>)</p>
<p>위 과정에서 heap에서 pop하는 동작이 있는데, 여기가 아주 골머리<del>~</del>  </p>
<p><strong>일단 힙에서는 최소힙이든 최대힙이든 루트 노드가 항상 먼저 배출되어야 한다. 배출되고 나서 생기는 빈자리는 가장 마지막 노드, 즉 배열에서 제일 뒤에 있는 값을 가져온다. 그리고 다시 루트노드서 부터 재정렬을 실행해준다.</strong></p>
<ol>
<li>만약 heap에 어떤 값도 없다면 null을 리턴한다.</li>
<li>만약 Heap의 길이가 1인 경우, 즉, 루트 노드 밖에 없는 경우라면, heap[0]을 pop하여 리턴한다.</li>
<li>1, 2번의 경우 외로 자식 노드들이 있는 경우, 루트 노드를 메서드가 끝날 때 return하기 위해 따로 저장한다.</li>
<li>루트 노드와 맨 마지막 노드를 교환하고, 맨 마지막 노드는 필요가 없어졌기 때문에 heap에서 pop() (배열에서의 pop을 의미)을 한다.</li>
<li>새롭게 바뀐 루트 노드를 자식 노드들과 비교하여 재정렬한다.</li>
<li>3번에서 저장했던 루트 노드를 리턴한다.</li>
</ol>
<p><em>재정렬</em></p>
<ol>
<li>루트 노드를 자식 노드들과 비교하여 정렬할 것이기 때문에 3가지 정보가 필요하다.</li>
</ol>
<ul>
<li>현재 노드의 위치 : 0</li>
<li>왼쪽 자식 노드의 위치</li>
<li>오른쪽 자식 노드의 위치</li>
</ul>
<ol start="2">
<li>아래 진행될 정렬을 왼쪽 자식 노드와 오른쪽 자식 노드보다 작을 때까지 계속 반복할 것이다.</li>
<li>주의할 점1. <code>왼쪽 자식 노드만 있고, 오른쪽 자식 노드는 없는 경우가 있음!</code></li>
<li>주의할 점2. <code>왼쪽 자식 노드도 있고, 오른쪽 자식 노드도 있는 경우, 더 작은 자식 노드와 위치를 바꾸어야 한다.</code></li>
<li>왼쪽 혹은 오른쪽 자식 노드와 위치를 바꾼 경우, current idx를 바꾼 자식 노드의 idx로 변경하고, 해당 위치로부터 다시 정렬한다.</li>
</ol>
<pre><code class="language-js">class Heap {
  constructor() {
    this.heap = [];
  }
  // 부모 idx = Math.floor(자식 idx / 2)
  getParentIdx(idx) {
    return Math.floor((idx - 1) / 2);
  }
  // 왼쪽 자식 idx = 부모 idx * 2
  getLeftChildIdx(idx) {
    return idx * 2 + 1;
  }
  // 오른쪽 자식 idx = 부모 idx * 2 + 1
  getRightChildIdx(idx) {
    return idx * 2 + 2;
  }
  swap(idx1, idx2) {
    [this.heap[idx1], this.heap[idx2]] = [this.heap[idx2], this.heap[idx1]];
  }
  push(value) {
    // 일단 마지막 노드에 들어온 값을 push하여 삽입한다. 이때 재귀적이든 반복문을 돌리든 부모노드를 확인하면서 들어온 값이 부모노드보다 작은지 큰지를 구분하여 위치를 교환을 계속 실행해주며 정렬해준다.
    this.heap.push(value);
    let current = this.heap.length - 1; // push 했기 때문에 heap 배열의 맨 뒤에 붙음
    let parent = this.getParentIdx(current);

    while (this.heap[parent] &gt; this.heap[current]) {
      this.swap(parent, current);
      current = parent;
      parent = this.getParentIdx(current);
    }
    return this.heap;
  }
  pop() {
    // heap에 아무것도 없는 경우,
    if (this.heap.length === 0) {
      return null;
    }
    // root만 있는 경우 ,
    if (this.heap.length === 1) {
      return this.heap.pop();
    }
    const min = this.heap[0]; // min에 0번째 값 저장
    this.heap[0] = this.heap.pop(); //  마지막 값이랑 0번째 값이랑 교체

    // 정렬
    let current = 0;
    let leftChild = this.getLeftChildIdx(current);
    let rightChild = this.getRightChildIdx(current);

    while (
      (this.heap[leftChild] &amp;&amp; this.heap[leftChild] &lt; this.heap[current]) ||
      (this.heap[rightChild] &amp;&amp; this.heap[rightChild] &lt; this.heap[current])
    ) {
      // 오른쪽 왼쪽 다 있고, 왼쪽이 더 큰 경우, -&gt; 오른쪽과 변경
      if (
        this.heap[rightChild] &amp;&amp;
        this.heap[rightChild] &lt; this.heap[leftChild]
      ) {
        this.swap(rightChild, current);
        current = rightChild;
      } else {
        this.swap(leftChild, current);
        current = leftChild;
      }

      leftChild = this.getLeftChildIdx(current);
      rightChild = this.getRightChildIdx(current);
    }
    return min;
  }
}

function solution(input, K) {
  var answer = 0;
  const heap = new Heap();
  for (const item of input) {
    heap.push(item);
  }
  while (heap.heap[0] &lt; K &amp;&amp; heap.heap.length &gt; 1) {
    // heap의 root가 k보다 작고, heap에 1개 이상의 데이터가 있다면 계속 할 것
    const first = heap.pop(); // 제일 작은 값과
    const second = heap.pop(); // 두번째로 작은 값을 빼내고,
    heap.push(first + second * 2); // 새로 만든 값을 push
    answer++;
  }
  // 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다. - `놓친 부분``
  if (heap.heap[0] &gt;= K) {
    return answer;
  } else {
    return -1;
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] Babel & Webpack]]></title>
            <link>https://velog.io/@isabel_noh/Javascript-Babel-Webpack</link>
            <guid>https://velog.io/@isabel_noh/Javascript-Babel-Webpack</guid>
            <pubDate>Fri, 11 Aug 2023 11:01:17 GMT</pubDate>
            <description><![CDATA[<h1 id="babel-webpack-">Babel, Webpack ?</h1>
<p>이제 취업 준비를 하다보면 공고에서 이런 글을 확인할 수 있을 것입니다.</p>
<blockquote>
<p>webpack, esbuild 등 <code>모듈 번들러</code> 활용 경험이 있는 분
Babel을 이용한 ES6+ 스펙의 사용 경험이 있는 분</p>
</blockquote>
<p>또 쉽게 우리는 React 앱을 시작할 때,  create-react-app 이라는 명령어를 통해 시작하죠? 이 때 webpack, babel이 자동으로 설치됩니다. Vue도 마찬가지에용. vue-cli를 통해 설치하면 webpack, babel이 자동으로 설치됩니다.</p>
<blockquote>
<p>💡 학습 목표 : 바벨과 웹팩이 뭔지 알고 가시길!</p>
</blockquote>
<h2 id="1-webpack이란">1. Webpack이란?</h2>
<blockquote>
<p>💡 webpack: 모던 Javascript 애플리케이션을 위한 정적 <code>모듈 번들러</code> (webpack 정의)</p>
</blockquote>
<p><strong>Webpack</strong>:  여러 개의 파일들을 하나로 묶어주는 번들러 </p>
<ul>
<li>모듈 번들러 : 웹 어플리케이션을 구성하는 자원(HTML, CSS, Javascript, Images 등)을 각각 <code>모듈</code>로 보고 이를 병합해서 하나의 결과물을 만드는 도구</li>
</ul>
<hr>
<h3 id="모듈-">모듈 <strong><strong><strong><strong><strong><strong><strong>****</strong></strong></strong></strong></strong></strong></strong></h3>
<ul>
<li>프로그래밍 관점<ul>
<li>특정 기능을 갖는 작은 코드 단위</li>
</ul>
</li>
<li>Webpack에서는?<ul>
<li>웹 애플리케이션을 구성하는 모든 자원 하나하나가 모두 모듈</li>
</ul>
</li>
</ul>
<ul>
<li>모듈 번들링: 웹 애플리케이션을 구성하는 여러 자원들을 하나의 파일로 병합 및 압축 해주는 동작</li>
</ul>
<h3 id="webpack은-왜-사용하나요">Webpack은 왜 사용하나요?</h3>
<ul>
<li><p>모듈화의 필요성</p>
<ul>
<li><p>파일 단위의 자바스크립트 모듈 관리</p>
<ul>
<li><p>자바스크립트의 변수의 유효 범위는 기본적으로 global → 어디에서든지 접근하기 용이함</p>
</li>
<li><p>하지만 위 특성이 어플리케이션을 생성할 때는 문제점으로 작용</p>
<pre><code class="language-jsx">  &lt;!-- index.html --&gt;
  &lt;html&gt;
    &lt;head&gt;
      &lt;!-- ... --&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;!-- ... --&gt;
      &lt;script src=&quot;./app.js&quot;&gt;&lt;/script&gt;
      &lt;script src=&quot;./main.js&quot;&gt;&lt;/script&gt;
          &lt;script&gt;
        getNum();  // main.js의 var num 값이 출력됨
      &lt;/script&gt;
    &lt;/body&gt;
  &lt;/html&gt;</code></pre>
<ul>
<li>위 두 파일들에서 동일한 이름의 변수를 선언하고 활용한다고 가정했을 때, (예를 들면 var num) 내가 원하는 대로 결과값이 도출되지 않을 수 있음</li>
</ul>
</li>
<li><p>하지만 파일 단위로 변수를 관리할 수 있게 된다면? → 웹팩은 파일 단위로 모듈화하여 관리</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>번들러를 사용하면 여러 파일을 하나로 묶어주기 때문에 네트워크 접속의 부담을 줄여 더 빠른 서비스를 제공할 수 있음</p>
</li>
<li><p>브라우저의 HTTP 요청 제약을 피할 수 있음 (한 번에 보낼 수 있는 HTTP 요청 수 : 6~8개, 2개 이런 브라우저도 있음)</p>
</li>
</ul>
<hr>
<p>but, 하나의 파일로 모듈화된 파일들을 요청하게 되면 첫 로딩시 속도가 너무 느려질 수 있음 </p>
<p>→ <strong><a href="https://www.notion.so/Babel-Webpack-ca6449bcf9114dfa90a7c5f1f6064e6d?pvs=21">Code Splitting</a>, 캐시</strong> 등의 방법으로 문제를 해결한다고 함</p>
<hr>
<p><strong>Code Splitting</strong></p>
<p>웹팩에서 번들링 한 코드를 분할하고, 요청에 따라 로드할 수 있도록 해주는 방법</p>
<ul>
<li>Code Splitting을 하지 않은 경우, 애플리케이션을 실행시켰을 때 모든 코드가 한번에 요청이 되어서 로딩 시간이 길어질 수 있음</li>
<li>Code Splitting을 하게 되면, 필요한 순간 필요한 코드만 불러오기 때문에 우선 순위를 제어할 수 있고, 로딩 시간도 줄일 수 있음</li>
</ul>
<h2 id="2-babel이란">2. Babel이란?</h2>
<blockquote>
<p>💡 Babel: Javascript compiler</p>
</blockquote>
<p><strong>Babel</strong>: 입력된 코드를 Javascript로 변환해주는 트랜스파일러</p>
<ul>
<li><strong>Transplier</strong>: 특정 언어로 작성된 코드를 비슷한 다른 언어로 변환</li>
</ul>
<h3 id="babel은-왜-사용하나요">Babel은 왜 사용하나요?</h3>
<p>모든 브라우저가 최신 문법, 기술(ES6)을 지원하는 것은 아니기 때문에 구 기능(ES5)으로 변환하는 작업이 필요</p>
<ul>
<li>ES6의 화살표 함수와 ES7의 지수 연산자</li>
</ul>
<pre><code class="language-jsx">[1, 2, 3].map(n =&gt; n ** n);</code></pre>
<ul>
<li>Transpiled</li>
</ul>
<pre><code class="language-jsx">// ES5
&quot;use strict&quot;;

[1, 2, 3].map(function (n) {
  return Math.pow(n, n);
});</code></pre>
<h3 id="babel이-하는-일">Babel이 하는 일</h3>
<ol>
<li><p>Transform syntax 구문 변환</p>
<ul>
<li>최신 자바스크립트 문법을 오래된 브라우저가 이해할 수 있도록 오래된 문법 ES5으로 변환</li>
</ul>
</li>
<li><p>JSX and React</p>
<ul>
<li><p>React에서 사용되는 JSX 문법을 Javascript로 트랜스파일링</p>
</li>
<li><p>JSX는 브라우저에서 바로 실행될 수 없기 때문에, Javascript로 변환해주어야 함</p>
</li>
<li><p>바벨로 컴파일된 JSX는 React.createElement를 호출하여 리액트 엘리먼트를 반환한다.</p>
</li>
<li><p>JSX 문법을 사용하는 컴포넌트 파일에는 React를 import해줘야 한다.</p>
<pre><code class="language-jsx">import React from &#39;react&#39;;</code></pre>
</li>
</ul>
</li>
</ol>
<hr>
<h2 id="babel과-webpack을-활용한-간단-es6-환경-구축">Babel과 Webpack을 활용한 간단 ES6 환경 구축!</h2>
<h3 id="webpack">Webpack</h3>
<ol>
<li><p><strong>Webpack 설치 및 초기 설정</strong></p>
<p> 1-1. npm 초기화 </p>
<pre><code class="language-bash"> npm init -y</code></pre>
<pre><code class="language-jsx"> //package.json
 {
   &quot;name&quot;: &quot;test&quot;,
   &quot;version&quot;: &quot;1.0.0&quot;,
   &quot;description&quot;: &quot;&quot;,
   &quot;main&quot;: &quot;index.js&quot;,
   &quot;scripts&quot;: {
     &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;
   },
   &quot;keywords&quot;: [],
   &quot;author&quot;: &quot;&quot;,
   &quot;license&quot;: &quot;ISC&quot;
 }</code></pre>
<p> 1-2. 로컬에서 webpack, webpack-cli (커맨드-라인에서 webpack을 실행할 때 사용되는 도구) 설치</p>
<pre><code class="language-bash"> npm install webpack webpack-cli --save-dev</code></pre>
<p> devDependecies에 아래와 같이 추가됨</p>
<pre><code class="language-jsx"> //package.json
 {..., 

 &quot;devDependencies&quot;: {
     &quot;webpack&quot;: &quot;^5.87.0&quot;,
     &quot;webpack-cli&quot;: &quot;^5.1.4&quot;
   }
 }</code></pre>
</li>
<li><p><strong>번들 생성</strong></p>
<ul>
<li><p>lodash 설치 (build 정상적으로 되는지 테스트 하기 위해 설치)</p>
<pre><code class="language-bash">npm i lodash</code></pre>
</li>
<li><p>index.html 파일 생성</p>
<pre><code class="language-jsx">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Webpack Demo&lt;/title&gt;
  &lt;script src=&quot;https://unpkg.com/lodash@4.16.6&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;script src=&quot;src/index.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
<li><p>src 폴더 생성 &gt; 폴더 안에 index.js 파일 생성</p>
<pre><code class="language-jsx">function component() {
var element = document.createElement(&#39;div&#39;);

/* lodash is required for the next line to work */
element.innerHTML = _.join([&#39;Hello&#39;,&#39;webpack&#39;], &#39; &#39;);

return element;
}

document.body.appendChild(component());</code></pre>
</li>
</ul>
</li>
</ol>
<ol>
<li><p><strong><strong>웹팩 빌드를 위한 구성 및 빌드</strong></strong></p>
<ul>
<li><p>웹팩 빌드 및 빌드 결과물로 실행하기 위해 각 파일에 아래 내용 반영</p>
<pre><code class="language-jsx">import _ from &#39;lodash&#39;;</code></pre>
</li>
<li><p>lodash를 Import하고 html 파일에서 lodash cdn import 관련 코드 삭제</p>
<pre><code class="language-html">&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Webpack Demo&lt;/title&gt;
  &lt;!-- &lt;script src=&quot;https://unpkg.com/lodash@4.16.6&quot;&gt;&lt;/script&gt; --&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;!-- &lt;script src=&quot;src/index.js&quot;&gt;&lt;/script&gt; --&gt;
  &lt;script src=&quot;dist/main.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
<li><p>웹팩 빌드 명령어를 실행하기 위해 <code>package.json</code> 파일에 아래 내용 추가</p>
<pre><code class="language-jsx">&quot;scripts&quot;: {
&quot;build&quot;: &quot;webpack --mode=none&quot;
}</code></pre>
</li>
<li><p><code>npm run build</code> 명령어 실행</p>
<pre><code class="language-bash">npm run build

&gt; test@1.0.0 build
&gt; webpack --mode=none

asset main.js 536 KiB [emitted] (name: main)
runtime modules 1.25 KiB 6 modules
cacheable modules 532 KiB
./src/index.js 268 bytes [built] [code generated]
./node_modules/lodash/lodash.js 531 KiB [built] [code generate</code></pre>
<p>정상 빌드 됨 → dist 폴더 가 생성되고 해당 폴더 안에 main.js라는 파일의 결과물이 생김</p>
</li>
</ul>
</li>
</ol>
<ol start="4">
<li>Using Configuration</li>
</ol>
<ul>
<li>버전 4부터 webpack은 어떠한 설정도 필요하지 않으나 복잡한 설정이 필요한 경우를 위해 설정파일을 작성할 수 있음</li>
<li><code>webpack.config.js</code>가 있으면 webpack은 이 파일을 기본으로 작동</li>
<li>프로젝트 폴더 루트 레벨에 <code>webpack.config.js</code> 파일 생성 후 아래 내용 추가</li>
</ul>
<pre><code class="language-jsx">// webpack.config.js
// `webpack` command will pick up this config setup by default
var path = require(&#39;path&#39;);

module.exports = {
  mode: &#39;none&#39;,
  entry: &#39;./src/index.js&#39;,
  output: {
    filename: &#39;main.js&#39;,
    path: path.resolve(__dirname, &#39;dist&#39;)
  }
};</code></pre>
<hr>
<ul>
<li><p><strong>entry</strong>
  : 웹팩이 <strong>빌드할 파일의 시작</strong> 위치
  : default [./src/index.js] </p>
</li>
<li><p><strong>output</strong>
  : 웹팩에 의해 생성된 <strong>번들을 내보낼 위치와 이름</strong> 지정
  : default [./dist/main.js]</p>
</li>
<li><p><strong>module</strong> </p>
</li>
<li><p><strong>loaders</strong>
  : <strong>JS가 아닌 파일들도 유효한 모듈로 변환</strong></p>
</li>
<li><p><strong>plugins</strong>
  : <strong>번들화된 JS를 난독화</strong>하거나 특정 텍스트를 추출
  : 번들된 css, js 파일들을 html 파일에 주입(html-webpack-plugin 사용)하는 역할
  : 번들을 최적화하거나, asset을 관리하고, 또 환경 변수 주입등과 같은 광범위한 작업 수행</p>
</li>
<li><p><strong>mode</strong>
  : production(최적화 빌드), development(빠른 빌드), none(그냥 빌드)
  : 웹팩 설정 모드로 3가지 중 선택 가능</p>
</li>
</ul>
<ol>
<li><p>NPM Scripts</p>
<ul>
<li><p>편리하게 사용하기 위해 단축 명령어를 사용할 수 있음</p>
</li>
<li><p>package.json 파일 수정</p>
<pre><code class="language-jsx">&quot;scripts&quot;: {
&quot;build&quot;: &quot;webpack&quot;
}</code></pre>
</li>
</ul>
</li>
<li><p>npm run build 정상 작동</p>
<pre><code class="language-bash"> npm run build

 &gt; test@1.0.0 build
 &gt; webpack

 asset main.js 536 KiB [compared for emit] (name: main)
 runtime modules 1.25 KiB 6 modules
 cacheable modules 532 KiB
   ./src/index.js 268 bytes [built] [code generated]
   ./node_modules/lodash/lodash.js 531 KiB [built] [code generated]
 webpack 5.87.0 compiled successfully in 116 ms</code></pre>
</li>
</ol>
<h3 id="babel">Babel</h3>
<ol>
<li>패키지 설치</li>
</ol>
<pre><code class="language-bash">npm install --save-dev @babel/core @babel/cli @babel/preset-env</code></pre>
<ul>
<li><p>@babel/core</p>
<p>  : 바벨의 핵심 기능이 있는 모듈 </p>
<p>  (<strong>parsing</strong>(코드를 추상 구문 트리로 파싱), <strong>traverse</strong>(추상 구문 트리를 오래된 문법으로 변환), <strong>generator</strong>(새로 생성된 추상 구문 트리를 바탕으로 새로운 코드 생성)를 한꺼번에 처리할 수 있는 함수를 제공 =&gt; transformSync)</p>
</li>
<li><p>@babel/cli</p>
<p>  : @babel/core를 터미널에서 커맨드를 입력해서 사용하기 위한 패키지</p>
</li>
<li><p>@babel/preset-env</p>
<p>  : 모던 자바스크립트를 지원하기 위한 모든 플러그인의 집합</p>
<p>  : ES6 이상(ES2015+)의 문법으로 작성된 코드를 ES5 문법의 코드로 변환해주는 모든 규칙을 정의’</p>
</li>
</ul>
<ol>
<li>전체 구성 파일 생성</li>
</ol>
<ul>
<li><p>프로젝트의 루트에 babel.config.json 파일을 생성한 후, 아래 예시 코드로 설정한다.</p>
<pre><code class="language-bash">  {
    &quot;presets&quot;: [
      [
        &quot;@babel/preset-env&quot;,
        {
          &quot;targets&quot;: {
            &quot;edge&quot;: &quot;17&quot;,
            &quot;firefox&quot;: &quot;60&quot;,
            &quot;chrome&quot;: &quot;67&quot;,
            &quot;safari&quot;: &quot;11.1&quot;
          },
          &quot;useBuiltIns&quot;: &quot;usage&quot;,
          &quot;corejs&quot;: &quot;3.6.5&quot;
        }
      ]
    ]
  }</code></pre>
</li>
</ul>
<ol>
<li><p>아래 코드를 package.json에 적용한 후, <code>npm run compile</code>을 터미널에 입력</p>
<ul>
<li><p>src 폴더에 있는 모든 JavaScript 파일을 구문 분석(parse) 하고 설정한 변환을 적용하여 각 파일을 dist 폴더로 출력한다.</p>
<pre><code class="language-bash">npm run compile

&gt; test@1.0.0 compile
&gt; babel src -d dist

Successfully compiled 1 file with Babel (210ms).</code></pre>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/795ca9a6-9b7c-45e2-b367-3246a56883dc/Untitled.png" alt="Untitled"></p>
</li>
</ul>
</li>
</ol>
<ul>
<li>compile 전 원본</li>
</ul>
<pre><code class="language-jsx">import _ from &quot;lodash&quot;;

function component() {
  var element = document.createElement(&quot;div&quot;);
  const a = () =&gt; {
    console.log(&quot;a&quot;);
  };

  /* lodash is required for the next line to work */
  element.innerHTML = _.join([&quot;Hello&quot;, &quot;webpack&quot;], &quot; &quot;);

  return element;
}

document.body.appendChild(component());</code></pre>
<ul>
<li>compile 후</li>
</ul>
<pre><code class="language-jsx">&quot;use strict&quot;;

var _lodash = _interopRequireDefault(require(&quot;lodash&quot;));
function _interopRequireDefault(obj) { return obj &amp;&amp; obj.__esModule ? obj : { default: obj }; }
function component() {
  var element = document.createElement(&quot;div&quot;);
  const a = () =&gt; {
    console.log(&quot;a&quot;);
  };

  /* lodash is required for the next line to work */
  element.innerHTML = _lodash.default.join([&quot;Hello&quot;, &quot;webpack&quot;], &quot; &quot;);
  return element;
}
document.body.appendChild(component());</code></pre>
<ul>
<li>but, 화살표함수는 ES5에서 안되지 않나요?</li>
</ul>
<ol>
<li><p><strong>plugin 사용하여 코드 변환 수행하기</strong></p>
<ul>
<li><p>ES2015+ 구문을 ES5로 변환하고자 한다면 @babel/plugin-transform-arrow-functions 플러그인을 사용하여 적용</p>
<pre><code class="language-bash">npm install --save-dev @babel/plugin-transform-arrow-functions</code></pre>
</li>
<li><p><code>babel.config.json</code> 파일에 도 설정</p>
<pre><code class="language-jsx">{
&quot;presets&quot;: [
  ...
],
&quot;plugins&quot;: [&quot;@babel/plugin-transform-arrow-functions&quot;]  // 추가
}</code></pre>
<p>이제는 화살표 함수도 선언형 함수 형태로 컴파일 해줄 수 있다. </p>
<pre><code class="language-jsx">&quot;use strict&quot;;

var _lodash = _interopRequireDefault(require(&quot;lodash&quot;));
function _interopRequireDefault(obj) { return obj &amp;&amp; obj.__esModule ? obj : { default: obj }; }
function component() {
var element = document.createElement(&quot;div&quot;);
const a = function a() {
  console.log(&quot;a&quot;);
};

/* lodash is required for the next line to work */
element.innerHTML = _lodash.default.join([&quot;Hello&quot;, &quot;webpack&quot;], &quot; &quot;);
return element;
}
document.body.appendChild(component());</code></pre>
</li>
</ul>
</li>
</ol>
<ul>
<li>그 외에도 추가적으로 preset, polyfill, configuration을 활용하여 더 다양하게 사용할 수 있다.</li>
</ul>
<p>한 줄 요약</p>
<blockquote>
<p>💡 웹팩은 자바스크립트 어플리케이션을 위한 모듈 번들러!
바벨은 자바스크립트 컴파일러! (or 트랜스파일러)</p>
</blockquote>
<hr>
<p><strong>참고</strong>
<a href="https://webpack.kr/">webpack</a>
<a href="https://babeljs.io/">Babel · Babel</a>
<a href="https://joshua1988.github.io/webpack-guide/motivation/why-webpack.html#%EC%9B%B9%ED%8C%A9%EC%9D%98-%EB%93%B1%EC%9E%A5-%EB%B0%B0%EA%B2%BD">웹팩이 필요한 이유 | 웹팩 핸드북</a>
<a href="https://velog.io/@suyeon9456/Babel#1-parsing-%ED%8C%8C%EC%8B%B1">Babel 직접 적용하며 이해하기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network] CDN(Content Delivery Network)]]></title>
            <link>https://velog.io/@isabel_noh/Network-CDNContent-Delivery-Network</link>
            <guid>https://velog.io/@isabel_noh/Network-CDNContent-Delivery-Network</guid>
            <pubDate>Fri, 11 Aug 2023 10:55:08 GMT</pubDate>
            <description><![CDATA[<h1 id="cdn">CDN</h1>
<blockquote>
<p>💡 웹사이트를 구성하는 수많은 리소스들이 있을 경우 어떻게 최적화할 수 있을까요?  -&gt; *<em>CDN!!! *</em></p>
</blockquote>
<h2 id="cdn이란">CDN이란?</h2>
<p>콘텐츠 전송 네트워크(Content Delivery Network)</p>
<p>데이터 사용량이 많은 애플리케이션의 <code>웹 페이지 로드 속도를 높이고자</code> 인터넷 콘텐츠를 전송하기 위한 지리적으로 분산된 상호 연결된 서버 집단</p>
<ul>
<li>보통 웹 사이트를 로드할 때 서버에 HTTP 요청을 보내서 리소스를 가져옴</li>
<li><code>CDN</code>은 클라이언트와 서버 사이에 중간 서버를 두고, <strong>사용자의 현재 지리적 위치에서 가장 가까운 서버에 리소스를 캐싱</strong>해놓고 이를 빠르게 가져오는 기법<ul>
<li>사용자가 원하는 데이터를 가진 서버가 멀리 있을 경우, 동영상 또는 웹 사이트 이미지와 같은 대용량 파일을 로드해오는데 시간이 오래 걸릴 수 있음</li>
<li>하지만 CDN 서버를 활용하면, 웹 사이트의 콘텐츠를 지리적으로 사용자와 가까운 CDN 서버에 저장하여 컴퓨터에 빨리 도달할 수 있음</li>
</ul>
</li>
</ul>
<h2 id="cdn-작동-원리">CDN 작동 원리</h2>
<p><strong>CDN을 사용하지 않은 경우</strong></p>
<ul>
<li>하나의 오리진 서버가 모든 클라이언트의 요청에 일일히 응답해야함</li>
<li>막대한 트래픽을 유발하고, 부하가 발생해 장애가 발생할 수 있음</li>
</ul>
<p><strong>CDN을 사용하는 경우</strong></p>
<ul>
<li>CDN을 사용한 경우, 트래픽을 분산하여 장애가 발생할 확률이 적어짐</li>
<li>사용자의 지리적으로 가까운 곳에 컨텐츠를 가진 서버를 위치하여, 보다 빠르게 데이터를 받아올 수 있음</li>
</ul>
<p>서버를 여러 지역에 분산시켜 두고, 각 CDN 서버에 데이터를 캐싱</p>
<p>사용자의 컨텐츠 요청이 들어오면 사용자와 가장 가까운 CDN 서버로 매핑시켜 요청된 컨텐츠의 캐싱된 내용을 전달 </p>
<p>만약 서버가 파일을 찾는데 실패하는 경우 CDN 플랫폼의 다른 서버에서 컨텐츠를 찾은 다음 응답을 전송</p>
<h3 id="cdn-서버의-데이터-캐싱-플로우"><strong>CDN 서버의 데이터 캐싱 플로우</strong></h3>
<blockquote>
<p>💡 1. 최초의 요청은 오리진 서버로부터 컨텐츠를 가져와 고객에게 전송하고 동시에 CDN 서버에 캐싱한다.
2. 최초 요청 이후로의 요청은 CDN 에서 지정하는 해당 컨텐츠 만료 시점까지 캐싱된 컨텐츠를 전송한다.
3. 자주 사용하는 페이지에 한해서 캐싱되며, 해당 컨텐츠 호출이 없을 경우 주기적으로 삭제된다.
4. 서버가 파일을 찾는 데 실패하면, CDN 플랫폼의 다른 서버에서 컨텐츠를 찾아서 엔드유저에게 응답을 제공한다. 
5. 컨텐츠를 오래되거나 사용할 수 없는 경우, CDN은 향후 요청에 대해 응답할 수 있도록 새로운 컨텐츠를 저장한다.</p>
</blockquote>
<h3 id="캐싱의-종류">캐싱의 종류</h3>
<ul>
<li><p>정적 캐싱 : 캐싱할 데이터들을 미리 각 엣지에 보내 놓음</p>
<ul>
<li>게임 클라이언트 다운로드 등</li>
</ul>
</li>
<li><p>동적 캐싱: 사용자가 요청을 보낼 때마다 보낼 컨텐츠가 엣지에 있는지 확인한 뒤, 있으면 (cache hit) 바로 사용자에게 보내고, 없으면 (cache miss) 그 때 서버로 요청하여 받아옴</p>
</li>
<li><p>url 접속 → DNS에서 IP 주소를 찾음 → 근데 여기에 origin server IP주소가 아니라 CDN IP 주소를 넣어놓음</p>
</li>
</ul>
<h2 id="cdn-사용-예시">CDN 사용 예시</h2>
<ol>
<li>고속 콘텐츠 전송<ul>
<li>Reuters는 BBC, CNN, New York Times, Washington Post와 같은 주요 채널에 뉴스를 공급하는 세계 최대 뉴스 통신사로, 뉴스 미디어로서 Reuters는 전 세계 고객에게 뉴스 콘텐츠를 신속하게 제공하기 위해 AWS의 CloudFront를 사용</li>
</ul>
</li>
<li>실시간 스트리밍</li>
<li>다중 사용자 확장<ul>
<li>온라인 게임의 오픈 베타테스트나 정식서비스 시작시점에 클라이언트의 다운로드 수요가 급격하게 증가 이럴 경우 병목 현상이 일어나거나 심한 경우 서버가 다운 되기도 하기 때문에 CDN이 필수적으로 사용됨  또한 대규모 업데이트를 위한 패치가 있을 경우에도 병목 현상을 막기 위해 CDN을 사용</li>
</ul>
</li>
</ol>
<h3 id="cdn의-장점">CDN의 장점</h3>
<ul>
<li>컨텐츠 송수신의 병목현상을 피할 수 있음</li>
<li>리소스를 캐싱해 놓고 가져오기 때문에 로딩 속도가 빠름</li>
<li>1개의 서버에서만 리소스를 가져오지 않기 때문에 서버의 부하가 줄어듦</li>
<li>보통 1개의 도메인이 10개의 병렬 연결을 허용 → CDN을 활용하면 병렬 연결 허용 가능 개수가 증가</li>
<li>웹 사이트 보안 강화<ul>
<li>DDoS(분산 서비스 거부) 공격은 대량 가짜 트래픽을 웹 사이트로 전송하여 어플리케이션이 작동 중지되도록 함</li>
<li>CDN은 여러 서버의 로드를 분산하여 origin 서버에 미치는 영향을 줄여 트래픽 급증을 처리할 수 있음</li>
</ul>
</li>
</ul>
<h3 id="cdn의-단점">CDN의 단점</h3>
<ul>
<li>서버를 구축하는 데 비용이 많이 듬</li>
<li>사용자가 해당 CDN을 막아 놓으면 리소스 로딩이 막힘</li>
<li>배포과정이 다소 복잡</li>
<li>CDN 서비스 회사는 각 나라마다 서버를 구축 → 해당 국가에 CDN이 없을 경우, 해외 CDN을 사용하여 로딩 속도가 더 증가할 수 있음</li>
</ul>
<hr>
<p>Reference
<a href="https://aws.amazon.com/ko/what-is/cdn/">CDN이란 무엇인가요? - 콘텐츠 전송 네트워크 설명 - AWS</a>
<a href="https://velog.io/@youngblue/CDN%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80">CDN이란 무엇인가</a>
<a href="https://www.youtube.com/watch?v=_kcoeK0ITkQ">웹서비스에 필수! CDN이 뭔가요?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] this 바인딩]]></title>
            <link>https://velog.io/@isabel_noh/Javascript-this-%EB%B0%94%EC%9D%B8%EB%94%A9</link>
            <guid>https://velog.io/@isabel_noh/Javascript-this-%EB%B0%94%EC%9D%B8%EB%94%A9</guid>
            <pubDate>Fri, 11 Aug 2023 10:51:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>💡 객체지향언어에서의 this?</p>
</blockquote>
<p>일반적으로 객체 지향 언어에서의 this는 함수가 속해있는 객체의 자기자신을 가리킴
하지만 Javascript에서의 this는 다름 !! </p>
<h1 id="javascript에서의-this">Javascript에서의 <code>this</code></h1>
<blockquote>
<p>💡 Object를 참조하는 keyword</p>
</blockquote>
<h3 id="javascript의-함수-→-일급-객체">Javascript의 함수 → <strong>일급 객체</strong></h3>
<p>함수를 … </p>
<ol>
<li>변수나 데이터에 할당할 수 있음</li>
<li>다른 함수의 인자로 사용할 수 있음</li>
<li>다른 함수의 반환값, return 값으로 사용될 수 있음 </li>
</ol>
<p>→ 이렇게 다양한 환경에서 함수가 호출될 수 있기 때문에, this의 의미도 함수가 호출되는 상황(<code>함수가 호출되는 방식</code>)에 따라 가리키는 객체가 달라짐</p>
<h3 id="javascript-실행과정">Javascript 실행과정</h3>
<ol>
<li>자바스크립트 엔진 실행</li>
<li>실행 가능한 코드 분석 <ul>
<li>전역 코드, 함수 코드, eval 코드, 블록문</li>
</ul>
</li>
<li>실행 컨텍스트 생성 <ul>
<li>변수 환경, 렉시컬 환경, this</li>
</ul>
</li>
</ol>
<h2 id="this-binding-rules">this binding Rules</h2>
<h3 id="1-기본-바인딩">1. 기본 바인딩</h3>
<p>1-1. 브라우저</p>
<p>함수를 단독으로 호출할 경우, <code>전역 객체</code> 에 바인딩됨 → 브라우저에서 실행하면, 전역 객체인 <code>window</code> 가 바인딩 됨</p>
<pre><code class="language-jsx">function foo() {
  const a = 10;
  console.log(this.a);
}

foo(); // undefined</code></pre>
<p>※ use strict 모드를 사용하면, 전역 객체를 this 바인딩 대상에서 제외시킴 → <code>undefined</code> 가 바인딩 됨</p>
<pre><code class="language-jsx">function showThis(){
    console.log(this);
}

function showThisinStrictMode(){
    &#39;use strict&#39;
    console.log(this);
}

showThis(); // window
showThisinStrictMode(); //undefined</code></pre>
<p>1-2. Node</p>
<p>함수를 단독으로 호출한 경우, 동일하게 <code>전역 객체</code> 에 바인딩 됨 → Node에서는 <code>global</code> 에 바인딩 됨</p>
<p>※ 함수 호출이 아니라, 그냥 전역에서 this를 호출한다면?</p>
<pre><code class="language-jsx">function showThis(){
    console.log(this);
}

showThis(); // object[global]
console.log(this); // { }</code></pre>
<p>→ 빈 객체 <code>{ }</code> 가 출력되는데, 이는 node에서의 <code>module.exports</code> 와 동일하다. </p>
<p><code>module.exports</code> : 파일을 모듈로 사용할 수 있게 해주는 객체</p>
<h3 id="2-암시적-바인딩">2. 암시적 바인딩</h3>
<p>객체의 메서드로 호출되는 경우, <code>Object.function();</code>
→ 호출된 객체 Object 에 바인딩 됨</p>
<pre><code class="language-jsx">const obj = {
    name : &quot;isabel&quot;,
    getName(){
        return this.name;
    }
}

console.log(obj.getName());</code></pre>
<p><strong>※ 참조 타입 Reference Type</strong></p>
<pre><code class="language-jsx">const obj = {
    name : &quot;isabel&quot;,
    getName(){
        return this.name;
    }
}

function showReturnValue(cb){
    console.log(cb());
}

showReturnValue(obj.getName); // undefined</code></pre>
<p>자바스크립트에서 객체를 할당한 변수는 그 객체를 참조하는 값을 저장함
→ obj.getName에는 getName에 대한 참조값이 들어있는 것</p>
<p>참조값을 함수의 인자로 넘기게 되면, 그 참조값을 복제하여 사용
→ showReturnValue에서는 같은 getName의 참조값을 복제하여 cb에 저장하는 것이고, 이는 같은 것을 참조하는 또 다른 객체가 생성되는 것</p>
<blockquote>
<p>💡 근데 같은 함수를 복제해서 쓰는데 showReturnValue에서는 왜 바인딩이 안 됨?</p>
</blockquote>
<p><code>.</code> 연산과 [] 연산을 통해서 객체의 property에 접근을 하면 <code>참조 타입</code>이라는 타입을 반환해줌</p>
<p><strong>참조 타입?</strong> </p>
<ul>
<li>Javascript 내부에서, 명세서 에서만 사용되는 타입(specification type)<ul>
<li>(base, name, strict)</li>
<li>base : 해당 객체</li>
<li>name : 프로퍼티 이름</li>
<li>strict : strict mode 여부</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">obj.getName : (obj, getName, false)</code></pre>
<p>위 함수를 호출하면 → 위의 obj에 this가 바인딩 됨</p>
<p>하지만 <code>.</code> 연산자와 <code>{ }</code> 연산자를 제외한 다른 연산자들은 참조타입이 아닌 해당 프로퍼티의 값만을 전달함
→ 다른 함수로 인자로 넘기는 경우에도 참조 타입이 아닌 프로퍼티의 값만 전달되므로, 해당 값에는 base, 즉 원래 가지고 있던 객체는 전달되지 않음</p>
<p>이러한 문제를 해결하고 싶다면?! </p>
<h3 id="3-명시적-바인딩">3. 명시적 바인딩</h3>
<p>3-1. call</p>
<pre><code class="language-jsx">call(context, arg1, arg2, ... )</code></pre>
<p>3-2. apply</p>
<pre><code class="language-jsx">apply(context, args)</code></pre>
<p>call, apply → this를 바인딩할 객체를 지정한 상태로 함수를 호출할 수 있음</p>
<pre><code class="language-jsx">const foo = {
  a: 20,
}

function bar() {
  console.log(this.a);
}
bar.call(foo); // 20
bar.apply(foo); // 20</code></pre>
<p>3-3. bind </p>
<pre><code class="language-jsx">func.bind(context, arg1, arg2, ... )</code></pre>
<p>this가 바인딩하는 객체를 <code>고정</code>시켜주는 함수로, this가 바인딩된 함수를 반환함</p>
<pre><code class="language-jsx">const foo = {
  a: 20,
}

function bar() {
  console.log(this.a);
}

const bound = bar.bind(foo)

bound(); // 20</code></pre>
<p>a.k.a. hard binding</p>
<h3 id="4-new-바인딩">4. new 바인딩</h3>
<pre><code class="language-jsx">function Person(name) {
  this.name = name;
}

const isabel = new Person(&quot;isabel&quot;); //Person { name: &#39;isabel&#39; }
console.log(isabel.name); // isabel</code></pre>
<p><code>new func()</code> → 생성자 함수로서의 기능을 수행할 수 있게 됨</p>
<ol>
<li>새로운 객체를 내부에서 생성           ← this는 이 객체에 바인딩됨 </li>
<li>함수의 코드 실행</li>
<li>새로 생성한 객체를 반환하여 변수에 할당</li>
</ol>
<h3 id="5-바인딩-종류에-따른-우선순위">5. 바인딩 종류에 따른 우선순위</h3>
<ol>
<li>new 바인딩</li>
<li>암시적 바인딩</li>
<li>명시적 바인딩</li>
<li>기본 바인딩</li>
</ol>
<h2 id="화살표-함수의-this-바인딩">화살표 함수의 this 바인딩</h2>
<pre><code class="language-jsx">const obj = {
    name : &quot;isabel&quot;,
    showNameInSec(sec){
        setTimeout(() =&gt; {
            console.log(this.name);
        }, sec);
    }
}

obj.showNameInSec(1500); // isabel</code></pre>
<ul>
<li>렉시컬 스코프와 상관없이 호출 당시에 의존하는 기존의 바인딩 방식과 달리, 화살표 함수에서는 선언될 당시의 <code>상위의 실행 컨텍스트</code> 의 this 바인딩 객체를 참조함</li>
<li>선언할 때 정적으로 결정</li>
<li>Lexical this라고도 함</li>
<li>위 코드의 경우, this.name의 this는 상위 스코프의 실행 컨텍스트에 있는 this, 즉 showNameInSec의 this를 가리키기 때문에, isabel을 정상적으로 출력할 수 있게 됨</li>
</ul>
<hr>
<p>참고
<a href="https://seungtaek-overflow.tistory.com/21">[JS] 알쏭달쏭 자바스크립트 this 바인딩</a>
<a href="https://www.youtube.com/watch?v=7RiMu2DQrb4">[10분 테코톡] 🥦 브콜의 This</a>
<a href="https://velog.io/@proshy/JS-%EC%83%81%ED%99%A9%EC%97%90-%EB%94%B0%EB%A5%B8-this-%EB%B0%94%EC%9D%B8%EB%94%A9#settimeout">[JS] 상황에 따른 this 바인딩</a>
<a href="https://ko.javascript.info/reference-type">참조 타입</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 리액트의 생명주기(Lifecycle)]]></title>
            <link>https://velog.io/@isabel_noh/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0Lifecycle</link>
            <guid>https://velog.io/@isabel_noh/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0Lifecycle</guid>
            <pubDate>Thu, 10 Aug 2023 09:35:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/isabel_noh/post/770e9d63-3d9c-47a1-960e-5071c6766946/image.png" alt=""></p>
<p>컴포넌트는 생명주기를 가짐 </p>
<ul>
<li>생성(mount) → 업데이트(update) → 제거(unmount)</li>
<li>리액트에서 클래스 컴포넌트는 Lifecycle Methods를 사용하고, 함수형 컴포넌트에서는 Hooks를 사용</li>
</ul>
<h1 id="1-class-components-lifecycle">1. Class Components Lifecycle</h1>
<h2 id="11-mount">1.1. Mount</h2>
<h3 id="111-constructor">1.1.1. Constructor</h3>
<p>컴포넌트 생성자 메서드 
컴포넌트가 생성되면 가장 먼저 실행되는 메서드 
this.props, this.state에 접근이 가능하고, React 요소를 반환 </p>
<h3 id="112-getderivedstatefromprops">1.1.2. getDerivedStateFromProps</h3>
<p>props로 받아온 것을 state에 넣어줌 </p>
<h3 id="113-render">1.1.3. render</h3>
<p>화면에 컴포넌트를 렌더링</p>
<h3 id="114-componentdidmount">1.1.4. componentDidMount</h3>
<p>컴포넌트의 첫번째 렌더링이 마치면 호출되는 메서드 
이 메서드가 호출될 때는 화면에 컴포넌트가 나타난 상태
해당 메서드에서 주로 DOM을 사용해야하는 외부 라이브러리 연동 혹은 해당 컴포넌트에서 필요한 데이터를 요청하기 위한 api 요청 등의 행위를 함</p>
<pre><code class="language-jsx">React.useEffect(()=&gt;{
    console.log(&quot;componentDidMount&quot;);
}, []);</code></pre>
<h2 id="12-update">1.2. Update</h2>
<h3 id="121-getderivedstatefromprops">1.2.1. getDerivedStateFromProps</h3>
<p>컴포넌트의 <code>props나 state가 바뀌었을 때도</code> 이 메서드가 호출</p>
<h3 id="122-shouldcomponentupdate">1.2.2. shouldComponentUpdate</h3>
<p>컴포넌트가 리랜더링할지 말지를 결정하는 메서드 
React.memo와 유사하게 boolean return으로 결정</p>
<h3 id="123-componentdidupdate">1.2.3. componentDidUpdate</h3>
<p>컴포넌트가 업데이트되면 발생</p>
<ul>
<li>의존성 배열이 변경되었을 때만 useEffect 실행되는 것과 동일</li>
</ul>
<pre><code class="language-jsx">React.useEffect(()=&gt;{
    console.log(&quot;countState or exampleProps changed&quot;);
}, [countState, exampleProps]);</code></pre>
<h2 id="13-unmount">1.3. Unmount</h2>
<p>Unmount는 화면에서 컴포넌트가 사라지는 것</p>
<h3 id="131-componentwillunmount">1.3.1. componentWillUnmount</h3>
<p>컴포넌트가 화면에서 사라지기 직전에 호출됨
해당 메서드에서 주로 DOM에 직접 등록했던 이벤트를 제거함
외부 라이브러리를 호출한 것이 있고, 해당 라이브러리에 dispose 기능이 있다면 여기서 호출</p>
<pre><code class="language-jsx">React.useEffect(()=&gt;{
    const timer = setTimeout(() =&gt; {
        console.log(&#39;timer&#39;);
}, 1000)
    return clearTimeout(timer);
}, []);</code></pre>
<h1 id="2-functional-components-hooks">2. Functional Components Hooks</h1>
<p>React의 함수형 컴포넌트에서 생명주기 관련 기능을 연동할 수 있도록 해주는 함수들
class없이 React를 사용할 수 있게 됨</p>
<h2 id="21-react-hooks의-도입-목적">2.1. React Hooks의 도입 목적</h2>
<p>기존 라이프 사이클 메서드 중심이 아니라 로직 중심으로 나눌 수 있게 되어 컴포넌트를 함수 단위로 잘게 쪼갤 수 있게 됨 → 유지보수 EZ</p>
<h2 id="22-react-hooks의-사용-규칙">2.2. React Hooks의 사용 규칙</h2>
<blockquote>
<p>💡 최상단에서만 Hook을 호출할 수 있다.</p>
</blockquote>
<ul>
<li>반복문, 조건문, 중첩된 함수 등에서 호출할 수 없다.</li>
<li>이 규칙을 따르면 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 호출되는 것이 보장된다.</li>
</ul>
<blockquote>
<p>💡 리액트 함수 컴포넌트 안에서만 hook을 호출할 수 있다.</p>
</blockquote>
<ul>
<li>일반 JS 안에서는 호출할 수 없다 .</li>
</ul>
<h2 id="23-hooks의-종류">2.3. Hooks의 종류</h2>
<h3 id="231-usestate">2.3.1. useState</h3>
<p>상태를 관리 </p>
<pre><code class="language-jsx">const [state, setState] = useState(initialState);</code></pre>
<p>useState의 데이터는 동기적으로 업데이트 되지 않음 (비동기처리)
→ 페이지의 수많은 useState 데이터가 모두 동기적으로 업데이트 된다면 리렌더링을 계속 발생시켜 성능 저하가 일어날 수 있음
→ 이러한 문제를 해결하기 위해서 useState는 setState가 연속적으로 호출되면 데이터를 배치(batch) 처리를 통해 한번에 처리하곤함 (16ms를 기준으로 한 번씩 업데이트된다고 한다. )</p>
<h3 id="232-useeffect">2.3.2. useEffect</h3>
<pre><code class="language-jsx">useEffect(() =&gt; {

}, [의존성1, 의존성2, ...])</code></pre>
<p>화면에 렌더링 된 이후에 한 번 실행
<code>componentDidMount</code>, <code>componentDidUpdate</code>, 그리고 <code>componentWillUnmount</code> 가 합쳐진 것</p>
<ul>
<li>만약 화면을 다 그리기 전에 동기화 되어야 하는 경우, <code>useLayoutEffect</code> 를 활용하여 컴포넌트 렌더링 - useLayoutEffect 실행 - 화면 업데이트 순으로 실행시킬 수 있음</li>
<li><code>useLayoutEffect</code>는 렌더링 후 layout과 paint 전에 <strong>동기적</strong>으로 실행됨</li>
<li><code>useEffect</code>는 렌더링 후,  layout과 paint가 완료된 후에 <strong>비동기적</strong>으로 실행됨</li>
<li><code>useInsertionEffect</code></li>
<li>useEffect 안에서 return은 clean-up을 사용하기 위해서 쓰임<ol>
<li>메모리 누수 방지를 위해 UI에서 컴포넌트를 제거하기 전에 수행</li>
<li>컴포넌트가 여러 번 렌더링된다면, 다음 effect가 수행되기 전에 이전 effect를 정리</li>
</ol>
</li>
</ul>
<h3 id="233-usecontext">2.3.3. useContext</h3>
<pre><code class="language-jsx">const ThemeContext = CreateContext(null);

export default function MyApp() {
  const [theme, setTheme] = useState(&#39;light&#39;);
  return (
    &lt;ThemeContext.Provider value={theme}&gt;
      &lt;Form /&gt;
      &lt;label&gt;
        &lt;input
          type=&quot;checkbox&quot;
          checked={theme === &#39;dark&#39;}
          onChange={(e) =&gt; {
            setTheme(e.target.checked ? &#39;dark&#39; : &#39;light&#39;)
          }}
        /&gt;
        Use dark mode
      &lt;/label&gt;
    &lt;/ThemeContext.Provider&gt;
  )
}

function Form({ children }) {
  return (
    &lt;Panel title=&quot;Welcome&quot;&gt;
      &lt;Button&gt;Sign up&lt;/Button&gt;
      &lt;Button&gt;Log in&lt;/Button&gt;
    &lt;/Panel&gt;
  );
}

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = &#39;panel-&#39; + theme;
  return (
    &lt;section className={className}&gt;
      &lt;h1&gt;{title}&lt;/h1&gt;
      {children}
    &lt;/section&gt;
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = &#39;button-&#39; + theme;
  return (
    &lt;button className={className}&gt;
      {children}
    &lt;/button&gt;
  );
}</code></pre>
<p>Context API를 통해 만들어진 Context에서 제공하는 value를 가져올 수 있음</p>
<p>컴포넌트에서 가장 가까운 <code>&lt;MyContext.Provider&gt;</code> 이 업데이트되면, 이 hook은 <code>MyContext Provider</code> 에게 전달된 가장 최신의 context value를 사용하여 렌더러를 trigger </p>
<p>전역 상태 관리로 많이 사용됨</p>
<h3 id="234-usereducer">2.3.4. useReducer</h3>
<p>useState 대체 함수로 컴포넌트 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있움
컴포넌트 바깥에서 로직을 작성할 수 있고, 심지어 다른 파일에서 작성한 후 불러와서 사용할 수도 있음</p>
<ul>
<li>reducer : 현재 상태와 액션 객체를 파라미터로 받아와 새로운 상태를 반환해주는 함수</li>
</ul>
<pre><code class="language-jsx">const [state, dispatch] = useReducer(reducer, initialArg, init?)</code></pre>
<pre><code class="language-jsx">import { useReducer } from &#39;react&#39;;

function reducer(state, action) {
  if (action.type === &#39;incremented_age&#39;) {
    return {
      age: state.age + 1
    };
  }
  throw Error(&#39;Unknown action.&#39;);
}

export default function Counter() {
  const [currentState, dispatch] = useReducer(reducer, { age: 42 }); // 여기에서는 {age : 42}가 initial state
  // ...

    return (
    &lt;&gt;
      &lt;button onClick={() =&gt; {
        dispatch({ type: &#39;incremented_age&#39; })
      }}&gt;
        Increment age
      &lt;/button&gt;
      &lt;p&gt;Hello! You are {state.age}.&lt;/p&gt;
    &lt;/&gt;
  );

}</code></pre>
<ul>
<li><code>dispatch</code> function<ul>
<li>state를 새로운 값으로 변경하게 하고, 리렌더링을 일으킨다.</li>
<li>dispatch함수에 매개변수로 <code>action</code>을 넘겨주어야 한다.</li>
<li>기존의 state 값은 dispatch한 action에 따라 변경된 값으로 return된다.</li>
<li><code>action</code> 은 각각을 구분하기 위해 <code>type</code> 프로퍼티를 가진다. (그냥 이름 같은 거)</li>
<li>redux를 생각하면 좀 더 이해가 잘 될 듯</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">function reducer(state, action) {
  switch (action.type) {  //switch ~ case ~ 문으로 조건문 사용
    case &#39;incremented_age&#39;: {
            // state를 직접 변경해서 return 하지 않기! 
            // 새로운 object를 만들어서 return 하기! -&gt; for 불변성
      return {
        name: state.name,
        age: state.age + 1
      };
    }
    case &#39;changed_name&#39;: {
      return {
        name: action.nextName,
        age: state.age
      };
    }
  }
  throw Error(&#39;Unknown action: &#39; + action.type);
}

function Form() {
  const [state, dispatch] = useReducer(reducer, { name: &#39;Taylor&#39;, age: 42 });

  function handleButtonClick() {
    dispatch({ type: &#39;incremented_age&#39; });
  }

  function handleInputChange(e) {
    dispatch({
      type: &#39;changed_name&#39;,
      nextName: e.target.value
    });
  }
  // ...</code></pre>
<blockquote>
<p>💡 <strong>“Too many re-renders”</strong></p>
</blockquote>
<p><code>Too many re-renders. React limits the number of renders to prevent an infinite loop.</code></p>
<p>렌더링 중에 무조건적으로 액션을 디스패치하여, 컴포넌트가 루프에 진입하게 되는 것</p>
<pre><code class="language-jsx">// 🚩 Wrong: calls the handler during render
return &lt;button onClick={handleClick()}&gt;Click me&lt;/button&gt;

// ✅ Correct: passes down the event handler
return &lt;button onClick={handleClick}&gt;Click me&lt;/button&gt;

// ✅ Correct: passes down an inline function
return &lt;button onClick={(e) =&gt; handleClick(e)}&gt;Click me&lt;/button&gt;</code></pre>
<h3 id="235-useref">2.3.5. useRef</h3>
<p>특정 DOM을 선택할 때 사용되며, 데이터를 저장하는 용도로도 쓰임
<code>.current</code> 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 리턴함
반환된 객체는 컴포넌트의 전 생애 주기를 통해 유지됨</p>
<pre><code class="language-jsx">const inputRef = useRef(null);

...

const handleInputClick = () =&gt; {
    inputRef.current.focus();
}

&lt;&gt;
    &lt;button onClick={handleInputClick}&gt;click here&lt;/button&gt;
    &lt;input ref={ inputRef } /&gt;
&lt;/&gt;</code></pre>
<pre><code class="language-jsx">const valueRef = useRef(0);

...
valueRef.current = valueRef.current + 1;</code></pre>
<hr>
<h2 id="performance-hooks">Performance Hooks</h2>
<p>리렌더링을 최적화하는 가장 일반적인 방법은 필요하지 않은 업무를 skip하는 것<br>리액트가 캐시된 연산 결과를 재사용하게 하거나 이전 렌더링에 비하여 데이터가 바뀌지 않았다면 리렌더링 하지 않게 하는 것</p>
<h3 id="236-usememo">2.3.6. useMemo</h3>
<pre><code class="language-jsx">const cachedValue = useMemo(calculateValue, dependencies)</code></pre>
<p>고연산의 연산 결과를 캐시할 수 있게 해줌 → 메모이제이션된 값을 반환
의존성이 변경되었을 때만 메모이제이션된 값을 다시 연산함
의존성 배열에 아무런 값도 없는 경우, 매 렌더링마다 새로운 값을 연산함</p>
<pre><code class="language-jsx">import { useMemo } from &#39;react&#39;;

function TodoList({ todos, tab, theme }) {
  const visibleTodos = useMemo(() =&gt; filterTodos(todos, tab), [todos, tab]);
  // ...
}</code></pre>
<p>최초 렌더시, <code>() =&gt; filterTodos(todos, tab)</code> 부분, 즉 사용자가 원하는 연산이 실행되고, 해당 연산의 return 값이 반환됨</p>
<p>매 re-render마다 리액트는 dependencies에 있는 값들을 이전 렌더의 값과 비교할 것</p>
<pre><code class="language-jsx">import { useMemo } from &#39;react&#39;;
import { filterTodos } from &#39;./utils.js&#39;

export default function TodoList({ todos, theme, tab }) {
  const visibleTodos = useMemo(
    () =&gt; filterTodos(todos, tab),
    [todos, tab]
  );
  return (
    &lt;div className={theme}&gt;
      &lt;p&gt;&lt;b&gt;Note: &lt;code&gt;filterTodos&lt;/code&gt; is artificially slowed down!&lt;/b&gt;&lt;/p&gt;
      &lt;ul&gt;
        {visibleTodos.map(todo =&gt; (
          &lt;li key={todo.id}&gt;
            {todo.completed ?
              &lt;s&gt;{todo.text}&lt;/s&gt; :
              todo.text
            }
          &lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre>
<ul>
<li><p>children Component 리렌더링 관리</p>
<p>  기본적으로 리액트는 컴포넌트가 리렌더링 되면, 그 자식들도 재귀적으로 모두 리렌더링됨</p>
<p>  props가 동일하다면, children 컴포넌트들은 리렌더링을 skip하게 할 수 있음 → <code>React.memo</code> 를 사용!</p>
<pre><code class="language-jsx">  import { memo } from &#39;react&#39;;

  const List = memo(function List({ items }) {
    // ...
  });</code></pre>
<p>  memo로 감싼다면, 해당 자식 컴포넌트는 props가 모두 바뀌지 않을 경우 리렌더링을 skip함!</p>
<p>  이 부분은 useCallback의 경우에도 동일! </p>
<pre><code class="language-jsx">  export default function TodoList({ todos, tab, theme }) {
    // Tell React to cache your calculation between re-renders...
    const visibleTodos = useMemo(
      () =&gt; filterTodos(todos, tab),
      [todos, tab] // ...so as long as these dependencies don&#39;t change...
    );
    return (
      &lt;div className={theme}&gt;
        {/* ...List will receive the same props and can skip re-rendering */}
        &lt;List items={visibleTodos} /&gt;
      &lt;/div&gt;
    );
  }</code></pre>
<p>  아니면, List 컴포넌트를 useMemo에 넣어도 동일한 결과를 유도할 수 있음</p>
<pre><code class="language-jsx">
  export default function TodoList({ todos, tab, theme }) {
    // Tell React to cache your calculation between re-renders...
    const visibleTodos = useMemo(() =&gt; filterTodos(todos, tab),[todos, tab]);
      const children = useMemo(() =&gt; &lt;List items={visibleTodos} /&gt;, [visibleTodos]);
    return (
      &lt;div className={theme}&gt;
       { children }
      &lt;/div&gt;
    );
  }</code></pre>
</li>
</ul>
<h3 id="237-usecallback">2.3.7. useCallback</h3>
<p>최적화된 컴포넌트로 넘기기 전에 함수 선언을 캐시할 수 있게 해줌
메모이제이션 된 콜백 함수를 반환
의존성이 변경되었을 때만 변경되며, 특정 함수를 새로 렌더링하지 않고 재사용할 수 있게 함</p>
<pre><code class="language-jsx">const cachedFn = useCallback(fn, dependencies)</code></pre>
<p>함수를 캐시하기 위해서는 해당 함수를 useCallback으로 감쌈
handleSubmit이 리턴되는 함수임 </p>
<pre><code class="language-jsx">import { useCallback } from &#39;react&#39;;

function ProductPage({ productId, referrer, theme }) {
  const handleSubmit = useCallback((orderDetails) =&gt; {
    post(&#39;/product/&#39; + productId + &#39;/buy&#39;, {
      referrer,
      orderDetails,
    });
  }, [productId, referrer]); // dependencies
  // ...

    return (
    &lt;div className={theme}&gt;
      &lt;ShippingForm onSubmit={handleSubmit} /&gt;
    &lt;/div&gt;
  );</code></pre>
<p>자바스크립트에서는 function(){} , () ⇒ {} 은 항상 다른 함수를 생성함 → 이 말은 렌더링 될 때마다 다른 함수를 생성한다는 의미</p>
<p>→ <code>useCallback</code> 을 사용하면 같은 함수가 계속 사용됨 (dependencies가 변경되지 않는 한)</p>
<p>useCallback은 아래와 같은 경우에 유용함</p>
<ul>
<li>함수를 memo로 감싸진 컴포넌트에게 prop으로 보내는 경우 → 이 경우는 개발자가 최적화를 원하는 경우니까</li>
<li>개발자가 넘기는 함수가 나중에 다른 Hook의 dependency로 사용되는 경우</li>
</ul>
<h3 id="reactmemo">React.memo</h3>
<p>props가 변경되지 않았을 때는 컴포넌트가 리렌더링을 skip할 수 있게 해줌</p>
<pre><code class="language-jsx">const MemoizedComponent = memo(SomeComponent, arePropsEqual?)</code></pre>
<pre><code class="language-jsx">export function Movie({ title, releaseDate }) {
  return (
    &lt;div&gt;
      &lt;div&gt;Movie title: {title}&lt;/div&gt;
      &lt;div&gt;Release date: {releaseDate}&lt;/div&gt;
    &lt;/div&gt;
  );
}

export const MemoizedMovie = React.memo(Movie);</code></pre>
<ul>
<li><strong>같은 props로 리렌더링이 자주 일어나는 컴포넌트에 사용할 것!</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL]DOM과 Virtual DOM]]></title>
            <link>https://velog.io/@isabel_noh/TILDOM%EA%B3%BC-Virtual-DOM</link>
            <guid>https://velog.io/@isabel_noh/TILDOM%EA%B3%BC-Virtual-DOM</guid>
            <pubDate>Fri, 09 Jun 2023 00:17:56 GMT</pubDate>
            <description><![CDATA[<p>React와 Vue에서는 화면에 보여지는 데이터가 변경되면 virtual DOM에 렌더링됩니다. 
그 후, 이전 virtual DOM에 있던 내용과 비교해서, 변경된 부분만 real DOM에 적용되게 합니다. </p>
<p>그러면 여기서 real DOM과 virtual DOM은 뭘까요? </p>
<blockquote>
<p>💡 학습 목표: Javascript에서의 DOM에 대해 알아보고, DOM과 virtual DOM의 차이점에 대해서 이해해봅시다.</p>
</blockquote>
<h2 id="브라우저-렌더링">브라우저 렌더링</h2>
<p><strong>브라우저</strong>: 웹에서 페이지를 찾아서 보여주고, 사용자가 하이퍼링크를 통해 다른 페이지로 이동할 수 있도록 하는 프로그램(MDN)</p>
<pre><code class="language-markdown">예) Chrome, Firefox, Safari, Opera …</code></pre>
<p><strong>렌더링</strong>: 서버로부터 HTML, CSS, JavaScript 등 작성한 파일을 받아 브라우저에 뿌려주는 것</p>
<h3 id="브라우저-렌더링-과정-5단계"><strong>브라우저 렌더링 과정 5단계</strong></h3>
<p><img src="https://velog.velcdn.com/images/isabel_noh/post/f71f114a-402f-4d68-92f6-ba6404e6b162/image.png" alt=""></p>
<ol>
<li><p><strong>Parsing</strong></p>
<p> HTML파일과 CSS파일을 서버로부터 받아와 parsing하여 DOM tree와 CSSOM tree를 생성</p>
</li>
<li><p><strong>Style</strong></p>
<p> 두 트리를 합쳐 Rendering Tree를 생성</p>
</li>
<li><p><strong>Layout/Reflow</strong></p>
<p> Rendering Tree에서 각 노드의 위치와 크기를 계산</p>
</li>
<li><p><strong>Painting(repaint)</strong></p>
<p> 계산된 값을 이용해 각 노드를 화면상의 실제 픽셀로 변환하고, 레이어 생성</p>
</li>
<li><p><strong>Composite</strong></p>
<p> 레이어를 합성하여 실제 화면에 출력</p>
</li>
</ol>
<h1 id="dom이란">DOM이란?</h1>
<ul>
<li>문서 객체 모델 ( <strong>Document Object Model</strong> )의 줄임말</li>
</ul>
<p><img src="https://velog.velcdn.com/images/isabel_noh/post/ab11edbc-94c0-437d-9cb4-026bcc889b1d/image.png" alt=""></p>
<ul>
<li>html 파일을 웹 브라우저에서 보여주게 하기 위해서는 <strong><code>브라우저 렌더링 엔진</code></strong>은 웹 문서를 parsing하여 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 올림 → <code>DOM</code></li>
<li>모든 요소, 텍스트, attribute들은 각각 객체로 만들어지고, 이 객체들은 위와 같이 트리 구조로 구성되어있기 때문에 <strong><code>DOM Tree</code></strong>라고 부름</li>
<li>DOM tree는 각 노드들로 이루어져있고, 이 노드들은 각 객체들임</li>
<li>화면에 그려진 DOM은 DOM API를 통해 Javascript와 같은 스크립팅 언어로 동적으로 조작할 수 있고, 이 변경된 DOM은 rendering에 반영됩니다.</li>
</ul>
<blockquote>
<p><strong>[DOM을 사용하는 API들의 목록]</strong>
  document.getElementById(id)
  document.getElementsByTagName(name)
  document.createElement(name)
  parentNode.appendChild(node)
  element.innerHTML
  element.setAttribute
  element.getAttribute
  element.addEventListener</p>
</blockquote>
<pre><code class="language-jsx">// DOM 조작 예시
document.querySelector(‘#title”).style.color = “red”;</code></pre>
<h1 id="virtual-dom">Virtual DOM</h1>
<h3 id="1-virtual-dom이-등장하게-된-배경">1. Virtual DOM이 등장하게 된 배경</h3>
<ul>
<li>화면에 보여지는 데이터값이 수정되면 브라우저의 렌더링 과정이 전체가 다시 실행되어, 비효율적</li>
<li>SPA로 된 웹페이지들이 점차 늘어나면서 사용자 인터렉션에 의해 화면이 즉각적으로 수정되어야 하는 경우가 더욱 많아짐</li>
<li>또한 CSR 방식으로 렌더링 되는 경우에는, 처음 렌더링 이후에는 서버로부터 데이터만 받아오고 뷰는 Javascript로 관리하기 때문에 브라우저에서 연산이 많아지면 렌더링 속도가 느려지는 문제도 발생할 수 있음</li>
</ul>
<p>→ 이러한 문제를 해결하기 위해서 virtual DOM이 등장!</p>
<h3 id="2--virtual-dom">2.  <code>Virtual DOM</code></h3>
<ul>
<li>Virtual DOM은 Real DOM을 컴포넌트 단위로 쪼개어 추상화시킨 메모리상에만 존재하는 복사본</li>
<li>html객체에 기반한 Javascript 객체로 표현되고, 실제 DOM이 아닌 메모리 상에서 동작</li>
</ul>
<p>html</p>
<pre><code class="language-html">&lt;ul id=&quot;items&quot;&gt;
    &lt;li&gt;Item 1&lt;/li&gt;
    &lt;li&gt;Item 2&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>javascript</p>
<pre><code class="language-jsx">let domNode = {
  tagName: &quot;ul&quot;,
  attributes: {
    id: &quot;items&quot;,
  },
  children: [
    {
      tagName: &quot;li&quot;,
      textContent: &quot;Item 1&quot;,
    },
    {
      tagName: &quot;li&quot;,
      textContent: &quot;Item 2&quot;,
    },
  ],
};</code></pre>
<ul>
<li>virtual DOM 적용<ul>
<li>데이터가 변경</li>
<li>전체가 virtual DOM에 렌더링</li>
<li><strong>이전</strong> virtual DOM에 있던 내용과 <strong>업데이트 후</strong>의 내용을 <strong>비교</strong></li>
<li>바뀐 부분만 실제 DOM에 적용</li>
</ul>
</li>
<li>변경되는 부분만 real DOM에 적용하기 때문에, 연산 비용 측면에서 효율적</li>
<li>수정 사항이 여러 개 있어도 virtual DOM은 real DOM에 렌더링을 1번만 발생<ul>
<li>DOM 요소의 변화를 <strong>묶어서</strong> 적용 후, 이를 Real DOM에 동기화</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/isabel_noh/post/d8d34a33-f97d-4861-9e27-1e418e78207d/image.png" alt=""></p>
<h3 id="3-react에서의-virtual-dom-렌더링">3. React에서의 Virtual DOM 렌더링</h3>
<p><strong>React의 두 개의 가상돔</strong></p>
<ol>
<li>렌더링 이전 화면 구조를 나타내는 가상돔</li>
<li>렌더링 이후에 보이게 될 화면 구조를 나타내는 가상돔</li>
</ol>
<ul>
<li>React에서 데이터 업데이트 시 virtual DOM에서 real DOM으로 렌더링되는 과정<ul>
<li>데이터 업데이트</li>
<li>React.createElement()를 통해 JSX.element를 렌더링</li>
<li>모든 virtual DO2M object가 업데이트 됨</li>
<li>React는 virtual DOM을 이전 virtual DOM의 스냅샷과 비교하여 바뀐 부분을 캐치!</li>
</ul>
</li>
</ul>
<hr>
<blockquote>
</blockquote>
<p>💡 <strong><code>Diffing</code></strong> Algorithm: virtual DOM이 업데이트되면, React는 virtual DOM을 이전 virtual DOM의 스냅샷과 비교하여 바뀐 부분을 검사</p>
<ul>
<li>element의 속성값만 바뀐 경우 → <strong>속성 값만 업데이트</strong></li>
<li>element의 태그 혹은 컴포넌트가 변경된 경우 → <strong>해당 node를 포함한 하위 node를 unmount 후 새로운 virtual DOM으로 대체</strong></li>
</ul>
<hr>
<p>Diffing 알고리즘을 통해 확인한 새로 바뀐 부분들을 DOM object에 적용 → <strong><code>재조정(reconciliation)</code></strong></p>
<h3 id="4-무조건-virual-dom이-좋음">4. 무조건 Virual DOM이 좋음?</h3>
<p>정보만 제공하고, 사용자의 interaction이 많지 않은 페이지라면 Real DOM이 성능이 더 좋을수도 있다.</p>
<blockquote>
<p>💡 SPA로 제작된 큰 규모의 웹페이지는 Virtual DOM을 활용하여 브라우저의 연산 양을 줄여 성능 개선에 도움을 줄 수 있다.</p>
</blockquote>
<hr>
<p>브라우저 렌더링 과정에 대해서 더 알아보고 싶다면…!? 
<a href="https://d2.naver.com/helloworld/59361">브라우저는 어떻게 동작하는가?</a></p>
<hr>
<p>참고자료
<a href="https://poiemaweb.com/js-dom">PoiemaWeb</a>
<a href="https://www.youtube.com/watch?v=PN_WmsgbQCo">[10분 테코톡] 🥁 지그의 Virtual DOM</a>
<a href="https://tecoble.techcourse.co.kr/post/2021-10-24-browser-rendering/">브라우저 렌더링 과정 이해하기.</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 백준 - 2605 줄 세우기]]></title>
            <link>https://velog.io/@isabel_noh/Python-%EB%B0%B1%EC%A4%80-2605-%EC%A4%84-%EC%84%B8%EC%9A%B0%EA%B8%B0</link>
            <guid>https://velog.io/@isabel_noh/Python-%EB%B0%B1%EC%A4%80-2605-%EC%A4%84-%EC%84%B8%EC%9A%B0%EA%B8%B0</guid>
            <pubDate>Tue, 02 Aug 2022 05:19:12 GMT</pubDate>
            <description><![CDATA[<h1 id="boj-2605-줄-세우기">BOJ 2605 줄 세우기</h1>
<p><a href="https://www.acmicpc.net/problem/2605">BOJ 2605 줄 세우기</a></p>
<h3 id="문제">문제</h3>
<p>점심시간이 되면 반 학생 모두가 한 줄로 줄을 서서 급식을 탄다. 그런데 매일 같이 앞자리에 앉은 학생들이 앞에 줄을 서 먼저 점심을 먹고, 뒷자리에 앉은 학생들은 뒤에 줄을 서 늦게 점심을 먹게 된다. 어떻게 하면 이러한 상황을 바꾸어 볼 수 있을까 고민하던 중 선생님이 한 가지 방법을 내 놓았다. 그 방법은 다음과 같다.</p>
<p>학생들이 한 줄로 줄을 선 후, 첫 번째 학생부터 차례로 번호를 뽑는다. 첫 번째로 줄을 선 학생은 무조건 0번 번호를 받아 제일 앞에 줄을 선다. 두 번째로 줄을 선 학생은 0번 또는 1번 둘 중 하나의 번호를 뽑는다. 0번을 뽑으면 그 자리에 그대로 있고, 1번을 뽑으면 바로 앞의 학생 앞으로 가서 줄을 선다. 세 번째로 줄을 선 학생은 0, 1 또는 2 중 하나의 번호를 뽑는다. 그리고 뽑은 번호만큼 앞자리로 가서 줄을 선다. 마지막에 줄을 선 학생까지 이와 같은 방식으로 뽑은 번호만큼 앞으로 가서 줄을 서게 된다. 각자 뽑은 번호는 자신이 처음에 선 순서보다는 작은 수이다.</p>
<p>예를 들어 5명의 학생이 줄을 서고, 첫 번째로 줄을 선 학생부터 다섯 번째로 줄을 선 학생까지 차례로 0, 1, 1, 3, 2번의 번호를 뽑았다고 하자, 첫 번째 학생부터 다섯 번째 학생까지 1부터 5로 표시하면 학생들이 줄을 선 순서는 다음과 같이 된다.</p>
<p>첫 번째 학생이 번호를 뽑은 후 : 1
두 번째 학생이 번호를 뽑은 후 : 2 1
세 번째 학생이 번호를 뽑은 후 : 2 3 1
네 번째 학생이 번호를 뽑은 후 : 4 2 3 1
다섯 번째 학생이 번호를 뽑은 후 : 4 2 5 3 1
따라서 최종적으로 학생들이 줄을 선 순서는 4, 2, 5, 3, 1이 된다.</p>
<p>줄을 선 학생들이 차례로 뽑은 번호가 주어질 때 학생들이 최종적으로 줄을 선 순서를 출력하는 프로그램을 작성하시오.</p>
<h4 id="입력">입력</h4>
<p>첫째 줄에는 학생의 수가 주어지고 둘째 줄에는 줄을 선 차례대로 학생들이 뽑은 번호가 주어진다. 학생의 수가 100 이하이고, 학생들이 뽑는 번호는 0 또는 자연수이며 학생들이 뽑은 번호 사이에는 빈 칸이 하나씩 있다.</p>
<h4 id="출력">출력</h4>
<p>학생들이 처음에 줄을 선 순서대로 1번부터 번호를 매길 때, 첫째 줄에 학생들이 최종적으로 줄을 선 순서를 그 번호로 출력한다. 학생 번호 사이에는 한 칸의 공백을 출력한다.</p>
<pre><code class="language-python">N = int(input()) # 5
arr = list(map(int, input().split()))
result_arr = []

for idx, number in enumerate(arr):
    if number == 0: # 0 : 자기 index 자리니까 지금 있는 arr에 뒤에 줄세움
        result_arr.append(idx+1) # 자리 순서라서 index + 1을 해줌! (1부터 N까지)
    else : # 0 카드 아니면 자기 자리보다 number만큼 뺀 자리로 이동!
        result_arr.insert(idx-number, idx+1) 

print(&quot; &quot;.join(map(str, result_arr)))</code></pre>
<p>insert(idx, 넣을 요소) : idx번째 자리에 두번째 인자를 넣어주는 함수<br>처음에는 딱 바로 정리가 되지는 않았지만 한줄씩 써 내려가면서 정리가 되었던 문제이다. insert를 사용하여 간단히 해결할 수 있었다!  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] 백준 - 2635. 수 이어가기]]></title>
            <link>https://velog.io/@isabel_noh/Python-%EB%B0%B1%EC%A4%80-2635.-%EC%88%98-%EC%9D%B4%EC%96%B4%EA%B0%80%EA%B8%B0</link>
            <guid>https://velog.io/@isabel_noh/Python-%EB%B0%B1%EC%A4%80-2635.-%EC%88%98-%EC%9D%B4%EC%96%B4%EA%B0%80%EA%B8%B0</guid>
            <pubDate>Tue, 02 Aug 2022 05:18:08 GMT</pubDate>
            <description><![CDATA[<h1 id="boj-2635-수-이어가기">BOJ 2635 수 이어가기</h1>
<p><a href="https://www.acmicpc.net/problem/2635">BOJ 2635 수 이어가기</a></p>
<h2 id="문제">문제</h2>
<p>다음과 같은 규칙에 따라 수들을 만들려고 한다.  </p>
<p>첫 번째 수로 양의 정수가 주어진다.<br>두 번째 수는 양의 정수 중에서 하나를 선택한다.<br>세 번째부터 이후에 나오는 모든 수는 앞의 앞의 수에서 앞의 수를 빼서 만든다. 예를 들어, 세 번째 수는 첫 번째 수에서 두 번째 수를 뺀 것이고, 네 번째 수는 두 번째 수에서 세 번째 수를 뺀 것이다.<br>음의 정수가 만들어지면, 이 음의 정수를 버리고 더 이상 수를 만들지 않는다.<br>첫 번째 수로 100이 주어질 때, 두 번째 수로 60을 선택하여 위의 규칙으로 수들을 만들면 7개의 수들 100, 60, 40, 20, 20 , 0, 20이 만들어진다. 그리고 두 번째 수로 62를 선택하여 위의 규칙으로 수들을 만들면 8개의 수들 100, 62, 38, 24, 14, 10, 4, 6이 만들어진다.   위의 예에서 알 수 있듯이, 첫 번째 수가 같더라도 두 번째 수에 따라서 만들어지는 수들의 개수가 다를 수 있다.  </p>
<p>입력으로 첫 번째 수가 주어질 때, 이 수에서 시작하여 위의 규칙으로 만들어지는 최대 개수의 수들을 구하는 프로그램을 작성하시오. 최대 개수의 수들이 여러 개일 때, 그중 하나의 수들만 출력하면 된다.  </p>
<h3 id="입력">입력</h3>
<p>첫 번째 수가 주어진다. 이 수는 30,000 보다 같거나 작은 양의 정수이다.</p>
<h3 id="출력">출력</h3>
<p>첫 번째 줄에는 입력된 첫 번째 수로 시작하여 위의 규칙에 따라 만들 수 있는 수들의 최대 개수를 출력한다.<br>둘째 줄에 그 최대 개수의 수들을 차례대로 출력한다. 이들 수 사이에는 빈칸을 하나씩 둔다.</p>
<hr>
<h4 id="문제-풀이">문제 풀이</h4>
<pre><code class="language-python">N = int(input()) #100 
max_list = []
max_cnt = 0
for i in range(N, -1, -1):
    cnt = 0
    list_a = [N, i]
    while True:
            temp = list_a[cnt] - list_a[cnt + 1]
            if temp &lt; 0:
                break
            else : 
                list_a.append(temp)
                cnt += 1

    if max_cnt &lt;= cnt :
        max_cnt = cnt
        max_list = list_a

str_s = &#39;&#39;
for i in max_list:
    str_s += (str(i) + &quot; &quot;)

print(len(max_list)) # 8 
print(str_s) #100 62 38 24 14 10 4 6</code></pre>
<hr>
<p>처음 입력받은 input 값만큼 뒤에서부터 하나씩 계산하는 브루트 포스 방법으로 문제를 풀었다. while문으로 n-2번째 값에서 n-1번째 값을 뺀 결과가 0보다 클때까지 반복하면서 해당 값들을 list_a에 저장하였다.  while문을 돌 때마다 count를 세어주어 count가 제일 클 때의 list를 max_list로 저장하여 문제를 해결하였다.<br>처음에는 for문의 range에 입력받은 N값은 포함되지 않는다고 생각하여 <code>for i in range(N-1, -1, -1)</code>로 놓고 문제를 풀었지만 계속 100%에서 틀렸다고 나왔고 더 보니 자기 자신 N을 포함시키지 않아 문제가 해결되지 않았던 것이다. 범위에 자신이 포함되는지 안되는지를 잘 생각해야 될 것이다.   </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Leetcode - 49. 애너그램]]></title>
            <link>https://velog.io/@isabel_noh/Python-Leetcode-49.-%EC%95%A0%EB%84%88%EA%B7%B8%EB%9E%A8</link>
            <guid>https://velog.io/@isabel_noh/Python-Leetcode-49.-%EC%95%A0%EB%84%88%EA%B7%B8%EB%9E%A8</guid>
            <pubDate>Tue, 26 Jul 2022 06:23:59 GMT</pubDate>
            <description><![CDATA[<h4 id="문자열-배열을-받아-애너그램-단위로-그룹핑하라">문자열 배열을 받아 애너그램 단위로 그룹핑하라</h4>
<h4 id="example-1">Example 1:</h4>
<blockquote>
<p>Input: strs = [&quot;eat&quot;,&quot;tea&quot;,&quot;tan&quot;,&quot;ate&quot;,&quot;nat&quot;,&quot;bat&quot;] 
Output: [[&quot;bat&quot;],[&quot;nat&quot;,&quot;tan&quot;],[&quot;ate&quot;,&quot;eat&quot;,&quot;tea&quot;]]</p>
</blockquote>
<p>cf) An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.</p>
<pre><code class="language-python">words = [&quot;eat&quot;, &quot;tea&quot;, &quot;tan&quot;, &quot;ate&quot;, &quot;nat&quot;, &quot;bat&quot;]

anagram_dict = {}  # 애너그램단위로 묶은 결과가 들어있는 딕셔너리
# key : 해당 단어를 정렬한 결과
# value : key와 같은 애너그램 그룹에 있는 단어들의 모음을 리스트로 만든다.

for word in words:
    sorted_word = &quot;&quot;.join(sorted(word))  # sorted() =&gt; 결과가 리스트, 문자열로 변환해야한다. ==&gt; join()
    # word = &quot;eat&quot;
    # sorted(word) = [&quot;a&quot; , &quot;e&quot; , &quot;t&quot;]
    # &quot;&quot;.join(sorted(word)) = &quot;aet&quot;
    # &quot;.&quot;.join(sorted(word)) = &quot;a.e.t&quot;

    if anagram_dict.get(sorted_word):  # 딕셔너리에 애너그램 그룹이 존재한다.
        anagram_dict[sorted_word].append(word)  # 존재하면 리스트에 추가를 해준다.
    else:
        anagram_dict[sorted_word] = [word]  # 존재하지 않으면 리스트를 새로 만들어준다.

print(anagram_dict)</code></pre>
<p>dictionary와 친해져야겠다. 
<code>dict[key].append(a)</code> -- dictionary의 key값에 리스트가 있다면 key에 접근하여 value에 해당하는 자리에 append()로 a를 추가할 수 있다. 
이와는 달리 <code>dict[key] = [a]</code> 로 새로운 key와 그에 해당하는 list value를 생성할 수 있다. </p>
<p><code>sorted()</code>함수를 사용하면 단어를 한 글자씩 쪼개어서 list로 만들 수 있다.  # [&#39;a&#39;, &#39;t&#39;, &#39;e&#39;]
이렇게 만든 리스트를 다시 <code>&quot;&quot;.join</code> 공백없이 join하면 쭈루룩 붙일 수 있다. # ate</p>
<p><code>dictionary.get(x)</code>을 통해 x가 dictionary의 key 중에 있는지 없는지를 확인할 수 있다.(이에 해당하는 value값을 return 함) key가 없을 경우, 에러가 발생하지 않고 <code>None</code>을 리턴한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Dictionary - Key / Value로 내림차순/오름차순 하기]]></title>
            <link>https://velog.io/@isabel_noh/Python-Dictionary-Key-Value%EB%A1%9C-%EB%82%B4%EB%A6%BC%EC%B0%A8%EC%88%9C%EC%98%A4%EB%A6%84%EC%B0%A8%EC%88%9C-%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@isabel_noh/Python-Dictionary-Key-Value%EB%A1%9C-%EB%82%B4%EB%A6%BC%EC%B0%A8%EC%88%9C%EC%98%A4%EB%A6%84%EC%B0%A8%EC%88%9C-%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 24 Jul 2022 03:03:22 GMT</pubDate>
            <description><![CDATA[<h2 id="key를-기준으로-오름차순-정렬">Key를 기준으로 오름차순 정렬</h2>
<p>key를 기준으로는 <code>sorted()</code>를 사용하면 오름차순으로 정렬할 수 있다. 
argument를 1개 받으며, dict.items()를 넣어주면 오름차순으로 정렬된다. 
tuple로 이루어진 list를 반환한다.</p>
<pre><code class="language-python">dict_a={&#39;파이썬&#39;:1, &#39;자바&#39;:2, &#39;자바스크립트&#39;:3, &#39;씨&#39;:4}
sorted_dict = sorted(dict_a.items())
print(sorted_dict)
# [(&#39;씨&#39;, 4), (&#39;자바&#39;, 2), (&#39;자바스크립트&#39;, 3), (&#39;파이썬&#39;, 1)]</code></pre>
<h3 id="key만-뽑아서-오름차순-정렬">Key만 뽑아서 오름차순 정렬</h3>
<p>key만 출력하는 경우에는 sorted함수에 dict을 넣으면 key만을 뽑아서 오름차순 정렬이 된다. </p>
<pre><code class="language-python">dict_a={&#39;파이썬&#39;:1, &#39;자바&#39;:2, &#39;자바스크립트&#39;:3, &#39;씨&#39;:4}
sorted_dict = sorted(dict_a)
print(sorted_dict)
#[&#39;씨&#39;, &#39;자바&#39;, &#39;자바스크립트&#39;, &#39;파이썬&#39;]</code></pre>
<hr>
<p>이제 여기서부터는 람다식을 이용해야 한다. </p>
<h2 id="key를-기준으로-내림차순-정렬">Key를 기준으로 내림차순 정렬</h2>
<p>내림차순의 경우에도 <code>sorted()</code>함수를 사용하는데, 내림차순이기 때문에 <code>reverse=True</code>를 인자로 건넨다. 또한 lambda를 key인자로 전달한다. </p>
<blockquote>
<p>sorted 함수의 key 파라미터는 어떤 것을 기준으로 정렬할 것인지를 정해준다. 즉, key 값을 기준으로 비교를 하여 정렬을 하는 것이다. </p>
</blockquote>
<p>아래에서 key는 기준으로서의 매개변수이다. <code>item[0]</code> 은 dicts.items()를 뽑아보면 (key, value) 튜플로 이루어진 리스트가 나오는데 이 튜플에서의 key를 의미한다. </p>
<pre><code class="language-python">sorted_dict = sorted(dict_a.items(), key = lambda item: item[0], reverse = True)
print(sorted_dict)</code></pre>
<h3 id="key만을-뽑아서-내림차순-정렬">Key만을 뽑아서 내림차순 정렬</h3>
<p>key만 출력할 경우에는 <code>sorted()</code>함수에 인자로 dictionary와 역순 정렬이라는 의미의 <code>reverse=True</code>를 넣어준다. </p>
<pre><code class="language-python">dict_a={&#39;파이썬&#39;:1, &#39;자바&#39;:2, &#39;자바스크립트&#39;:3, &#39;씨&#39;:4}
sorted_dict = sorted(dict_a,reverse=True)
print(sorted_dict)
#[&#39;파이썬&#39;, &#39;자바스크립트&#39;, &#39;자바&#39;, &#39;씨&#39;]</code></pre>
<h2 id="value를-기준으로-오름차순-정렬">Value를 기준으로 오름차순 정렬</h2>
<p>value를 기준으로 오름차순 정렬한 sorted_dict을 출력하기 위해서 key로 lambda를 주고, 여기서의 <code>item[1]</code>은 value를 의미한다. <code>item[1]</code>(value)을 기준으로 정렬을 하겠다는 의미이다. </p>
<pre><code class="language-python">dict_a={&#39;파이썬&#39;:1, &#39;자바&#39;:2, &#39;자바스크립트&#39;:3, &#39;씨&#39;:4}
sorted_dict = sorted(dict_a.items(), key= lambda item:item[1])
print(sorted_dict)
#[(&#39;씨&#39;, 4), (&#39;자바스크립트&#39;, 3), (&#39;자바&#39;, 2), (&#39;파이썬&#39;, 1)]</code></pre>
<h2 id="value를-기준으로-내림차순-정렬">Value를 기준으로 내림차순 정렬</h2>
<p>value를 기준으로 오름차순 정렬한 sorted_dict을 출력하기 위해서 key로 lambda를 주고, 여기서의 <code>item[1]</code>은 value를 의미한다. <code>item[1]</code>(value)을 기준으로 역순 정렬을 하겠다는 의미이다. </p>
<pre><code class="language-python">dict_a={&#39;파이썬&#39;:1, &#39;자바&#39;:2, &#39;자바스크립트&#39;:3, &#39;씨&#39;:4}
sorted_dict = sorted(dict_a.items(), key= lambda item:item[1], reverse=True)
print(sorted_dict)
#[(&#39;씨&#39;, 4), (&#39;자바스크립트&#39;, 3), (&#39;자바&#39;, 2), (&#39;파이썬&#39;, 1)]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] SWEA - 1959 두 개의 숫자열]]></title>
            <link>https://velog.io/@isabel_noh/Python-SWEA-1959-%EB%91%90-%EA%B0%9C%EC%9D%98-%EC%88%AB%EC%9E%90%EC%97%B4</link>
            <guid>https://velog.io/@isabel_noh/Python-SWEA-1959-%EB%91%90-%EA%B0%9C%EC%9D%98-%EC%88%AB%EC%9E%90%EC%97%B4</guid>
            <pubDate>Tue, 19 Jul 2022 06:58:09 GMT</pubDate>
            <description><![CDATA[<h1 id="swea-1959-두-개의-숫자열">SWEA 1959 두 개의 숫자열</h1>
<p><a href="https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PpoFaAS4DFAUq">SWEA 1959</a></p>
<p>각 길이가 다른 두 개의 숫자열의 서로 마주보는 숫자들을 곱한 뒤 더했을 때 최댓값을 구하는 문제이다.</p>
<pre><code class="language-python">#testcase
T = int(input())

for i in range(0, T) : 
    #각 숫자열의 길이
    NM = input()

    A = input().split() 
    A = list(map(int, A)) # 배열의 모든 값을 정수형(int)로 변환한 list를 만듦
    B = input().split() 
    B = list(map(int, B))

    # B열의 길이가 더 짧을 경우, A와 B swab (이렇게 하면 항상 B열이 더 긺)
    if len(A) &gt; len(B) :
        B, A = A, B

    arr = []

    for k in range(len(B)-len(A)+1) : 
        sum = 0
        for r in range(len(A)) : 
            sum += A[r] * B[r+k]
        arr.append(sum)  # 각 시도들을 배열에 넣고 그 중에서 제일 큰 값을 출력 

    print(f&#39;#{i+1} {max(arr)}&#39;)</code></pre>
<h2 id="조건">조건</h2>
<p>단, 더 긴 쪽의 양끝을 벗어나서는 안 된다.</p>
<hr>
<ul>
<li>더 긴 쪽의 양끝을 벗어나서는 안 되기 때문에, 각 testcase마다 시도는 긴 열에서 짧은 열의 길이를 뺀 것보다 1번 더 가능하다.<pre><code>e.g.) len(A) = 5, len(B) = 3 --- &gt; try_no = 3</code></pre></li>
<li>그리고 각 testcase의 한 번의 시도마다 A열과 B열이 곱하는 횟수는 A열의 길이만큼 가능하다.
시도는 아래와 같이 시행된다.<pre><code class="language-python">arr = [A1*B1 + A2*B2 + A3*B3, A1*B2 + A2*B3 + A3*B4, A1*B3 + A2*B4 + A3*B5 ]</code></pre>
</li>
<li>위 arr의 값들 중에서 제일 큰 값을 찾는다.</li>
</ul>
<hr>
<p>여전히 memory error가 발생한다.
리스트나 변수를 굳이 만들지 않고 코드를 작성하는 법을 익혀야 될 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Git]]></title>
            <link>https://velog.io/@isabel_noh/TIL-Git</link>
            <guid>https://velog.io/@isabel_noh/TIL-Git</guid>
            <pubDate>Mon, 18 Jul 2022 14:20:01 GMT</pubDate>
            <description><![CDATA[<h1 id="git_협업-복구-백업">Git_&quot;협업, 복구, 백업&quot;</h1>
<p> 리눅스 개발자인 리누스 토르발스이 개발한 것으로 분산 버전 관리 시스템이다. 다른 개발자들과 함께 업무를 할 때 예전에는 중앙집중식으로 버전 관리를 했으나 중앙집중식으로 관리를 하게 되면 서버의 데이터가 다 타버렸을 때, 복구할 수 없다는 단점이 있다. 이러한 단점을 방지하기 위해 만든 것이 <code>git</code>이다. 로컬에 원격 Repository의 모든 데이터를 복제하기 때문에 개발자의 수만큼 백업이 되어있다. </p>
<h2 id="github--gitlab-">GitHub ? Gitlab ?</h2>
<p>GitHub과 Gitlab은 git을 통해 이용하는 Cloud서비스</p>
<h5 id="github-장점">GitHub 장점</h5>
<ol>
<li>Microsoft사의 서비스이기 때문에 비교적 안정적임</li>
<li>개인 이용 시 무료 </li>
<li>Git저장소임에 동시에 개발 관련 정보를 공유할 수 있는 플랫폼</li>
</ol>
<h4 id="그런데도-회사에서-github-말고-gitlab을-사용하는-이유는">그런데도 회사에서 GitHub 말고 Gitlab을 사용하는 이유는?</h4>
<ol>
<li>보안상의 이유</li>
<li>비용상의 이유 - 기업으로 사용할 경우 GitHub이 요금이 더 비쌈</li>
<li>GitHub 이용 시 소스코드를 Microsoft사에 올리는 것으로 영업 비밀 유출 가능성 있다고 생각되어 꺼림</li>
</ol>
<p>CLI(Command-Line Interface) &lt;-&gt; GUI(Graphic User Interface)
CLI : 명령어를 통해 사용자와 컴퓨터가 상호작용을 하는 방식 ex)MacOS - terminal / Windows - 명령 프롬프트(.cmd)
Why CLI? </p>
<ul>
<li>GUI는 CLI에 비하여 컴퓨터의 성능을 더 많이 소모함</li>
<li>많은 서버 / 개발 시스템이 CLI를 통한 조작 환경을 제공함</li>
</ul>
<p>home : C: &gt; user &gt; 현재 로그인한 사용자 </p>
<p>git bash: 쉘(Shell)이란 키보드로 입력한 명령어(Command)를 운영체제(OS)에 전달하여, 키보드로 입력한 명령어를 실행하게끔 하는 프로그램</p>
<ul>
<li>Markup vs Markdown
Markdown - e.g) velog, notion에성 마크다운 형식으로 글을 작성하게 되어있음
마크다운을 활용하게 되면 텍스트와 코드(w/ highlight syntex)를 같이 작성할 수 있음</li>
</ul>
<ul>
<li>README.md (md: markdown)
활용: 오픈소스의 공식문서 작성 / 개인 프로젝트 소개 문서 작성 / WIL(Weekly I Learned) 작성 / 블로그 작성 / 소프트웨어의 배포 방법 안내</li>
</ul>
<p>왜 Typora ?</p>
<ol>
<li>실시간 마크다운 변환 </li>
<li>제공이미지 / 표 삽입</li>
</ol>
<hr>
<h1 id="repository">Repository</h1>
<h3 id="원격-repository">원격 Repository</h3>
<h3 id="local-repository">Local Repository</h3>
<ul>
<li>git init 명령어: local repository 생성 및 초기화 <pre><code>  (git을 사용하기 위해 가장 기본적으로 필요한 요소를 초기화)</code></pre></li>
</ul>
<h3 id="git---3가지-영역을-바탕으로-관리함">git - 3가지 영역을 바탕으로 관리함</h3>
<blockquote>
<p>Working Directory
Staging Area
Repository</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/isabel_noh/post/4d0d10d7-fde4-46a0-9a83-754b09dd8e06/image.png" alt=""></p>
<h4 id="staging-area를-거치는-이유">Staging Area를 거치는 이유???</h4>
<p>Staging Area : commit으로 남기고 싶은, 특정 버전으로 관리하고 싶은 파일이 있는 곳
commit: Staging Area안의 파일 하나 하나를 기록하는 것이 아니라, Staging Area 자체를 새로운 버전으로 기록함</p>
<h3 id="git-로컬에서-작업하기">git 로컬에서 작업하기</h3>
<blockquote>
<ul>
<li><strong>git init</strong>: local repository 생성 및 초기화 </li>
</ul>
</blockquote>
<ul>
<li><strong>git add 파일이름.확장자</strong>: 작업 디렉토리(working directory) 상의 변경 내용(삭제, 수정, 파일 생성 등... )을 버전으로 관리하고자, Staging Area에 추가하는 명령어</li>
<li><strong>git add .</strong> : 현재 Working Directory의 모든 변경사항을 Staging Area에 올리는 명령어</li>
<li><strong>git status</strong>: 현재 폴더의 git 상태를 확인하는 명령어</li>
<li><strong>git commit -m 메시지내용</strong>: &#39;메시지 내용&#39;을 커밋 메시지(수정 이유)로 남기면서 버전을 기록하는 명령어</li>
<li><strong>git log</strong>: 커밋한 기록을 확인하는 명령어</li>
<li><strong>git log --oneline</strong> : 커밋한 기록을 간단하게 한 줄로만 확인하는 명령어</li>
</ul>
<h3 id="git과-원격저장소-연결하기">git과 원격저장소 연결하기</h3>
<blockquote>
<ul>
<li><strong>git remote add origin 원격레포지토리url</strong>: git과 원격 저장소 연결하는 명령어</li>
</ul>
</blockquote>
<ul>
<li><strong>git remote -v</strong>: origin <a href="http://github.com/">http://github.com/</a>~~ 등록한 Remote Repository 정보 확인</li>
<li><strong>git push origin master</strong>: 연결된 원격 저장소(여기서 원격 저장소의 이름은 origin, 브랜치는  master 브랜치)에 로컬의 변경사항 업데이트 하기(master 브랜치에 업데이트)</li>
<li><strong>git push -u origin master</strong>:<ul>
<li>git push</li>
</ul>
</li>
<li><strong>git pull origin master</strong> : 원격 저장소의 변경 사항을 업데이트(원격 저장소로부터 받아와서 sync)</li>
<li><strong>git clone 원격레포지토리url</strong> : 원격 저장소를 로컬 저장소로 복제해온다</li>
</ul>
<h2 id="협업과-복구-및-백업">협업과 복구 및 백업</h2>
<h3 id="remote-repo-생성-및-연결하기">Remote Repo 생성 및 연결하기</h3>
<p><code>원격 저장소에 Push하기 전에 반드시 최소 하나 이상의 Commit을 가져야한다.</code></p>
<h4 id="github">GitHub</h4>
<ol>
<li>기본 브랜치 이름 master로 변경하기</li>
<li>new Repo 생성 버튼 클릭 (원격 저장소 생성)<ol>
<li>이름 설정</li>
<li>생성</li>
</ol>
</li>
</ol>
<h4 id="local">Local</h4>
<ol start="3">
<li><p>새로운 디렉토리 생성 </p>
<ol>
<li>mkdir</li>
<li>cd 경로로 이동</li>
<li><strong>git init</strong>: Local Repository 생성</li>
<li>git remote add origin 원격레포지토리url<ol start="5">
<li>git remote: origin 이름으로 remote 추가된 것 확인하기</li>
<li>touch README.md<ol>
<li>내용 수정(Optional)</li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
<li><p>버전 남기기(remote repository로 push하기 전에 반드시 commit해야 함)</p>
<ol>
<li>git add 파일명.확장자 / git add .</li>
<li>git commit -m &#39;커밋메시지&#39;<ol start="3">
<li>git push origin master</li>
</ol>
</li>
</ol>
</li>
</ol>
<h3 id="branch">Branch</h3>
<p><code>흐름의 분기</code>
<strong>pointer</strong>는 하나의 커밋만 바라볼 수 있음
<strong>master</strong>은 일반적으로 상용 pointer</p>
<blockquote>
<ul>
<li><strong>git branch</strong> : branch 리스트를 확인하는 명령어<ul>
<li><code>*</code>이 붙은  branch가 HEAD가 바라보는 branch</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li><strong>git branch branch이름</strong> : 새로운 &#39;branch이름&#39;이름의 branch 생성하는 명령어</li>
<li><strong>git switch branch이름</strong> : HEAD가 바라보는 branch를 변경하는 명령어</li>
<li><strong>git switch -c branch이름</strong> : (-c : create ) &#39;branch이름&#39;이름의 branch를 생성하고 pointer을 생성한 branch로 옮기는 명령어</li>
</ul>
<h3 id="3-way-merging">3-way Merging</h3>
<p>3-way Merging의 방법으로 머지를 하면 merge commit의 상태를 비교적 확실하게 확인할 수 있다. </p>
<h4 id="3-way-merging의-순서">3-way Merging의 순서</h4>
<blockquote>
<ol>
<li>내 브랜치 commit</li>
<li>다른 사람의 브랜치 commit</li>
<li>두 브랜치의 공통 조상이 되는 merge commit</li>
</ol>
</blockquote>
<p><a href="https://wonyong-jang.github.io/git/2021/02/05/Github-Merge.html">3-way Merge 참고</a></p>
<h3 id="git-ignore">Git Ignore</h3>
<p><code>.gitignore</code> : 저장소에 추가되면 안 되는 파일과 폴더 목록을 모아놓은 파일
<strong>git repository를 생성하자마자 .gitignore파일을 생성해야 함</strong></p>
<blockquote>
<p>참고 <a href="https://www.toptal.com/developers/gitignore">gitignore.io</a>
 gitignore.io: 언어, OS 나 Framework, IDE 별로 저장소에 추가되면 안 되는 파일과 폴더 목록인 .gitignore 를 자동으로 생성해 주는 서비스</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Python - 01 기초 문법]]></title>
            <link>https://velog.io/@isabel_noh/TIL-Python-01-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@isabel_noh/TIL-Python-01-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Mon, 18 Jul 2022 14:19:45 GMT</pubDate>
            <description><![CDATA[<h3 id="학습-마인드-셋">학습 마인드 셋</h3>
<h4 id="1-개념-구조화하기-개념을-명확히-알고-그것을-구조화하기">1. 개념 구조화하기: 개념을 명확히 알고, 그것을 구조화하기!</h4>
<p>해당 개념과 하위 개념을 잘 묶어서 머릿속에  저장하는 것 </p>
<blockquote>
<ol>
<li>개념의 정의  </li>
<li>개념의 포함 관계  </li>
<li>두 개념의 차이점  </li>
</ol>
</blockquote>
<h4 id="2-기본기-탄탄하게-쌓기">2. 기본기 탄탄하게 쌓기</h4>
<h4 id="3-동료-학습">3. 동료 학습</h4>
<p>상호작용을 기반으로 한 학습 </p>
<blockquote>
<p>친구에게 배운 개념 설명하기<br>친구 코드의 에러 함께 해결하기<br>모르는 내용 서로 질문&amp;대답하면서 지식의 빈틈 채우기  </p>
</blockquote>
<hr>
<h2 id="프로그래밍">프로그래밍</h2>
<p>컴퓨터에게 일을 시키기 위해서 컴퓨터가 해야할 일을 순서대로 적어 놓은 프로그램을 만드는 행위</p>
<h2 id="프로그램">프로그램</h2>
<p>특정 작업을 수행하는 일련의 명령어들의 모음</p>
<h2 id="프로그래밍-언어">프로그래밍 언어</h2>
<p>컴퓨터는 0과 1(2진법)로 이루어진 기계어로 소통
처음 컴퓨터가 발명될 때, 전기 신호로 전기가 들어왔는지(1) 안 들어왔는지(0) 확인하던 것을 지금까지 사용</p>
<p>하지만 기계어로 의사소통하는 것은 어려움이 있음
기계어의 대안으로 사람이 이해할 수 있는 새로운 언어 개발 -&gt; <strong>프로그래밍 언어</strong>
사람이 이해할 수 있는 문자로 구성
기본적인 규칙과 문법이 존재</p>
<h2 id="소스-코드source-code">소스 코드(Source Code)</h2>
<p>프로그래밍 언어로 작성된 프로그램</p>
<h2 id="번역기-interpreter--compiler">번역기 (interpreter / compiler)</h2>
<p>소스코드를 컴퓨터가 이해할 수 있는 기계어로 번역해줌
|| e.g. Python - 인터프리터</p>
<hr>
<h1 id="python">Python</h1>
<h2 id="python을-배워야하는-이유">Python을 배워야하는 이유</h2>
<h3 id="1-알고리즘-코딩-테스트에-유리">1. 알고리즘 코딩 테스트에 유리</h3>
<h3 id="2-구현-코딩-테스트에-유리">2. 구현 코딩 테스트에 유리</h3>
<p>유용한 라이브러리 중에서 최소한만 사용하여 프로그램을 개발할 수 있어 가장 유리한 언어</p>
<h3 id="3-가장-인기가-많은-언어">3. 가장 인기가 많은 언어</h3>
<p>프로그래밍 인기척도로 사용하는 PYPL index와 TIOBE index에서 2022년 6월 1위를 기록
AI개발, 데이터 분석, 웹 개발, 업무 자동화 등 Python 활용 분야가 늘어나고 많은 회사에서 도입 중</p>
<h2 id="python의-특징">Python의 특징</h2>
<h3 id="1-easy-to-learn">1. Easy to Learn</h3>
<p>타 프로그래밍 언어에 비해 문법이 간결하고, 유연함 (변수에 별도의 타입 저장이 필요치 않음)
비교적 쉽게 익히고, 프로그래밍 사고에 집중할 수 있음</p>
<h3 id="2-인터프리터-언어-interpreter">2. 인터프리터 언어 (Interpreter)</h3>
<p>Python은 기계어로 번환할 때, 통역하듯이 1줄씩 변환</p>
<h3 id="3-객체지향-프로그래밍oop-object-oriented-programming">3. 객체지향 프로그래밍(OOP, Object Oriented Programming)</h3>
<p>현대 프로그래밍의 기본적인 설계 방법론으로 자리잡은 <strong>객체 지향 프로그램</strong>
Python은 객체 지향 언어로, 모든 것은 객체로 구현되어있음</p>
<h2 id="python의-개발-환경">Python의 개발 환경</h2>
<p><strong>IDE</strong> (Integrated Development Environment): 통합 개발 환경
<code>개발에 필요한 다양한 기능들이 포함되어 있음</code>
|| e.g.) VS Code, XCode, Eclipse 등</p>
<p><strong>Jupyter Notebook</strong>: 문법 학습을 위한 최적의 도구로, 소스코드와 함께 실행결과와 마크다운 저장 가능
open source 기반의 웹 플랫폼 및 어플리케이션
실시간으로 결과를 확인하며 학습할 수 있음</p>
<p><strong>IDLE</strong> (Integrated Development and Learning Environment)</p>
<hr>
<h1 id="기초-문법">기초 문법</h1>
<h2 id="코드-작성법">코드 작성법</h2>
<p>: 코드를 어떻게 작성할지에 대한 가이드 라인
<strong>파이썬에서 제안하는 스타일 가이드  : [PEP8] (<a href="https://www.python.org/dev/peps/pep-0008">https://www.python.org/dev/peps/pep-0008</a>)</strong>
각 회사/프로젝트마다 따로 스타일 가이드를 설정하기도 함
|| e.g. [Google Style Guide] (<a href="https://google.github.io/styleguide/pyguide.html">https://google.github.io/styleguide/pyguide.html</a>)</p>
<h3 id="들여쓰기">들여쓰기</h3>
<p>Space Sensitive 
문장을 구분할 때 중괄호 대신 들여쓰기(Indentation) 사용 </p>
<ul>
<li>Tab으로 들여쓰거나 Spacebar4칸으로 들여쓰기 할 수 있음 (<strong>하나만 골라야함</strong>)</li>
<li>PEP8에서는 공백(빈칸, Space)를 권장함</li>
</ul>
<h3 id="주석-comment">주석 Comment</h3>
<p>-코드를 보다 이해하기 쉽게하여 분석 및 수정이 용이해짐
-*<em>초기부터 주석을 다는 습관을 들일 것! *</em>
-잘 달린 주석은 어떤 정보보다 유용함 
-코드의 내용을 잘 이해할 수 있도록 작성
-가독성을 저해할 정도로 <em>무분별한 사용은 자제</em>
-주석은 실행에 영향을 미치지 않고 프로그램의 속도를 느리게 하지 않으며 용량을 늘리지 않음</p>
<ul>
<li><p>한줄 주석
주석으로 처리될 내용 앞에 <code>#</code>을 입력</p>
</li>
<li><p>여러 줄 주석
한줄 씩 <code>#</code>을 사용하거나, <code>&quot;&quot;&quot;</code> 혹은 <code>```</code>으로 묶어서 표현할 수 있음</p>
</li>
</ul>
<h2 id="변수variable">변수(Variable)</h2>
<h3 id="변수란">변수란?</h3>
<p>데이터를 저장하기 위해서 사용
변수를 사용하면 복잡한 값들을 쉽게 사용할 수 있음(<strong>추상화</strong>)</p>
<ul>
<li>코드의 가독성 증가</li>
<li>의미 단위로 작성 가능</li>
<li>코드 수정이 용이해짐</li>
</ul>
<p>동일 변수에 다른 데이터를 언제든지 할당(저장)할 수 있음</p>
<h3 id="변수의-할당">변수의 할당</h3>
<p>변수는 할당 연산자<code>=</code>을 통해 값을 할당(assignment)</p>
<pre><code class="language-python">americano_price = 2000
cookie_price = 1500</code></pre>
<p>같은 값을 동시에 할당할 수 있음</p>
<pre><code class="language-python">americano_price = cookie_price = 2000</code></pre>
<p>다른 값을 동시에 할당할 수 있음</p>
<pre><code class="language-python">americano_price, moka_price = 2000, 3000 </code></pre>
<h4 id="각-변수의-값을-바꿔서-저장하기">각 변수의 값을 바꿔서 저장하기</h4>
<pre><code>x = 10, y = 20일 때, 각 값을 바꿔서 저장하는 코드를 작성해보자</code></pre><ul>
<li>방법 1) 임시변수 temp 활용<pre><code class="language-python">x, y = 10, 20
</code></pre>
</li>
</ul>
<p>temp = x
x = y 
y = temp
print(x, y) #20, 10</p>
<pre><code>- 방법 2) Pythonic한 방법!!
```python
x, y = 10, 20

y, x = x, y
print(x, y) #20, 10</code></pre><h3 id="식별자">식별자</h3>
<p>변수 이름 규칙 </p>
<ul>
<li>식별자의 이름은 영문 알파벳, 언더 스코어<code>_</code>, 숫자로 구성</li>
<li>첫 글자에 숫자가 올 수 없음</li>
<li>길이 제한이 없고, 대소문자를 구별함</li>
<li>다음 키워드는 예약어<code>reserved words</code>로 변수 이름으로 사용할 수 없음<pre><code class="language-python">import keyword
print(keyword.kwlist)
</code></pre>
</li>
</ul>
<p>#출력 결과
[&#39;False&#39;, &#39;None&#39;, &#39;True&#39;, &#39;and&#39;, &#39;as&#39;, &#39;assert&#39;, &#39;async&#39;, &#39;await&#39;, 
&#39;break&#39;, &#39;class&#39;, &#39;continue&#39;, &#39;def&#39;, &#39;del&#39;, &#39;elif&#39;, &#39;else&#39;, &#39;except&#39;, 
&#39;finally&#39;, &#39;for&#39;, &#39;from&#39;, &#39;global&#39;, &#39;if&#39;, &#39;import&#39;, &#39;in&#39;, &#39;is&#39;, &#39;lambda&#39;, 
&#39;nonlocal&#39;, &#39;not&#39;, &#39;or&#39;, &#39;pass&#39;, &#39;raise&#39;, &#39;return&#39;, &#39;try&#39;, &#39;while&#39;, &#39;with&#39;, &#39;yield&#39;]</p>
<pre><code>
- 내장 함수나 모듈 등의 이름도 사용하지 않아야 함


## 연산자
### 산술 연산자(Arithmetic Operator)
기본적인 사칙연산 및 수식 계산
```python
+ : 덧셈
- : 뺄셈
* : 곱셈
/ : 나눗셈
% : 나머지
// : 몫
** : 거듭제곱</code></pre><h3 id="연산자-우선순위">연산자 우선순위</h3>
<p><code>괄호</code>가 가장 먼저 계산되고, 그 다음에 <code>곱하기와 나누기</code>가 <code>더하기와 빼기</code>보다 먼저 계산됨</p>
<h2 id="자료형">자료형</h2>
<h3 id="자료형datatype-분류">자료형(Datatype) 분류</h3>
<p>프로그래밍에서는 다양한 종류와 값(data)를 쓸 수 있음
사용할 수 있는 데이터의 종류들을 자료형(Datatype)이라고 함</p>
<blockquote>
<p>수치형(Numeric Type)
    - int(정수, integer)
    - float(부동소수점, 실수, floating point number)
    - complex(복소수, complex number)
문자열(String Type)
불린형(Boolean Type)
None</p>
</blockquote>
<h2 id="수치형">수치형</h2>
<h3 id="정수형-int">정수형 (int)</h3>
<p>0, 100, -200 같은 정수를 표현하는 자료형
일반적인 수학 연산 가능</p>
<h4 id="진수-표현">진수 표현</h4>
<pre><code>- 2진수 binary : 0b
- 8진수 octal : 0o
- 16진수 hexadecimal : 0x</code></pre><h3 id="실수형float">실수형(float)</h3>
<p>유리수와 무리수를 포함하는 &#39;실수&#39;를 다루는 자료형
0.1, 100.0, -0.001 등</p>
<blockquote>
<h4 id="실수-연산시-주의할-점부동-소수점">실수 연산시 주의할 점(부동 소수점)</h4>
<p>실수 값을 처리할 때 의도치 않은 값이 나올 수 있음</p>
</blockquote>
<p><strong>부동 소수점</strong></p>
<ul>
<li>컴퓨터는 2진수를, 사람은 10진법을 사용</li>
<li>이 때 10진수 0.1은 2진수로 표현하면 0.00011001100110011.. 같이 무한으로 반복됨</li>
<li>무한대 숫자를 그대로 저장할 수 없어서 사람이 사용하는 10진법의 근사값만 표시</li>
<li>0.1의 경우, 0.1에 가깝지만 정확히 동일하지 않음</li>
<li>이런 과정에서 예쌍치 못한 결과가 나타남(Floating Point Rouding Error)</li>
</ul>
<blockquote>
<h4 id="실수-연산시-주의할-점부동-소수점---해결책">실수 연산시 주의할 점(부동 소수점) - 해결책</h4>
<p> 값을 비교하는 과정에서 정수가 아닌 실수라면 주의할 것
<strong>매우 작은 수보다 작은지를 확인하거나 math 모듈 활용</strong></p>
</blockquote>
<pre><code class="language-python">a = 0.1
b = 1.2 - 1.1 #0.9999999999999987
# 매우 작은 수와 비교
print(abs(a-b) &lt;= 1e-10)
# math 모듈 활용
import math
print(math.isclose(a,b)) #True</code></pre>
<h2 id="문자열-자료형-string-type">문자열 자료형 (String Type)</h2>
<p>모든 문자는 <code>str</code> 타입
문자열은 작은따옴표 <code>&#39;</code>나 큰따옴표<code>&quot;</code>를 활용하여 표기</p>
<h3 id="escape-sequence">Escape Sequence</h3>
<p>역슬래시(backslash) 뒤에 특정 문자가 와서 특수한 기능을 하는 문자 조합</p>
<pre><code>\n : 줄바꿈
\t : 탭
\r : 캐리지 리턴(carriage return) - 커서를 맨 앞으로 옮김
\o : Null
\\ : \
\&#39; : 단일인용부호(&#39;)
\&quot; : 이중인용부호(&quot;)
</code></pre><h3 id="문자열-연산">문자열 연산</h3>
<ul>
<li><p>덧셈 (String Concatenation)
파이썬에서 문자열 덧셈은 문자열을 연결함</p>
</li>
<li><p>곱셉
문자열&quot;Python&quot;*3 ?</p>
<pre><code class="language-python">&quot;Python&quot;*3  # PythonPythonPython</code></pre>
<h3 id="string-interpolation문자열을-변수를-활용하여-만드는-법">String Interpolation(문자열을 변수를 활용하여 만드는 법)</h3>
</li>
<li><p>f-string: python 3.6+</p>
<pre><code class="language-python">name = &#39;Kim&#39;
score = 4.5
</code></pre>
</li>
</ul>
<p>print(f&#39;Hello, {name}! Your score is {score}&#39;)
#Hello, Kim! Your score is 4.5</p>
<pre><code>- % - formatting
```python
name = &#39;Kim&#39;
score = 4.5

print(&#39;Hello, %s&#39; % name) #Hello, Kim
print(&#39;My score is %d&#39; % score) #My score is 4.5
print(&#39;My score is %f&#39; % score) #My score is 4.500000</code></pre><ul>
<li>str.format()<pre><code class="language-python">name = &#39;Kim&#39;
score = 4.5
</code></pre>
</li>
</ul>
<p>print(&#39;Hello, {}! Your score is {}&#39;.format(name, score))
#Hello, Kim! Your score is 4.5</p>
<pre><code>
## None
- 파이썬 자료형 중 하나
- `값이 없음`을 표현하기 위한 타입
- 일반적으로 반환값이 없는 함수에서 사용함

## Boolean형 - True, False
- 논리자료형으로 참과 거짓을 표현하는 자료형
- 바교/논리 연산에서 활용됨
```python
&lt; : 미만
&lt;= : 이하
&gt; : 초과
&gt;= : 이상
== : 같음
!= : 같지 않음
is : 객체 아이덴티티(OOP)
is not : 객체 아이덴티티가 아님</code></pre><h3 id="비교-연산자">비교 연산자</h3>
<ul>
<li>수학에서의 등호/부등호와 동일한 개념</li>
<li>주로 <code>조건문</code>에서 사용되며 값을 비교할 때 사용</li>
<li><blockquote>
<p>True / False 값을 return함</p>
</blockquote>
</li>
</ul>
<h3 id="논리-연산자">논리 연산자</h3>
<p>여러 가지 조건이 있을 때 모든 조건을 만족하거나 (and), 여러 조건 중 하나만 만족해도 될 때 (or) 특정 코드를 실행하고 싶을 때 사용</p>
<pre><code>A and B : A와 B 모두 True이면, True
A or B : A와 B 모두 False이면, False
    A와 B 중 하나라도 True이면, True
Not : True를 False로, False를 True로 </code></pre><blockquote>
<h4 id="논리-연산자-주의할-점--not-연산자">논리 연산자 주의할 점 / not 연산자</h4>
</blockquote>
<ul>
<li><code>Falsy</code> : False는 아니지만 False로 취급되는 다양한 값
0, 0.0, (), {}, [], None, &quot;&quot;(빈 문자열)</li>
<li>논리 연산자도 우선순위가 존재함
not, and, or 순으로 우선순위가 높음</li>
</ul>
<h3 id="논리-연산자의-단축-평가">논리 연산자의 단축 평가</h3>
<ul>
<li>결과가 확실한 경우, 두번째 값은 확인하지 않고 첫번째 값 반환</li>
<li>and 연산자에서 첫번째 값이 False인 경우, 무조건 False --&gt; 첫번째 값 return </li>
<li>or 연산자에서 첫번째 값이 True인 경우, 무조건 True --&gt; 첫번째 값 return </li>
<li>0은 False, 1은 True</li>
</ul>
<pre><code class="language-python">print(3 and 5) #5, 첫번째 값 True, 두번째 값도 True, and는 모든 값 확인해야하기 때문에 두번째 값까지 확인 후 두번째 값 출력
print(3 and 0) #0 둘 중 하나의 값이 False이므로 0 출력
print(0 and 3) #0 둘 중 하나의 값이 False이므로 0 출력 ==&gt; 당연히 False 첫번째 값 출력
print(0 and 0) #0 둘 중 두 값이 모두 False이므로 0 출력

print(5 or 3) #5 둘 중 하나의 값이 True이면 True ==&gt; 두번째 값 확인하지 않고 첫번째 값 출력
print(3 or 0) #3 둘 중 하나의 값이 True이면 True ==&gt; 두번째 값 확인하지 않고 첫번째 값 출력
print(0 or 3) #3 둘 중 하나의 값이 True이면 True ==&gt; 첫번재 값 False, 두번째 값까지 확인 후 두번째 값 출력
print(0 or 0) #0 둘 중 두 값이 모두 False이므로 0 출력</code></pre>
<hr>
<h2 id="컨테이너container">컨테이너(Container)</h2>
<h3 id="컨테이너">컨테이너</h3>
<p>여러 개의 값(데이터)를 담을 수 있는 것(객체)으로, 서로 다른 자료형을 저장할 수 있음
|| e.g. 시퀀스형 (List, Tuple, Range), 비시퀀스형 (Set, Dictionary)
|| e.g. 가변형 (List, Set, Dictionary), 불변형 (Tuple, Range)</p>
<h3 id="컨테이너의-분류">컨테이너의 분류</h3>
<ul>
<li>순서가 있는 Ordered 데이터 vs 순서가 없는 Unordered 데이터</li>
<li>순서가 있다 != 정렬되어 있다</li>
</ul>
<h2 id="list">List</h2>
<p>여러 개의 값을 순서가 있는 구조로 저장하고 싶을 때 사용
가변 자료형(mutable)</p>
<h3 id="list의-생성과-접근">List의 생성과 접근</h3>
<p>대괄호<code>[]</code> 혹은 <code>list()</code>를 통해 생성
Python에서는 어떤 자료형도 저장할 수 있으며, 리스트 안에 리스트도 넣을 수 있음
순서가 있는 시퀀스로 index를 통해 접근 가능 
<code>list[i]</code> 로 값에 접근할 수 있음</p>
<h2 id="tuple">Tuple</h2>
<p>여러 개의 값을 순서가 있는 구조로 저장하고 싶을 때 사용
리스트와의 차이점 : 생성 후, 담고 있는 값 변경 불가 (불가변 자료형, immutable)
소괄호 형태<code>()</code>로 사용</p>
<h3 id="tuple의-생성과-접근">Tuple의 생성과 접근</h3>
<p>소괄호<code>()</code>혹은 <code>tuple()</code>을 통해 생성
수정불가능한 시퀀스로 index로 접근 가능
<code>tuple[i]</code>로 값에 접근할 수 있음</p>
<blockquote>
<h4 id="tuple-생성-주의사항">Tuple 생성 주의사항</h4>
</blockquote>
<ul>
<li>단일 항목의 경우,
하나의 항목으로 구성된 튜플은 생성 시 갑 뒤에 쉼표를 붙여야 함<pre><code class="language-python">tuple_a = (1,) 
tuple_b = 1,</code></pre>
</li>
<li>복수 항목의 경우,
마지막 항목에 붙은 쉼표는 없어도 되지만, 넣는 것을 권장(Trailing Comma)<pre><code class="language-python">tuple_c = (1, 2, 3,)
tuple_d = (1, 2, 3)
tuple_e = 1, 2, 3,
tuple_f = 1, 2, 3</code></pre>
</li>
</ul>
<h3 id="tuple-대입tuple-assignment">Tuple 대입(Tuple Assignment)</h3>
<p>우변의 값을 좌변의 변수에 한 번에 할당하는 과정
일반적으로 파이썬 내부에서 활용</p>
<pre><code class="language-python">x, y = 1, 2
print(x, y) # 1 2

#실제로 튜플로 처리
x, y = (1, 2)
print(x, y) # 1 2</code></pre>
<h2 id="range">Range</h2>
<p>숫자의 시퀀스를 나타내기 위해 사용
주로 반복문과 함께 사용됨</p>
<pre><code class="language-python">print(range(o, 4)) #0, 1, 2, 3</code></pre>
<h3 id="range-사용-방법">Range 사용 방법</h3>
<ul>
<li>기본형 : <code>range(n)</code> : 0 ~ n-1의 숫자의 시퀀스</li>
<li>범위 지정 : <code>range(n, m)</code> : n ~ m-1의 숫자의 시퀀스</li>
<li>범위 및 스텝 지정 : <code>range(n, m, s)</code> : n ~ m-1까지 s만큼 증가시키며 숫자의 시퀀스</li>
</ul>
<blockquote>
<p>범위 및 스텝을 지정하여 <strong>역순</strong>으로 시퀀스를 만들 수 있음</p>
</blockquote>
<pre><code class="language-python">range(6, 1, -1) #[6, 5, 4, 3, 2, 1]
range(6, 1, -2) #[6, 4, 2]
range(6, 1, 1) #[]</code></pre>
<h2 id="슬라이싱-연산자">슬라이싱 연산자</h2>
<h3 id="sequence를-특정-단위로-슬라이싱">Sequence를 특정 단위로 슬라이싱</h3>
<p>인덱스와 콜론을 사용하여 문자열의 특정 부분만 잘라낼 수 있음
slicing할 때, 콜론을 기준으로 앞 인덱스에 해당하는 문자는 포함하고 뒤 인덱스에 해당하는 문자는 미포함</p>
<pre><code class="language-python">print([1, 2, 3, 5][1:4]) #[2, 3, 5]
print((1, 2, 3)[:2]) #(1, 2)
print(range(10)[5:8]) #range(5, 8)
print(&#39;abcd&#39;[2:4]) # cd</code></pre>
<h3 id="sequence를-k간격으로-슬라이싱">Sequence를 k간격으로 슬라이싱</h3>
<pre><code class="language-python">print([1, 2, 3, 5][0:4:2]) #[1, 3]
print((1, 2, 3, 5)[0:4:2]) #(1, 3)
print(range(10)[1:5:3]) #range(1, 5, 3)
print(&#39;abcdefg&#39;[1:3:2]) # b</code></pre>
<h2 id="set">Set</h2>
<p>= 집합</p>
<ul>
<li><p>중복되는 요소가 없이, 순서에 상관없는 데이터들의 묶음
데이터의 <strong>중복을 허용하지 않음</strong> -&gt; 중복되는 원소가 있다면 하나만 저장
순서가 없기 때문에 <strong>index를 이용한 접근 불가능</strong></p>
</li>
<li><p>집합 연산이 가능 - 합집합, 교집합, 차집합 (여집합을 표현하는 연산자는 별도로 X)</p>
</li>
<li><p>가변 자료형(mutable)</p>
</li>
</ul>
<h3 id="set-생성">Set 생성</h3>
<p>중괄호<code>{}</code> 혹은 <code>set()</code>을 통해 생성
빈 Set을 만들기 위해서는 반드시 <code>set()</code>을 활용하여야 함</p>
<pre><code>빈 중괄호는 type이 Dictionary임
black = {}
blank_set = set()</code></pre><p>순서가 없어 별도의 값에 접근할 수 없음</p>
<h3 id="set-사용하기">Set 사용하기</h3>
<ul>
<li>set으로 다른 컨테이너에서 중복된 값을 쉽게 제거할 수 있음</li>
<li><ul>
<li>단, 순서가 무시되므로 순서가 중요할 경우 사용하면 안 됨**</li>
</ul>
</li>
</ul>
<pre><code class="language-python">my_list = [&#39;서울&#39;, &#39;서울&#39;, &#39;서울&#39;, &#39;광주&#39;, &#39;거제&#39;, &#39;광주&#39;, &#39;부울경&#39;]
print(len(set(my_list))) #4</code></pre>
<h3 id="set-연산자">Set 연산자</h3>
<pre><code class="language-python">| : 합집합
&amp; : 교집합
- : 차집합
^ : 대칭차집합 (합집합 - 교집합)
여집합은 없음</code></pre>
<h2 id="dictionary">Dictionary</h2>
<p>키-값(Key-Value) 쌍으로 이루어진 자료형 (3.7+ ordered, 이하 버전은 unordered)</p>
<ul>
<li><strong>Dictionary의 Key</strong>
key는 변경불가능한 데이터만 활용 가능(immutable)
String, Integer, Float, Boolean, Tuple, Range</li>
<li><strong>각 Key의 Value(값)</strong>
어떤 형태이든 관계없음</li>
</ul>
<h3 id="dictionary-생성">Dictionary 생성</h3>
<p>중괄호<code>{}</code> 혹은 <code>dict()</code>을 통해 생성
key를 통해 value에 접근</p>
<pre><code class="language-python">dict_a = {&#39;a&#39;:&#39;apple&#39;, &#39;b&#39;:&#39;banana&#39;, &#39;list&#39;:[1,2,3]}
print(dict_a[&#39;a&#39;]) #apple

dict_b = dict(a = &#39;apple&#39;, b = &#39;banana&#39;, list = [1,2,3])</code></pre>
<h2 id="형변환">형변환</h2>
<p>파이썬에서 데이터 형태는 서로 변환할 수 있음</p>
<ul>
<li><p><strong>암시적 형 변환(Implicit)</strong>
사용자가 의도하지 않고, <strong>파이썬</strong> 내부적으로 자료형을 변환하는 경우</p>
<ul>
<li><p>bool (True = 1, False = 0)</p>
</li>
<li><p>numeric type (int, float)</p>
<p>print(True + 3) # 4
 print(3 + 5.0) # 8.0</p>
</li>
</ul>
</li>
<li><p><strong>명시적 형 변환(Explicit)</strong></p>
</li>
<li><p><em>사용자(개발자)*</em> 가 특정 함수를 활용하여 <strong>의도적</strong>으로 자료형을 변환하는 경우</p>
<ul>
<li>int<ul>
<li>str, float =&gt; int
단, 형식에 맞는 문자열만 정수로 변환 가능
<strong>문자열</strong>은 암시적 타입 변환이 되지 않음
<strong>명시적 타입 변환이 필요</strong>함</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>float</p>
<ul>
<li>str(참고), int =&gt; float
단, 형식에 맞는 문자열만 float으로 변환 가능
정수 형식인 경우에도 float으로 타입 변환
float 형식이 아닌 경우, 타입 변환할 수 없음</li>
</ul>
</li>
<li><p>str</p>
<ul>
<li>int, float, list, tuple, dict =&gt; str</li>
</ul>
</li>
</ul>
<blockquote>
<p>참고)
<strong>input()</strong> : 사용자로부터 데이터를 입력 받음 
입력받은 데이터는 <strong>string</strong>으로 저장됨</p>
</blockquote>
<hr>
<h1 id="파이썬-프로그램-구성-단위">파이썬 프로그램 구성 단위</h1>
<h2 id="프로그램-구성-단위">프로그램 구성 단위</h2>
<h3 id="식별자identifier">식별자(identifier)</h3>
<p>변수, 함수, 클래스 등 프로그램이 실행되는 동안 다양한 값을 가질 수 있는 이름
예약어(reserved words)</p>
<h3 id="리터럴literla">리터럴(literla)</h3>
<p>읽혀지는 대로 쓰여있는 값 그 자체</p>
<h3 id="표현식expression">표현식(expression)</h3>
<p>새로운 데이터 값을 생성하거나 계산하는 코드 조각</p>
<h3 id="문장statement">문장(statement)</h3>
<p>특정한 작업을 수행하는 코드 전체
파이썬이 실행가능한 최소한의 코드 단위</p>
<blockquote>
<p>*<em>모든 표현식expression은 문장statement이다. *</em></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] SWEA - 1989 초심자의 회문 검사]]></title>
            <link>https://velog.io/@isabel_noh/Python-SWEA1989-%EC%B4%88%EC%8B%AC%EC%9E%90%EC%9D%98-%ED%9A%8C%EB%AC%B8-%EA%B2%80%EC%82%AC</link>
            <guid>https://velog.io/@isabel_noh/Python-SWEA1989-%EC%B4%88%EC%8B%AC%EC%9E%90%EC%9D%98-%ED%9A%8C%EB%AC%B8-%EA%B2%80%EC%82%AC</guid>
            <pubDate>Sun, 17 Jul 2022 15:24:17 GMT</pubDate>
            <description><![CDATA[<p>메모리..메모리... 
testCase 문제번호 꼭 쓰기</p>
<p><a href="https://swexpertacademy.com/main/code/problem/problemDetail.do">SWEA1989 - 초심자의 회문 검사</a></p>
<pre><code class="language-python">T = int(input())
j = 0
sign = True
while j &lt; T :
    word = input()
    word = word.replace(&quot; &quot;, &quot;&quot;)
    arr = list(word)
    arr1 = []
    for i in range(len(arr)) : 
        arr1.insert(0, arr[i])

    for i in range(len(arr)) :
        if arr[i] == arr1[i] :
            sign = True
        else :
            sign = False
            break
    if sign == True :
        print(f&#39;#{j+1} 1&#39;)
    else : 
        print(f&#39;#{j+1} 0&#39;)
    j = j + 1</code></pre>
<hr>
<p>다른 사람의 문제 풀이를 보니 </p>
<pre><code class="language-python">temp = &#39;&#39; 
for i in range( len(word)-1, -1, -1) :
    temp += word[i]</code></pre>
<p>이런식으로 각 단어의 i번째 단어로 자를 수 있는 것 같다 .
range (n, m, p) 에서는 n번째부터 m번째 전까지 갭을 p만큼 두고 for문을 돌리는 것이다. 위에서는 word의 길이-1번째 즉 맨 마지막 글자부터 시작하여 -1미만, 즉 0번째 글자까지 for문을 돌 것이며 gap의 값이 -1이므로 for문을 돌릴 때 역순으로 돌리게 되는 것이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] SWEA - 1946 간단한 압출 풀기]]></title>
            <link>https://velog.io/@isabel_noh/Python-SWEA-1946-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%95%95%EC%B6%9C-%ED%92%80%EA%B8%B0</link>
            <guid>https://velog.io/@isabel_noh/Python-SWEA-1946-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%95%95%EC%B6%9C-%ED%92%80%EA%B8%B0</guid>
            <pubDate>Sat, 16 Jul 2022 05:53:40 GMT</pubDate>
            <description><![CDATA[<p><a href="https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PmkDKAOMDFAUq">SWEA 1946 간단한 압축 풀기</a></p>
<pre><code class="language-python">#testcase
T = int(input())

for i in range (0, T) :
    arr = []
    #number of alphabet 
    num = int(input())

    for j in range (0, num) : 
        temp = input().split()
        arr.append(temp[0])
        arr.append(temp[1])
    temp = &quot;&quot;
    for j in range(len(arr)) : # 0, 1, 2
        if j % 2 != 1 : # 짝수번째 배열값일 때 
            print(int(arr[j+1]))
            for k in range(int(arr[j+1])) :
                temp = temp + arr[j]

    print(f&#39;#{i+1}&#39;)
    for j in range(0, len(temp)//10+1) : 
        print(temp[j*10 : (j*10)+10])
</code></pre>
<p>VSCODE로 예제를 돌려봤을 때는 문제가 풀리지만 SWEA에서 돌리면 계속 아래와 같은 오류가 발생했다. </p>
<pre><code>(Runtime error)
Error Message:
Memory error occured, (e.g. segmentation error, memory limit Exceed, stack overflow,... etc)</code></pre><p>아직 문제푸는 방법을 잘 모르는 것인지 메모리를 너무 잡아먹는가보다ㅠㅠ 
그 생각을 하면서 문제를 풀어야될 것 같다! 
문자*int를 하면 문자가 int만큼 반복되어 출력된다는 것을 몰랐어서 괜히 어렵게 풀었던 것 같다. python 문법에 익숙해져야겠다. ! </p>
<pre><code class="language-python">#testcase
T = int(input())

for i in range (0, T) :
    arr = []
    #number of alphabet 
    num = int(input())

    for j in range (0, num) : 
        temp = input().split()
        arr.append(temp[0])
        arr.append(temp[1])
    temp = &quot;&quot;
    for j in range(len(arr)) :
        if j % 2 == 0 : 
            temp = temp + arr[j]*int(arr[j+1])

    print(f&#39;#{i+1}&#39;)
    for j in range(0, len(temp)//10+1) : 
        print(temp[j*10 : (j*10)+10])
</code></pre>
<p>성공! 쿡</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Javascript] 백준 - 2839 설탕공장]]></title>
            <link>https://velog.io/@isabel_noh/Javascript-%EB%B0%B1%EC%A4%80-2839-%EC%84%A4%ED%83%95%EA%B3%B5%EC%9E%A5</link>
            <guid>https://velog.io/@isabel_noh/Javascript-%EB%B0%B1%EC%A4%80-2839-%EC%84%A4%ED%83%95%EA%B3%B5%EC%9E%A5</guid>
            <pubDate>Tue, 28 Jun 2022 05:28:37 GMT</pubDate>
            <description><![CDATA[<h2 id="문제설명">문제설명</h2>
<p>상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.</p>
<p>상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.</p>
<p>상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.</p>
<h2 id="입력">입력</h2>
<p>첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000)</p>
<h2 id="출력">출력</h2>
<p>상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.</p>
<pre><code class="language-jsx">let n = require(&#39;fs&#39;).readFileSync(&#39;/dev/stdin&#39;);
let result = 0;

while(true){
  if (n&lt;0) {
    console.log (-1);
    break;
  }
  if (n%5 === 0) {
    result = result + n/5;
    console.log(result);
    break;

  } else {
    n = n - 3;
    result++;
  }
}
</code></pre>
<h3 id="문제풀이">문제풀이</h3>
<p>처음에는 3의 배수로 끝날 때, 5의 배수로 끝날 때 나눠서 해결하고, 나머지 경우를 else문으로 해결하려고 했다. 그렇게 했더니 경우를 일일이 나눠서 확인해보아야 했기 때문에 너무 코드가 길어지고 복잡해졌다. 숫자가 3과 5의 공배수라면 5사이즈의 가방에 넣는 경우가 더 적은 가방의 수를 return하기 때문에 먼저 5의 배수인지 확인하고 아니라면 3씩 차감(3사이즈의 가방에 넣기) 가방의 개수를 하나씩 늘렸다. 그런 방식으로 3씩 감하다가 3의 배수도 아니고 5의 배수도 아니어서 음수가 되는 경우에는 &#39;-1&#39;을 return 하게 계산하였다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 왜 리액트를 사용하나요?]]></title>
            <link>https://velog.io/@isabel_noh/React-%EC%99%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@isabel_noh/React-%EC%99%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B2%8C-%EB%90%98%EC%97%88%EB%82%98%EC%9A%94</guid>
            <pubDate>Sun, 26 Jun 2022 08:00:06 GMT</pubDate>
            <description><![CDATA[<h1 id="왜-react">왜 React?</h1>
<p>리액트는 페이스북에서 개발하고 관리하는** 사용자 인터페이스(UI)<strong>를 만들기 위한</strong> Javascript 라이브러리**이다. 왜 프론트 개발을 할 때 리액트를 사용하게 되었는지에 대한 이유 및 장점, 단점에 대해서 정리해보려고 한다. </p>
<h3 id="가상-dom을-이용한-성능-향상">가상 DOM을 이용한 성능 향상</h3>
<p>리액트는 <strong>가상 돔(virtual dom)</strong>으로 UI를 빠르게 업데이트 해주고, 메모리에 가상돔을 올려놓고 이전과 이후를 비교하여 변경될 UI의 최소 집합을 계산해준다.
가상 DOM은 가상 트리 형태의 자료구조에 실제 DOM 트리가 매핑된 형태로 동작한다. 매 변경시마다 실제 DOM트리를 변경하게 될 경우, 매번 DOM 전체를 직접 접근하여 변화를 주면 html, css, js파일 전체를 다시 리랜더링하기 때문에 성능이 매우 떨어진다. React에서는 데이터가 변경되면 리액트는 가상 DOM를 변경한다. 그리고 이전의 가상 DOM과 비교해서 변경된 부분을 체크하고 변경된 부분만 실제 DOM에 적용하기 때문에 real DOM을 매번 업데이트 하는 것에 비하여 성능을 향상시킬 수 있다. </p>
<h3 id="단방향-데이터-바인딩">단방향 데이터 바인딩</h3>
<p>앵귤러나 뷰에서 사용하는 MVC패턴은 Model에 데이터를 정의해 두고, Controller를 이용해 Model 데이터를 생성 / 조회 / 수정 / 삭제(CRUD)하고, 변경된 데이터를 View에 출력되면서 사용자에게 전달하는 방식이다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/9acfbef2-4d0e-4e69-89f3-756b6f498958/image.png" alt="">
하지만 위 패턴을 이용하게 되면, 양방향 데이터 바인딩으로 Application의 규모가 커질수록 데이터의 흐름이 점점 복잡해지게 된다. 또한 MVC 패턴은 데이터의 변경 사항을 신속하게 전파하기가 어렵다.
<img src="https://velog.velcdn.com/images/isabel_noh/post/cc0a8444-b837-4dec-b4de-69a880e10362/image.png" alt=""></p>
<p>하지만 리액트의 경우, FLUX구조의 단방향 데이터 바인딩 흐름을 이용한다. Action-Dispatcher-Store-View의 구조로 데이터가 흐름으로써 양방향 데이터 바인딩의 문제를 해결할 수 있다. 
<img src="https://velog.velcdn.com/images/isabel_noh/post/4f85ed70-380d-4ecb-acdb-ea5a43a9dfb7/image.png" alt="">
여기 store은 MVC의 model과 비슷하지만, 여러 데이터 객체들을 저장할 수 있다. 단방향 데이터 바인딩의 경우, 데이터가 한 방향으로 흐르기 때문에 디버깅이 용이하고 예측 가능성이 높아 코드가 더 안정적이다.</p>
<h3 id="컴포넌트-단위-작성">컴포넌트 단위 작성</h3>
<p>리액트에서는 화면을 Component단위로 나눠 독립적으로 관리할 수 있다. 버튼이면 버튼, 인풋이면 인풋 각각 나눠서 관리하기 때문에, 나중에 같은 기능이 다른 페이지에서 필요할 경우 가져다 사용하기만 하면 되어서, 재사용성이 높다. 또한 컴포넌트 별로 구성하기 때문에 가독성이 매우 높고 간단하여 유지보수하기가 쉽다. </p>
<h3 id="view에-집중">View에 집중</h3>
<p>다른 프레임워크들과 달리 React는 MVC(Model-View-Controller)패턴으로 구성되어 있지 않고 View만 제공한다. MVC패턴에 메일 필요없이 다른 필요한 부분들이 있다면 별도 기능을 제공하는 라이브러리를 같이 사용하면 된다. </p>
<h4 id="오픈소스-프로젝트">오픈소스 프로젝트</h4>
<p>누구나 코드를 볼 수 있고 수정 또는 새로운 기능을 제안할 수 있다. </p>
<h4 id="큰-생태계">큰 생태계</h4>
<p>페이스북의 지원으로 계속적으로 신 기능이 나오고, 유지보수가 원활히 시행된다. </p>
<hr>
<h3 id="단점">단점</h3>
<h4 id="view에-집중-1">VIEW에 집중</h4>
<p>뷰에 집중하기 때문에 자질구레한 기능들이 없어 간단하지만, 반대로 없는 기능들이 많아 VIEW 이외의 기능은 써드파티 라이브러리(Third party library)를 이용하거나 직접 구현해야한다는 단점이 있다. </p>
<h4 id="ie8이하는-지원하지-않음">IE8이하는 지원하지 않음</h4>
<p>하지만 이제 IE 자체가 지원 종료되어 이 부분은 걱정을 하지 않아도 될 것이다. </p>
<p><a href="https://velog.io/@dea8307/React%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0">참고 블로그</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 반려식물 재배 도우미 서비스 '초록']]></title>
            <link>https://velog.io/@isabel_noh/React-%EB%B0%98%EB%A0%A4%EC%8B%9D%EB%AC%BC-%EC%9E%AC%EB%B0%B0-%EB%8F%84%EC%9A%B0%EB%AF%B8-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%B4%88%EB%A1%9D</link>
            <guid>https://velog.io/@isabel_noh/React-%EB%B0%98%EB%A0%A4%EC%8B%9D%EB%AC%BC-%EC%9E%AC%EB%B0%B0-%EB%8F%84%EC%9A%B0%EB%AF%B8-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%B4%88%EB%A1%9D</guid>
            <pubDate>Sun, 05 Jun 2022 19:17:24 GMT</pubDate>
            <description><![CDATA[<h1 id="반려식물-재배-도우미-서비스-초록">반려식물 재배 도우미 서비스 &#39;초록&#39;</h1>
<p>6주간의 프로젝트가 드디어 끝이 났다. 
말이 6주지 실질적으로는 4주반? 5주에 가까웠던 것 같다.<br>일단 어마어마한 뷰의 양에 기가 눌린 채로 시작했지만 어찌어찌 완성을 하게 되었다. 여러모로 부족했던 나로서는 팀원들에게 많이 배우면서 작업을 진행해 나갔던 것 같다. 끝나고 나서보니 성능적으로 부족한 것이 많아 보인다. 차차 포트폴리오 및 이력서 작업을 하면서 성능적으로 어떻게 하면 개선할 수 있을까 고민해보려고 한다. (이미지 down-sizing, 데이터 구조 변경 등 )</p>
<blockquote>
<p><a href="https://chorok.kr"><strong>CHOROK 초록</strong></a>
: _Chorok은 식물 집사들을 위한 일정관리 및 커뮤니티 서비스_입니다.
나만의 식물을 등록하고, 매일매일 내 식물만을 위한 작업일정을 관리해보세요!</p>
</blockquote>
<p><a href="https://youtu.be/CjtoA3dOzfQ">발표자료 영상</a></p>
<p><img src="https://velog.velcdn.com/images/isabel_noh/post/7d8ff15e-4831-4dad-b223-754f1b8331e7/image.png" alt=""></p>
<h3 id="주요-기능">주요 기능</h3>
<ul>
<li><strong>일정관리</strong><ul>
<li>내 식물별 투두 생성</li>
<li>캘린더 탭을 통한 기록 일람</li>
</ul>
</li>
<li><strong>식물도감</strong><ul>
<li>식물 타입별 필터링</li>
<li>원하는 키워드로 식물 검색</li>
</ul>
</li>
<li><strong>식물 추천</strong><ul>
<li>레이블링 테스트를 통한 
사용자 니즈에 알맞는 식물 추천</li>
</ul>
</li>
<li><strong>커뮤니티</strong><ul>
<li>플랜테리어 공유 / 질문 등</li>
</ul>
</li>
</ul>
<h3 id="내가-담당했던-부분">내가 담당했던 부분</h3>
<ul>
<li><p>회원가입 및 이메일 인증, 로그인 (소셜 로그인 포함 ), 비밀번호 재설정 등 각종 회원 관련 뷰 및 기능 구현 </p>
</li>
<li><p>초록톡 페이지 게시글 CRUD와 댓글 CRUD</p>
<ul>
<li>+) 필터를 통한 게시글 분류</li>
</ul>
</li>
<li><p>사용자 맞춤 식물 추천</p>
</li>
<li><p>마이페이지 조회</p>
<ul>
<li>나의 사진, 스크랩한 사진 조회</li>
<li>나의 식물 조회 및 수정, 스크랩한 식물 조회</li>
<li>나의 글, 스크랩한 글 등 조회</li>
</ul>
</li>
<li><p>Progressive Web Application 적용</p>
</li>
</ul>
<hr>
<p>CRUD를 중심적으로 다루면서 데이터를 백으로부터 받아올 때의 흐름을 이해하는 데에 도움이 되었다. 전에는 좀 더 vague하게 알았던 전역 상태 관리의 부분에 대해서도 더 자세히 알게 되었다. 
하지만 새로운 기술보다는 CRUD를 많이 다룬 것이 조금 아쉽기는 하다. </p>
<p>다른 팀의 사람들과 이야기를 더 나누어 보니 아직 성능적으로 부족한 부분들이 많은 것 같았다. 추후에 취업 준비를 하면서 더욱 효율적이고 사용자가 이용했을 때 편리할 서비스로 수정과 보완을 해나갈 예정이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CSS] reset CSS]]></title>
            <link>https://velog.io/@isabel_noh/CSS-reset-CSS</link>
            <guid>https://velog.io/@isabel_noh/CSS-reset-CSS</guid>
            <pubDate>Sun, 05 Jun 2022 10:30:19 GMT</pubDate>
            <description><![CDATA[<p> 웹브라우저에 따라 디폴트 스타일이 상이하고 지원하는 tag나 style도 제각각이기 때문에 개발자의 의도와 다르게 나타날 수 있다. 그렇기 때문에 사전에 CSS를 초기화 해주는 작업을 해줄 수 있는데, 이를 reset CSS라고 한다. </p>
<p> 아래 예시는 <code>Eric Meyer’s reset css</code>라고 하는 reset CSS 방법이다. </p>
<pre><code class="language-css">/* http://meyerweb.com/eric/tools/css/reset/
  v2.0 | 20110126
  License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
  display: block;
}
body {
  line-height: 1;
}
ol, ul {
  list-style: none;
}
blockquote, q {
  quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
  content: &#39;&#39;;
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}</code></pre>
<p>reset CSS를 해주고 나면 브라우저에서 다른 설정값 없이 내가 원하는 방향으로 CSS를 조정하기가 용이해질 것이다. </p>
]]></description>
        </item>
    </channel>
</rss>