<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kimmoonju-102.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요:) </description>
        <lastBuildDate>Mon, 21 Apr 2025 13:49:59 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kimmoonju-102.log</title>
            <url>https://velog.velcdn.com/images/kimmoonju-102/profile/3daab6b2-648c-4205-81c9-550c89a0ff3b/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kimmoonju-102.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kimmoonju-102" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[ React ] 이미지 압축해서 성능 개선 ( browser-image-compression 라이브러리)]]></title>
            <link>https://velog.io/@kimmoonju-102/React-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%95%95%EC%B6%95%ED%95%B4%EC%84%9C-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0-browser-image-compression-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@kimmoonju-102/React-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%95%95%EC%B6%95%ED%95%B4%EC%84%9C-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0-browser-image-compression-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Mon, 21 Apr 2025 13:49:59 GMT</pubDate>
            <description><![CDATA[<h2 id="browser-image-compression란"><strong>Browser Image Compression</strong>란?</h2>
<blockquote>
<p>서버에 업로드하기 전에 <strong>해상도</strong>나 <strong>저장 크기</strong>를 줄여 <code>jpeg</code>, <code>png</code>, <code>webp</code>, <code>bmp</code> 이미지를 압축할 수 있는 라이브러리입니다.</p>
</blockquote>
<h2 id="사용하게-된-배경">사용하게 된 배경</h2>
<p>프로젝트에서 게시글 작성 시 이미지를 업로드하는 기능을 개발했습니다.</p>
<p>초기에 구현한 방식은 <strong>이미지를 압축 없이 원본 그대로 업로드</strong>하는 방식이었습니다.</p>
<p>하지만 테스트 과정에서 다음과 같은 문제를 발견했습니다.</p>
<ul>
<li>원본 파일 그대로 업로드 시 로딩 속도 저하</li>
<li>렌더링 시간 증가로 UX 품질 저하</li>
</ul>
<p>이를 해결하기 위해 <strong>클라이언트 측에서 먼저 이미지를 압축</strong>한 후 업로드하는 방식으로 개선했습니다.</p>
<blockquote>
<p><strong>사용 방법</strong></p>
<p>압축을 원하는 파일과 옵션을 지정한 뒤, <code>imageCompression</code> 비동기 함수를 사용해 압축 시켜주면 됩니다!</p>
</blockquote>
<h2 id="코드-설명">코드 설명</h2>
<h3 id="💻수정-전-코드">💻수정 전 코드</h3>
<pre><code class="language-jsx">const handleImageChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    const file = e.target.files ? e.target.files[0] : null;
    if (file) {
      // 선택된 파일을 상태로 저장
      setSelctedImageFIle(file);
      const reader = new FileReader();
      reader.onload = () =&gt; {
        setPreviewImage(reader.result as string);
      };
      reader.readAsDataURL(file);
      // 파일 입력 필드 초기화
      e.target.value = &#39;&#39;;
    }
  };</code></pre>
<p><strong>문제점</strong></p>
<ul>
<li>압축되지 않은 파일 업로드</li>
<li>큰 이미지 파일은 네트워크와 렌더링 성능에 부하를 줌</li>
</ul>
<h3 id="💻수정-후-코드">💻수정 후 코드</h3>
<pre><code class="language-jsx">const handleImageChange = async (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    const file = e.target.files?.[0];
    if (!file) return;

    const maxFileSizeMB = 5;
    if (file.size &gt; maxFileSizeMB * 1024 * 1024) {
      alert(`파일 크기가 ${maxFileSizeMB}MB를 초과했습니다.`);
      return;
    }
        // 이미지 옵션
    const options = {
      maxSizeMB: 0.2,
      maxWidthOrHeight: 1226,
      useWebWorker: true,
    };

    try {
      // 이미지 압축
      const compressedBlob = await imageCompression(file, options);
      const compressedFile = new File([compressedBlob], file.name, {
        type: file.type,
        lastModified: Date.now(),
      });

      setSelectedImageFile(compressedFile);

      // 미리보기 이미지 생성
      const reader = new FileReader();
      reader.onload = () =&gt; setPreviewImage(reader.result as string);
      reader.readAsDataURL(compressedFile);

      // 파일 입력 필드 초기화
      e.target.value = &#39;&#39;;
    } catch (error) {
      alert(&#39;이미지를 처리하는 도중 오류가 발생했습니다. 다시 시도해 주세요.&#39;);
    }
  };</code></pre>
<p><strong>개선된 점</strong></p>
<ul>
<li>서버에서 5MB 제한을 지정해줌 → 사용자에게 명확한 피드백 제공</li>
<li>최대 크기 0.2MB로 압축 → 게시글 권장 크기(100~200KB) 준수</li>
<li>최대 너비 또는 높이 1224px 제한</li>
<li>압축 후 Blob → File 변환<ul>
<li>서버 업로드를 위한 일관된 파일 형식 유지</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>1224px 결정 이유</strong></p>
<p>업로드된 이미지가 다양한 페이지에서 사용되는데,</p>
<p>가장 작은 사이즈에 맞추면 다른 뷰에서 이미지가 깨질 위험이 있었습니다.</p>
<p>그래서 여러 화면에서 가장 무난하고 균형 잡힌 크기로 보이도록 1224px로 지정했습니다.</p>
</blockquote>
<h3 id="결과">결과</h3>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/80e977ad-0fd4-405d-ab51-05fa7a984c64/image.jpg" alt=""></p>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/6f7cea27-7d9a-4b57-9c3f-86249a80135d/image.jpg" alt=""></p>
<p>같은 이미지를 개선 전·후 적용해본 결과, <strong>파일 크기는 4.3MB → 145KB, 로딩 시간은 1.01초 → 820ms로 개선</strong>되었습니다. 이로 <strong>인해 페이지 로딩 속도 향상, 사용자 경험 개선을 향상</strong> 시켰습니다.</p>
<blockquote>
<p><strong>라이브러리</strong>
<a href="https://www.npmjs.com/package/browser-image-compression">https://www.npmjs.com/package/browser-image-compression</a>
<strong>더 자세한 코드는 깃허브 참고</strong>
<a href="https://github.com/Co-Drive/Driver-Client/pull/369">https://github.com/Co-Drive/Driver-Client/pull/369</a> </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ JS ] this]]></title>
            <link>https://velog.io/@kimmoonju-102/JS-this</link>
            <guid>https://velog.io/@kimmoonju-102/JS-this</guid>
            <pubDate>Thu, 17 Apr 2025 13:34:03 GMT</pubDate>
            <description><![CDATA[<h1 id="this란">this란?</h1>
<p><code>this</code>는 <em>자신이 속한 객체</em>를 가리킨다.</p>
<p>하지만 함수 호출 방식에 따라 <code>this</code>가 참조하는 값은 달라진다. (동적 바인딩)</p>
<p>이번 글에서는 <strong>일반 함수 호출</strong>, <strong>메서드 호출</strong>, <strong>생성자 함수 호출</strong>, <strong>콜백 함수 호출</strong> 네 가지 상황에서 <code>this</code>가 어떻게 바뀌는지 정리해보자!</p>
<hr>
<h2 id="1-일반-함수-호출">1. 일반 함수 호출</h2>
<p>일반 함수로 호출했을 때, <code>this</code>는 <strong>전역 객체</strong>를 가리킨다.</p>
<p>(브라우저에서는 <code>window</code>, Node.js에서는 <code>global</code>)</p>
<pre><code class="language-jsx">
console.log(this);
// 브라우저 → window 객체 출력
</code></pre>
<pre><code class="language-jsx">
function func() {
  console.log(this);
}

func();
// 일반 함수로 호출 → this는 window
</code></pre>
<hr>
<h2 id="2-메서드-호출">2. 메서드 호출</h2>
<p><strong>메서드</strong>는 <em>객체의 프로퍼티로 등록된 함수</em>를 말한다.</p>
<p>메서드로 호출하면, <code>this</code>는 <strong>그 메서드를 소유한 객체</strong>를 가리킨다.</p>
<pre><code class="language-jsx">
const cafe = {
  brand: &quot;이디야&quot;,
  menu: &quot;커피&quot;,
  newCafe: {
    brand: &quot;커피&quot;,
    menu: &quot;음료&quot;,
    print: function () {
      console.log(this);
    },
  },
};

cafe.newCafe.print();
// → { brand: &#39;커피&#39;, menu: &#39;음료&#39;, print: ƒ }
</code></pre>
<p>✅ 요점:</p>
<ul>
<li><code>cafe.newCafe.print()</code> 호출 시 <code>this</code>는 <code>newCafe</code> 객체를 가리킨다.</li>
</ul>
<hr>
<h2 id="3-메서드를-일반-함수처럼-호출한-경우">3. 메서드를 일반 함수처럼 호출한 경우</h2>
<p>메서드를 변수에 할당하고 호출하면 어떻게 될까?</p>
<pre><code class="language-jsx">
const game = {
  name: &quot;answn&quot;,
  age: &quot;29&quot;,
  print: function () {
    console.log(this);
  },
};

const myGame = game.print;
myGame();
// 일반 함수 호출 → this는 window
</code></pre>
<p>✅ 요점:</p>
<ul>
<li><code>game.print</code>는 객체에 묶여있지만 <code>myGame</code>에 할당하는 순간 연결이 끊긴다.</li>
<li><code>myGame()</code>을 일반 함수처럼 호출했기 때문에 <code>this</code>는 전역 객체(<code>window</code>)를 가리킨다.</li>
</ul>
<hr>
<h2 id="중간-요약">중간 요약</h2>
<table>
<thead>
<tr>
<th>호출 방식</th>
<th>this 값</th>
</tr>
</thead>
<tbody><tr>
<td>일반 함수 호출</td>
<td>전역 객체 (<code>window</code>, <code>global</code>)</td>
</tr>
<tr>
<td>메서드 호출</td>
<td>메서드를 소유한 객체</td>
</tr>
</tbody></table>
<hr>
<h2 id="4-생성자-함수-호출">4. 생성자 함수 호출</h2>
<p><strong>생성자 함수</strong>는 <code>new</code> 키워드와 함께 호출해서 <strong>새로운 객체</strong>를 만든다.</p>
<pre><code class="language-jsx">
function Cafe(menu) {
  console.log(this); // Cafe {}
  this.menu = menu;
}

let myCafe = new Cafe(&quot;latte&quot;);
console.log(myCafe);
// → Cafe { menu: &#39;latte&#39; }
</code></pre>
<p>✅ 요점:</p>
<ul>
<li><code>new Cafe(&quot;latte&quot;)</code> 호출 시, 새로운 객체가 생성되고 <code>this</code>는 그 객체를 가리킨다.</li>
</ul>
<h3 id="만약-new-없이-호출한다면">만약 <code>new</code> 없이 호출한다면?</h3>
<pre><code class="language-jsx">
let myCafe = Cafe(&quot;latte&quot;);
</code></pre>
<ul>
<li><strong>일반 함수 호출</strong>로 취급된다.</li>
<li><code>this</code>는 전역 객체(<code>window</code>)를 가리킨다.</li>
<li><code>menu</code>가 <code>window.menu</code>로 설정된다.</li>
<li>반환값이 없기 때문에 <code>myCafe</code>는 <code>undefined</code>가 된다.</li>
</ul>
<pre><code class="language-jsx">
console.log(window.menu); // &quot;latte&quot;
console.log(myCafe); // undefined
</code></pre>
<hr>
<h2 id="5-콜백-함수-호출">5. 콜백 함수 호출</h2>
<p>콜백 함수에서는 <code>this</code>가 예상과 다를 수 있다.</p>
<pre><code class="language-jsx">
const game = {
  name: &quot;answn&quot;,
  age: &quot;&quot;,
  setGame: function (age) {
    this.age = age;
  },
};
</code></pre>
<p><code>setGame</code>은 전달받은 <code>age</code>를 <code>game</code> 객체의 <code>age</code> 프로퍼티에 할당하는 메서드다.</p>
<h3 id="문제-상황">문제 상황</h3>
<pre><code class="language-jsx">
function getGame(age, callback) {
  callback(age);
}

getGame(&quot;29&quot;, game.setGame);

console.log(game);
// { name: &#39;answn&#39;, age: &#39;&#39;, setGame: ƒ }
</code></pre>
<p>❌ <code>game.age</code>가 기대했던 <code>&quot;29&quot;</code>로 업데이트되지 않았다.</p>
<h3 id="이유는">이유는?</h3>
<ul>
<li><code>getGame</code> 안에서 <code>callback(age)</code>를 <strong>일반 함수 호출</strong>로 실행했다.</li>
<li>콜백이 객체와 분리되어 <strong>this가 전역 객체(window)</strong> 를 가리키게 됐다.</li>
<li>결과적으로 <code>window.age = &quot;29&quot;</code>가 되어버렸다.</li>
</ul>
<pre><code class="language-jsx">console.log(window.age); // &quot;29&quot;
</code></pre>
<hr>
<h2 id="최종-요약">최종 요약</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>this 값</th>
</tr>
</thead>
<tbody><tr>
<td>일반 함수 호출</td>
<td>전역 객체 (<code>window</code>)</td>
</tr>
<tr>
<td>메서드 호출</td>
<td>메서드를 소유한 객체</td>
</tr>
<tr>
<td>생성자 함수 호출</td>
<td>새로 생성된 객체</td>
</tr>
<tr>
<td>콜백 함수 호출 (일반)</td>
<td>전역 객체 (<code>window</code>)</td>
</tr>
<tr>
<td>콜백 함수 호출 (화살표 함수)</td>
<td>원하는 객체</td>
</tr>
</tbody></table>
<hr>
<h2 id="한-줄-정리">한 줄 정리</h2>
<blockquote>
<p>&quot;함수가 어떻게 호출되었느냐&quot;에 따라 this가 결정된다.</p>
<p>new 키워드, 호출 방식, 콜백 전달 방식에 주의하자.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ JS ] DOM, DOM 트리, DOM API란?]]></title>
            <link>https://velog.io/@kimmoonju-102/DOM-DOM-%ED%8A%B8%EB%A6%AC-DOM-API%EB%9E%80</link>
            <guid>https://velog.io/@kimmoonju-102/DOM-DOM-%ED%8A%B8%EB%A6%AC-DOM-API%EB%9E%80</guid>
            <pubDate>Wed, 16 Apr 2025 07:00:13 GMT</pubDate>
            <description><![CDATA[<h2 id="dom이란">DOM이란?</h2>
<p><strong>DOM</strong>(Document Object Model)은 HTML 문서를 브라우저가 이해하고 자바스크립트로 조작할 수 있도록 <strong>객체(Object) 형태로 구조화한 모델</strong>이다.</p>
<p>HTML 요소들을 트리 형태로 구성하여 자바스크립트가 이 구조에 접근하고, 내용을 <strong>읽거나 수정하거나 삭제</strong>할 수 있게 만든 것이다.</p>
<ul>
<li>DOM은 프로그래밍 언어와 독립적으로 설계된 API를 기반으로 동작한다.</li>
<li>자바스크립트를 통해 DOM을 조작함으로써 웹페이지를 동적으로 제어할 수 있다.</li>
</ul>
<hr>
<h2 id="dom-트리란">DOM 트리란?</h2>
<p>HTML 문서는 계층적인 구조를 가지고 있고, 브라우저는 이를 <strong>트리 형태의 객체 구조</strong>로 변환한다. 이 구조를 <strong>DOM 트리</strong>라고 부른다.</p>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/0e2acf3d-c567-49d3-ae68-5252a164624e/image.png" alt=""></p>
<h3 id="dom-트리의-특징">DOM 트리의 특징</h3>
<ul>
<li>각 HTML 요소는 <strong>노드(Node)</strong>로 표현된다.</li>
<li>노드들은 <strong>부모-자식 관계</strong>를 이루며 연결된다.</li>
<li>최상단의 <code>&lt;html&gt;</code> 요소가 <strong>루트 노드(root node)</strong>가 된다.</li>
</ul>
<h3 id="주요-노드-종류">주요 노드 종류</h3>
<table>
<thead>
<tr>
<th>노드 타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Element Node</td>
<td><code>&lt;div&gt;</code>, <code>&lt;p&gt;</code> 같은 요소 노드</td>
</tr>
<tr>
<td>Text Node</td>
<td>텍스트(콘텐츠)</td>
</tr>
<tr>
<td>Attribute Node</td>
<td><code>class</code>, <code>id</code> 등 속성 값</td>
</tr>
</tbody></table>
<p>이러한 트리 구조 덕분에 특정 요소를 찾아내고, 삭제하거나 변경할 수 있다.</p>
<hr>
<h2 id="dom-api">DOM API</h2>
<p>자바스크립트는 다양한 <strong>DOM API</strong>를 통해 HTML 요소에 접근하고, 이를 조작할 수 있다.</p>
<h3 id="1-요소-선택하기">1. 요소 선택하기</h3>
<pre><code class="language-jsx">document.getElementById(&#39;myId&#39;)
document.querySelector(&#39;.my-class&#39;)
document.querySelectorAll(&#39;div &gt; p&#39;)
</code></pre>
<ul>
<li><code>getElementById</code>, <code>querySelector</code>, <code>querySelectorAll</code> 등은 DOM 트리에서 노드를 찾을 때 사용됩니다.</li>
</ul>
<h3 id="2-속성-변경">2. 속성 변경</h3>
<pre><code class="language-jsx">const element = document.querySelector(&#39;#title&#39;)
element.textContent = &#39;새로운 제목&#39;
element.setAttribute(&#39;data-role&#39;, &#39;header&#39;)
</code></pre>
<ul>
<li><code>textContent</code>: 텍스트 변경</li>
<li><code>setAttribute</code>, <code>getAttribute</code>: HTML 속성 조작</li>
</ul>
<h3 id="3-클래스-조작">3. 클래스 조작</h3>
<pre><code class="language-jsx">element.classList.add(&#39;active&#39;)  // 클래스 추가
element.classList.remove(&#39;hidden&#39;) // 클래스 제거
element.classList.toggle(&#39;on&#39;) // 클래스 토글
</code></pre>
<p>📍 예시:
버튼 클릭 시 &#39;on&#39; 클래스를 추가해서 스타일을 바꾸거나, &#39;hidden&#39; 클래스를 제거해 요소를 보이게 만들 수 있다.</p>
<h3 id="4-dom-요소-생성삽입삭제">4. DOM 요소 생성/삽입/삭제</h3>
<pre><code class="language-jsx">const newElement = document.createElement(&#39;div&#39;)
newElement.textContent = &#39;새로운 요소&#39;

// 삽입
document.body.appendChild(newElement)

// 삭제
document.body.removeChild(newElement)
</code></pre>
<p>❗removeChild()는 반드시 부모 요소가 자식 요소를 제거하는 형태여야 작동한다.
<br/></p>
<p>💻참고 사이트</p>
<ul>
<li><a href="https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model">https://developer.mozilla.org/ko/docs/Web/API/Document_Object_Model</a></li>
<li><a href="https://ko.javascript.info/dom-nodes">https://ko.javascript.info/dom-nodes</a></li>
<li><a href="https://yozm.wishket.com/magazine/detail/1803/">https://yozm.wishket.com/magazine/detail/1803/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ JS ] 스코프]]></title>
            <link>https://velog.io/@kimmoonju-102/JS-%EC%8A%A4%EC%BD%94%ED%94%84</link>
            <guid>https://velog.io/@kimmoonju-102/JS-%EC%8A%A4%EC%BD%94%ED%94%84</guid>
            <pubDate>Fri, 04 Apr 2025 06:31:31 GMT</pubDate>
            <description><![CDATA[<h1 id="▪︎-스코프란">▪︎ 스코프란?</h1>
<p>모든 식별자(변수, 함수, 클래스 등)는 <strong>자신이 선언된 위치에 따라</strong> 참조할 수 있는 <strong>유효 범위(scope)</strong>가 결정된다. 이를 <strong>스코프</strong>라고 하며, 크게 <strong>전역 스코프</strong>와 <strong>지역 스코프</strong>로 나눌 수 있다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
<th>스코프</th>
<th>변수 종류</th>
</tr>
</thead>
<tbody><tr>
<td>전역</td>
<td>코드의 가장 바깥 영역</td>
<td>전역 스코프</td>
<td>전역 변수</td>
</tr>
<tr>
<td>지역</td>
<td>함수나 블록 내부</td>
<td>지역 스코프</td>
<td>지역 변수</td>
</tr>
</tbody></table>
<hr>
<h2 id="▫︎-전역-스코프">▫︎ 전역 스코프</h2>
<ul>
<li>코드의 가장 바깥 영역에 선언된 변수는 어디서든 <strong>전역적으로 참조 가능</strong>하다.</li>
<li>예를 들어 함수 바깥에서 선언된 변수는 모든 함수 내부에서 사용할 수 있다.</li>
</ul>
<h2 id="▫︎-지역-스코프">▫︎ 지역 스코프</h2>
<ul>
<li>지역 변수는 <strong>자신이 선언된 지역과 하위 지역에서만</strong> 참조할 수 있다.</li>
<li>즉, 특정 함수나 블록 내부에서 선언된 변수는 <strong>그 범위 내에서만 유효</strong>하다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/b54599d0-f9da-486c-97ad-7ab67c9fb2cc/image.png" alt=""></p>
<p>예시 설명:</p>
<ul>
<li><code>outer</code> 함수 내부에서 선언된 <code>z</code> 변수는 지역 변수이며,<ul>
<li><code>outer</code> 함수 내부와 그 하위 지역인 <code>inner</code> 함수에서도 참조할 수 있다.</li>
<li>하지만 전역 스코프에서는 참조할 수 없기 때문에 참조 에러가 발생한다.</li>
</ul>
</li>
<li><code>inner</code> 함수 내부에서 선언된 <code>x</code> 변수는 <code>inner</code> 함수 안에서만 참조할 수 있다.<ul>
<li>전역 스코프 또는 <code>outer</code> 함수에서는 참조할 수 없으며, 참조 시 에러가 발생한다.</li>
</ul>
</li>
</ul>
<h2 id="▫︎-스코프-체인">▫︎ 스코프 체인</h2>
<ul>
<li>스코프는 <strong>함수의 중첩 구조</strong>에 따라 계층적으로 형성된다.</li>
<li>자바스크립트 엔진은 변수를 참조할 때 <strong>자신의 스코프에서 시작하여 상위 스코프 방향으로</strong> 올라가며 식별자를 검색한다.</li>
<li>이를 <strong>스코프 체인</strong>이라고 하며, 다음과 같은 특징이 있다:<ul>
<li><strong>하위 스코프</strong>에서는 상위 스코프의 변수를 자유롭게 참조할 수 있다.</li>
<li>반대로 <strong>상위 스코프</strong>에서는 하위 스코프의 변수에 접근할 수 없다.</li>
</ul>
</li>
</ul>
<h2 id="▫︎-코드의-문맥과-환경-렉시컬-환경--실행-컨텍스트">▫︎ 코드의 문맥과 환경: 렉시컬 환경 &amp; 실행 컨텍스트</h2>
<ul>
<li><strong>렉시컬 환경</strong>: 코드가 <strong>어디에서, 어떤 문맥에서 선언되었는지</strong>를 의미하며, 스코프의 기반이 된다.</li>
<li><strong>실행 컨텍스트</strong>는 이러한 렉시컬 환경을 <strong>구현한 개념</strong>으로, 코드가 평가되고 실행되는 환경이다.</li>
</ul>
<h2 id="▫︎-식별자란">▫︎ 식별자란?</h2>
<ul>
<li><strong>식별자</strong>는 변수, 함수, 클래스 등의 <strong>이름을 나타내는 고유한 문자열</strong>이다.</li>
<li>동일한 스코프 내에서는 <strong>중복될 수 없으며</strong>, 하나의 값은 하나의 식별자에만 연결되어야 한다.</li>
</ul>
<h2 id="▫︎-var-let-const의-스코프-차이">▫︎ var, let, const의 스코프 차이</h2>
<h3 id="🔹-블록-레벨-스코프-let-const">🔹 블록 레벨 스코프 (<code>let</code>, <code>const</code>)</h3>
<ul>
<li><code>let</code>과 <code>const</code>는 <strong>코드 블록</strong>(<code>{}</code>)을 기준으로 스코프가 생성된다.</li>
<li><code>if</code>, <code>for</code>, <code>while</code>, <code>try/catch</code> 등 모든 코드 블록 내에서 유효한 스코프를 <strong>블록 레벨 스코프</strong>라 부른다.</li>
<li>동일한 스코프 내에서 <strong>중복 선언이 허용되지 않는다.</strong></li>
</ul>
<pre><code class="language-js">function bar() {
  let x = 1;
  let x = 2; // ❌ SyntaxError: Identifier &#39;x&#39; has already been declared
}
bar();
</code></pre>
<h3 id="🔹-함수-레벨-스코프-var">🔹 함수 레벨 스코프 (var)</h3>
<ul>
<li><p>var는 오직 함수 코드 블록만을 지역 스코프로 인식한다.</p>
</li>
<li><p>블록(if, for 등) 안에서 선언해도 함수 전체에서 접근 가능하다.</p>
</li>
<li><p>동일한 스코프 내에서 중복 선언이 허용되며, 의도치 않게 변수값이 덮어쓰일 수 있다.</p>
</li>
</ul>
<pre><code class="language-js">function example() {
  var y = 1;
  var y = 2; // ✅ 가능하지만 예기치 않은 동작을 유발할 수 있음
  console.log(y); // 2
}
example();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ JS ] Early Return]]></title>
            <link>https://velog.io/@kimmoonju-102/JS-Early-Return</link>
            <guid>https://velog.io/@kimmoonju-102/JS-Early-Return</guid>
            <pubDate>Wed, 02 Apr 2025 02:12:20 GMT</pubDate>
            <description><![CDATA[<h1 id="early-return란">Early Return란?</h1>
<p>우선, 중첩된 조건문을 사용하는 코드를 확인해 봅시다.</p>
<pre><code class="language-jsx">function compare(num) {
  if (num === 0) {
    console.log(&quot;num의 값이 0입니다.&quot;);
  } else if (num &lt; 0) {
    console.log(&quot;num의 값이 0보다 작습니다.&quot;);
  } else {
    if (num &gt;= 10) {
      console.log(&quot;num의 값이 10보다 크거나 같습니다.&quot;);
    } else {
      console.log(&quot;num의 값이 0보다 크고 10보다 작습니다.&quot;);
    }
  }
} </code></pre>
<p>위 코드는 <code>if-else</code> 문이 중첩되어 있어 가독성이 떨어집니다. 이를 <strong>Early Return 패턴</strong>을 적용해 개선할 수 있습니다.</p>
<pre><code class="language-jsx">function compare(num) {
  if (num === 0) {
    return &quot;num의 값이 0입니다.&quot;;
  }
  if (num &lt; 0) {
    return &quot;num의 값이 0보다 작습니다.&quot;;
  }
  if (num &gt;= 0) {
    return &quot;num의 값이 10보다 크거나 같습니다.&quot;;
  }
  return &quot;num의 값이 0보다 크고 10보다 작습니다.&quot;;
}</code></pre>
<h2 id="✔-early-return을-사용하는-이유">✔ Early Return을 사용하는 이유</h2>
<p>위 코드처럼 조건을 만족하면 <strong>즉시 return하여 불필요한 else를 없앨 수 있습니다.</strong></p>
<p>이를 통해 <strong>중첩된 조건문을 줄이고, 가독성을 높이며, 코드의 흐름을 단순화</strong>할 수 있습니다.</p>
<p>우테코 프리코스에서는 <strong>else를 사용하지 않는 것을 요구사항으로 명시</strong>하기도 하는데,</p>
<p>그 이유는 <strong>불필요한 중첩을 방지하여 코드를 읽기 쉽게 하기 위함</strong>입니다.</p>
<p>하지만 <strong>무조건 Early Return을 적용하는 것이 항상 좋은가?</strong>에 대해서는 고민이 필요합니다.</p>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/2e4dddf6-ba63-4465-96fd-8bb7053b8785/image.png" alt=""></p>
<h2 id="✅-early-return의-장점"><strong>✅ Early Return의 장점</strong></h2>
<ul>
<li>중첩 조건문을 줄여 코드의 <strong>가독성을 높이고</strong> 읽기 쉽게 만든다.</li>
<li>조건이 추가될 때 깊은 중첩을 방지할 수 있다.</li>
<li>빠르게 특정 조건을 검사하고 함수 실행을 종료할 수 있다.</li>
</ul>
<h2 id="❌-early-return의-단점">❌ Early Return의 단점</h2>
<ul>
<li>함수 내에 <strong>여러 개의 return이 존재하면 흐름을 추적하기 어려울 수 있다.</strong></li>
<li><strong>코드가 지나치게 여러 곳에서 return하면 유지보수가 어려워질 가능성이 있다.</strong></li>
<li>특정 상황에서는 <code>if-else</code>보다 흐름을 이해하기 어려울 수 있다.</li>
</ul>
<h3 id="결론"><strong>결론</strong></h3>
<p>Early return 패턴은 적절히 활용하면 <strong>가독성과 유지보수성을 높일 수 있는 강력한 패턴</strong>이지만,</p>
<p>너무 남용하면 오히려 <strong>코드 흐름을 이해하기 어렵게 만들 수도 있습니다.</strong></p>
<p>따라서 <strong>상황에 맞게 사용하는 것이 중요합니다!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ CS ] 쿠키]]></title>
            <link>https://velog.io/@kimmoonju-102/CS-%EC%BF%A0%ED%82%A4</link>
            <guid>https://velog.io/@kimmoonju-102/CS-%EC%BF%A0%ED%82%A4</guid>
            <pubDate>Mon, 24 Feb 2025 03:03:30 GMT</pubDate>
            <description><![CDATA[<h2 id="🍪-쿠키cookie란">🍪 쿠키(Cookie)란?</h2>
<blockquote>
<p>쿠키는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각으로, 브라우저가 저장했다가 동일한 서버에 재요청 시 함께 전송하는 방식으로 동작합니다. HTTP 요청을 수신할 때, 서버는 응답과 함께 Set-Cookie 헤더를 전송할 수 있으며, 이후 해당 쿠키는 같은 서버로 보내는 요청의 Cookie 헤더에 포함됩니다.</p>
</blockquote>
<h2 id="📌-쿠키의-목적">📌 쿠키의 목적</h2>
<p>쿠키는 두 요청이 동일한 브라우저에서 들어왔는지를 판단하는 데 사용됩니다. 주요 목적은 다음과 같습니다.</p>
<p>세션 관리</p>
<ul>
<li>로그인, 장바구니, 게임 스코어 등의 정보를 유지하는 데 활용됩니다. (예: 로그인 상태 유지)</li>
</ul>
<p>개인화</p>
<ul>
<li>사용자 선호도, 테마 설정 등을 저장하여 개인 맞춤 환경을 제공합니다. (예: 다크 모드, 언어 설정)</li>
</ul>
<p>트래킹</p>
<ul>
<li>사용자 행동을 기록하고 분석하는 용도로 사용됩니다. (예: 광고 맞춤화)</li>
</ul>
<p>쿠키는 다양한 활용이 가능하지만, 보안 및 개인정보 보호 측면에서 단점이 있습니다. 정보가 클라이언트 측에 저장되기 때문에 악용될 가능성이 있으며, 보안에 취약할 수 있습니다. 이를 보완하기 위해 Secure 속성을 설정하여 HTTPS에서만 전송되도록 하고, HttpOnly 속성을 추가하여 JavaScript 접근을 차단할 수 있습니다. 또한 SameSite 속성을 이용해 CSRF(사이트 간 요청 위조) 공격을 방지하고, 쿠키 암호화를 통해 중요한 정보를 직접 저장하지 않는 것이 좋습니다.</p>
<h2 id="📌-쿠키가-만들어지는-과정">📌 쿠키가 만들어지는 과정</h2>
<ol>
<li><p>사용자가 페이지에 접근</p>
</li>
<li><p>서버에서 Set-Cookie 헤더를 포함하여 응답</p>
</li>
<li><p>브라우저가 쿠키를 저장</p>
</li>
<li><p>사용자가 페이지에 다시 접근할 때 저장된 쿠키를 서버로 전송</p>
</li>
<li><p>서버에서 해당 쿠키를 인식하고 처리</p>
</li>
<li><p>쿠키 값이 변경되었다면, 업데이트된 정보로 다시 저장</p>
</li>
</ol>
<h2 id="📌-쿠키의-종류">📌 쿠키의 종류</h2>
<p><strong>세션 쿠키 (Session Cookie)</strong> : 브라우저 종료 시 삭제되며, 로그인 세션 유지 등에 사용됩니다.</p>
<p><strong>영구 쿠키 (Persistent Cookie)</strong> : 만료 날짜(Expires 또는 Max-Age)가 설정되어 일정 기간 동안 유지됩니다. 자동 로그인, 사용자 설정 저장 등에 활용됩니다.</p>
<p><strong>퍼스트파티 쿠키 (First-Party Cookie)</strong> : 사용자가 방문한 웹사이트에서 직접 생성한 쿠키로, 로그인 상태 유지 등 사용자 경험 개선에 사용됩니다.</p>
<p><strong>서드파티 쿠키 (Third-Party Cookie)</strong> : 광고 업체 등 다른 도메인에서 제공하는 쿠키로, 사용자 추적 및 광고 맞춤화에 사용됩니다. 최근 브라우저 정책에 따라 점점 차단되고 있습니다. (예: Chrome의 서드파티 쿠키 차단 정책)</p>
<h2 id="📌-정리">📌 정리</h2>
<p>웹 쿠키는 사용자 경험을 향상시키고 맞춤형 서비스를 제공하는 데 중요한 역할을 하지만, 보안 및 개인정보 보호 측면에서 취약할 수 있습니다. 따라서 적절한 설정이 필요하며, 경우에 따라 쿠키가 아닌 LocalStorage나 SessionStorage와 같은 대체 저장 방식을 활용하여 보안을 강화하는 것이 좋습니다. 웹 개발 시 쿠키의 활용과 보안 설정을 고려하여 안전하고 효율적인 환경을 구축하는 것이 중요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 리액트란?]]></title>
            <link>https://velog.io/@kimmoonju-102/React%EB%9E%80</link>
            <guid>https://velog.io/@kimmoonju-102/React%EB%9E%80</guid>
            <pubDate>Fri, 15 Mar 2024 11:39:32 GMT</pubDate>
            <description><![CDATA[<h1 id="react란">React란?</h1>
<blockquote>
<p>Meta(Facebook)이 개발한 오픈소스 JavaScript 라이브러리로서, 사용자 인터페이스를 구축하기 위해 사용된다. </p>
</blockquote>
<h2 id="react의-기술적인-특징">React의 기술적인 특징</h2>
<ol>
<li>컴포넌트를 기반으로 UI를 표현한다.</li>
<li>화면 업데이트 구현이 쉽다.</li>
<li>화면 업데이트가 빠르게 처리된다.<br/>


</li>
</ol>
<h3 id="1-컴포넌트를-기반으로-ui를-표현한다">1. 컴포넌트를 기반으로 UI를 표현한다.</h3>
<p>페이지의 모든 요소를 컴포넌트라는 단위로 모듈화해서 개발하기 때문에 여러 페이지에서 공통으로 사용되는 요소가 필요할 때 필요한 컴포넌트를 만들고 불러와서 사용한다. 이와 같이 사용하면 좋은 점은 중복 코드가 발생 하지 않고, 재사용할 수 있게 만들 수 있어서 유지보수가 쉽고 확장하기 용이한 코드를 작성할 수 있다.</p>
<h3 id="2-화면-업데이트-구현이-쉽다">2. 화면 업데이트 구현이 쉽다.</h3>
<p>여기서 업데이트란?
사용자의 이벤트에 따라 웹페이지가 스스로 모습을 바꿔 상호작용하는 것을 말한다.</p>
<p><strong>React는 선언형 프로그래밍이다.</strong></p>
<blockquote>
<p><strong>선언형 프로그래밍이란?</strong>
과정은 생략하고 목적만 간결히 명시하는 방법 (코드가 간결함)</p>
</blockquote>
<p>페이지를 컴포넌트 단위로 개발하게 되는데 컴포넌트에는 state(상태) 현재 상태를 저장하는 변수를 저장할 수 있다. state의 값이 바뀌면 컴포넌트가 바뀐 state 값에 따라 각각 다른 UI를 화면에 렌더링 하도록 설정할 수 있다. </p>
<h3 id="3-화면-업데이트가-빠르게-처리된다">3. 화면 업데이트가 빠르게 처리된다.</h3>
<p>자바스크립트로 DOM을 수정해서 업데이트를 구현할 때 DOM 수정 횟수를 최소화 해야 되기 때문에 
다양한 업데이트들이 있을 때 한 번 한 번 다 수정시키도록 만드는 게 아니라 어딘가의 변수라든지 등등의 장소에 업데이트들을 다 모아두었다가 한 번만 DOM을 수정할 수 있도록 각별히 신경을 써줘야 한다.</p>
<p>위에 설명한 이러한 작업을 리액트는 자동으로 처리해 준다. *<em>(Virtual DOM) *</em>
그렇기 때문에 우리가 리액트를 쓸 때는 아무리 많은 업데이트를 동시에 발생시킨다고 하더라도 대부분의 상황에 충분히 빠르게 업데이트를 구현할 수 있도록 도와준다. </p>
<blockquote>
<p><strong>Virtual DOM(가상 돔) 이란?</strong></p>
</blockquote>
<ul>
<li>실제 돔과 같은 내용을 담고 있는 복사본이라 생각하면 된다. 복사본은 실제 돔이 아닌 자바스크립트 객체 형태로 메로리 안에 저장되어 있다.</li>
<li>리액트는 두 개의 가상 돔을 갖고 있다.<ul>
<li>첫 번째 가상 돔은 변경 이전의 내용을 담고 있다.<ul>
<li>두 번째 가상 돔은 변경 이후에 보여질 내용을 담고 있다.</li>
</ul>
</li>
</ul>
</li>
<li>변경된 내용이 화면에 새롭게 그려지기 이전, 곧 실제 DOM이 변경되기 이전에 리액트는 두 개의 가상 돔을 비교해서 정확히 어떤 부분이 바뀌었는지 비교하여 파악한다. 그리고 이러한 과정을 Diffing이라고 부른다. </li>
<li>Diffing을 통해서 변경된 부분들을 파악한 이후에, 리액트는 Batch Update를 수행함으로 실제 DOM에 한 번에 적용시켜 준다. 그리고 이러한 과정을 Reconsiliation, 재조정이라고 한다.</li>
</ul>
<br/>

<h3 id="참고">참고</h3>
<blockquote>
<p><a href="https://ko.legacy.reactjs.org/">https://ko.legacy.reactjs.org/</a>
<a href="https://www.youtube.com/watch?v=gc-kXt0tjTM">https://www.youtube.com/watch?v=gc-kXt0tjTM</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[session, JWT, OAuth 대해 알아보자]]></title>
            <link>https://velog.io/@kimmoonju-102/session-JWT-OAuth-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@kimmoonju-102/session-JWT-OAuth-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Fri, 01 Mar 2024 02:26:15 GMT</pubDate>
            <description><![CDATA[<p>모든 웹 페이지에는 로그인과 회원가입 기능이 들어가 있다. 그중에 로그인이 어떻게 동작하고 있는지 알아보자. </p>
<h3 id="로그인회원가입-기능-동작-방식">로그인/회원가입 기능 동작 방식</h3>
<p>우선 로그인과 회원가입이 어떻게 동작하는지 어떤 방식이 있는지 가볍게 알아보고, 로그인 기능부터 알아보자.</p>
<p><strong>회원가입</strong></p>
<ul>
<li>유저가 회원가입을 하면 아이디/비번을 DB에 저장해 둔다.</li>
</ul>
<p><strong>로그인</strong></p>
<ul>
<li>유저가 로그인 시 아이디/비번을 서버로 보낸다.</li>
<li>서버는 DB에 있는 아이디/비번과 유저가 보낸 아이디/비번이 일치하는 경우 입장권을 발급해 준다.</li>
</ul>
<p>*<em>로그인이 필요한 서버 기능 *</em></p>
<ul>
<li>유저는 서버에 GET/POST로 데이터 요청 시 입장권도 함께 제시한다.</li>
<li>서버는 입장권 확인 후 데이터나 페이지 보내준다.
여기서 입장권을 만들 땐 대표적으로 session, token 방식이 있다.<br/>

</li>
</ul>
<h3 id="session-방식">session 방식</h3>
<p>세션이란 쉽게 말하면 서버의 컴퓨터(서버에 세션 저장소)에 클라이언트의 정보를 기억하고 유지하는 것이다. 유저(정확히는 브라우저)가 로그인을 하였다면 서버의 컴퓨터(세션 저장소)에서 사용자 정보(주로 브라우저에 쿠키에 저장하게 된다)를 확인한 뒤 확인되었다면 일정 시간 동안 유지시키며 이후 사용자가 서비스를 요청할 때마다 세션 저장소에서 세션을 조회하고 작업을 처리하는 방식이다.</p>
<p>서버 측에 { 유저의 아이디, 로그인 날짜, 유효기간, <code>session id</code> } 등의 유저의 정보를 저장하고, <code>식별자(Session ID)</code>값을 클라이언트 쿠키에 남겨둔 후 사용자 상태를 유지하기 위해 세션 <code>식별자(Session ID)</code>를 사용합니다. 이러한 <strong>장점은 매번 GET/POST 요청할 때 마다 DB를 조회해 보기 때문에 하나하나의 요청마다 엄격하게 유저를 체크해볼 수 있고, 세션 ID값만 가지고 접근할 수 있고 저장하기 때문에 접근이 매우 용이하다.</strong></p>
<p><strong>단점</strong>은 그만큼 DB의 부담이 심해질 수 있고, 모든 서버끼리 같은 세션을 공유하여야 하므로 확장성 문제도 있다. </p>
<h3 id="token-방식">token 방식</h3>
<p>token 방식은 대부분 우리가 알고 있는 JWT방식 이다. JWT(JSON Web Token)</p>
<p>JWT는 사용자 정보를 JSON 객체에 담아 이를 암호화하고 해싱 작업을 거쳐 문자열 토큰을 생성하는 방식이다. 유저가 로그인하면 유저에게 입장권을 발급해 줄 때 입장권에 { 유저의 아이디, 로그인 날짜, 유효기간 } 등을 적어두고 암호화해서 보냅니다. 그리고 별 이상 없으면 통과시켜 준다. DB에 뭐 저장하거나 그런 건 없음.</p>
<p><strong>장점은 매번 GET/POST 요청할 때마다 DB를 조회할 필요가 없어서 DB 부담이 적다.</strong></p>
<p><strong>단점</strong>은 누군가 토큰을 빼간다면 토큰을 이용하여 권한을 수행할 수 있기 때문에 보안에 신경 쓸 필요가 있다. 그렇다고 매번 그 누군가를 잡아서 DB 같은 곳에 기록해 두고 조회해서 로그인시킨다면 이건 session 방식과 딱히 다른 점이 없다.</p>
<h3 id="oauth">OAuth</h3>
<p>OAuth는 입장권 같은 건 아니고 OAuth의 뜻은 유저의 A 사이트의 사용 권한을 B 사이트를 운영하는 내가 잠깐 빌릴 수 있는데 그 과정을 정의하는 규칙 같은 거다.</p>
<p>그래서 OAuth를 잘 이용하면 유저의 A 사이트 회원 정보를 가져와서 내가 운영하는 B 사이트 회원가입 시 사용할 수도 있고 이걸 흔히 소셜 로그인이라고도 부른다.</p>
<h3 id="마무리">마무리</h3>
<p>간단하게 session token OAuth방식을 알아봤는데 각자의 장단점이 있기 때문에 제작하고 있는 페이지와 유저를 고려한 뒤 적절하게 사용해서 기능을 구현해야 겠다. 다음 글은 <strong>Next-Auth (Auth.js)</strong> 라이브러리를 가지고 로그인 하는 방법을 가져올게요.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NextJs] Server Component vs Client Component ]]></title>
            <link>https://velog.io/@kimmoonju-102/NextJs-Server-Component-vs-Client-Component</link>
            <guid>https://velog.io/@kimmoonju-102/NextJs-Server-Component-vs-Client-Component</guid>
            <pubDate>Fri, 23 Feb 2024 12:38:42 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가며">들어가며</h3>
<p>기본적으로 Next.js는 서버 컴포넌트를 사용한다. 이를 통해 추가 구성 없이 서버 렌더링을 자동으로 구현할 수 있으며, 필요할 때 클라이언트 컴포넌트 사용을 선택할 수 있다. 그래서 클라이언트 컴포넌트는 언제 사용하는가?🤔 같이 알아보자.</p>
<hr>
<h3 id="server-component">Server Component</h3>
<ul>
<li>페이지를 요청할 때마다 서버에서 해당 페이지의 HTML을 생성하여 클라이언트에게 전달한다.</li>
<li>검색 엔진 최적화(SEO)에 유리하며, 초기 로딩 시간이 짧은 사용자 경험을 제공한다.</li>
</ul>
<h3 id="client-component">Client Component</h3>
<ul>
<li>초기에는 서버에서 빈 페이지를 제공하고, 그 후에 자바스크립트가 실행되어 클라이언트에서 페이지를 렌더링한다.<br/>

</li>
</ul>
<hr>
<h3 id="server-component와-client-component-특징">Server Component와 Client Component 특징</h3>
<p><strong>Server Component</strong></p>
<blockquote>
<p>Next.js에서는 /app 디렉터리 내부에 컴포넌트를 만들면, 디폴트로 Server Component가 된다.</p>
</blockquote>
<ul>
<li>모든 컴포넌트는 <code>Server Component</code>가 <strong>디폴트</strong>이다. 따라서 Client Component로 사용하고 싶다면,  <code>&#39;use Client&#39;</code> 를 입력해주면 된다.</li>
<li>자바스크립트 번들 감소</li>
<li><code>Hydration</code> 과정이 없다.
(정적인 HTML 요소들에 JS 코드들이 결합되며 버튼 클릭에 따른 이벤트 처리 등이 가능한 것)</li>
<li>Event Listener(onClick 등) 사용 불가</li>
<li>React Hooks(useEffect 등)사용 불가</li>
<li>Client Component 사용 불가</li>
<li>async 함수로 정의 가능<br/>

</li>
</ul>
<p>*<em>Client Component *</em></p>
<blockquote>
<p>Client Component를 정의하기 위해서는 컴포넌트 파일 최상단에 <code>&#39;use client&#39;</code>를 추가해 주면 된다.</p>
</blockquote>
<pre><code>&#39;use client&#39;

import { useState } from &#39;react&#39;

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    &lt;div&gt;
      &lt;p&gt;You clicked {count} times&lt;/p&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;Click me&lt;/button&gt;
    &lt;/div&gt;
  )
}</code></pre><p>장점 : html 안에 자바스크립트 마음대로 넣어서 기능 개발 가능
단점 : 자바스크립트로 인해 페이지 용량도 커지고 로딩 속도도 느려질 수 있다.</p>
<p><strong>특히</strong> client component를 로드하려면 <code>hydration</code>이라는 과정을 거치게 되는데 html을 로드하고 나서 거기에 리액트 문법을 적용하기 위해 컴퓨터가 html을 읽고 분석하는 과정이 필요한데 그걸 <code>hydration</code>이라고 부른다.
<br/></p>
<h3 id="hydration이란">hydration이란?</h3>
<blockquote>
<p>Server-Side에서 렌더링 된 정적 페이지(HTML)와 번들링 된 JS 파일을 클라이언트에게 보내면, Client-Side에서 HTML 코드와 JS(React) 코드를 서로 매칭시키는 과정</p>
</blockquote>
<p>hydration 과정을 이해하려면 next.js렌더링 방식을 정확히 이해하고 있어야 한다. 렌더링 방식은 다음에 알아보자.</p>
<br />

<h3 id="server-component-client-component-언제-사용할까">Server Component, Client Component 언제 사용할까?</h3>
<p>이표는 Server Component와 Client Component의 다른 사용 사례를 요약
<img src="https://velog.velcdn.com/images/kimmoonju-102/post/ce4fbb79-4835-40e4-ad75-e1a036e280df/image.png" alt=""></p>
<br/>

<blockquote>
<p>참고</p>
</blockquote>
<ul>
<li><a href="https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns">https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns</a> (공식문서)</li>
<li><a href="https://curryyou.tistory.com/539">https://curryyou.tistory.com/539</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NextJs] 페이지 이동 방법]]></title>
            <link>https://velog.io/@kimmoonju-102/NextJs-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%9D%B4%EB%8F%99-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@kimmoonju-102/NextJs-%ED%8E%98%EC%9D%B4%EC%A7%80-%EC%9D%B4%EB%8F%99-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 02 Feb 2024 12:19:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/9f28571f-7568-4ee6-9b5a-a10b4efb5251/image.webp" alt=""></p>
<p>Next.Js 공부하면서 다양한 페이지 이동 방법을 이용해 코드를 작성해 봤다. 잊어버리기 전에 정리해보자.
오늘은 우선 Link컴포넌트와 useRouter 방식을 알아보자.</p>
<h3 id="link">Link</h3>
<blockquote>
<p><code>&lt;Link&gt;</code>은 HTML <code>&lt;a&gt;</code> 요소를 확장하여 prefetching과 클라이언트 측 라우트 간 탐색을 제공하는 React 컴포넌트이다.</p>
</blockquote>
<pre><code>import Link from &quot;next/link&quot;;
import DetailLink from &quot;./DetailLink&quot;;

  return (
    &lt;div className=&quot;list-bg&quot;&gt;
      {result.map((a, i) =&gt; (
        &lt;div className=&quot;list-item&quot; key={i}&gt;
          &lt;Link href={&quot;/이동할 경로/&quot; + result[i]._id}&gt;
            &lt;h4&gt;{result[i].title}&lt;/h4&gt;
          &lt;/Link&gt;
          &lt;p&gt;1월 1일&lt;/p&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
}</code></pre><p>위에 코드처럼 <code>href</code>에 이동하고자 하는 경로를 입력하면 라우터로 이동한다. </p>
<p><strong>Link</strong> 컴포넌트의 구성요소</p>
<ul>
<li>href : href=&quot;/이동할 경로”</li>
<li>replace : replace={false} 기본값은 <code>false</code> 이며 브라우저 기록 에 새 URL을 추가하는 대신 현재 기록 상태를 대처한다.</li>
<li>scroll : scroll={false} 기본값은 <code>true</code> 이며 <code>&lt;Link&gt;</code>새 경로의 맨 위로 스크롤하거나 앞뒤 탐색을 위해 스크롤 위치를 유지하는 것이다.</li>
<li>prefetch : prefetch={false} 전체 경로와 해당 데이터가 미리 가져온다. (아래에서 자세히 알아보자.)</li>
</ul>
<br/>

<h3 id="userouter">useRouter</h3>
<blockquote>
<p>next.js에서 제공하는 <strong><code>useRouter</code></strong> 훅을 이용하면 클라이언트 컴포넌트 내에서 사용할 수 있다. <strong>하지만</strong> 특별한 요구사항이 없다면 Link컴포넌트를 사용하는 것이 권장된다.</p>
</blockquote>
<pre><code>&#39;use client&#39;

import {useRouter} from &#39;next/navigation&#39;

export default function DetailLink(){
  let router = useRouter()
  return (
    &lt;button onClick={()=&gt;{ router.push(&#39;이동할경로&#39;) }}&gt;버튼&lt;/button&gt;
  )
}</code></pre><p>위에 코드 처럼 <code>useRouter</code> 훅을 사용하여 라우터 객체를 얻고, 이를 통해 클라이언트 사이드에서 라우트를 변경할 수 있다. <code>router.push</code> 메서드 안에 <code>‘이동할경로’</code>를 적어준다.
<br/></p>
<pre><code>import Link from &quot;next/link&quot;;
import DetailLink from &quot;./DetailLink&quot;;

  return (
    &lt;div className=&quot;list-bg&quot;&gt;
      {result.map((a, i) =&gt; (
        &lt;div className=&quot;list-item&quot; key={i}&gt;
          &lt;Link href={&quot;/이동할 경로/&quot; + result[i]._id}&gt;
            &lt;h4&gt;{result[i].title}&lt;/h4&gt;
          &lt;/Link&gt;
          &lt;DetailLink /&gt;
          &lt;p&gt;1월 1일&lt;/p&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
}</code></pre><p>위에 코드처럼 server component에서 useRouter를 사용하고 싶으면 따로 client component(<code>&lt;DetailLink /&gt;</code>)를 만들어서 server component에 import하는 방식으로 사용해야 한다.
<br/>
<code>router.push</code>뿐만 아니라 <code>useRouter</code>에는 다양한 메서드를 이용해 내비게이션 작업을 수행할 수 있다. 같이 알아보자.</p>
<ul>
<li>router.push(href: string, { scroll: boolean }): 주어진 라우트로 클라이언트 측 네비게이션을 수행합니다. 브라우저의 히스토리 스택에 새 항목을 추가합니다.</li>
<li>router.replace(href: string, { scroll: boolean }): 브라우저의 히스토리 스택에 새 항목을 추가하지 않고 주어진 라우트로 클라이언트 측 네비게이션을 수행합니다.</li>
<li>router.refresh(): 현재 라우트를 새로고침합니다. 서버에 새로운 요청을 보내고 데이터 요청을 다시 가져오며 서버 컴포넌트를 다시 렌더링합니다. 클라이언트는 업데이트된 React 서버 컴포넌트 페이로드를 유지하면서 영향받지 않은 클라이언트 측 React (예: useState) 또는 브라우저 상태 (예: 스크롤 위치)를 재병합합니다.</li>
<li>router.prefetch(href: string): 주어진 라우트를 미리 가져와 더 빠른 클라이언트 측 전환을 위한 작업을 수행합니다.</li>
<li>router.back(): 브라우저의 히스토리 스택에서 이전 라우트로 이동합니다.</li>
<li>router.forward(): 브라우저의 히스토리 스택에서 다음 페이지로 이동합니다.<br/>
</li>
</ul>
<hr>
<br/>

<h3 id="prefetch">prefetch</h3>
<p>위에 있는 메서드 중 <code>Link컴포넌트</code>와 <code>useRouter</code> 둘 다 갖고있는 <strong><code>prefetch</code></strong>속성 기능에 대해 알아보자.</p>
<h4 id="link-1">Link</h4>
<pre><code class="language-jsx">&lt;Link href={&#39;/이동할 경로&#39;} prefetch&gt;링크&lt;/Link&gt;

-------------------------------------------------------

&lt;Link href={&#39;/이동할 경로&#39;} prefetch={false}&gt;링크&lt;/Link&gt;</code></pre>
<ul>
<li>Link 컴포넌트는 기본적으로 <code>prefetch</code> 이 활성화 되어 있기 때문에 사용자가 실제로 그 페이지로 이동하기 전에 미리 가져오는 작업을 하고, 이렇게 하면 웹페이지 로딩과 렌더링 속도가 모두 빨라진다.</li>
<li><code>prefetch</code> 은 기본적으로 <strong><code>true</code></strong>로 활성화 되어 있기 때문에 기능을 사용하고 싶지 않으면 <code>prefetch</code>속성을 <strong><code>false</code></strong>로 바꿔줘야 한다.<br/>

</li>
</ul>
<h4 id="userouter-1">useRouter</h4>
<pre><code class="language-jsx">&lt;button onClick={()=&gt;{ router.prefetch(&#39;/이동할 경로&#39;) }}&gt;버튼&lt;/button&gt;</code></pre>
<ul>
<li>useRouter도 <code>prefetch</code> 를 사용하면 미리 가져오는 작업을 해줘서 사용자가 해당 페이지로 이동할 때 더 빠르게 로딩된다.</li>
</ul>
<br/>

<h4 id="참고">참고</h4>
<p>&lt;next.js 공식문서&gt;
<a href="https://nextjs.org/docs/app/api-reference/components/link">https://nextjs.org/docs/app/api-reference/components/link</a>
<a href="https://nextjs.org/docs/app/api-reference/functions/use-router">https://nextjs.org/docs/app/api-reference/functions/use-router</a>
<a href="https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching">https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#2-prefetching</a>
&lt;코딩애플&gt;
<a href="https://codingapple.com/course/next-js/">https://codingapple.com/course/next-js/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 약수의 개수와 덧 - Javascript]]></title>
            <link>https://velog.io/@kimmoonju-102/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%BD%EC%88%98%EC%9D%98-%EA%B0%9C%EC%88%98%EC%99%80-%EB%8D%A7-Javascript</link>
            <guid>https://velog.io/@kimmoonju-102/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%95%BD%EC%88%98%EC%9D%98-%EA%B0%9C%EC%88%98%EC%99%80-%EB%8D%A7-Javascript</guid>
            <pubDate>Mon, 22 Jan 2024 06:03:38 GMT</pubDate>
            <description><![CDATA[<h3 id="📄문제설명">📄문제설명</h3>
<p><strong>문제 설명</strong>
두 정수 left와 right가 매개변수로 주어집니다. left부터 right까지의 모든 수들 중에서, 약수의 개수가 짝수인 수는 더하고, 약수의 개수가 홀수인 수는 뺀 수를 return 하도록 solution 함수를 완성해주세요.</p>
<p><strong>제한사항</strong>
1 ≤ left ≤ right ≤ 1,000</p>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/d4c0f048-27b5-4970-8ff9-82daf61f6a78/image.png" alt=""></p>
<hr>
<h3 id="💡문제이해">💡문제이해</h3>
<ul>
<li>주어진 left, right 범위 내의 모든 숫자 약수의 개수 구하기</li>
<li>약수의 개수가 짝이면 더하고, 홀수면 뺀다.</li>
</ul>
<hr>
<h3 id="💻코드작성">💻코드작성</h3>
<p><strong>나의 풀이</strong></p>
<pre><code>function solution(left, right) {
    var answer = 0;
    for (let num = left; num &lt;= right; num++) {
        let divisorsCount = 0; 

        // 약수의 개수 구하기
        for(let i = 1; i &lt;= num; i++) {
            if(num % i === 0) {
                divisorsCount++;
            }
        }

        // 약수의 개수가 짝이면 더하고, 홀수면 뺀다.
        if(divisorsCount % 2 === 0) {
            answer += num;
        }else {
            answer -= num;
        }
    }
    return answer;
}</code></pre><br />

<p><strong>다른 풀이</strong></p>
<pre><code>function solution(left, right) {
    var answer = 0;
    for (let i = left; i &lt;= right; i++) {
        if (Number.isInteger(Math.sqrt(i))) {
            answer -= i;
        } else {
            answer += i;
        }
    }
    return answer;
}
</code></pre><hr>
<h3 id="😄정리">😄정리</h3>
<p>약수의 개수를 직접 구했는데 이 풀이는 약수의 개수를 직접 계산하지 않고, 각 숫자의 제곱근을 이용하여 약수의 개수가 짝수인지 홀수인지를 판별하는 방식으로 문제를 해결했다. 
<code>Math.sqrt()</code> 문법으로 제곱근을 구한 뒤 <code>Number.isInteger()</code> 문법을 사용하여 정수를 구별해 주고 제곱근이 정수인 경우 빼주고, 정수가 아닌 경우에는 더해 줬다.
기억하자 제곱근이 정수면 약수의 개수는 홀수다...✍️</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 가운데 글자 가져오기 - Javascript]]></title>
            <link>https://velog.io/@kimmoonju-102/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EA%B8%80%EC%9E%90-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0-Javascript</link>
            <guid>https://velog.io/@kimmoonju-102/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B0%80%EC%9A%B4%EB%8D%B0-%EA%B8%80%EC%9E%90-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0-Javascript</guid>
            <pubDate>Fri, 19 Jan 2024 12:34:56 GMT</pubDate>
            <description><![CDATA[<h3 id="📄문제설명">📄문제설명</h3>
<p><strong>문제 설명</strong>
단어 s의 가운데 글자를 반환하는 함수, solution을 만들어 보세요. 단어의 길이가 짝수라면 가운데 두글자를 반환하면 됩니다.</p>
<p><strong>재한사항</strong>
s는 길이가 1 이상, 100이하인 스트링입니다.</p>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/0028246c-099e-4d7c-84c0-b282777a0942/image.png" alt=""></p>
<hr>
<h3 id="💡문제이해">💡문제이해</h3>
<ul>
<li>middleIndex: 문자열의 중앙 인덱스를 계산합니다. Math.floor 함수를 사용하여 소수점 이하를 버린다.</li>
<li>문자열의 길이가 짝수이면, 중앙의 두 글자를 반환한다. slice 함수를 사용하여 시작 인덱스부터 종료 인덱스 전까지의 부분 문자열을 추출한다.</li>
<li>문자열의 길이가 홀수이면, 중앙의 한 글자를 반환한다. charAt 함수를 사용하여 특정 인덱스의 문자를 가져온다.</li>
</ul>
<hr>
<h3 id="💻코드작성">💻코드작성</h3>
<pre><code>function solution(s) {
    const length = s.length;
    const middleIndex = Math.floor(length / 2);

    if(length % 2 === 0) {
        return s.slice(middleIndex -1, middleIndex + 1);
    } else {
        return s.charAt(middleIndex);
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 얕은 복사, 깊은복사]]></title>
            <link>https://velog.io/@kimmoonju-102/JavaScript-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80%EB%B3%B5%EC%82%AC</link>
            <guid>https://velog.io/@kimmoonju-102/JavaScript-%EC%96%95%EC%9D%80-%EB%B3%B5%EC%82%AC-%EA%B9%8A%EC%9D%80%EB%B3%B5%EC%82%AC</guid>
            <pubDate>Fri, 19 Jan 2024 12:20:17 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트가 제공하는 타입은 크게 <strong>원시 타입</strong>과 <strong>객체 타입</strong>으로 구분할 있다.</p>
<p><strong>원시 타입</strong> </p>
<ul>
<li>변경 불가능한 값</li>
<li>원시 값을 변수에 할당하면 변수(확보된 메모리 공간)에는 실제 값이 저장된다.</li>
</ul>
<p><strong>객체 타입</strong> </p>
<ul>
<li>객체(참조) 변경 가능한 값</li>
<li>객체를 변수에 할당하면 변수(확보된 메모리 공간)에는 참조 값이 저장된다.</li>
</ul>
<br />

<hr>
<h3 id="얕은-복사-깊은-복사">얕은 복사, 깊은 복사</h3>
<p>객체를 프로퍼티 값으로 갖는 객체의 경우 얕은 복사는 한 단계까지만 복사하는 것을 말하고 깊은 복사는 객체에 중되어 있는 개체까지 모두 복사하는 것을 말한다.</p>
<p>📄예시를 통해 알아보자!</p>
<blockquote>
<p><strong>얕은 복사(Shallow Copy)</strong>
얕은 복사란 객체를 복사할 때 기존 값과 복사된 값이 같은 참조를 가리키고 있는 것을 말한다.
객체 안에 객체가 있을 경우 한 개의 객체라도 기존 변수의 객체를 참조하고 있다면 이를 얕은 복사라고 한다. </p>
</blockquote>
<pre><code>const arr = [{ j: &#39;k&#39; }, { l: &#39;m&#39; }];
const shallowCopy = [...arry]; // 스프레드 문법
console.log(arr === shallowCopy); // false
console.log(arr[0] === shallowCopy[0]); // true</code></pre><ul>
<li>arr 배열에는 두 개의 객체를 포함하고 있고, <strong><code>스프레드 문법</code></strong>을 사용하여 arr을 복사하여 shallowCopy 배열을 만들었다. </li>
<li>원본 배열과 복사된 배열을 비교했을 때 얕은 복사를 통해 새로운 배열이 생성되었으므로 두 배열은 서로 다른 객체이기 때문에 <strong><code>false</code></strong>가 출력 된다.</li>
<li>하지만 배열 내부의 객체들은 얕은 복사를 통해 참조값이 복사되었기 때문에, 두 배열의 첫 번째 요소는 같은 객체를 참조하고 있습니다. 따라서 이 비교는 <strong><code>true</code></strong>를 출력한다.</li>
</ul>
<p><strong>요약하자면</strong>, 얕은 복사를 통해 배열을 복사하면 배열 자체는 새로운 객체가 되지만 내부의 객체들은 여전히 원본과 동일한 참조를 유지한다.
<br /></p>
<blockquote>
<p><strong>깊은복사(Deep Copy)</strong>
깊은 복사된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어지고 복사를 해온다.</p>
</blockquote>
<pre><code>const reference = arr; // 참조
const deepCopy = JSON.parse(JSON.stringify(arr)); // 깊은 복사

console.log(arr === reference); // true
console.log(arr === deepCopy); // false
console.log(arr[0] === deepCopy[0]); // false
</code></pre><ul>
<li>reference라는 변수에 arr을 할당하고 이는 단순히 참조를 복사하는 것이다.</li>
<li><strong><code>JSON.stringify()</code></strong>를 사용하여 객체나 배열을 문자열로 변환하고, 그 문자열을 다시 <strong><code>JSON.parse()</code></strong>를 사용하여 새로운 객체나 배열로 변환하는 방법을 사용하여 깊은 복사를 했다.
이러한 방법은 간단하게 모든 객체나 배열을 문자열로 변환하고 다시 파싱하는 것으로, 원본과는 별개의 객체를 생성한다.</li>
<li>arr과 reference는 동일한 배열을 가리키기 때문에 <strong><code>true</code></strong>가 출력됩니다.</li>
<li>arr과 deepCopy는 서로 다른 객체이기 때문에 <strong><code>false</code></strong>가 출력됩니다.</li>
<li>arr과 deepCopy의 첫 번째 요소도 서로 다른 객체이기 때문에 <strong><code>false</code></strong>가 출력된다.</li>
</ul>
<br />

<hr>
<h3 id="마무리">마무리</h3>
<p><strong>얕은 복사(Shallow Copy)</strong>는 객체를 복사할 때 원본 객체의 프로퍼티들을 새로운 객체로 복사하지만, 프로퍼티 값이 객체인 경우 해당 객체는 참조로 유지되어 두 객체가 같은 객체를 가리키게 된다. 이에 반해 <strong>깊은 복사(Deep Copy)</strong>는 객체를 복사할 때 내부 객체까지 재귀적으로 복사하여, 원본과는 독립적인 새로운 객체를 생성합니다. 따라서 얕은 복사는 내부 객체의 변경이 복사된 객체에도 영향을 미칠 수 있지만, 깊은 복사는 내부 객체의 변경이 영향을 미치지 않는다. 따라서 상황에 맞게 적절히 활용해야 할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[멋쟁이사자처럼 프론트엔드 스쿨 4기 1,2주차 회고 - 차근차근]]></title>
            <link>https://velog.io/@kimmoonju-102/%EB%A9%8B%EC%9F%81%EC%9D%B4%EC%82%AC%EC%9E%90%EC%B2%98%EB%9F%BC-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%8A%A4%EC%BF%A8-4%EA%B8%B0-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC</link>
            <guid>https://velog.io/@kimmoonju-102/%EB%A9%8B%EC%9F%81%EC%9D%B4%EC%82%AC%EC%9E%90%EC%B2%98%EB%9F%BC-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EC%8A%A4%EC%BF%A8-4%EA%B8%B0-12%EC%A3%BC%EC%B0%A8-%ED%9A%8C%EA%B3%A0-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC</guid>
            <pubDate>Sun, 11 Dec 2022 15:17:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/5928a30d-c9ba-4134-92a5-567498687934/image.png" alt=""></p>
<blockquote>
<p>1, 2주차 회고록 (GIT, HTML, CSS, 스프린트회고)</p>
</blockquote>
<h3 id="느낀점">느낀점</h3>
<p> 멋사 프론트엔드 스쿨은 비대면 수업으로 진행된다.
생각보다 정신없던 이주였다. 일단 비대면으로 듣는 게 처음이라 적응하는 데 꽤 걸렸다. 현장에서만 느낄 수 있는 느낌 동기부여 등들이 있는데 못 느껴서 아쉽지만 온라인 안에서도 서로 도와주고 이끌어 나가는 관경을 보고 비대면 수업도 괜찮다는 생각을 했다.</p>
<h3 id="배운것들">배운것들</h3>
<p> 1주 차에는 현업에서 가장 중요한 코드 관리! git을 배웠다.
git 이란 소스 코드를 효율적으로 관리하기 위해 만들어진 &quot;분산형 버전 관리 시스템&quot;이다. git을 이용하는 방식은 두 가지인데 첫 번째 방식은 GUI 방식이고 두 번째는 CLI 방식이다. 항상 git을 push 할 때 GUI 방식을 이용하여 레파지토리에 올렸는데 CLI 방식을 배우고 나선 git과 더 친해지기 위해 CLI 방식을 이용하여 git 관리를 하고 있는 중이다.</p>
<ol>
<li>터미널에 명령어를 이용하는 CLI 방식</li>
<li>소스 트리 등의 프로그램을 사용하는 GUI 방식</li>
</ol>
<p>2주 차에는 본격적으로 마크업 구조와 css 스타일을 공부하였다.
마크업을 할 땐 웹 접근성을 항상 고려해야 하고, 장애를 가진 사람들이 스크린 리더기를 사용하는 등 여러 가지 방법으로 웹에 쉽게 접근할 수 있도록 구조를 설계해야 한다. css는 아직 더 배우는 중이지만 알고 있던 속성보다 더 다양한 속성들을 배워서 생각보다 공부할게 많다.(얼른 복습하자...)</p>
<h3 id="개선할점">개선할점</h3>
<p>생각보다 게으른 2주를 보냈다. 파이팅 넘치는 동기들을 보니 나도 공부를 해야겠다는 생각이 들어서 회고록부터 작성하기 시작했다. 이번 주부터 배웠던 것들을 정리하면서 마무리해야 마지막까지 지치지 않고 수료할 것 같다.</p>
<h3 id="목표">목표</h3>
<p>3주차 목표 - css flexbox와 position속성에 익숙해져 보기.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git&GitHub 정리]]></title>
            <link>https://velog.io/@kimmoonju-102/GitGitHub-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@kimmoonju-102/GitGitHub-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 01 Nov 2022 14:31:59 GMT</pubDate>
            <description><![CDATA[<p>git이 뭐야! github는 뭔데 commit, push....</p>
<p>git과 github를 모르면 취업 못합니다. 얘기를 듣고 호다닥 공부했습니다. </p>
<h1 id="git이란">Git이란?</h1>
<p> 소스 코드를 효율적으로 관리하기 위해 만들어진 버전관리소프트웨어이다.</p>
<h3 id="git-장점">git 장점</h3>
<ul>
<li>작업한 코드들을 기록하고 보관이 가능하다.</li>
<li>특정 시점에 저장된 버전과 비교하거나 특정 시점으로 되돌아갈 수 있습니다.</li>
</ul>
<h3 id="git-저장소-생성-git-init">git 저장소 생성 [git init]</h3>
<pre><code>git init</code></pre><ul>
<li>새로운 git 저장소를 생성할 때 사용하는 git 명령어 이다.</li>
<li>&quot;git init&quot; 명령어 실행</li>
</ul>
<h3 id="git-status">git status</h3>
<pre><code>git status</code></pre><ul>
<li>파일 상태 확인 명령어 이다.</li>
</ul>
<h3 id="git-용어-정리">git 용어 정리</h3>
<p><img src="https://velog.velcdn.com/images/kimmoonju-102/post/8ad164f4-f50c-45c1-827a-47e331d816bb/image.jpg" alt=""></p>
<ul>
<li>staging area : commit 할 파일 골라놈</li>
<li>local repository : 기록 저장소에 옮김</li>
</ul>
<p>더 공부하면서 채워 나가겠습니다.</p>
]]></description>
        </item>
    </channel>
</rss>