<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mini.log</title>
        <link>https://velog.io/</link>
        <description>백엔드 개발을 좋아하고 공부하고 있습니다. 코드 작성 뿐만 아니라 쿼리 성능 고려, 클린 코드, 테스트 케이스 작성에 주력해 모든 에러 상황을 대비하는 개발자로 성장하고 싶습니다.</description>
        <lastBuildDate>Fri, 03 Apr 2026 14:54:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mini.log</title>
            <url>https://velog.velcdn.com/images/mini_log/profile/e26c3952-eb91-4023-aa39-fa3b60bd1379/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mini.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mini_log" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[면접왕 이형 [체인지업] 2026 3-4월 후기]]></title>
            <link>https://velog.io/@mini_log/%EB%A9%B4%EC%A0%91%EC%99%95-%EC%9D%B4%ED%98%95-%EC%B2%B4%EC%9D%B8%EC%A7%80%EC%97%85-2026-3-4%EC%9B%94-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@mini_log/%EB%A9%B4%EC%A0%91%EC%99%95-%EC%9D%B4%ED%98%95-%EC%B2%B4%EC%9D%B8%EC%A7%80%EC%97%85-2026-3-4%EC%9B%94-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 03 Apr 2026 14:54:27 GMT</pubDate>
            <description><![CDATA[<p>작년 상반기에 체인지업 1<del>2, 3</del>4시즌을 진행하고 취업해 이번에는 중고신입으로 이직하기 위해 참여했다.
면접왕 이형님은 대학교시절부터 몇년동안 시청했던 사람으로써 취준생에게 적은 가격으로 많은 도움을 주시는 분 같다!</p>
<p>체인지업에 대해 설명을 하자면</p>
<ol>
<li>매주 과제</li>
<li>공식 세션과 보너스 세션</li>
<li>매일 루틴</li>
<li>스터디</li>
</ol>
<p>이러한 것들을 통해 취준을 어떻게 하는지 정확하게 체험하고 알 수 있다.</p>
<h3 id="1-과제">1. 과제</h3>
<p>과제는 자소서분반, 면접분반에 맞춰 진행되며 차례대로 경험 리스트업, 3C4P, 자기소개 작성, 지원동기 작성 이런식으로 차근차근 진행된다.
과제라는 강제성이 있었기 때문에 억지로라도 하면서 자소서를 완성할 수 있었던 것 같다.</p>
<h3 id="2-공식-세션과-보너스-세션">2. 공식 세션과 보너스 세션</h3>
<p>세션에는 이형님도 오시고, 다른 엄청난 분들도 오셔서 강의해주기 때문에 무조건 꼬박꼬박 듣는 게 좋다!
또한, 요번에는 따로 기업 맞춤 자소서 문항 분석 세션이 있어 도움이 많이 되었다.
한화시스템을 작성할 때, 새로운 문항으로 시간이 많이 걸릴 뻔했는데 분석과 작성 방법을 알려주셔서 금방 작성할 수 있었다!</p>
<h3 id="3-매일-루틴">3. 매일 루틴</h3>
<p>루틴으로는 아침 8시 기상, 경제신문스크랩, 1일1형, 1일1지원, 운동이 있다.
스터디원들과 매일 루틴을 인증하고 인증하지 못할 시, 벌금이 있어 꾸준히 참여할 수 있었다.
그리고 체인지업에서는 항상 완벽주의말고 완성주의가 되라고 한다.
4월에도 스터디원들과 꾸준히 루틴을 적용할 예정이다.</p>
<p><img src="https://velog.velcdn.com/images/mini_log/post/fb3d1b21-0115-45be-9ae3-75af0347720d/image.png" alt=""></p>
<h3 id="4-스터디">4. 스터디</h3>
<p>마지막으로 제일 도움을 많이 받은 스터디다.
체인지업은 온라인이기 때문에 아무리 과제가 있어도 안하면 그만이다.
그래서 스터디를 해서 강제성을 부여한 것이 제일 좋았던 것 같다.
평일에는 3C4P, 자소서 기반 피드백을 진행하였고 주말에는 면접 스터디를 진행했다.
확실히 서로서로의 것들을 보면서 많이 피드백을 하니까 완성도가 조금 더 높아지고, 어떻게 3C4P를 써야하는지도 알게 된다!</p>
<h3 id="결론">결론</h3>
<p>직장을 병행하다 보니 작년 풀취준보다는 확실히 절대적인 시간이 부족한 것 같다.
중고신입 트랙은 3지원이지만, 4월에는 더 많이 지원해야겠다. 
체인지업을 진행하니 이직준비에 대한 루틴이 잡혀 이직 성공까지 계속 참여할 예정이다.
혼자한다고 시간을 낭비하기 보다는 체인지업을 통해 적은 비용으로 빠른 취준을 하고 취뽀를 하길 바란다!</p>
<p>다들 취뽀합시다 ㅎㅎ 화이팅!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 1. 누적합(Prefix Sum) 알고리즘]]></title>
            <link>https://velog.io/@mini_log/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-1.-%EB%88%84%EC%A0%81%ED%95%A9Prefix-Sum-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@mini_log/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-1.-%EB%88%84%EC%A0%81%ED%95%A9Prefix-Sum-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Wed, 04 Dec 2024 14:41:37 GMT</pubDate>
            <description><![CDATA[<h2 id="🐤-서론">🐤 서론</h2>
<p>엄청 오랜만에 블로그를 쓰는 것 같다.
이렇게 글로 쓰는 것도 오랜만이지만, 공부의 흔적을 남기고 제대로 더 열심히 취준하기 위해서 습관을 들여야할 것 같다!
오늘부터 SSAFY가 거의 끝나고 알고리즘 공부를 빡세게 해야할거 같아서 시작했다.
인프런에 있는 강의인 큰돌님의 10주완성 C++ 코딩테스트의 커리큘럼을 혼자 따라갈 예정이다.
C++이고 가격이 조금 나가서 구매하지는 않았지만 백준 문제집에 문제들은 있어서 이거 보고 따라가기로 했다!
이 강의는 160문제를 추천해주는데 문제 자체가 많아서 좋은 것같다.
그치만, 백준 문제집에 1~2주 이렇게 묶여 있어서 알고리즘마다 찾기 쫌 힘들다..ㅠㅠ
그래서 기본적인 알고리즘 문제는 구글링해서 찾아서 풀면서 개념 익히고, 추가로 큰돌님 문제집을 풀려고 한다.</p>
<p><img src="https://velog.velcdn.com/images/mini_log/post/70823647-a133-4cde-b305-0fffe3457087/image.png" alt=""></p>
<p>&lt; 큰돌님 커리큘럼은 이러하다 &gt;
<img src="https://velog.velcdn.com/images/mini_log/post/d4dc8ba4-36d5-4420-8310-f2cbe25534e7/image.png" alt=""></p>
<p>내가 C++로 준비를 했으면 결제를 했을듯 하다!
혹시 C++로 준비를 하는 사람이라면 고민해보길 바란다.
<a href="https://www.inflearn.com/course/10%EC%A3%BC%EC%99%84%EC%84%B1-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%81%B0%EB%8F%8C">https://www.inflearn.com/course/10%EC%A3%BC%EC%99%84%EC%84%B1-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%81%B0%EB%8F%8C</a></p>
<h2 id="🐤-누적합-개념">🐤 누적합 개념</h2>
<h3 id="🍡-누적합-언제-배웠지">🍡 누적합 언제 배웠지??</h3>
<p>SSAFY에서는 1학기에 알고리즘 개념을 전체적으로 다 배운다.
근데 누적합이라는 개념은 들어본 적이 없는듯했다... 그래서 어려운 알고리즘 개념인가 생각하였다..ㅎㅎ</p>
<p>구글링을 하면서 누적합이 뭔지 찾아보았는데 내가 아는 개념이였다..!!
바로 DP에서 1개의 배열로 계속 더해가면서 계산하는 방식이였다. 이 방식을 단순한 DP 문제를 풀때 엄청 많이 적용한 개념이였다.</p>
<p>1번째 커리큘럼이 누적합이기도 하고, 이번에 제대로 개념을 알고 넘어가고자 한다!</p>
<h3 id="🍡-누적합-개념-설명">🍡 누적합 개념 설명</h3>
<p>누적합(Prefix Sum) 알고리즘은 데이터를 효율적으로 처리하기 위해 배열이나 리스트에서 특정 구간의 합을 빠르게 계산하는데 사용되는 알고리즘이다.
이 알고리즘을 통해서 반복 계산의 필요성을 줄이고 성능을 최적화할 수 있다.
또한, 누적합을 통해서 부분합이라는 개념이 나올 수 있다.
부분합은 해당 부분의 합을 구하고 싶을 때, 구한 누적합을 통해서 연산 한번만으로 구할 수 있는 로직이다.
단순한 알고리즘이라서 개념은 이쯤에서 넘어가도 될것 같다. 
그리고 사실 나는 이렇게 글로 이해하는 것보다 예제를 보는데 더 이해가 빠른 것 같아서 예제로 바로 넘어가보자!</p>
<h3 id="🍡-누적합의-시간복잡도-공간복잡도">🍡 누적합의 시간복잡도, 공간복잡도</h3>
<p>먼저 1차원과 2차원인 경우를 나눠서 생각해보자!</p>
<h4 id="🎀-1차원-누적합의-문제인-경우">🎀 1차원 누적합의 문제인 경우</h4>
<p>시간복잡도의 경우에는 N개가 들어있는 배열을 한번 순회하니까, O(N)이 된다.
공간복잡도의 경우에도, N의 배열만 사용되기 때문에 O(N)이다.</p>
<h4 id="🎀-2차원-누적합의-문제인-경우">🎀 2차원 누적합의 문제인 경우</h4>
<p>1차원의 경우와는 달리 배열의 크기가 N^2이기 때문에 이것도 한번 순회하므로 , O(N^2)이 된다.
공간복잡도도 동일하게, 2차원 배열만 그대로 사용되기 때문에 O(N^2)이다.</p>
<blockquote>
<p>시간복잡도별 실행시간에 따른 n의 크기이다.<img src="https://velog.velcdn.com/images/mini_log/post/6a78ca3d-8b21-4446-8f64-6a4245cd5461/image.png" alt="">
따라서, 1차원의 경우에는 N이 10,000,000까지 가능하고, 2차원은 N이 5000까지일때 누적합을 사용할 수 있다.
항상 문제의 알고리즘을 적용할 때 시간복잡도를 보는 습관을 가져야 한다!!</p>
</blockquote>
<h2 id="🐤-누적합-예제">🐤 누적합 예제</h2>
<h3 id="🍡-누적합-예제-1--수열2559">🍡 누적합 예제 1 ) 수열(2559)</h3>
<p><a href="https://www.acmicpc.net/problem/2559">https://www.acmicpc.net/problem/2559</a>
먼저, 백준의 기본 누적합 문제인 수열(2559)에 대해 풀어보자.</p>
<p>이 문제의 시간복잡도를 먼저 살펴보자!
여기서 N은 2이상 100,000 이하이므로 천만보다 작기 때문에 누적합으로 풀이가 가능하다!</p>
<p>그리고 이 문제는 연속적인 며칠 동안 온도의 합이 가장 큰 값을 구하는 것이므로, 누적합을 통해서 최종적으로 부분합을 구하는 문제이다.</p>
<p>문제의 예시를 통해 정확히 풀어보자!</p>
<ol>
<li><p>10일간의 온도가 주어졌다.
<img src="https://velog.velcdn.com/images/mini_log/post/281b192e-2b73-4aa9-98cb-98d4b7c98b7a/image.png" alt=""></p>
</li>
<li><p>부분의 합을 알기 위해 누적합을 구해보자
2-1. 이전의 누적합에서 자신을 더한것을 해당 배열에 저장한다.
1번째 값이 3이고 2번째 값이 -2이기때문에 3+(-2) = 1로 배열에 저장한다.
이런식으로 배열을 반복하면서 해당 배열의 누적합을 저장한다!
<img src="https://velog.velcdn.com/images/mini_log/post/8eeef7a1-0cdf-4497-b53e-42da081437f9/image.png" alt=""><img src="https://velog.velcdn.com/images/mini_log/post/cd11a6e2-3995-4eb5-85fc-7493491e7815/image.png" alt=""><img src="https://velog.velcdn.com/images/mini_log/post/df3046c2-a151-4bd6-b1ef-9594cfb7e7c9/image.png" alt=""></p>
</li>
</ol>
<blockquote>
<p>여기서 코드로 구현시, 중요한 점이 있다.
1번째 인덱스의 값을 배열 0에서부터 시작할 경우, 0번은 -1이 없기 때문에 추가적인 조건문을 써야한다.
이러한 것을 줄이기 위해, 임의적으로 0번의 인덱스에는 0을 넣고, 1번부터 시작해서 arr[N+1] 배열을 만들자!!</p>
</blockquote>
<h4 id="🎀-1차원-누적합-구현-코드">🎀 1차원 누적합 구현 코드</h4>
<p>밑의 코드와 같이 배열의 크기를 N+1만큼하고, 반복문을 통해 arr[i]에 자신의 값과 i-1까지의 누적합을 더해서 저장한다.</p>
<pre><code class="language-java">int[] arr = new int[N+1];

st = new StringTokenizer(br.readLine());
for(int i=1;i&lt;=N;i++){
  arr[i] = Integer.parseInt(st.nextToken()) + arr[i-1];
}</code></pre>
<ol start="3">
<li>이제 누적합을 모두 구했다면, 진짜 답인 부분합을 구해야 한다.
이 예시에서 해당 부분의 크기는 K라는 것으로 정해져 있고 우리는 K가 2라고 가정해보자.</li>
</ol>
<p>3-1. 부분합을 구하려면, (부분의 마지막 인덱스의 누적합) - (부분의 마지막 인덱스 - K의 누적합) 이렇게 구현하면 해당 부분의 합이 도출된다.
<img src="https://velog.velcdn.com/images/mini_log/post/8b401665-8a31-4eb5-9587-2e8be68e8bc9/image.png" alt=""></p>
<h4 id="🎀-1차원-부분합-구현-코드">🎀 1차원 부분합 구현 코드</h4>
<p>for문을 사용해 K~N까지 돌리면서, 누적합 배열인 arr로 (arr[i] - arr[i-K]) 의 최대값을 찾는다.
K부터 시작하는 이유는 1부터 K까지는 앞에 뺄 값이 없기 때문에 누적합 그대로이기도 하고, -K를 할때 인덱스가 0보다 작아질 경우를 대비해서이다.</p>
<pre><code class="language-java">answer = arr[K];
for(int i=K;i&lt;=N;i++){
   answer =  Math.max(answer,arr[i]-arr[i-K]);
}</code></pre>
<h4 id="🎀-전체-코드">🎀 전체 코드</h4>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Bj_2559_수열 {
    public static void main(String[] args) throws IOException{
        BufferedReader br  =new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int K = Integer.parseInt(st.nextToken());
        int answer =0;
        int[] arr = new int[N+1];

        st = new StringTokenizer(br.readLine());
        for(int i=1;i&lt;=N;i++){
            arr[i] = Integer.parseInt(st.nextToken()) + arr[i-1];
        }

        answer = arr[K];
        for(int i=K;i&lt;=N;i++){
            answer =  Math.max(answer,arr[i]-arr[i-K]);
        }

        System.out.println(answer);
    }
}
</code></pre>
<h4 id="🎀-회고">🎀 회고</h4>
<p>이렇게 부분합의 1차원배열 기본 문제를 풀어보았다.
백준 Java8기준 19등으로 1페이지안에 들어서 기분이 좋았다 ㅎㅎ
<img src="https://velog.velcdn.com/images/mini_log/post/0873bfb0-facd-45da-b5a5-41c03f04eed5/image.png" alt=""></p>
<h3 id="🍡-누적합-예제-2--구간-합-구하기-411659">🍡 누적합 예제 2 ) 구간 합 구하기 4(11659)</h3>
<p><a href="https://www.acmicpc.net/problem/11659">https://www.acmicpc.net/problem/11659</a>
이 문제는 위의 수열 문제와 푸는 방법은 동일한데, 부분합에서 구해야하는 부분을 입력받기 때문에 이 점만 다르다고할 수 있다.</p>
<ol>
<li>일단 중요한것 첫번째 문제를 풀기 전에 시간복잡도를 먼저 보자</li>
</ol>
<ul>
<li>N이 10만이고, 시간 제한은 1초이므로 누적합 O(N)의 N은 천만까지이므로 풀이가 가능하다.
<img src="https://velog.velcdn.com/images/mini_log/post/99fec4e4-c8ce-4e7f-a3e2-b2d6f6287192/image.png" alt=""></li>
</ul>
<ol start="2">
<li>위의 문제와 동일하게 누적합을 먼저 구하자</li>
</ol>
<ul>
<li><p>예제 입력 1의 예시
<img src="https://velog.velcdn.com/images/mini_log/post/51be76f9-045f-4b6e-9dab-1d64f582ee40/image.png" alt=""></p>
</li>
<li><p>누적합을 구하면 이렇게 배열이 완성된다.
<img src="https://velog.velcdn.com/images/mini_log/post/e9a664bc-a580-41fd-8834-88497153293d/image.png" alt=""></p>
</li>
</ul>
<h4 id="🎀-1차원-누적합-구현-코드-1">🎀 1차원 누적합 구현 코드</h4>
<pre><code class="language-java">int[] arr = new int[N+1];

st = new StringTokenizer(br.readLine());
for(int i=1;i&lt;=N;i++) {
    arr[i] = Integer.parseInt(st.nextToken()) + arr[i-1];
}</code></pre>
<ol start="3">
<li>이제 입력 값들에 따라 부분합을 구해보자</li>
</ol>
<ul>
<li>공식으로는 <strong>arr[j] - arr[i-1]</strong> 를 해주면 된다.
3-1. 1번째 구간은 i=1 ~ j=3
<img src="https://velog.velcdn.com/images/mini_log/post/bb1224ec-230a-47ba-8d1e-c8e430dbec1b/image.png" alt="">
3-2. 2번째 구간은 i=2 ~ j=4
<img src="https://velog.velcdn.com/images/mini_log/post/6ab20f29-3b52-47ff-85f7-8f5de3e91d2d/image.png" alt="">
3-3. 3번째 구간은 i=5 ~ j=5
<img src="https://velog.velcdn.com/images/mini_log/post/bcdae1f5-d980-4db0-884b-3de477767764/image.png" alt=""></li>
</ul>
<h4 id="🎀-1차원-부분합-구현-코드-1">🎀 1차원 부분합 구현 코드</h4>
<pre><code class="language-java">for(int i=0;i&lt;M;i++){
   st = new StringTokenizer(br.readLine());
   int start = Integer.parseInt(st.nextToken());
   int end = Integer.parseInt(st.nextToken());
   sb.append(arr[end]-arr[start-1]).append(&quot;\n&quot;);
}</code></pre>
<h4 id="🎀-전체-코드-1">🎀 전체 코드</h4>
<pre><code class="language-java">import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Bj_11659_구간합구하기4 {
    public static void main(String[] args)throws Exception{
        BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuilder sb = new StringBuilder();

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        int[] arr = new int[N+1];

        st = new StringTokenizer(br.readLine());
        for(int i=1;i&lt;=N;i++) {
            arr[i] = Integer.parseInt(st.nextToken()) + arr[i-1];
        }

        for(int i=0;i&lt;M;i++){
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int end = Integer.parseInt(st.nextToken());
            sb.append(arr[end]-arr[start-1]).append(&quot;\n&quot;);
        }
        System.out.println(sb.toString());
    }
}</code></pre>
<h4 id="🎀-회고-1">🎀 회고</h4>
<p>이렇게 부분합의 1차원배열 문제를 풀어보았다.
이제 조금 부분합에 대해서 알 것 같다!
백준 Java8기준 27등을 했다.
<img src="https://velog.velcdn.com/images/mini_log/post/6e6dd94a-9f59-4f81-8c00-5d994b27f408/image.png" alt=""></p>
<h3 id="🍡-누적합-예제-3--구간-합-구하기-511660">🍡 누적합 예제 3 ) 구간 합 구하기 5(11660)</h3>
<p><a href="https://www.acmicpc.net/problem/11660">https://www.acmicpc.net/problem/11660</a>
이 문제는 2차원 누적합 문제이다.
2차원이기 때문에, 시간복잡도에 대해서 꼭 확인해봐야 한다!</p>
<ol>
<li><p>시간복잡도 체크
NxN 배열이라서 시간복잡도가 O(N^2)이고 1초에 5000까지 가능하다.
이 문제에서는 N이 1024까지이므로 누적합으로 푸는 것이 가능하다!
<img src="https://velog.velcdn.com/images/mini_log/post/fe48d6b8-2bcd-4d12-aeaf-b2fbd0d1ecf0/image.png" alt=""></p>
</li>
<li><p>시간복잡도를 확인했으면 2차원 누적합을 구해보자</p>
</li>
</ol>
<ul>
<li><p>문제의 예시처럼 N=4인 경우
<img src="https://velog.velcdn.com/images/mini_log/post/6c9fcdf9-04ee-4cb7-a3bb-c9257bef3ef0/image.png" alt=""></p>
</li>
<li><p>2차 for문으로 (1,1)부터 해당 값인 (i,j)까지의 누적합을 저장한다.
2차원 누적합을 구할 때는,1차원 누적합 배열과는 달리 겹치는 부분이 생기기 때문에 이걸로 고려해서 겹치는 부분은 빼고 계산해야한다!
<img src="https://velog.velcdn.com/images/mini_log/post/ce0d3951-b5ad-49ff-9518-fecc8f51c400/image.png" alt=""></p>
<blockquote>
<p>공식 : <strong>arr[i-1][j]+arr[i][j-1] - arr[i-1][j-1]) + arr[i][j]</strong>
여기서 arr[i-1][j-1] 이부분이 바로 겹치는 부분이다!</p>
</blockquote>
</li>
</ul>
<h4 id="🎀-2차원-누적합-구현-코드">🎀 2차원 누적합 구현 코드</h4>
<p>2차원 누적합도 동일하게 조건문이 추가되지 않기 위해 배열을 [N+1][N+1]로 잡아서 i-1이나 j-1을 했을때 오류를 막을 수 있다.</p>
<pre><code class="language-java">arr =new int[N+1][N+1];

for(int i=1;i&lt;=N;i++){
   st = new StringTokenizer(br.readLine());
   for(int j=1;j&lt;=N;j++){
       arr[i][j] = Integer.parseInt(st.nextToken())+(arr[i-1][j] + arr[i][j-1] -arr[i-1][j-1]);
  }
}</code></pre>
<ol start="3">
<li>이제 정답인 입력값들에 대한 2차원의 부분합을 구해보자</li>
</ol>
<ul>
<li>입력 값을 x1,y1,x2,y2라고 한다면 arr[x2][y2]의 누적합에서 빼야하는 부분인 arr[x2][y1-1]과 arr[x1-1][y2]를 빼주고 중복으로 들어간 값인 arr[x1-1][y1-1]을 한번 더해주면 된다.</li>
</ul>
<blockquote>
<p>공식 :  <strong>arr[x2][y2] - arr[x2][y1-1] - arr[x1-1][y2] + arr[x1-1][y1-1]</strong> </p>
</blockquote>
<p>3-1. 1번째 구간은 (2,2) ~ (3,4)
3-2. 2번째 구간은 (3,4) ~ (3,4)
3-3. 3번째 구간은 (1,1) ~ (4,4)
<img src="https://velog.velcdn.com/images/mini_log/post/6e324b68-6401-447a-89b0-be9743dc260f/image.png" alt=""></p>
<h4 id="🎀-2차원-부분합-구현-코드">🎀 2차원 부분합 구현 코드</h4>
<pre><code class="language-java">for(int i=0;i&lt;M;i++){
   st = new StringTokenizer(br.readLine());
   int x1 = Integer.parseInt(st.nextToken());
   int y1 = Integer.parseInt(st.nextToken());
   int x2 = Integer.parseInt(st.nextToken());
   int y2 = Integer.parseInt(st.nextToken());
   calculate(x1,y1,x2,y2);
}

static void calculate(int x1,int y1,int x2, int y2){
    int result = arr[x2][y2]-arr[x2][y1-1]-arr[x1-1][y2]+arr[x1-1][y1-1];
}</code></pre>
<h4 id="🎀-전체-코드-2">🎀 전체 코드</h4>
<pre><code class="language-java">import java.util.*;
import java.io.*;
public class Bj_11660_구간합구하기5 {
    static int N,M;
    static StringBuilder sb = new StringBuilder();
    static int[][] arr;
    public static void main(String[] args) throws Exception{
        BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st  =new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        arr =new int[N+1][N+1];

        for(int i=1;i&lt;=N;i++){
            st = new StringTokenizer(br.readLine());
            for(int j=1;j&lt;=N;j++){
                arr[i][j] = Integer.parseInt(st.nextToken())+(arr[i-1][j] + arr[i][j-1] -arr[i-1][j-1]);
            }
        }

        for(int i=0;i&lt;M;i++){
            st = new StringTokenizer(br.readLine());
            int x1 = Integer.parseInt(st.nextToken());
            int y1 = Integer.parseInt(st.nextToken());
            int x2 = Integer.parseInt(st.nextToken());
            int y2 = Integer.parseInt(st.nextToken());
            calculate(x1,y1,x2,y2);
        }
        System.out.println(sb);
    }
    static void calculate(int x1,int y1,int x2, int y2){
        int result = arr[x2][y2]-arr[x2][y1-1]-arr[x1-1][y2]+arr[x1-1][y1-1];
        sb.append(result).append(&quot;\n&quot;);
    }
}
</code></pre>
<h4 id="🎀-회고-2">🎀 회고</h4>
<p>2차원의 누적합과 부분합에 대해서 이해가 완료된것 같다.
더 심화된 누적합 문제를 찾아서 풀어보면 좋을 것 같다!!!</p>
<h2 id="🐤-마무리">🐤 마무리</h2>
<p>이렇게 누적합의 개념을 공부하고 3개의 문제를 풀어 봤는데 문제를 풀고 복습의 느낌으로 블로그를 정리하면 훨씬 기억에 더 잘남는것 같다!!
앞으로도 알고리즘 개념을 먼저 공부하고, 여러개의 문제를 풀고 블로그에 정리하면서 복습하는 형식으로 하면 좋을 것같다.</p>
<p>취준이 힘들긴 하겠지만, 열심히 하면 그만큼 성과가 따를것이라고 확신한다!!
그러니까 매일 내일만 보고 열심히 그냥 하자!</p>
<p>다음 블로그는 누적합의 확장인 IMOS로 돌아오겠습니다~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 6장 Express 웹 서버 구현  [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-6%EC%9E%A5-Express-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@mini_log/Node.js-6%EC%9E%A5-Express-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Wed, 04 Dec 2024 11:42:43 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>6.1 시작</p>
<ul>
<li><p>npm init → package.json 생성</p>
<pre><code class="language-jsx">//package.json
{
&quot;name&quot;: &quot;learn-express&quot;,
&quot;version&quot;: &quot;0.0.1&quot;,
&quot;description&quot;: &quot;익스프레스를 배우자&quot;,
&quot;main&quot;: &quot;app.js&quot;,
&quot;scripts&quot;: {
  &quot;start&quot;: &quot;nodemon app&quot; //추가해주기! (app.js를 nodemon으로 실행, 서버 코드에 수정 사항 생길 때마다 서버 자동 재시작)
},
&quot;author&quot;: &quot;ZeroCho&quot;,
&quot;license&quot;: &quot;MIT&quot;
}</code></pre>
</li>
<li><p>express 시작</p>
<pre><code class="language-jsx">$ npm i express
$ npm i -D nodemon</code></pre>
</li>
<li><p>서버 역할 app.js</p>
<ul>
<li>GET 요청 외에도 POST, PUT, PATCH, DELETE, OPTIONS에 대한 라우터를 위한 app.post, app.put, app.patch. app.delete, app.options 메서드가 존재</li>
</ul>
<pre><code class="language-jsx">//app.js
const express=require(&#39;express&#39;);

const app=express();
app.set(&#39;port&#39;,process.env.PORT ||3000); //서버 실행될 포트 설정
//process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용

app.get(&#39;/&#39;,(req,res)=&gt;{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
  res.send(&#39;Hello, Express&#39;);  //현재 GET / 요청 시 응답으로 Hello, Express 전송
});

app.listen(app.get(&#39;port&#39;),()=&gt;{ //서버 시작!!! 꼭 해야함~~ 중요!
  console.log(app.get(&#39;port&#39;),&#39;번 포트에서 대기 중&#39;);
});</code></pre>
</li>
<li><p>서버 실행 : npm start</p>
</li>
</ul>
</li>
<li><p>6.2 자주 사용하는 미들웨어</p>
<ul>
<li><p>app.use</p>
<pre><code class="language-jsx">  //app.js
  const express=require(&#39;express&#39;);

  const app=express();
  app.set(&#39;port&#39;,process.env.PORT ||3000); //서버 실행될 포트 설정
  //process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용

  app.use((req,res,next)=&gt;{ //app.use : 미들웨어 역할, 매개변수 : req,res,next
      //next : 다음 미들웨어로 넘어가는 함수, next를 실행하지 않으면 다음 미들웨어 실행X 
      console.log(&#39;모든 요청에 다 실행됨&#39;);
      next();
  });

  app.get(&#39;/&#39;,(req,res,next)=&gt;{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
      res.send(&#39;Hello, Express&#39;);  //현재 GET / 요청 시 응답으로 Hello, Express 전송
      next();
  },(req,res)=&gt;{ //아래 미들웨어로 전달
      throw new Error(&#39;에러는 에러 처리 미들웨어로 갑니다!&#39;);
  });

  app.use((err,req,res,next)=&gt;{ //에러 처리 미들웨어 매개변수 : err,req,res,next ,모든 매개변수 사용안해도 꼭 4개여야함
      console.error(err);
      res.status(500).send(err.message); //기본값 : 200, 특별한 경우 아니면 에러 처리 미들웨어는 가장 아래 위치
  });

  app.listen(app.get(&#39;port&#39;),()=&gt;{ //서버 시작!!! 꼭 해야함~~ 중요!
      console.log(app.get(&#39;port&#39;),&#39;번 포트에서 대기 중&#39;);
  });</code></pre>
</li>
<li><p>실무 사용 패키지</p>
<pre><code class="language-jsx">  $ npm i morgan cookie-parser express-session dotenv</code></pre>
<ul>
<li><p>body-parser 패키지 설치</p>
<pre><code class="language-jsx">$ npm i body-parser</code></pre>
<pre><code class="language-jsx">//app.js
const express=require(&#39;express&#39;);
const morgan=require(&#39;morgan&#39;); //요청과 응답에 대한 정보 콘솔에 기록
const cookieParser=require(&#39;cookie-parser&#39;);
const session=require(&#39;express-session&#39;);
const dotenv=require(&#39;dotenv&#39;); //process.env 관리, .env파일 읽어서 process.env로 만든다
const path=require(&#39;path&#39;); 
const bodyParser = require(&#39;body-parser&#39;);

dotenv.config();
const app=express();
app.set(&#39;port&#39;,process.env.PORT || 3000);

app.use(morgan(&#39;dev&#39;)); //개발 환경 : dev, 배포 환경 : combined

app.use(&#39;/&#39;,express.static(path.join(__dirname,&#39;public&#39;))); //static : 정적인 파일 제공하는 라우터 역할, app.use(&#39;요청 경로&#39;, express.static(&#39;실제 경로&#39;));
//서버의 폴더 경로와 요청 경로가 다른 문제를 해결함

//body-parser: 요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어, 보통 폼 데이터나 AJAX 요청의 데이터 처리
//멀티파트(이미지,동영상,파일)데이터 처리 못함, express에서 일부 제공, 버퍼나 텍스트 요청처리하려면 따로 설치 필요
//body-parser 는 내부적으로 스트림 처리해 req.body에 추가된다!!
app.use(express.json()); //json 형식
app.use(express.urlencoded({extended:false})); //URL-encoded형식(폼 전송), extended: false 면 노드의 querystring모듈을 사용해 쿼리스트링 해석, ture면 qs모듈 사용해 쿼리 스트링 해석
app.use(bodyParser.raw());
app.use(bodyParser.text());

app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
  resave:false,
  saveUninitialized:false,
  secret:process.env.COOKIE_SECRET,
  cookie:{
      httpOnly:true,
      secure:false,
  },
  name:&#39;session-cookie&#39;,
}));

app.use((req,res,next)=&gt;{
  console.log(&#39;모든 요청에 다 실행됩니다.&#39;);
  next();
});</code></pre>
<pre><code class="language-jsx">//.env
COOKIE_SECRETo=cookiesecret</code></pre>
</li>
</ul>
</li>
<li><p>6.2.6 미들웨어 특성 활용</p>
<ul>
<li><p>미들웨어는 req, res, next를 매개변수로 갖는 함수(에러 처리 미들웨어만 예외적으로 err, req, res, next를 가집니다)로서 app.use나 app.get, app.post 등으로 장착합니다. 특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 됩니다.</p>
</li>
<li><p>미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을수도 있음</p>
<p><img src="https://velog.velcdn.com/images/mini_log/post/d05559e8-d187-433b-8e55-6cbc6f1f3eff/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>    - app.set : 익스프레스에서 전역적으로 사용, 하나의 요청 안에서만 유지되어야 하는 값을 넣기에는 부적절

        → res.local 객체 사용, 하나의 요청 안에서만 유지

    - 미들웨어 안에 미들웨어 넣는 방법 : 기존 미들웨어 기능 확장, 조건문에 따라 다른 미들웨어 처리
        - ex) 분기 처리

    ```jsx
    app.use((req, res, next) =&gt; {
      if (process.env.NODE_ENV === &#39;production&#39;) {
        morgan(&#39;combined&#39;)(req, res, next);
      } else {
        morgan(&#39;dev&#39;)(req, res, next);
      }
    });
    ```

- 6.2.7 multer
    - 이미지, 동영상  등 여러 가지 파일을 멀티파트 형식으로 업로드할 때 사용</code></pre><ul>
<li><p>6.3 Router 객체로 라우팅 분리</p>
<pre><code class="language-jsx">  //routes/index.js
  const express=require(&#39;express&#39;);

  const router=express.Router();

  //GET / 라우터
  router.get(&#39;/&#39;,(req,res)=&gt;{
      res.send(&#39;Hello,Express&#39;);
  });

  module.exports=router;</code></pre>
<pre><code class="language-jsx">  //routes/user.js
  const express=require(&#39;express&#39;);

  const router=express.Router();

  //GET /user 라우터
  router.get(&#39;/&#39;,(req,res)=&gt;{
      res.send(&#39;Hello,user&#39;);
  });

  module.exports=router;</code></pre>
<pre><code class="language-jsx">  //app.js
  const express=require(&#39;express&#39;);
  const morgan=require(&#39;morgan&#39;); //요청과 응답에 대한 정보 콘솔에 기록
  const cookieParser=require(&#39;cookie-parser&#39;);
  const session=require(&#39;express-session&#39;);
  const dotenv=require(&#39;dotenv&#39;); //process.env 관리, .env파일 읽어서 process.env로 만든다
  const path=require(&#39;path&#39;); 
  const bodyParser = require(&#39;body-parser&#39;);

  dotenv.config();
  const indexRouter = require(&#39;./routes/index&#39;);
  const userRouter = require(&#39;./routes/user&#39;);

  const app=express();
  app.set(&#39;port&#39;,process.env.PORT || 3000);

  //app.js에 연결할 때 주소가 합쳐짐
  app.use(&#39;/&#39;, indexRouter);
  app.use(&#39;/user&#39;, userRouter);

  app.use((req, res, next) =&gt; {
    res.status(404).send(&#39;Not Found&#39;);
  });

  app.listen(3000,()=&gt;{  //서버 시작!!! 꼭 해야함~~ 중요!
      console.log(&quot;서버 시작!&quot;)
  })</code></pre>
<ul>
<li><p>그 외의 라우터 기능</p>
<ul>
<li><p>next(’route’), next() : 라우터에 연결된 나머지 미들웨어들 건너뛰고 싶을 때 사용</p>
<pre><code class="language-jsx">router.get(&#39;/&#39;, (req, res, next) =&gt; {
next(&#39;route&#39;);
}, (req, res, next) =&gt; {
console.log(&#39;실행되지 않습니다&#39;);
next();
}, (req, res, next) =&gt; {
console.log(&#39;실행되지 않습니다&#39;);
next();
});
router.get(&#39;/&#39;, (req, res) =&gt; {
console.log(&#39;실행됩니다&#39;);
res.send(&#39;Hello, Express&#39;);
});</code></pre>
</li>
<li><p>라우터 주소에 정규표현식을 비롯한 특수한 패턴 사용가능!</p>
<p>→ 라우트 매개변수 패턴</p>
<pre><code class="language-jsx">router.get(&#39;/user/:id&#39;, (req, res) =&gt; {
console.log(&#39;얘만 실행됩니다.&#39;);
});
router.get(&#39;/user/like&#39;, (req, res) =&gt; {
console.log(&#39;전혀 실행되지 않습니다.&#39;);
});</code></pre>
</li>
<li><p>/users/1 이나 /users/123 등의 요청도 이 라우터가 처리</p>
</li>
<li><p>:id에 해당하는 1이나 123을 조회 가능, req,params 객체안에 들어있음</p>
</li>
<li><p>:id면 req.params.id로 , :type 이면 req.params.type으로 조회 가능!</p>
</li>
<li><p>주의 할점: 일반 라우터보다 뒤에 꼭 위치해야함!!!</p>
</li>
<li><p>주소에 쿼리스트링도 가능 : 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어있음</p>
<p>  ex) /users/123?limit=5&amp;skip=10 주소 요청</p>
<p>  → req.params와 req.query : <code>{ id: &#39;123&#39; } { limit: &#39;5&#39;, skip: &#39;10&#39; }</code></p>
</li>
<li><p>app.js에서 에러 처리 미들웨어 위에 넣어둔 미들웨는 일치하는 라우터 없을 때 404 상태 코드 응답 역할  →  익스프레스가 자체적으로 404에러 처리해주기는 하지만, 웬만하면 404응답 미들웨어와 에러 처리 미들웨어를 연결하는게 좋음!!</p>
<pre><code class="language-jsx">app.use((req, res, next) =&gt; {
res.status(404).send(&#39;Not Found&#39;);
});</code></pre>
</li>
<li><p>주소는 같지만 메서드는 다른 코드가 있을 때, 하나의 덩어리로 묶음</p>
<pre><code class="language-jsx">router.route(&#39;/abc&#39;)
.get((req, res) =&gt; {
  res.send(&#39;GET /abc&#39;);
})
.post((req, res) =&gt; {
  res.send(&#39;POST /abc&#39;);
});</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>6.4 req,res 객체 살펴보기</p>
<ul>
<li><p>req 객체</p>
<ul>
<li>req.app: req 객체를 통해 app 객체에 접근할 수 있습니다. req.app.get(&#39;port&#39;)와 같은 식으로 사용할 수 있습니다.</li>
<li>req.body: body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체입니다.</li>
<li>req.cookies: cookie-parser 미들웨어가 만드는 요청의 쿠키를 해석한 객체입니다.</li>
<li>req.ip: 요청의 ip 주소가 담겨 있습니다.</li>
<li>req.params: 라우트 매개변수에 대한 정보가 담긴 객체입니다.</li>
<li>req.query: 쿼리스트링에 대한 정보가 담긴 객체입니다.</li>
<li>req.signedCookies: 서명된 쿠키들은 req.cookies 대신 여기에 담겨 있습니다.</li>
<li>req.get(헤더 이름): 헤더의 값을 가져오고 싶을 때 사용하는 메서드입니다.</li>
</ul>
</li>
<li><p>res 객체</p>
<ul>
<li>res.app: req.app처럼 res 객체를 통해 app 객체에 접근할 수 있습니다.</li>
<li>res.cookie(키, 값, 옵션): 쿠키를 설정하는 메서드입니다.</li>
<li>res.clearCookie(키, 값, 옵션): 쿠키를 제거하는 메서드입니다.</li>
<li>res.end(): 데이터 없이 응답을 보냅니다.</li>
<li>res.json(JSON): JSON 형식의 응답을 보냅니다.</li>
<li>res.locals: 하나의 요청 안에서 미들웨어 간에 데이터를 전달하고 싶을 때 사용하는 객체입니다.</li>
<li>res.redirect(주소): 리다이렉트할 주소와 함께 응답을 보냅니다.</li>
<li>res.render(뷰, 데이터): 다음 절에서 다룰 템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드입니다.</li>
<li>res.send(데이터): 데이터와 함께 응답을 보냅니다. 데이터는 문자열일 수도, HTML일 수도, 버퍼일 수도, 객체나 배열일 수도 있습니다.</li>
<li>res.sendFile(경로): 경로에 위치한 파일을 응답합니다.</li>
<li>res.set(헤더, 값): 응답의 헤더를 설정합니다.</li>
<li>res.status(코드): 응답 시의 HTTP 상태 코드를 지정합니다.</li>
</ul>
</li>
<li><p>메서드 체이닝</p>
<pre><code class="language-jsx">res
.status(201)
.cookie(&#39;test&#39;, &#39;test&#39;)
.redirect(&#39;/admin&#39;);</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 6장 Express 웹 서버 구현 [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-6%EC%9E%A5-Express-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80-qejvq5tj</link>
            <guid>https://velog.io/@mini_log/Node.js-6%EC%9E%A5-Express-%EC%9B%B9-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80-qejvq5tj</guid>
            <pubDate>Fri, 07 Apr 2023 09:36:57 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>6.1 시작</p>
<ul>
<li><p>npm init → package.json 생성</p>
<pre><code class="language-jsx">//package.json
{
&quot;name&quot;: &quot;learn-express&quot;,
&quot;version&quot;: &quot;0.0.1&quot;,
&quot;description&quot;: &quot;익스프레스를 배우자&quot;,
&quot;main&quot;: &quot;app.js&quot;,
&quot;scripts&quot;: {
  &quot;start&quot;: &quot;nodemon app&quot; //추가해주기! (app.js를 nodemon으로 실행, 서버 코드에 수정 사항 생길 때마다 서버 자동 재시작)
},
&quot;author&quot;: &quot;ZeroCho&quot;,
&quot;license&quot;: &quot;MIT&quot;
}</code></pre>
</li>
<li><p>express 시작</p>
<pre><code class="language-jsx">$ npm i express
$ npm i -D nodemon</code></pre>
</li>
<li><p>서버 역할 app.js</p>
<ul>
<li>GET 요청 외에도 POST, PUT, PATCH, DELETE, OPTIONS에 대한 라우터를 위한 app.post, app.put, app.patch. app.delete, app.options 메서드가 존재</li>
</ul>
<pre><code class="language-jsx">//app.js
const express=require(&#39;express&#39;);

const app=express();
app.set(&#39;port&#39;,process.env.PORT ||3000); //서버 실행될 포트 설정
//process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용

app.get(&#39;/&#39;,(req,res)=&gt;{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
  res.send(&#39;Hello, Express&#39;);  //현재 GET / 요청 시 응답으로 Hello, Express 전송
});

app.listen(app.get(&#39;port&#39;),()=&gt;{ //서버 시작!!! 꼭 해야함~~ 중요!
  console.log(app.get(&#39;port&#39;),&#39;번 포트에서 대기 중&#39;);
});</code></pre>
</li>
<li><p>서버 실행 : npm start</p>
</li>
</ul>
</li>
<li><p>6.2 자주 사용하는 미들웨어</p>
<ul>
<li><p>app.use</p>
<pre><code class="language-jsx">  //app.js
  const express=require(&#39;express&#39;);

  const app=express();
  app.set(&#39;port&#39;,process.env.PORT ||3000); //서버 실행될 포트 설정
  //process.env.PORT에 속성값이 있다면 사용하고, 없다면 기본값 3000번 포트 이용

  app.use((req,res,next)=&gt;{ //app.use : 미들웨어 역할, 매개변수 : req,res,next
      //next : 다음 미들웨어로 넘어가는 함수, next를 실행하지 않으면 다음 미들웨어 실행X 
      console.log(&#39;모든 요청에 다 실행됨&#39;);
      next();
  });

  app.get(&#39;/&#39;,(req,res,next)=&gt;{ //주소에 대한 GET 요청이 올때 어떤 동작하는지, req: 요청에 관한 정보 객체, res: 응답에 관한 정보 객체
      res.send(&#39;Hello, Express&#39;);  //현재 GET / 요청 시 응답으로 Hello, Express 전송
      next();
  },(req,res)=&gt;{ //아래 미들웨어로 전달
      throw new Error(&#39;에러는 에러 처리 미들웨어로 갑니다!&#39;);
  });

  app.use((err,req,res,next)=&gt;{ //에러 처리 미들웨어 매개변수 : err,req,res,next ,모든 매개변수 사용안해도 꼭 4개여야함
      console.error(err);
      res.status(500).send(err.message); //기본값 : 200, 특별한 경우 아니면 에러 처리 미들웨어는 가장 아래 위치
  });

  app.listen(app.get(&#39;port&#39;),()=&gt;{ //서버 시작!!! 꼭 해야함~~ 중요!
      console.log(app.get(&#39;port&#39;),&#39;번 포트에서 대기 중&#39;);
  });</code></pre>
</li>
<li><p>실무 사용 패키지</p>
<pre><code class="language-jsx">  $ npm i morgan cookie-parser express-session dotenv</code></pre>
<ul>
<li><p>body-parser 패키지 설치</p>
<pre><code class="language-jsx">$ npm i body-parser</code></pre>
<pre><code class="language-jsx">//app.js
const express=require(&#39;express&#39;);
const morgan=require(&#39;morgan&#39;); //요청과 응답에 대한 정보 콘솔에 기록
const cookieParser=require(&#39;cookie-parser&#39;);
const session=require(&#39;express-session&#39;);
const dotenv=require(&#39;dotenv&#39;); //process.env 관리, .env파일 읽어서 process.env로 만든다
const path=require(&#39;path&#39;); 
const bodyParser = require(&#39;body-parser&#39;);

dotenv.config();
const app=express();
app.set(&#39;port&#39;,process.env.PORT || 3000);

app.use(morgan(&#39;dev&#39;)); //개발 환경 : dev, 배포 환경 : combined

app.use(&#39;/&#39;,express.static(path.join(__dirname,&#39;public&#39;))); //static : 정적인 파일 제공하는 라우터 역할, app.use(&#39;요청 경로&#39;, express.static(&#39;실제 경로&#39;));
//서버의 폴더 경로와 요청 경로가 다른 문제를 해결함

//body-parser: 요청의 본문에 있는 데이터를 해석해서 req.body 객체로 만들어주는 미들웨어, 보통 폼 데이터나 AJAX 요청의 데이터 처리
//멀티파트(이미지,동영상,파일)데이터 처리 못함, express에서 일부 제공, 버퍼나 텍스트 요청처리하려면 따로 설치 필요
//body-parser 는 내부적으로 스트림 처리해 req.body에 추가된다!!
app.use(express.json()); //json 형식
app.use(express.urlencoded({extended:false})); //URL-encoded형식(폼 전송), extended: false 면 노드의 querystring모듈을 사용해 쿼리스트링 해석, ture면 qs모듈 사용해 쿼리 스트링 해석
app.use(bodyParser.raw());
app.use(bodyParser.text());

app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
  resave:false,
  saveUninitialized:false,
  secret:process.env.COOKIE_SECRET,
  cookie:{
      httpOnly:true,
      secure:false,
  },
  name:&#39;session-cookie&#39;,
}));

app.use((req,res,next)=&gt;{
  console.log(&#39;모든 요청에 다 실행됩니다.&#39;);
  next();
});</code></pre>
<pre><code class="language-jsx">//.env
COOKIE_SECRETo=cookiesecret</code></pre>
</li>
</ul>
</li>
<li><p>6.2.6 미들웨어 특성 활용</p>
<ul>
<li><p>미들웨어는 req, res, next를 매개변수로 갖는 함수(에러 처리 미들웨어만 예외적으로 err, req, res, next를 가집니다)로서 app.use나 app.get, app.post 등으로 장착합니다. 특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 됩니다.</p>
</li>
<li><p>미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을수도 있음</p>
<p><img src="https://velog.velcdn.com/images/mini_log/post/637b47cf-4c70-46bd-9da6-84db66224e2e/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>    - app.set : 익스프레스에서 전역적으로 사용, 하나의 요청 안에서만 유지되어야 하는 값을 넣기에는 부적절

        → res.local 객체 사용, 하나의 요청 안에서만 유지

    - 미들웨어 안에 미들웨어 넣는 방법 : 기존 미들웨어 기능 확장, 조건문에 따라 다른 미들웨어 처리
        - ex) 분기 처리

    ```jsx
    app.use((req, res, next) =&gt; {
      if (process.env.NODE_ENV === &#39;production&#39;) {
        morgan(&#39;combined&#39;)(req, res, next);
      } else {
        morgan(&#39;dev&#39;)(req, res, next);
      }
    });
    ```

- 6.2.7 multer
    - 이미지, 동영상  등 여러 가지 파일을 멀티파트 형식으로 업로드할 때 사용</code></pre><ul>
<li><p>6.3 Router 객체로 라우팅 분리</p>
<pre><code class="language-jsx">  //routes/index.js
  const express=require(&#39;express&#39;);

  const router=express.Router();

  //GET / 라우터
  router.get(&#39;/&#39;,(req,res)=&gt;{
      res.send(&#39;Hello,Express&#39;);
  });

  module.exports=router;</code></pre>
<pre><code class="language-jsx">  //routes/user.js
  const express=require(&#39;express&#39;);

  const router=express.Router();

  //GET /user 라우터
  router.get(&#39;/&#39;,(req,res)=&gt;{
      res.send(&#39;Hello,user&#39;);
  });

  module.exports=router;</code></pre>
<pre><code class="language-jsx">  //app.js
  const express=require(&#39;express&#39;);
  const morgan=require(&#39;morgan&#39;); //요청과 응답에 대한 정보 콘솔에 기록
  const cookieParser=require(&#39;cookie-parser&#39;);
  const session=require(&#39;express-session&#39;);
  const dotenv=require(&#39;dotenv&#39;); //process.env 관리, .env파일 읽어서 process.env로 만든다
  const path=require(&#39;path&#39;); 
  const bodyParser = require(&#39;body-parser&#39;);

  dotenv.config();
  const indexRouter = require(&#39;./routes/index&#39;);
  const userRouter = require(&#39;./routes/user&#39;);

  const app=express();
  app.set(&#39;port&#39;,process.env.PORT || 3000);

  //app.js에 연결할 때 주소가 합쳐짐
  app.use(&#39;/&#39;, indexRouter);
  app.use(&#39;/user&#39;, userRouter);

  app.use((req, res, next) =&gt; {
    res.status(404).send(&#39;Not Found&#39;);
  });

  app.listen(3000,()=&gt;{  //서버 시작!!! 꼭 해야함~~ 중요!
      console.log(&quot;서버 시작!&quot;)
  })</code></pre>
<ul>
<li><p>그 외의 라우터 기능</p>
<ul>
<li><p>next(’route’), next() : 라우터에 연결된 나머지 미들웨어들 건너뛰고 싶을 때 사용</p>
<pre><code class="language-jsx">router.get(&#39;/&#39;, (req, res, next) =&gt; {
next(&#39;route&#39;);
}, (req, res, next) =&gt; {
console.log(&#39;실행되지 않습니다&#39;);
next();
}, (req, res, next) =&gt; {
console.log(&#39;실행되지 않습니다&#39;);
next();
});
router.get(&#39;/&#39;, (req, res) =&gt; {
console.log(&#39;실행됩니다&#39;);
res.send(&#39;Hello, Express&#39;);
});</code></pre>
</li>
<li><p>라우터 주소에 정규표현식을 비롯한 특수한 패턴 사용가능!</p>
<p>→ 라우트 매개변수 패턴</p>
<pre><code class="language-jsx">router.get(&#39;/user/:id&#39;, (req, res) =&gt; {
console.log(&#39;얘만 실행됩니다.&#39;);
});
router.get(&#39;/user/like&#39;, (req, res) =&gt; {
console.log(&#39;전혀 실행되지 않습니다.&#39;);
});</code></pre>
</li>
<li><p>/users/1 이나 /users/123 등의 요청도 이 라우터가 처리</p>
</li>
<li><p>:id에 해당하는 1이나 123을 조회 가능, req,params 객체안에 들어있음</p>
</li>
<li><p>:id면 req.params.id로 , :type 이면 req.params.type으로 조회 가능!</p>
</li>
<li><p>주의 할점: 일반 라우터보다 뒤에 꼭 위치해야함!!!</p>
</li>
<li><p>주소에 쿼리스트링도 가능 : 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어있음</p>
<p>  ex) /users/123?limit=5&amp;skip=10 주소 요청</p>
<p>  → req.params와 req.query : <code>{ id: &#39;123&#39; } { limit: &#39;5&#39;, skip: &#39;10&#39; }</code></p>
</li>
<li><p>app.js에서 에러 처리 미들웨어 위에 넣어둔 미들웨는 일치하는 라우터 없을 때 404 상태 코드 응답 역할  →  익스프레스가 자체적으로 404에러 처리해주기는 하지만, 웬만하면 404응답 미들웨어와 에러 처리 미들웨어를 연결하는게 좋음!!</p>
<pre><code class="language-jsx">app.use((req, res, next) =&gt; {
res.status(404).send(&#39;Not Found&#39;);
});</code></pre>
</li>
<li><p>주소는 같지만 메서드는 다른 코드가 있을 때, 하나의 덩어리로 묶음</p>
<pre><code class="language-jsx">router.route(&#39;/abc&#39;)
.get((req, res) =&gt; {
  res.send(&#39;GET /abc&#39;);
})
.post((req, res) =&gt; {
  res.send(&#39;POST /abc&#39;);
});</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>6.4 req,res 객체 살펴보기</p>
<ul>
<li><p>req 객체</p>
<ul>
<li>req.app: req 객체를 통해 app 객체에 접근할 수 있습니다. req.app.get(&#39;port&#39;)와 같은 식으로 사용할 수 있습니다.</li>
<li>req.body: body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체입니다.</li>
<li>req.cookies: cookie-parser 미들웨어가 만드는 요청의 쿠키를 해석한 객체입니다.</li>
<li>req.ip: 요청의 ip 주소가 담겨 있습니다.</li>
<li>req.params: 라우트 매개변수에 대한 정보가 담긴 객체입니다.</li>
<li>req.query: 쿼리스트링에 대한 정보가 담긴 객체입니다.</li>
<li>req.signedCookies: 서명된 쿠키들은 req.cookies 대신 여기에 담겨 있습니다.</li>
<li>req.get(헤더 이름): 헤더의 값을 가져오고 싶을 때 사용하는 메서드입니다.</li>
</ul>
</li>
<li><p>res 객체</p>
<ul>
<li>res.app: req.app처럼 res 객체를 통해 app 객체에 접근할 수 있습니다.</li>
<li>res.cookie(키, 값, 옵션): 쿠키를 설정하는 메서드입니다.</li>
<li>res.clearCookie(키, 값, 옵션): 쿠키를 제거하는 메서드입니다.</li>
<li>res.end(): 데이터 없이 응답을 보냅니다.</li>
<li>res.json(JSON): JSON 형식의 응답을 보냅니다.</li>
<li>res.locals: 하나의 요청 안에서 미들웨어 간에 데이터를 전달하고 싶을 때 사용하는 객체입니다.</li>
<li>res.redirect(주소): 리다이렉트할 주소와 함께 응답을 보냅니다.</li>
<li>res.render(뷰, 데이터): 다음 절에서 다룰 템플릿 엔진을 렌더링해서 응답할 때 사용하는 메서드입니다.</li>
<li>res.send(데이터): 데이터와 함께 응답을 보냅니다. 데이터는 문자열일 수도, HTML일 수도, 버퍼일 수도, 객체나 배열일 수도 있습니다.</li>
<li>res.sendFile(경로): 경로에 위치한 파일을 응답합니다.</li>
<li>res.set(헤더, 값): 응답의 헤더를 설정합니다.</li>
<li>res.status(코드): 응답 시의 HTTP 상태 코드를 지정합니다.</li>
</ul>
</li>
<li><p>메서드 체이닝</p>
<pre><code class="language-jsx">res
.status(201)
.cookie(&#39;test&#39;, &#39;test&#39;)
.redirect(&#39;/admin&#39;);</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 강의 4장 RESTAPI - [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-4%EC%9E%A5-RESTAPI-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-4%EC%9E%A5-RESTAPI-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Mon, 03 Apr 2023 01:05:16 GMT</pubDate>
            <description><![CDATA[<p><strong>- REST : REpresentational State Transfer, 서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법을 가리킴, 일종의 약속</strong></p>
<ul>
<li>종류<ul>
<li>GET: 서버 자원을 가져오고자 할 때 사용합니다. 요청의 본문(body)에 데이터를 넣지 않습니다. 데이터를 서버로 보내야 한다면 쿼리스트링을 사용합니다.</li>
<li>POST: 서버에 자원을 새로 등록하고자 할 때 사용합니다. 요청의 본문에 새로 등록할 데이터를 넣어 보냅니다.</li>
<li>PUT: 서버의 자원을 요청에 들어 있는 자원으로 치환하고자 할 때 사용합니다. 요청의 본문에 치환할 데이터를 넣어 보냅니다.</li>
<li>PATCH: 서버 자원의 일부만 수정하고자 할 때 사용합니다. 요청의 본문에 일부 수정할 데이터를 넣어 보냅니다.</li>
<li>DELETE: 서버의 자원을 삭제하고자 할 때 사용합니다. 요청의 본문에 데이터를 넣지 않습니다.</li>
<li>OPTIONS: 요청을 하기 전에 통신 옵션을 설명하기 위해 사용합니다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mini_log/post/4248cef3-a062-4447-9f2f-76bb0f3cb61b/image.png" alt=""></p>
<ul>
<li>PUT과 PATCH의 차이<pre><code>- PUT은 update시 전체를 불러와야함. (자원 전체 교체)
    - ex) 게시물 전체를 새로운 내용으로 교체하려는 경우
- PATCH는 pk와 update할 항목만 불러오면 된다. (자원의 부분 교체)
    - ex) 게시물에서 제목만 수정하려는 경우
- 현업에서 둘다 많이 사용
- 일반적으로 개인정보 수정을 위해서는 PATCH 메서드를 사용하는 것이 좋습니다. 이는 요청 본문에 변경된 필드만 포함하면 되므로 요청의 크기가 더 작아집니다. 또한 PUT 메서드를 사용하여 모든 필드를 업데이트하는 경우 이전 값이 덮어씌워질 가능성이 있으므로 PATCH 메서드를 사용하는 것이 더 안전합니다.</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Mysql & Node.js DB 연동]]></title>
            <link>https://velog.io/@mini_log/Mysql-Node.js-DB-%EC%97%B0%EB%8F%99</link>
            <guid>https://velog.io/@mini_log/Mysql-Node.js-DB-%EC%97%B0%EB%8F%99</guid>
            <pubDate>Mon, 03 Apr 2023 01:03:06 GMT</pubDate>
            <description><![CDATA[<h3 id="error-connect-econnrefused-13306">Error: connect ECONNREFUSED ::1:3306</h3>
<p>→ 해결방법</p>
<pre><code class="language-jsx">const mysql=require(&#39;mysql&#39;);
const conn={
    host: &#39;127.0.0.1&#39;, // 여기 수정함
    user: &#39;root&#39;,
    password: &#39;12345678&#39;,
    database: &#39;shopdb&#39;,
    port: &#39;3306&#39;,
};

var connection = mysql.createConnection(conn); // DB 커넥션 생성
connection.connect();   // DB 접속

var testQuery = &quot;SELECT * FROM usertbl&quot;;

connection.query(testQuery, function (err, results, fields) { // testQuery 실행
    if (err) {
        console.log(err);
    }
    console.log(results);
});

connection.end(); // DB 접속 종료</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 강의 3장 - [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-3%EC%9E%A5-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-3%EC%9E%A5-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Thu, 30 Mar 2023 01:03:22 GMT</pubDate>
            <description><![CDATA[<h3 id="📗-3장-노드-기능-알아보기">📗 3장 노드 기능 알아보기</h3>
<ul>
<li><p>this</p>
<ul>
<li>자바스크립트 : function마다 this 다름, 화살표하면서 쓰면 부모의 this 물려받음</li>
<li>function 외의 최상위 스코프에 존재하는 this는 module.exports(또는 exports 객체) 가리킴</li>
</ul>
</li>
<li><p>require</p>
<ul>
<li>require가 제일 위에 올 필요 X, import 는 첫번째 와야함</li>
<li>require.cache에 한번 require한 모듈에 대한 캐쉬 정보 들어있음</li>
<li>require.main은 노드 실행 시 첫 모듈을 가리킴</li>
</ul>
</li>
<li><p>순환참조</p>
<ul>
<li><p>노드 자체적으로 순환 참조 막아줌 → dep1의 module.exports가 함수가 아니라 빈 객체로 표시</p>
<pre><code class="language-jsx">//dep1.js
const dep2 = require(&#39;./dep2&#39;);

module.exports = () =&gt; {
console.log(&#39;dep2&#39;, dep2);
};</code></pre>
<pre><code class="language-jsx">//dep2.js
const dep1 = require(&#39;./dep1&#39;);

module.exports = () =&gt; {
console.log(&#39;dep1&#39;, dep1);
};</code></pre>
</li>
</ul>
</li>
<li><p>3.3.2 ECMAScript 모듈</p>
<ul>
<li><p>공식적인 자바스크립트 모듈 형식</p>
<pre><code class="language-jsx">//var.mjs
export const odd = &#39;MJS 홀수입니다&#39;;
export const even = &#39;MJS 짝수입니다&#39;;</code></pre>
<pre><code class="language-jsx">//func.mjs
import { odd, even } from &#39;./var.mjs&#39;;

function checkOddOrEven(num) {
if (num % 2) { // 홀수이면
  return odd;
}
return even;
}

export default checkOddOrEven;</code></pre>
<pre><code class="language-jsx">//index.mjs
import { odd, even } from &#39;./var.mjs&#39;;
import checkNumber from &#39;./func.mjs&#39;; //이름 달라도 상관없음!

function checkStringOddOrEven(str) {
if (str.length % 2) { // 홀수이면
  return odd;
}
return even;
}

console.log(checkNumber(10));
console.log(checkStringOddOrEven(&#39;hello&#39;));</code></pre>
</li>
<li><p>콘솔에 <strong>$ node index.mjs</strong> 로 실행</p>
</li>
<li><p>js 확장자에서 import 사용하면 SyntaxError: Cannot use import statement outside a module 에러 발생</p>
<ul>
<li>해결방법 : mjs 확장자 대신 js 확장자를 사용하면서 ES 모듈 사용하려면 package.json에 type: “module” 속성 추가</li>
</ul>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/de8d4986-56d5-4c48-8daf-8074b784a1cf/Untitled.png" alt="Untitled"></p>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8335b146-3500-480f-a74a-c57f608b878c/Untitled.png" alt="Untitled"></p>
</li>
</ul>
</li>
<li><p>3.3.3 다이나믹 임포트</p>
<ul>
<li><p>CommonJS 모듈에서는 가능, ES 모듈에서는 불가능</p>
</li>
<li><p>조건부로 모듈을 불러오는 것</p>
<pre><code class="language-jsx">//dynamic.js
const a = false;
if (a) {
  require(&#39;./func&#39;);
}
console.log(&#39;성공&#39;);</code></pre>
</li>
<li><p>ES 모듈에서 사용하는 방법!</p>
<ul>
<li>ES모듈은 async 함수 없이도 await 가능</li>
</ul>
<pre><code class="language-jsx">//dynamic.mjs
const a = false;
if (a) {
  import &#39;./func.mjs&#39;;
}
console.log(&#39;성공&#39;);
//=&gt; 위의 코드는 에러남

//수정후
const a = true;
if (a) {
  const m1 = await import(&#39;./func.mjs&#39;); //import는 Promise를 반환하기에 await이나 then을 붙여야함
  console.log(m1);
  const m2 = await import(&#39;./var.mjs&#39;); 
  console.log(m2);
}</code></pre>
</li>
</ul>
</li>
<li><p>3.3.4 __filename, __dirname</p>
<ul>
<li>노드는 __filename, __dirname이라는 키워드로 경로에 대한 정보 제공</li>
<li>파일에 __filename과 __dirname을 넣어두면 실행 시 현재 파일 명과 현재 파일 경로로 변경됨</li>
<li>ES모듈에서는 둘다 사용 불가능<ul>
<li>import.meta.url로 경로 가져오기 가능</li>
</ul>
</li>
</ul>
</li>
<li><p>3.4 노드 내장 객체</p>
<ul>
<li>1) console<ul>
<li>console.time(레이블): console.timeEnd(레이블)과 대응되어 같은 레이블을 가진 time과 timeEnd 사이의 시간을 측정합니다.</li>
<li>console.log(내용): 평범한 로그를 콘솔에 표시합니다. console.log(내용, 내용, …)처럼 여러 내용을 동시에 표시할 수도 있습니다.</li>
<li>console.error(에러 내용): 에러를 콘솔에 표시합니다.</li>
<li>console.table(배열): 배열의 요소로 객체 리터럴을 넣으면, 객체의 속성들이 테이블 형식으로 표현됩니다. 아래 결과를 확인해보세요.</li>
<li>console.dir(객체, 옵션): 객체를 콘솔에 표시할 때 사용합니다. 첫 번째 인수로 표시할 객체를 넣고, 두 번째 인수로 옵션을 넣습니다. 옵션의 colors를 true로 하면 콘솔에 색이 추가되어 보기가 한결 편해집니다. depth는 객체 안의 객체를 몇 단계까지 보여줄지를 결정합니다. 기본값은 2입니다.</li>
<li>console.trace(레이블): 에러가 어디서 발생했는지 추적할 수 있게 합니다. 보통은 에러 발생 시 에러 위치를 알려주므로 자주 사용하지 않지만, 위치가 나오지 않는다면 사용할 만합니다.</li>
</ul>
</li>
<li>2) 타이머<ul>
<li>setTimeout(콜백 함수, 밀리초): 주어진 밀리초(1,000분의 1초) 이후에 콜백 함수를 실행합니다.</li>
<li>setInterval(콜백 함수, 밀리초): 주어진 밀리초마다 콜백 함수를 반복 실행합니다.</li>
<li>setImmediate(콜백 함수): 콜백 함수를 즉시 실행합니다.</li>
<li>clearTimeout(아이디): setTimeout을 취소합니다.</li>
<li>clearInterval(아이디): setInterval을 취소합니다.</li>
<li>clearImmediate(아이디): setImmediate를 취소합니다.</li>
</ul>
</li>
<li>3) process<ul>
<li>process.env : 시스템 환경변수 출력, 임의로 환경 변수 저장 가능, 서비스의 중요한 키 저장 공간으로도 사용</li>
<li>process.nextTick(콜백):  이벤트 루프가 다른 콜백 함수들보다 nextTick의 콜백 함수를 우선으로 처리하도록 만듦</li>
<li>process.exti(코드) : 실행중인 노드 프로세스 종료<ul>
<li>인수를 주지 않거나 0을 주면 정상 종료를 뜻하고, 1을 주면 비정상 종료를 뜻함</li>
</ul>
</li>
</ul>
</li>
<li>4) URL, URLSearchParams</li>
<li>5) AbortController, FormData, fetch, Headers, Request, Response, Event, EventTarget: 브라우저에서 사용하던 API가 노드에도 동일하게 생성</li>
<li>6) TextDecoder: Buffer를 문자열로 바꿉니다.</li>
<li>7) TextEncoder: 문자열을 Buffer로 바꿉니다.</li>
<li>8) WebAssembly: 웹어셈블리 처리를 담당합니다.</li>
</ul>
</li>
<li><p>3.5 노드 내장 모듈 사용하기</p>
<ul>
<li>1) os : require(&#39;os&#39;) 또는 require(&#39;node:os&#39;), 사용자  컴퓨터의 운영체제 정보<ul>
<li>ex) const os=require(’os’);</li>
<li>os.arch(): process.arch와 동일합니다.</li>
<li>os.platform(): process.platform과 동일합니다.</li>
<li>os.type(): 운영체제의 종류를 보여줍니다.</li>
<li>os.uptime(): 운영체제 부팅 이후 흐른 시간(초)을 보여줍니다. process.uptime()은 노드의 실행 시간이었습니다.</li>
<li>os.hostname(): 컴퓨터의 이름을 보여줍니다.</li>
<li>os.release(): 운영체제의 버전을 보여줍니다.</li>
<li>os.homedir(): 홈 디렉터리 경로를 보여줍니다.</li>
<li>os.tmpdir(): 임시 파일 저장 경로를 보여줍니다.</li>
<li>os.cpus(): 컴퓨터의 코어 정보를 보여줍니다.</li>
<li>os.freemem(): 사용 가능한 메모리(RAM)를 보여줍니다.</li>
<li>os.totalmem(): 전체 메모리 용량을 보여줍니다.</li>
</ul>
</li>
<li>2) path : 폴더와 파일의 경로 쉽게 조작 가능한 모듈<ul>
<li>ex) const path =require(’path’);</li>
<li>path.sep: 경로의 구분자입니다. 윈도는 , POSIX는 /입니다.</li>
<li>path.delimiter: 환경 변수의 구분자입니다. process.env.PATH를 입력하면 여러 개의 경로가 이 구분자로 구분되어 있습니다. 윈도는 세미콜론(;)이고, POSIX는 콜론(:)입니다.</li>
<li>path.dirname(경로): 파일이 위치한 폴더 경로를 보여줍니다.</li>
<li>path.extname(경로): 파일의 확장자를 보여줍니다.</li>
<li>path.basename(경로, 확장자): 파일의 이름(확장자 포함)을 표시합니다. 파일의 이름만 표시하고 싶다면 basename의 두 번째 인수로 파일의 확장자를 넣으면 됩니다.</li>
<li>path.parse(경로): 파일 경로를 root, dir, base, ext, name으로 분리합니다.</li>
<li>path.format(객체): path.parse()한 객체를 파일 경로로 합칩니다.</li>
<li>path.normalize(경로): /나 \를 실수로 여러 번 사용했거나 혼용했을 때 정상적인 경로로 변환합니다.</li>
<li>path.isAbsolute(경로): 파일의 경로가 절대경로인지 상대경로인지를 true나 false로 알립니다.</li>
<li>path.relative(기준경로, 비교경로): 경로를 두 개 넣으면 첫 번째 경로에서 두 번째 경로로 가는 방법을 알립니다.</li>
<li>path.join(경로, …): 여러 인수를 넣으면 하나의 경로로 합칩니다. 상대경로인 ..(부모 디렉터리)과 .(현 위치)도 알아서 처리합니다.</li>
<li>path.resolve(경로, …): path.join()과 비슷하지만 차이가 있습니다. 차이점은 다음에 나오는 Note에서 설명합니다.</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Mac Mysql 설치 & dbeaver 연동(M1)]]></title>
            <link>https://velog.io/@mini_log/Mac-Mysql-%EC%84%A4%EC%B9%98-dbeaver-%EC%97%B0%EB%8F%99M1</link>
            <guid>https://velog.io/@mini_log/Mac-Mysql-%EC%84%A4%EC%B9%98-dbeaver-%EC%97%B0%EB%8F%99M1</guid>
            <pubDate>Tue, 28 Mar 2023 00:33:04 GMT</pubDate>
            <description><![CDATA[<h3 id="mysql-설치homebrew-사용">Mysql 설치(Homebrew 사용)</h3>
<ol>
<li>Homebrew 설치</li>
</ol>
<pre><code class="language-jsx">$ /bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)&quot;</code></pre>
<ol start="2">
<li>Mysql 설치</li>
</ol>
<pre><code class="language-jsx">$ brew install mysql
$ brew services start mysql
$ mysql_secure_installation</code></pre>
<ol start="3">
<li>Mysql 시작</li>
</ol>
<pre><code class="language-jsx">$ mysql -h localhost -u root -p
Enter password: [비밀번호 입력]
mysql&gt;</code></pre>
<blockquote>
<p>권한 에러 발생시</p>
</blockquote>
<pre><code class="language-jsx">//에러
Error: The following directories are not writable by your user:
/usr/local/share/info
You should change the ownership of these directories to your user.
  sudo chown -R $(whoami) /usr/local/share/info
And make sure that your user has write permission.
  chmod u+w /usr/local/share/info</code></pre>
<p>-&gt; 해결방법(이것도 안댕,,)</p>
<pre><code class="language-jsx">//뒤의 /usr/local/share/info는 저장경로 다르기 때문에 which info, which mysql로 경로 확인하기
$ sudo chown -R $(whoami) /usr/local/share/info
$ chmod u+w /usr/local/share/info</code></pre>
<blockquote>
<p>비밀번호 에러 발생 시</p>
</blockquote>
<pre><code class="language-jsx">//이것은 비밀번호 틀렸다는 것
Your connection attempt failed for user &#39;root&#39; to the MySQL server at 127.0.0.1:3306:
Access denied for user &#39;root&#39;@&#39;localhost&#39; (using password: YES)</code></pre>
<pre><code class="language-jsx">//이것은 비밀번호가 없을 때 에러
Your connection attempt failed for user &#39;root&#39; to the MySQL server at 127.0.0.1:3306:
Access denied for user &#39;root&#39;@&#39;localhost&#39; (using password: NO)</code></pre>
<p>→ 해결방법(나는 다 안됨,,)</p>
<pre><code class="language-jsx">//비밀번호 설정안되어 있으면 그냥 엔터
$ mysql -u root -p
$ALTER user &#39;root&#39;@&#39;localhost&#39; IDENTIFIED WITH mysql_native_password BY &#39;바꿀 비밀번호&#39;;</code></pre>
<h3 id="권한-에러-다-설정해도-안되면-mysql-지우고-brew-다시-깔기-⇒-이렇게-해서-성공">권한 에러 다 설정해도 안되면, mysql 지우고 brew 다시 깔기!! ⇒ 이렇게 해서 성공!</h3>
<ul>
<li><p>dbeaver 연동</p>
<ol>
<li><p>dbeaver 설치
<img src="https://velog.velcdn.com/images/mini_log/post/0960d6b0-4a76-4a9e-b5b0-5056678cf095/image.png" alt=""></p>
</li>
<li><p>맨 위쪽 플러그모양 눌러서 Mysql 선택</p>
</li>
</ol>
</li>
<li><p>use db명 할시, No Active connection에러
  → 위의 N/A 되있었는거 localhost로 변경!
<img src="https://velog.velcdn.com/images/mini_log/post/d0526a73-f79f-4dd6-9ecf-ba850bdeefd8/image.png" alt=""></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 강의 3장 3.3 [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-3%EC%9E%A5-3.3-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-3%EC%9E%A5-3.3-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Mon, 27 Mar 2023 09:53:26 GMT</pubDate>
            <description><![CDATA[<h3 id="📗-3장-노드-기능-알아보기">📗 3장. 노드 기능 알아보기</h3>
<ul>
<li>3.3 모듈로 만들기</li>
<li>주의 ) 파일에서 단 1번만 써야함!</li>
<li>CommonJS 모듈</li>
</ul>
<pre><code class="language-jsx">//var.js 
const odd = &#39;CJS 홀수입니다&#39;;
const even = &#39;CJS 짝수입니다&#39;;

module.exports = { //모듈 사용 (객체로 묶음)
  odd,
  even,
};</code></pre>
<pre><code class="language-jsx">//func.js
const { odd, even } = require(&#39;./var&#39;); //var.js의 모듈 불러옴, 구조 분해 할당

function checkOddOrEven(num) {
  if (num % 2) { // 홀수이면
    return odd;
  }
  return even;
}

module.exports = checkOddOrEven; //ckeckOddOrEven 함수 모듈 설정</code></pre>
<pre><code class="language-jsx">//index.js
const { odd, even } = require(&#39;./var&#39;); //var.js 모듈
const checkNumber = require(&#39;./func&#39;); //func.js 모듈

function checkStringOddOrEven(str) {
  if (str.length % 2) { // 홀수이면
    return odd;
  }
  return even;
}

console.log(checkNumber(10));
console.log(checkStringOddOrEven(&#39;hello&#39;));</code></pre>
<p><img src="https://velog.velcdn.com/images/mini_log/post/d6b4891d-3440-4067-877b-de03ae815ff2/image.png" alt=""></p>
<ul>
<li>exports 모듈<ul>
<li>exports는 각각 사용해야함.</li>
<li>module.exports === exports =={} (객체 개념)</li>
<li>exports 와 moduls.exports 같이 사용 불가능!</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">exports.odd = &#39;CJS 홀수입니다&#39;;
exports.even = &#39;CJS 짝수입니다&#39;;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js 강의 2장 
 [개정 3판] Node.js 교과서 - 기본부터 프로젝트 실습까지]]></title>
            <link>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-2%EC%9E%A5-1-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@mini_log/Node.js-%EA%B0%95%EC%9D%98-2%EC%9E%A5-1-%EA%B0%9C%EC%A0%95-3%ED%8C%90-Node.js-%EA%B5%90%EA%B3%BC%EC%84%9C-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Mon, 27 Mar 2023 09:49:13 GMT</pubDate>
            <description><![CDATA[<h3 id="📕-2장-알아두어야-할-자바스크립트"><strong>📕 2장. 알아두어야 할 자바스크립트</strong></h3>
<ul>
<li>이벤트 루프</li>
</ul>
<pre><code class="language-jsx">function oneMore(){
    console.log(&#39;one more&#39;);
}
function run(){
    console.log(&#39;run run&#39;);
    setTimeout(()=&gt;{
        console.log(&#39;wow&#39;);
    },0);
    new Promise((resolve)=&gt;{
        resolve(&#39;hi&#39;);
    })
        .then(console.log);
    oneMore();
}

setTimeout(run,5000);</code></pre>
<p> 1) 호출스택 → anonymous 
2) 호출스택 → anonymous, setTimeout(run,5000) </p>
<p>3) 호출스택 → anonymous , 백그라운드 → 타이머(run,5초)</p>
<p>4) 백그라운드 → 타이머(run,5초) </p>
<ul>
<li>5초 센 다음에 run함수를 테스크 큐로 보냄</li>
</ul>
<p>5) 테스크 큐 → run (이제 호출 스택이 비었으니 이동, 비어있어야 이동가능!)</p>
<p>6) 호출스택 → run, 콘솔 → run run</p>
<p>7) 호출스택 → run, setTimeout(익명,0) , 콘솔 → run run</p>
<ul>
<li>Timeout은 바로 실행X, 무조건 백그라운드 가야함</li>
</ul>
<p>8) 호출스택 → run, 백그라운드 → 타이머(익명,0), 콘솔 → run run</p>
<p>9) 호출스택 → run, new Promise , resolve(’hi’) , 백그라운드 → 타이머(익명,0), 콘솔 → run run</p>
<p>10) 호출스택 → run , 백그라운드 → 타이머(익명,0) , then console.log(hi)</p>
<ul>
<li>then 만나는 순간 비동기로 가서 백그라운드로 감</li>
</ul>
<p>11) 호출스택 → run, oneMore, console.log , 백그라운드 → 타이머(익명,0), then console.log(hi) , 콘솔 → run run</p>
<p>12) 백그라운드 → 타이머(익명,0), then console.log(hi) , 콘솔 → run run , one more</p>
<ul>
<li>백그라운드 안에서는 먼저 끝나는 쪽이 먼저 태스크 큐로 감</li>
</ul>
<p>13) 태스크 큐 → 익명 , console.log(hi) </p>
<ul>
<li>(중요!) 우선순위 then &gt; 타이머 ⇒ then이 먼저 호출 스택으로 감</li>
</ul>
<p>14) 호출 스택 → console.log(hi) , 테스크 큐 → 익명</p>
<p>15) 최종 콘솔 : run run , one more, hi , wow</p>
<ul>
<li><p>2.1.1 const, let</p>
<ul>
<li><p>const : 블록밖에서 사용X, 블록: if,while,for,function 등의 중괄호({와} 사이), const 는 다른 값 할당불가(상수)</p>
<pre><code class="language-jsx">const a=3;
a=&#39;5&#39;; //에러

const b={name : &#39;zerocho&#39;};
b.name =&#39;nerocho&#39;; //이건 가능

const c; //에러</code></pre>
</li>
</ul>
</li>
<li><p>2.1.2 템플릿 문자열</p>
<pre><code class="language-jsx">  var won=1000;
  va result=&#39;이 과자는&#39; + won + &#39;원입니다.;
  //이 과자는1000원입니다. (띄어쓰기 안댐 -&gt; 직접 해야함)

  const result=`이 과자는 ${won}원입니다`; //최신기능

  function a() {}
  a(); //예전 함수호출
  a``; //최신버전 함수호출</code></pre>
</li>
<li><p>2.1.3 객체 리터럴</p>
<ul>
<li><p>예전버전</p>
<pre><code class="language-jsx">var sayNode=function(){
  console.log(&#39;Node&#39;);
};
var es=&#39;ES&#39;;
var oldObject={
  sayJS:function(){
      console.log(&#39;JS&#39;);
  },
  sayNode:sayNode,
];
oldObject[es+6]=&#39;fantastic&#39;;
oldObject.sayNode(); //Node
oldObject.sayJS(); //JS
console.log(oldObject.ES6); //fantastic</code></pre>
</li>
<li><p>최신버전</p>
<pre><code class="language-jsx">const newObject={
  sayJS(){ //:function 삭제(객체의 메서드에 함수를 연결할 때, 콜론과 function 붙이지 않아도댐)
      console.log(&#39;JS&#39;);
  },
  sayNode, //:sayNode 삭제(속성명과 변수명 동일한 경우 한번만 써도 가능!)
  [es+6]:&#39;fantastic&#39;, //바로 넣음(객체의 속성명을 동적으로 변경 가능, 객체 리터럴 안에 동적 속성 선언 가능!)
};
newObject.sayNode(); //Node
newObject.sayJS(); //JS
console.log(newObject.ES6); //fantastic</code></pre>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>2.1.4 화살표 함수</p>
<ul>
<li><p>function 과 ⇒ 의 차이점</p>
<ul>
<li>funtion은 this가 각자 다른 함수 스코프의 this 가짐, 전체 부모 relationship1의 this를 가져오려면 that으로 변수를 사용해야함</li>
<li>화살표는 this가 따로 없기 때문에 relationship2의 this 그대로 가져옴</li>
</ul>
</li>
<li><p>결론 : 기본적으로 화살표 함수를 쓰되, this를 사용해야 하는 경우에는 화살표 함수와 함수 선언문(function) 둘 중 하나 고르기!!</p>
<pre><code class="language-jsx">var relationship1 = {
name: &#39;zero&#39;,
friends: [&#39;nero&#39;, &#39;hero&#39;, &#39;xero&#39;],
logFriends: function () {
  var that = this; // relationship1을 가리키는 this를 that에 저장
  this.friends.forEach(function (friend) {
    console.log(that.name, friend); //this로 변경할 경우, undefined nero, undefined hero, undefined xero
  });
},
};
relationship1.logFriends(); //zero nero, zero hero, zero xero

const relationship2 = {
name: &#39;zero&#39;,
friends: [&#39;nero&#39;, &#39;hero&#39;, &#39;xero&#39;],
logFriends() {
  this.friends.forEach(friend =&gt; {
    console.log(this.name, friend);
  });
},
};
relationship2.logFriends(); //zero nero, zero hero, zero xero</code></pre>
</li>
</ul>
</li>
<li><p>2.1.5 구조 분해 할당</p>
<ul>
<li><p>객체와 배열로부터 속성이나 요소 쉽게 꺼낼 수 있음</p>
</li>
<li><p>단, this는 함수를 호출할 때 어떻게 호출되었냐에 따라 결정되기 때문에 this가 있으면 구조 분해 할당을 안하는 것이 좋음!!, 구조분해 할당하면 함수의 this가 달라짐</p>
<ul>
<li>달라진 this를 원래대로 바꿔주려면 bind함수를 따로 사용해야함</li>
</ul>
<pre><code class="language-jsx">var candyMachine = {
status: {
  name: &#39;node&#39;,
  count: 5,
},
getCandy: function () {
  this.status.count--;
  return this.status.count;
},
};
var getCandy = candyMachine.getCandy;
var count = candyMachine.status.count;

//위의 코드 이렇게 변경 가능
const candyMachine = {
status: {
  name: &#39;node&#39;,
  count: 5,
},
getCandy() {
  this.status.count--;
  return this.status.count;
},
};
const { getCandy, status: { count } } = candyMachine;</code></pre>
<pre><code class="language-jsx">var array = [‘nodejs’, {}, 10, true];
var node = array[0];
var obj = array[1];
var bool = array[3];

//구조 분해 할당(배열)
const array = [‘nodejs’, {}, 10, true];
const [node, obj, , bool] = array;</code></pre>
</li>
</ul>
</li>
<li><p>2.1.6 클래스</p>
<ul>
<li><p>다른 언어처럼 클래스 기반 동작X, 프로토타입 기반으로 동작하지만 보기 좋게 클래스로 바꾼것</p>
</li>
<li><p>프로토타입으로만 작성한 것(예전 버전)</p>
<pre><code class="language-jsx">var Human = function(type) {
this.type = type || &#39;human&#39;;
};

Human.isHuman = function(human) {
return human instanceof Human;
}

Human.prototype.breathe = function() {
alert(&#39;h-a-a-a-m&#39;);
};

var Zero = function(type, firstName, lastName) {
Human.apply(this, arguments);
this.firstName = firstName;
this.lastName = lastName;
};

Zero.prototype = Object.create(Human.prototype);
Zero.prototype.constructor = Zero; // 상속하는 부분
Zero.prototype.sayName = function() {
alert(this.firstName + &#39; &#39; + this.lastName);
};
var oldZero = new Zero(&#39;human&#39;, &#39;Zero&#39;, &#39;Cho&#39;);
Human.isHuman(oldZero); // true</code></pre>
</li>
<li><p>클래스로 바꾼것(최신 버전) → 프로토타입 기반으로 동작!!!</p>
<pre><code class="language-jsx">class Human {
constructor(type = &#39;human&#39;) { //생성자 함수
  this.type = type;
}

static isHuman(human) { //Human.isHuman같은 클래스 함수 static 전환
  return human instanceof Human;
}

breathe() {
  alert(&#39;h-a-a-a-m&#39;);
}
}

class Zero extends Human { //extends: 상속
constructor(type, firstName, lastName) {
  super(type); //super : Human
  this.firstName = firstName;
  this.lastName = lastName;
}

sayName() {
  super.breathe();
  alert(`${this.firstName} ${this.lastName}`);
}
}

const newZero = new Zero(&#39;human&#39;, &#39;Zero&#39;, &#39;Cho&#39;);
Human.isHuman(newZero); // true</code></pre>
</li>
</ul>
</li>
<li><p>2.1.7 Promise</p>
<ul>
<li><p>자바스크립트와 노드는 주로 비동기를 접함 → 이벤트 리스너 사용에서 콜백말고 프로미스기반으로 재구성, 중요!!</p>
</li>
<li><p>실행은 바로 하되 결과값은 나중에 받는 객체, 결과값은 실행이 완료된 후 then이나 catch메서드를 통해 받음!</p>
<ul>
<li>밑의 코드에서 new Promise는 바로 실행되지만, 결과값은 then을 붙였을 때 받음</li>
</ul>
<pre><code class="language-jsx">const condition = true; // true이면 resolve, false이면 reject
const promise = new Promise((resolve, reject) =&gt; {  //1. 프로미스 생성
if (condition) {
  resolve(&#39;성공&#39;);
} else {
  reject(&#39;실패&#39;);
}
});
// 다른 코드가 들어갈 수 있음
promise
.then((message) =&gt; {
  console.log(message); // 성공(resolve)한 경우 실행
})
.catch((error) =&gt; {
  console.error(error); // 실패(reject)한 경우 실행
})
.finally(() =&gt; { // 끝나고 무조건 실행
  console.log(&#39;무조건&#39;);
});</code></pre>
<pre><code class="language-jsx">function findAndSaveUser(Users) {
Users.findOne({}, (err, user) =&gt; { // 첫 번째 콜백
  if (err) {
    return console.error(err);
  }
  user.name = &#39;zero&#39;;
  user.save((err) =&gt; { // 두 번째 콜백
    if (err) {
      return console.error(err);
    }
    Users.findOne({ gender: &#39;m&#39; }, (err, user) =&gt; { // 세 번째 콜백
      // 생략
    });
  });
});
}

//위의 콜백 코드를 프로미스로 변경!
function findAndSaveUser(Users) {
Users.findOne({})
  .then((user) =&gt; {
    user.name = &#39;zero&#39;;
    return user.save();
  })
  .then((user) =&gt; {
    return Users.findOne({ gender: &#39;m&#39; });
  })
  .then((user) =&gt; {
    // 생략
  })
  .catch(err =&gt; {
    console.error(err);
  });
}</code></pre>
</li>
</ul>
</li>
<li><p>2.1.8 async/await</p>
<ul>
<li>프로미스를 사용한 코드를 한 번 더 깔끔하게 줄여줌</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">function findAndSaveUser(Users) {
  Users.findOne({})
    .then((user) =&gt; {
      user.name = &#39;zero&#39;;
      return user.save();
    })
    .then((user) =&gt; {
      return Users.findOne({ gender: &#39;m&#39; });
    })
    .then((user) =&gt; {
      // 생략
    })
    .catch(err =&gt; {
      console.error(err);
    });
}

//async/await로 변경한것!
async function findAndSaveUser(Users) {
  let user = await Users.findOne({}); //프로미스 앞에 await 붙임, 함수는 해당 프로미스가 resolve될 때까지 기다린 뒤 다음 로직으로 넘어감
  user.name = &#39;zero&#39;;
  user = await user.save();
  user = await Users.findOne({ gender: &#39;m&#39; }); 
  // 생략
}

//try, catch로 에러 처리
async function findAndSaveUser(Users) {
  try {
    let user = await Users.findOne({});
    user.name = &#39;zero&#39;;
    user = await user.save();
    user = await Users.findOne({ gender: &#39;m&#39; });
    // 생략
  } catch (error) {
    console.error(error);
  }
}

//화살표 사용!!
const findAndSaveUser = async (Users) =&gt; {
  try {
    let user = await Users.findOne({});
    user.name = &#39;zero&#39;;
    user = await user.save();
    user = await Users.findOne({ gender: &#39;m&#39; });
    // 생략
  } catch (error) {
    console.error(error);
  }
};</code></pre>
<ul>
<li>2.1.9 Map/Set<ul>
<li>Map : 객체 리터럴과 비슷, 속성들 간의 순서를 보장하고 반복문 사용 가능, 속성명으로 문자열이 아닌 값도 사용 가능하고, size 메서드를 통해 속성의 수를 알 수 있음</li>
<li>Set: 배열 리터럴과 비슷, 중복 허용X</li>
</ul>
</li>
</ul>
<pre><code class="language-jsx">const m = new Map(); //map 생성

m.set(&#39;a&#39;, &#39;b&#39;); // set(키, 값)으로 Map에 속성 추가
m.set(3, &#39;c&#39;); // 문자열이 아닌 값을 키로 사용 가능합니다
const d = {};
m.set(d, &#39;e&#39;); // 객체도 됩니다

m.get(d); // get(키)로 속성값 조회
console.log(m.get(d)); // e

m.size; // size로 속성 개수 조회
console.log(m.size) // 3

for (const [k, v] of m) { // 반복문에 바로 넣어 사용 가능합니다
  console.log(k, v); // &#39;a&#39;, &#39;b&#39;, 3, &#39;c&#39;, {}, &#39;e&#39;
} // 속성 간의 순서도 보장됩니다

m.forEach((v, k) =&gt; { // forEach도 사용 가능합니다
  console.log(k, v); // 결과는 위와 동일
});

m.has(d); // has(키)로 속성 존재 여부를 확인합니다
console.log(m.has(d)); // true

m.delete(d); // delete(키)로 속성을 삭제합니다
m.clear(); // clear()로 전부 제거합니다
console.log(m.size); // 0</code></pre>
<pre><code class="language-jsx">const s = new Set();
s.add(false); // add(요소)로 Set에 추가합니다
s.add(1);
s.add(&#39;1&#39;);
s.add(1); // 중복이므로 무시됩니다
s.add(2);

console.log(s.size); // 중복이 제거되어 4

s.has(1); // has(요소)로 요소 존재 여부를 확인합니다
console.log(s.has(1)); // true

for (const a of s) {
  console.log(a); // false 1 &#39;1&#39; 2
}

s.forEach((a) =&gt; {
  console.log(a); // false 1 &#39;1&#39; 2
})

s.delete(2); // delete(요소)로 요소를 제거합니다
s.clear(); // clear()로 전부 제거합니다</code></pre>
<ul>
<li><p>2.1.10 널 병합/옵셔널 체이닝</p>
<ul>
<li><p>널 병합(??) : 주로 || 연산자 대용으로 사용되며, falsy 값(0,’’,false,NaN,null,undefined)중 null과 undefined만 따로 구분</p>
<pre><code class="language-jsx">const a = 0;
const b = a || 3; // || 연산자는 falsy 값이면 뒤로 넘어감
console.log(b); // 3

const c = 0;
const d = c ?? 3; // ?? 연산자는 null과 undefined일 때만 뒤로 넘어감
console.log(d); // 0;

const e = null;
const f = e ?? 3;
console.log(f); // 3;

const g = undefined;
const h = g ?? 3;
console.log(h); // 3;</code></pre>
</li>
<li><p>옵셔널 체이닝: null이나 undefine의 속성을 조회하는 경우 에러가 발생하는 것을 막음(?.)</p>
<pre><code class="language-jsx">const a = {}
a.b; // a가 객체이므로 문제없음

const c = null;
try {
c.d;
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading &#39;d&#39;)
//위의 에러 주의!!! -&gt; reading &#39;d&#39;는 d가 null이 아니라 앞에 c 가 null임!!!!
}
c?.d; // 문제없음

try {
c.f();
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading &#39;f&#39;)
}
c?.f(); // 문제없음

try {
c[0];
} catch (e) {
console.error(e); // TypeError: Cannot read properties of null (reading &#39;0&#39;)
}
c?.[0]; // 문제없음</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>