<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>anti_mang0.log</title>
        <link>https://velog.io/</link>
        <description>망고짱쉬룸</description>
        <lastBuildDate>Tue, 21 May 2024 16:39:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>anti_mang0.log</title>
            <url>https://velog.velcdn.com/images/anti_mang0/profile/91ba67a8-8cdc-4146-a005-97683c7bfcce/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. anti_mang0.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/anti_mang0" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[코드잇 스프린트 3기를 마치며]]></title>
            <link>https://velog.io/@anti_mang0/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-3%EA%B8%B0%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0</link>
            <guid>https://velog.io/@anti_mang0/%EC%BD%94%EB%93%9C%EC%9E%87-%EC%8A%A4%ED%94%84%EB%A6%B0%ED%8A%B8-3%EA%B8%B0%EB%A5%BC-%EB%A7%88%EC%B9%98%EB%A9%B0</guid>
            <pubDate>Tue, 21 May 2024 16:39:46 GMT</pubDate>
            <description><![CDATA[<h1 id="🥰소개">🥰소개</h1>
<p>안녕하세요, 달리기를 완주한 3기 수료생입니다. 처음엔 학교 공지 단톡방에 올라오는 코드잇 스프린트의 광고를 보고 지원하게 되었어요. 본격적인 스프린트를 하기에 앞서 기본적인 학습을 하는데, 이전에 전공 선택으로 학습했던 웹 프로그래밍 강의가 떠올랐습니다. 그때는 정말 아무것도 모르고 시작을 했었죠..
 간단한 테스트가 끝나고, 인터뷰를 하면서 제가 상당히 이른 시기에 부트캠프를 선택했다는걸 알게 되었고, 걱정 반 설렘 반으로 시작하게 되었습니다. 그땐 리액트가 뭔지도, Node.JS가 뭔지도 모르는 때였는데 말이죠 ㅎㅎ</p>
<h1 id="😂도전과-극복">😂도전과 극복</h1>
<h2 id="프론트엔드가-리액트를-모르면-쓰나-openmind">프론트엔드가 리액트를 모르면 쓰나, &#39;OpenMind&#39;</h2>
<p>처음엔 레벨업도 빠르고, 하나하나 배우는 것 마다 바로 적용이 되니까 재미를 붙일 수 있었습니다. 하지만 첫 번째 프로젝트와 함께 시작한 React는... 제가 상상한것보다 어려웠습니다. 팀원분들은 슥슥 해내시는 것 같은데, 잘 못하는 제 모습을 보고 자책도 많이 하고 자존감도 많이 떨어지는 시기였습니다. 그리고 완벽히 준비되지 않은 상황에서 마주친 프로젝트까지, 제 멘탈은 강도 9 대지진이 난 것 같았습니다. 팀원분들께 &#39;어렵다. 도와달라&#39; 라고 말하는데까지 정말 많은 마음의 준비를 했기도 했습니다. 하하.. 아무튼 그렇게 <code>JavaScript</code>로 끝낸 프로젝트 뒤 찾아온 TS는.. 절 해탈하게 만들어주었습니다. 덕분에 밤을 잘 새게 되었어요. </p>
<p>앞서 너무 안좋은 이야기만 한 것 같아 좀 웃기지만, 그만큼 <strong>리액트</strong>의 러닝커브는 제게 큰 성장을 안겨주었습니다. 학교 수업을 통해서도 느끼지만, &#39;프로젝트가 실력을 올려준다&#39;는 말은 불변인가봅니다. 그때 정말 많이 배웠었어요. </p>
<h2 id="타입스크립트에-익숙해졌나-taskify">타입스크립트에 익숙해졌나?, &#39;Taskify&#39;</h2>
<p>두번째 프로젝트도 정말 많이 배웠습니다. 전 주로 로그인, 회원가입, 마이페이지같은 유저 정보를 관리하는 페이지를 맡았는데, <code>TypeScript</code>에 대해 많이 배우기도 했고, <code>react-query</code>와 <code>react-hook-form</code>같은 같이 쓰면 좋은 것들에 대해 조금씩 알아가기 시작했던 것 같습니다. 사실 아직 어렵긴 하지만 이때 처음 알게 되었고, 공부를 시작했다는거에 의미를 두고 싶습니다.</p>
<h2 id="라이브러리를-학습하자-blob">라이브러리를 학습하자, &#39;BLOB&#39;</h2>
<p>마지막 프로젝트는.. 배운걸 쏟아붓는 느낌이였습니다. 이쯤 와서 새로운 것에 대한 학습은, 다른 프로젝트보다 더 무겁게 느껴졌습니다. 4-5시간 공부한 결과가 코드로는 별로 나타나지 않아서 뒤쳐지는 느낌도 들었고, 팀원들에게 미안한 마음과 제대로 하고 있지 못하는 것 같다는 압박과 불안이 제일 저를 괴롭혔던 것 같아요. (남의 코드를 잘 읽지 못하면 오픈소스 라이브러리를 가져다 쓰는 건 어렵습니다..) 그래도 해야지! 라는 생각으로 직접 공부도 해 보고, 옵시디언에 필기도 하면서 학습을 했었습니다. 덕분에 <code>react-hook-form</code> 실력도 많이 늘고, <strong>컴포넌트 분리</strong>도 잘 하게 된 것 같아요. 새로운 기술의 도입도 무서워지지 않았습니다. </p>
<h2 id="그래서">그래서?</h2>
<p>&#39;여러 가지를 학습했다&#39;라고 말할 수 있겠지만, 전 리액트 학습이 제일 중요하고 갚진 일이였다 생각합니다. taskify, blob을 진행하면서 기반에 깔린 기술이 리액트였으니까요.</p>
<h1 id="🧐핵심-학습-내용">🧐핵심 학습 내용</h1>
<h2 id="html-css-js">HTML, CSS, JS</h2>
<p>사실 프로젝트를 진행하면서, 이제 내가 과연 바닐라 JS로 페이지를 만들 수 있을까..? 싶어졌습니다. 추후에 다시 훑는 학습을 하면서 게시글로 올려보려고 합니다ㅎㅎ..ㅠㅠ</p>
<h2 id="react">React</h2>
<h3 id="react는-ui를-만들기-위한-javascript-라이브러리이다">React는 UI를 만들기 위한 JavaScript 라이브러리이다</h3>
<p>React는 스스로 상태를 관리하는 캡슐화된 컴포넌트를 조합해 복잡한 UI를 만들 수 있도록 지원하며, 데이터가 변경됨에 따라 적절한 컴포넌트만 효율적으로 갱신하고 렌더링합니다.</p>
<h3 id="react의-원리-특징이-무엇인가">React의 원리, 특징이 무엇인가?</h3>
<p>React는 상태 변화에 따른 UI 변경점을 결정하기 위해 재조정(Reconciliation)이라는 알고리즘을 사용하며, 이를 구현하기 위해 Virtual DOM이라는 패턴을 사용하였습니다.</p>
<p>또한 React 16부터 React Fiber엔진을 사용하여, 리액트의 Reconciler를 정비하였습니다.</p>
<h3 id="그래서-1">그래서?</h3>
<p>사실 리액트도 더 배워야 할 게 많습니다.. 프로젝트와 6개월이라는 짧은 시간에 급급해서 학습한 부분이 많아서, 이제 자세한 부분을 조금씩 학습하려 합니다. </p>
<h2 id="ts--nextjs">TS &amp; Next.js</h2>
<h3 id="typescript">Typescript</h3>
<blockquote>
<p>마이크로소프트에서 구현한 JavaScript의 슈퍼셋(Superset) 프로그래밍 언어이며 확장자로는 .ts를 사용하며, 컴파일의 결과물로 JavaScript 코드를 출력한다. 최종적으로 런타임에서는 이렇게 출력된 JavaScript 코드를 구동시켜야 한다.</p>
</blockquote>
<h4 id="특징">특징</h4>
<ol>
<li>타입스크립트는 정적 타입의 컴파일 언어이며 코드 작성 단계에서 타입을 체크해 오류를 확인할 수 있고 미리 타입을 결정하기 때문에 실행 속도가 매우 빠르다는 장점이 있습니다. 하지만 코드 작성 시 매번 타입을 결정해야 하기 때문에 번거롭고 코드량이 증가하며 컴파일 시간이 오래 걸린다는 단점이 있습니다. </li>
<li>유효한 자바스크립트로 작성한 코드는 확장자를 .js에서 .ts로 변경하고 타입스크립트로 컴파일해 변환할 수 있습니다. </li>
<li>타입스크립트는 ES6(ECMAScript 6)에서 새롭게 사용된 문법을 포함하고 있으며 클래스, 인터페이스, 상속, 모듈 등과 같은 객체 지향 프로그래밍 패턴을 제공합니다. </li>
</ol>
<h4 id="따라서">따라서..</h4>
<p>개발자가 의도한 변수나 함수 등의 목적들을 명확하게 전달할 수 있고 그렇게 전달된 정보를 토대로 풍부한 피드백을 받을 수 있게 되므로 자바스크립트를 실제로 사용하기 전에 타입 에러들을 미리잡는것이라고 할 수 있습니다. </p>
<h3 id="nextjs">Next.js</h3>
<blockquote>
<p>nextjs는 React로 만드는 서버사이드 렌더링 프레임워크입니다. SSR을 함으로 얻는 이득은 다음과 같습니다.</p>
</blockquote>
<ul>
<li>클라이언트 렌더링 : 모든 js 파일을 로드하고 사용자는 웹을 보게됩니다. 이때까지 사용자는 많은 시간을 <strong>대기</strong>해야 합니다.</li>
<li>seo 문제 : 클라이언트 사이드의 경우 자바스크립트가 로드 되지 않은 경우 아무런 정보를 보이지 않습니다. 구글의 검색엔진의 경우 자바스크립트가 로드되지 않은 페이지를 검색엔진으로 스캔함으로 결론적으로 검색에 아무 페이지도 걸리지 않게 됩니다.</li>
</ul>
<p>이 두가지를 해결하는 것이 <code>SSR</code>입니다.</p>
<ol>
<li><p>서버에서 자바스크립트를 로딩함으로 클라이언트 측에서는 자바스크립트를 로딩하는 시간이 줄어들게 되고,</p>
</li>
<li><p>검색엔진이 자바스크립트를 읽는 것이 아닌 서버 측에서 자바스크립트, html, css를 만들어 컨텐츠를 직접 업로드 함으로 검색엔진에 게시글이 걸리게 됩니다.</p>
</li>
</ol>
<p>또한 meta 태그를 자유롭게 추가함으로 seo를 용이하게 할수 있습니다. </p>
<h3 id="그래서-2">그래서?</h3>
<p>음.. 넥스트를 잘 쓰지 않는다고 누구는 말하고, 누구는 쓰면 가산점이라고 하는데, 그 경지가 없어질 때까지 공부하는게 좋은 것 같습니다. 다만! 타입스크립트는 꼭 써야 합니다. 아직 타입에러가 많이 나는데, 많이 연습해서.. 익숙해져보도록 하겠습니다. </p>
<h1 id="🖥️프로젝트-하이라이트">🖥️프로젝트 하이라이트</h1>
<h2 id="당연하게도-blob">당연하게도 BLOB.</h2>
<p>기획부터 제작, 배포, 리팩토링까지 신경쓸만한 가치가 있다고 느낀 프로젝트였습니다. 제가 개발자로 들어간 팀에서 나온 결과물중에 제일 자랑스럽게 여길 만한 프로젝트였어요. 기획 단계에선 걱정투성이 서비스였지만, 이제와서는 애지중지 아끼는 황금알을 낳는 거위가 되었네요. 하하</p>
<h2 id="주-기술-참여한것만">주 기술 (참여한것만)</h2>
<h3 id="기획--디자인-백엔드">기획 (+ 디자인, 백엔드)</h3>
<p>기획은 주로 피그잼과 노션을 이용해 실시간 회의로 진행되었습니다. &#39;여행 SNS&#39;라는 큰 틀은 잡혔지만, 내부에서 서로 생각하는 방향성이 많이 달라서 조율하는 데 신경을 많이 썼습니다. 디자인은 피그마를 통해 진행되었고, 송이님이 정말 예쁘게 만들어주셨습니다. 감사해요🤗ㅎㅎ 피드백이 매우빨랐던 백엔드 채린님, 덕영님 감사합니다. 두분 다 너무 유능하셔서.. 본인이 원하는 회사 꼭 가시길 바라겠습니다🫡</p>
<h3 id="프론트엔드">프론트엔드</h3>
<ul>
<li><p>기술
Next.JS 14 App router 방식을 사용했고, scss module을 사용하여 스타일링을 진행했습니다. Zustand를 이용해 전역상태관리를 했습니다. Storybook을 본격적으로 사용해보았는데, 어느정도 볼륨이 있는 프로젝트라 꽤 괜찮았던 것 같았습니다. 배포는 Vercel로 진행하였습니다. </p>
</li>
<li><p>사실 엄청나게 처음 써보는 기술은 그나마 스토리북정도라, 크게 다룰 말이 없네요.. 궁금하시면 깃허브 구경하시길.. ㅎㅎ</p>
</li>
<li><p>규칙</p>
<blockquote>
<p>알잘딱깔센따윈 없습니다. </p>
</blockquote>
</li>
</ul>
<p>팀의 규칙을 처음부터 잘 쌓는 게 중요하다고 생각하여 꼼꼼하게 정하고 시작했습니다. 중요한걸 몇개 뽑아보자면.. 전원 PR 하기, 백로그 작성, (반말문화) 등등 있겠네요. 다같이 PR리뷰에 관심을 가지다 보니, 문제가 생겨서 멘션이 발생했을 때의 피드백이 빨랐고, Merge된 코드에 대해서 자기 코드가 아닌데도 잘 도와줄 수 있었습니다. 후에 바빠질 땐 서로가 서로의 코드를 보완해주며 프로젝트를 완성했습니다. 
 이게 맞나? 싶을 정도로 잘 짠 컨벤션은 프로젝트의 삐걱거리는 곳에 윤활제가 되어주었습니다👍</p>
<h1 id="🎈배운-점과-앞으로의-목표">🎈배운 점과 앞으로의 목표</h1>
<h2 id="학습-여정을-통해-얻은-가장-중요한-교훈은-무엇인가요">학습 여정을 통해 얻은 가장 중요한 교훈은 무엇인가요?</h2>
<p>좋은 사람들을 알아주는 것, 그게 정말 중요한 것 같습니다. 스프린트 과정 중 어느 하나 쉬운 것은 없었습니다. 초반이 수월했던 이유는 제가 그냥 조금 더 일찍 배웠었기 때문이고, 후반에 지쳤던 이유는 끝없는 배움의 길이 있다는 걸 깨달았기 때문입니다. 하지만 스프린트가 끝난 지금, 어떤 걸 배워보고 싶은지, 그걸 배워서 어떻게 활용하고 싶은지 머릿속에 조금씩 떠오르는 것 같습니다. 멘토님들이 해 주셨던 좋은 말씀들, 팀원들과 합을 맞추면서 나눈 에너지와 열정들, 심적으로 힘들 때 좋은 조언을 해 주셨던 매니저님들 덕분에 열심히 달린 후 러너스 하이가 온 듯 개운해지고, 더 공부하고싶은 마음이 생겼습니다. 좋은 사람들이 주변에 있는 게 정말 중요한 것 같아요. </p>
<h2 id="앞으로-어떤-개발자가-되고-싶으며-달성하고자-하는-목표는-무엇인가요">앞으로 어떤 개발자가 되고 싶으며, 달성하고자 하는 목표는 무엇인가요?</h2>
<blockquote>
<p>스타일을 못하는 개발자는 프론트엔드 개발자가 아니다.</p>
</blockquote>
<p>ㅋㅋㅋㅋ 거의 꺼내지 않은 이야기인 스타일에 대해 여기서 말해보고 싶습니다. 스타일을 못 하는 개발자는 프론트엔드 개발자가 아니라고 생각합니다. 열심히 만들어주신 디자인 파일을 똑같이 구현해내고, 유저들에게 좋은 경험을 선사해주는게 저의 목표입니다. 제 팀이 만든 사이트를 이용할 때, &#39;어떻게 해야 하지?&#39; 라는 생각이 들기 전에 눈으로 먼저, 손으로 먼저 경험을 할 수 있는, 사용자들을 자연스럽게 이끄는 사이트를 만들고 싶습니다. 이러려면 스타일링을 잘 해야겠죠. 주종목으로 잡은 Styled-components로 기초공사를 잘 하고, 다른 스타일링도 익혀서 어떤 스타일 라이브러리를 들고와도 잘 적용할 수 있는 FE 개발자가 되고 싶습니다. </p>
<h4 id="🥹오글거리지만-3기-수료생분들과-매니저님-멘토님">🥹오글거리지만 3기 수료생분들과 매니저님, 멘토님..</h4>
<p>6개월의 짧은 시간동안 같이 달려준 분들께 정말 감사합니다. 이렇게 긍정적인 에너지를 한바가지 얻고 갑니다 ㅎㅎ 앞으로 더 멋진 모습으로 만납시다!🤗🫡</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모던 자바스크립트 Deep Dive [24] 클로저]]></title>
            <link>https://velog.io/@anti_mang0/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Deep-Dive-24-%ED%81%B4%EB%A1%9C%EC%A0%80</link>
            <guid>https://velog.io/@anti_mang0/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Deep-Dive-24-%ED%81%B4%EB%A1%9C%EC%A0%80</guid>
            <pubDate>Sun, 25 Feb 2024 16:56:37 GMT</pubDate>
            <description><![CDATA[<h1 id="24장-클로저">24장 클로저</h1>
<hr>
<h2 id="클로저란">클로저란?</h2>
<p>함수를 일급 객체로 취급하는 함수형 프로그래밍 언어(클로저, 스칼라, 하스켈 등)에서 사용되는 특성이며, 자바스크립트만의 개념이 아닙니다. </p>
<blockquote>
<p>MDN : A closure is the combination of a function and the lexical environmnet within which that function was declared.
 클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.</p>
</blockquote>
<pre><code class="language-javascript">const x = 1 ;

function outerFunc() {
  const x = 10;

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

  innerFunc();
}

outerFunc();</code></pre>
<p> 본 코드에서의 <code>innerFunc()</code>의 경우에는 <code>outerFunc()</code>가 상위 스코프에 위치하기에 <code>outerFunc</code>함수의 변수를 참조하여 10이 출력됩니다. </p>
<pre><code class="language-javascript">const x = 1 ;

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

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

outerFunc();</code></pre>
<p>이 코드에서 <code>innerFunc()</code>의 경우에는 함수 내부에 존재하는 중첩 함수의 형태가 아니므로 <code>outerFunc</code> 함수의 변수에 접근하지 못해 1이 출력됩니다. </p>
<p>=&gt; 따라서 자바스크립트는 렉시컬 스코프를 따른다는 것을 알 수 있습니다.</p>
<hr>
<h2 id="렉시컬-스코프">렉시컬 스코프</h2>
<p>자바스크립트 엔진은  함수를 어디서 호출했는지가 아닌, 함수를 어디에 <strong>정의</strong>했는지에 따라 상위 스코프를 결정하며, 이를 <strong>렉시컬(정적) 스코프</strong>라 합니다. </p>
<p>스코프는 사실 실행 컨텍스트의 렉시컬 환경입니다. 이 렉시컬 환경의 자신의 &quot;외부 렉시컬 환경에 대한 참조&quot;를 통해 상위 렉시컬 환경과 연결됩니다. 이것이 바로 스코프 체인입니다. </p>
<p>따라서, &quot;함수의 상위 스코프를 결정한다.&quot; 는 것은 <strong>&quot;렉시컬 환경의 외부 렉시컬 환경에 대한 참조에 저장할 참조값을 결정한다. &quot;</strong>는 것과 같습니다. 렉시컬 환경의 &quot;외부 렉시컬 환경에 대한 참조&quot;에 저장할 참조값이 바로 상위 렉시컬 환경에 대한 참조이며, 이것이 상위 스코프이기 때문입니다. 이 개념을 반영해 다시 렉시컬 스코프를 정의해보면 다음과 같습니다. </p>
<blockquote>
<p>렉시컬 환경의 &quot;외부 렉시컬 환경에 대한 참조&quot;에 저장할 참조값, 즉 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경(위치)에 의해 결정된다. 이것이 바로 렉시컬 스코프.</p>
</blockquote>
<hr>
<h2 id="함수-객체의-내부-슬롯-environment">함수 객체의 내부 슬롯 [[Environment]]</h2>
<p><strong>함수가 정의된 환경과 호출되는 환경은 다를 수 있습니다.</strong> 따라서 렉시컬 스코프가 가능하려면 함수는 자신이 호출되는 환경과는 상관없이 자신이 정의된 환경, 즉 <strong>상위 스코프를 기억</strong>해야 합니다. 이를 위해 함수는 자심의 내부 슬롯 [[Environment]]에 자신이 정의되는 환경, 즉 상위 스코프의 참조를 저장합니다. </p>
<p>다시말해, <strong>함수 정의가 평가되어 함수 객체를 생성</strong>할 때 자신이 <strong>정의된 환경</strong>(위치)에 의해 결정된 <strong>상위 스코프의 참조를 함수 객체 자신의 내부 슬롯[[Environment]]에 저장</strong>합니다. 이때, 자신의 내부 슬롯 [[Environment]]에 저장된 상위 스코프의 참조는 현재 실행 중인 실행 컨텍스트의 렉시컬 환경을 가리킵니다.</p>
<p>예를 들어, <strong>전역에서 정의된 함수 선언문은 전역 코드가 평가되는 시점에 평가</strong>되어 함수 객체를 생성합니다. 이때 생성된 함수 객체의 내부 슬롯 [[Environment]]에는 함수 정의가 평가되는 시점, 즉 전역 코드 평가 시점에 실행중인 실행 컨텍스트의 렉시컬 환경인 전역 렉시컬 환경의 참조가 저장됩니다. </p>
<p>함수 <strong>내부</strong>에서 정의된 함수 표현식은 <strong>외부 함수 코드가 실행되는 시점에 평가되어 함수 객체를 생성</strong>합니다. 이때 생성된 함수 객체의 내부 슬롯 [[Environment]]에는 함수 정의가 평가되는 시점, 즉 외부 함수 코드 실행 시점에 실행중인 실행 컨텍스트의 렉시컬 환경인 외부 함수 렉시컬 환경의 참조가 저장됩니다. </p>
<p>따라서 함수 객체의 내부 슬롯 [[Environment]]에 저장된 현재 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 바로 상위 스코프입니다. 또한 자신이 호출되었을 때 생성될 함수 렉시컬 환경의 &quot;외부 렉시컬 환경에 대한 참조&quot;에 저장될 참조값입니다. 함수 객체는 내부 슬롯 [[Environment]]에 저장한 렉시컬 환경의 참조, 즉 상위 스코프를 자신이 존재하는 한 기억합니다. </p>
<hr>
<h2 id="클로저와-렉시컬-환경">클로저와 렉시컬 환경</h2>
<pre><code class="language-javascript">const x = 1;

// ⓐ
function outer() {
  const x = 10;
  const inner = function () {console.log(x);}; // ⓑ
  return inner;
}

// outer 함수를 호출하면 중첩 함수 inner를 반환한다.
// 그리고 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 팝되어 제거된다.
const innerFunc = outer(); // ⓒ
innerFunc(); // ⓓ 10</code></pre>
<p>위 코드를 a-b-c-d순으로 살펴보도록 하겠습니다. </p>
<p>ⓐ outer 함수가 평가 되어 함수 객체를 생성할 때, 현재 실행 중인 실행 컨텍스트의 렉시컬 환경, 즉 전역 렉시컬 환경을 outer 함수 객체의 [[Environment]] 내부 슬롯에 상위 스코프로서 저장합니다.</p>
<p>outer 함수를 호출하면 outer 함수의 렉시컬 환경이 생성되고 앞서 outer 함수 객체의 [[Environment]] 내부 슬롯에 저장된 전역 렉시컬 환경을 outer 함수 렉시컬 환경의 &quot;외부 렉시컬 환경에 대한 참조&quot; 에 할당합니다.</p>
<p>ⓑ 중첩 함수 inner가 평가됩니다. 이때 중첩 함수 inner는 자신의 [[Environment]] 내부 슬롯에 현재 실행중인 실행 컨텍스트의 렉시컬 환경, 즉  outer 함수의 렉시컬 환경을 상위 스코프로서 저장합니다.</p>
<p>ⓒ outer 함수의 실행이 종료하면 inner 함수를 반환하면서 outer 함수의 생명주기가 종료됩니다. 즉 outer 함수의 실행 컨텍스트가 실행 컨텍스트 스택에서 제거됩니다.</p>
<p>이때 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 제거되지만 outer 함수의 렉시컬 환경까지 소멸하는 것은 아닙니다. </p>
<p>outer 함수의 렉시컬 환경은 inner 함수의 [[Environment]] 내부 슬롯에 의해 참조되고 있고 inner 함수는 전역 변수 innerFunc에 의해 참조되고 있으므로 가비지 컬렉션의 대상이 되지 않기 때문입니다. 가비지 컬렉터는 누군가가 참조하고 있는 메모리 공간을 함부로 해제하지 않습니다.</p>
<p>ⓓ  outer 함수가 반환한 inner 함수를 호출하면 inner 함수의 실행 컨텍스트가 생성되고, 실행 컨텍스트 스택에 push 됩니다. 그리고 렉시컬 환경의 외부 렉시컬 환경에 대한 참조에는 inner 함수 객체의 [[Environment]] 내부 슬롯에 저장되어 있는 참조 값이 할당됩니다.</p>
<p>이처럼 외부 함수의 생존 여부와 상관 없이 자신이 정의된 위치에 의해 결정된 상위 스코프를 기억하여 외부 함수보다 중첩 함수가 더 오래 유지 되는 이러한 중첩 함수를 클로저라고 부릅니다. 이때 클로저에 의해 참조되는 상위 스코프의 변수를 자유 변수라고 부릅니다.</p>
<hr>
<h2 id="캡슐화와-정보-은닉">캡슐화와 정보 은닉</h2>
<blockquote>
</blockquote>
<p>캡슐화는 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 메서드를  하나로 묶는 것을 말한다.
캡슐화는 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 정보 은닉이라 한다.</p>
<blockquote>
</blockquote>
<p>정보 은닉은 외부에 공개할 필요가 없는 구현의 일부를 외부에 공개되지 않도록 감추어 적절치 못한 접근으로부터 객체의 상태가 변경되는 것을 방지해 정보를 보호하고, 객체 간의 상호 의존성, 즉 결합도를 낮추는 효과가 있습니다.</p>
<p>대부분의 객체지향 프로그래밍 언어는 클래스를 정의하고 그 클래스를 구성하는 멤버(프로퍼티와 메서드)에 대하여 public, privated, protected 같은 접근 제한자를 선언하여 공개 범위를 한정할 수 있습니다.</p>
<p>public으로 선언된 프로퍼티와 메서드는 클래스 외부에서 참조할 수 있지만 private으로 선언된 경우는 클래스 외부에서 참조할 수 없습니다.</p>
<p>자바스크립트는 public, private, protected 같은 접근 제한자를 제공하지 않습니다. 따라서 자바스크립트 객체의 모든 프로퍼티와 메서드는 기본적으로 외부에 공개되어 있습니다. 즉, 객체의 모든 프로퍼티와 메서드는 기본적으로 public 합니다.</p>
<pre><code class="language-javascript">function Person(name, age) {
  this.name = name; // public
  let _age = age; // private

  // 인스턴스 메서드
  this.sayHi = function () {
    console.log(`Hi! My name is ${this.name}. I am ${_age}.`);
  };
}

const me = new Person(&#39;Lee&#39;, 20);
me.sayHi(); // Hi! My name is Lee. I am 20.
console.log(me.name); // Lee
console.log(me._age); // undefined

const you = new Person(&#39;Kim&#39;, 30);
you.sayHi(); // Hi! My name is Kim. I am 30.
console.log(me.name); // Kim
console.log(me._age); // undefined</code></pre>
<p>위의 코드에서 name 프로퍼티는 외부로 공개되어 있어서 자유롭게 참조하거나 변경할 수 있습니다. 즉, name 프로퍼티는 public 합니다. 하지만 _age 변수는 Person 생성자 함수의 지역 변수이므로 Person 생성자 함수 외부에서 참조하거나 변경할 수 없습니다. 즉, _age 변수는 private 합니다.</p>
<p>sayHi 메서드는 인스턴스 메서드이므로 Person 객체가 생성될 때마다 중복 생성됩니다. 중복 생성을 방지하기 위해 sayHi 메서드를 프로토타입 메서드로 변경하면 코드는 다음과 같습니다.</p>
<pre><code class="language-javascript">function Person(name, age) {
  this.name = name; // public
  let _age = age; // private
 }

 // 프로토타입 메서드
 Person.prototype.sayHi = function () {
   // Person 생성자 함수의 지역 변수 _age를 참조할 수 없다.
   console.log(`Hi! My name is ${this.name}. I am ${_age}`);

 };

const me = new Person(&#39;Lee&#39;, 20);
me.sayHi(); // Uncaught ReferenceError: _age is not defined at Person.sayHi
console.log(me.name); // Lee
console.log(me._age); // undefined</code></pre>
<p>하지만 이 경우 Person.prototype.sayHi 메서드 내에서 Person 생성자 함수의 지역 변수 _age를 참조할 수 없는 문제가 발생됩니다. 따라 아래의 코드와 같이 즉시 실행 함수를 사용하여 Person 생성자 함수와 Person.prototype.sayHi 메서드를 하나의 함수내에 모아야 합니다.</p>
<pre><code class="language-javascript">const Person = (function(){
  let _age = 0; // private

  // 생성자 함수
  function Person(name, age){
    this.name = name; // public
    _age = age;
  }

  // 프로토타입 메서드
  Person.prototype.sayHi = function(){
    console.log(`Hi! My name is ${this.name}. I am ${_age}.`);
  };

  // 생성자 함수를 반환
  return Person;  
}());

const me = new Person(&#39;Lee&#39;, 20);
me.sayHi(); // Hi! My name is Lee. I am 20.
console.log(me.name); // Lee
console.log(me._age); // undefined

const you = new Person(&#39;Kim&#39;, 30);
you.sayHi(); // Hi! My name is Kim. I am 30.
console.log(you.name); // Kim
console.log(you._age); // undefined
</code></pre>
<p>이를 실행하면 즉시 실행 함수가 반환하는 Person 생성자 함수와 Person 생성자 함수의 인스턴스가 상속받아 호출할 Person.prototype.sayHi 메서드는 즉시 실행 함수가 종료된 이후 호출됩니다. 하지만 Person 생성자 함수와 sayHi 메서드는 이미 종료되어 소멸한 즉시 실행 함수의 지역 변수 _age를 참조할 수 있는 클로저 입니다.</p>
<p>그치만 이 역시도 Person 생성자 함수가 여러 개의 인스턴스를 생성할 경우 다음과 같이 변수의 상태가 유지되지 않는 문제가 발생됩니다.</p>
<pre><code class="language-javascript">const me = new Person(&#39;Lee&#39;, 20);
me.sayHi(); // Hi! My name is Lee, I am 20.

const you = new Person(&#39;Kim&#39;, 30);
you.sayHi(); // Hi! My name is Kim, I am 30.

// _age 변수 값이 변경된다!
me.sayHi(); // Hi! My name is Lee, I am 30.</code></pre>
<p>이처럼 자바스크립트는 정보 은닉을 흉내낼 수는 있지만 완전하게 지원하지 않습니다.</p>
<hr>
<h2 id="자주-발생하는-실수">자주 발생하는 실수</h2>
<p>아래는 클로저를 사용할 때 자주 발생할 수 있는 실수를 보여주는 코드입니다.</p>
<pre><code class="language-javascript">var funcs = [];

for (var i = 0; i &lt; 3; i++) {
  funcs[i] = function () { return i; }; // ⓐ
}

for (var j = 0; j &lt; funcs.length; j++) {
  console.log(funcs[j]()); // ⓑ
}</code></pre>
<p>ⓐ 첫 번째 for 문의 코드 블록 내에서  함수가 func 배열의 요소로 추가됩니다.</p>
<p>ⓑ 두 번째 for문의 코드 블록 내에서 funcs 배열의 요소로 추가된 함수를 순차적으로 호출합니다. 이때 func 배열의 요소로 추가된 3개의 함수가 0,1,2 를 반환할 것으로 예상하지만 결과는 모두 3을 반환합니다.</p>
<p>이는 for 문의 변수 선언문에서 var 키워드로 선언한 i 변수는 블록 레벨 스코프가 아닌 함수 레벨 스코프를 갖기 때문에 전역 변수입니다. 전역 변수는 0, 1, 2 가 순차적으로 할당됩니다. 따라서 funcs 배열의 요소로 추가한 함수를 호출하면 전역 변수 i를 참조하여 i의 값 3이 출력됩니다.</p>
<p>따라 클로저를 사용해 원하는 형태로 바르게 동작하는 코드를 만들면 이는 아래와 같습니다.</p>
<pre><code class="language-javascript">var funcs = [];

for (var i = 0; i &lt; 3; i++){
  funcs[i] = (function (id) { // ⓐ
    return function () {
      return id;
    };
  }(i));
}

for (var j = 0; j &lt; funcs.length; j++) {
  console.log(funcs[j]());
}</code></pre>
<p>ⓐ 에서 즉시 실행 함수는 전역 변수 i 에 현재 할당되어 있는 값을 인수로 전달받아 매개변수 id에 할당한 후 중첩 함수를 반환하고 종료됩니다. 즉시 실행 함수가 반환한 함수는 funcs 배열에 순차적으로 저장됩니다.</p>
<p>이때 즉시 실행 함수의 매개 변수 id는 즉시 실행 함수가 반환한 중첩 함수의 상위 스코프에 존재합니다. 즉시 실행 함수가 반환환 중첩 함수는 자신의 상위 스코프를 기억하는 클로저이고, 매개변수 id는 즉시 실행 함수가 반환한 중첩 함수에 묶여있는 자유 변수가 되어 그 값이 유지됩니다.</p>
<p>아래와 같이 let 키워드를 통해 더 깔끔하게 코드를 만들수도 있습니다.</p>
<pre><code class="language-javascript">const funcs = [];

for (let i = 0; i &lt; 3; i++) {
  funcs[i] = function () { return i; };
}

for (let i = 0; i &lt; funcs.length; i++) {
  console.log(funcs[i]()); // 0 1 2
}</code></pre>
<p>이는 let이나 const 키워드를 사용하는 반복문은 코드 블록을 반복 실행할 때마다 새로운 렉시컬 환경을 생성하여 저장하기에 가능합니다. 단, 이는 반복문의 코드 블록 내부에서 정의할 때만 의미가 있는데, 반복문의 코드 블록 내부에 함수 정의가 없는 반복문이 생성하는 새로운 렉시컬 환경은 반복 직후, 아무도 참조하지 않기 때문에 가비지 컬렉션의 대상이 되기 때문입니다.</p>
<p>또 다른 방법으로는 고차 함수를 사용하는 방법이 있습니다. 이 방법은 변수와 반복문의 사용을 억제할 수 있기 때문에 오류를 줄이고 가독성을 좋게 만듭니다.</p>
<pre><code class="language-javascript">// 요소가 3개인 배열을 생성하고 배열의 인덱스를 반환하는 함수를 요소로 추가한다.
// 배열의 요소로 추가된 함수들은 모두 클로저다.
const funcs = Array.from(new Array(3), (_, i) =&gt; () =&gt; i); // (3) [ƒ, ƒ, ƒ]

// 배열의 요소로 추가된 함수 들을 순차적으로 호출한다.
funcs.forEach(f =&gt; console.log(f())); // 0 1 2</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CORS에러와 SEO란?]]></title>
            <link>https://velog.io/@anti_mang0/CORS%EC%97%90%EB%9F%AC%EC%99%80-SEO%EB%9E%80</link>
            <guid>https://velog.io/@anti_mang0/CORS%EC%97%90%EB%9F%AC%EC%99%80-SEO%EB%9E%80</guid>
            <pubDate>Fri, 23 Feb 2024 10:52:06 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-cors-에러에-대해-설명하고-어떻게-해결하면-될지-설명해-주세요">📌 CORS 에러에 대해 설명하고, 어떻게 해결하면 될지 설명해 주세요.</h2>
<h3 id="cors란">CORS란?</h3>
<p>브라우저에서는 보안적인 이유로 cross-origin HTTP요청들을 제한한다, 그래서 cross-origin 요청을 하려면 서버의 동의가 필요하게 된다. 서버가 OK하면 브라우저는 요청을 허락하고, OK하지 않으면 브라우저에서 거절한다. </p>
<p>이렇게 허락을 구하고 거절하는 메커니즘을 HTTP-header를 이용해서 가능한데, 이를 CORS라 한다. </p>
<p>브라우저에서는 cross-origin 요청을 안전하게 할 수 있도록 하는 메커니즘이다. </p>
<h3 id="cross-origin">Cross-Origin</h3>
<p>cross-origin은 다음 중 한 가지라도 다른 경우를 말한다. </p>
<ol>
<li>프로토콜 -&gt; http와 https의 프로토콜이 다르다.</li>
<li>도메인 -&gt; domain.com과 other-domain.com은 다르다.</li>
<li>포트 번호 -&gt; 7777포트와 3000포트는 다르다.</li>
</ol>
<h3 id="cors에러와-해결-방법">CORS에러와 해결 방법</h3>
<blockquote>
<p>Warning ! 
      Access to fetch at ‘<a href="https://myhompage.com%E2%80%99">https://myhompage.com’</a> from origin ‘<a href="http://localhost:3000%E2%80%99">http://localhost:3000’</a> has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
      &#39;<a href="https://myhomepage.com&#39;%EC%97%90%EC%84%9C">https://myhomepage.com&#39;에서</a> &#39;<a href="https://localhost:3000&#39;">https://localhost:3000&#39;</a> 출처로 가져올 수 있는 액세스가 CORS 정책에 의해 차단되었습니다. 요청된 리소스에 &#39;Access-Control-Allow-Origin&#39; 헤더가 없습니다. 불투명한 응답이 필요에 적합한 경우, 요청 모드를 &#39;no-cors&#39;로 설정하여 CORS가 비활성화된 리소스를 가져오십시오.</p>
</blockquote>
<p>CORS에러가 났을 때의 메세지이다. 앞서 말한 CORS의 의미를 토대로 에러를 확인하면, 결국 서버의 허용이 필요하다는 것이다. 서버에서 Access-Control-Allow-Origin 헤더에 허용할 출처를 기재하여 클라이언트에게 응답하면 된다. 이건 프론트가 어떻게 하질 못한다...</p>
<p>그래도 해결해야겠다! 싶다면 </p>
<h4 id="1-chrome-확장-프로그램-이용">1. Chrome 확장 프로그램 이용</h4>
<p>Chrome에서는 CORS 문제를 해결하기 위한 확장 프로그램을 제공해준다.
본 링크에서 &#39;<a href="https://chromewebstore.google.com/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?pli=1">Allow CORS: Access-Control-Allow-Origin</a>&#39; 크롬 확장 프로그램을을 설치 해준다. 그럼 localhost 환경에서 API 테스트 시, CORS 문제를 해결할 수 있다. </p>
<h4 id="2-프록시-사이트-이용">2. 프록시 사이트 이용</h4>
<p>Proxy란 클라이언트와 서버 사이의 중계 대리점이라고 보면 된다. 즉, 프론트에서 직접 서버에 리소스를 요청했더니 서버에서 따로 설정을 안해줘서 CORS에러가 뜬다면, 모든 출처를 허용한 서버 대리점을 통해 요청하면 된다..</p>
<h4 id="3-서버에서-access-control-allow-origin-헤더-세팅">3. 서버에서 Access-Control-Allow-Origin 헤더 세팅</h4>
<p>가장 정석적인 방법이다. 직접 서버에서 HTTP헤더 설정을 통해 출처를 허용하게 설정하는 것이다. 서버의 종류도 노드 서버, 스프링 서버, 아파치 버서 등 여러가지가 있으니, 이에 대한 각각의 해결 방법이 있다. </p>
<h2 id="📌-seo가-무엇인지-설명하고-개선을-위해-어떤-작업을-할-수-있을지-설명해-주세요">📌 SEO가 무엇인지 설명하고, 개선을 위해 어떤 작업을 할 수 있을지 설명해 주세요.</h2>
<h3 id="검색-엔진-최적화">검색 엔진 최적화</h3>
<p>SEO는 &#39;검색엔진 최적화(Search Engine Optimization)&#39; 또는 &#39;검색엔진 최적화 전문업체(Search Engine Optimizer)&#39;의 약어이다. 비즈니스, 웹 사이트의 소유주들이 자신의 정보를 노출이 많이 되도록 최적화시키는 것이다. 검색 엔진은 웹 페이지의 콘텐츠를 살펴보고 판단하기 위해 크롤링하는 로봇인 웹 크롤러를 사용한다. </p>
<h3 id="개선-방법">개선 방법</h3>
<h4 id="1-문법에-맞는-html작성">1. 문법에 맞는 HTML작성</h4>
<ul>
<li>시멘틱 태그를 이용해 홈페이지를 마크업한다. </li>
<li>잘못된 마크업을 사용했는지 Google Rich Result Test를 이용해 디버깅한다. <h4 id="2-고유하고-정확한-페이지-제목-만들기">2. 고유하고 정확한 페이지 제목 만들기</h4>
</li>
<li>클릭률을 높일 수 있도록 눈길을 사로잡는 문구를 사용한다. </li>
<li>페이지마다 고유한 title태그를 사용한다. </li>
<li>제목의 시작이나 끝에 사이트 이름을 포함하고 나머지 제목은 -, :, | 등을 사용한다.<h4 id="3-메타-태그-사용하기">3. 메타 태그 사용하기</h4>
</li>
<li>가능하면 특정 페이지를 정확하게 나타내는 설명을 작성한다. </li>
<li>모든 페이지를 작성할 수 없는 상황이라면, 홈페이지 내 각 페이지에 우선순위를 두어 주요 페이지들만 작성해야 한다.</li>
<li>설명에 콘텐츠 관련 정보를 포함한다. <h4 id="4-anchor-태그를-활용한-적절한-키워드-매칭">4. anchor 태그를 활용한 적절한 키워드 매칭</h4>
</li>
<li>div, button 태그 보다는 a 태그를 이용한다.</li>
<li>a href 요소가 없으면 Google은 URL을 크롤링하지 않는다.<h4 id="5-이미지-최적화">5. 이미지 최적화</h4>
</li>
<li>img 또는 picture 태그를 사용한다.</li>
<li>CSS를 사용하여 색인을 생성하지 않는다.</li>
<li>alt 속성을 사용한다.<h4 id="6-사이트를-모바일-친화적으로">6. 사이트를 모바일 친화적으로</h4>
</li>
<li>반응형 웹 디자인을 적용한다.</li>
<li>meta name=&quot;viewport&quot; 태그를 사용하여 브라우저에 콘텐츠 조정 방법을 알린다.</li>
<li>Google Mobile Friendly로 모바일 페이지를 테스트해서 내 홈페이지가 휴대기기와 원활히 호환되는지 확인한다.<h4 id="7-https-적용하기">7. HTTPS 적용하기</h4>
</li>
<li>동일 사이트일 때, http보다 https 보안 프로토콜을 사용하는 웹 사이트에 SEO 점수를 추가적으로 부여한다. <h4 id="8-페이지-로딩-속도-높이기">8. 페이지 로딩 속도 높이기</h4>
</li>
<li>속도가 느리면 잠재 고객을 유지시킬 수 없으며 이는 이탈률이 높아지는 결과를 초래하므로 페이지 로딩 속도를 높인다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[인터렉티브 자바스크립트 시작하기]]></title>
            <link>https://velog.io/@anti_mang0/%EC%9D%B8%ED%84%B0%EB%A0%89%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@anti_mang0/%EC%9D%B8%ED%84%B0%EB%A0%89%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 20 Dec 2023 17:06:59 GMT</pubDate>
            <description><![CDATA[<h2 id="indexjs-파일-html에-넣기">index.js 파일 html에 넣기</h2>
<pre><code class="language-javscsript">&lt;script src=&quot;index.js&quot;&gt;&lt;/script&gt;</code></pre>
<p>   이걸 주로 사용한다. 이때 넣는 위치는 body태그의 맨 밑에 넣는게 룰이라고 한다. </p>
<h2 id="id로-태그-선택하기">ID로 태그 선택하기</h2>
<p>맨 처음 자바스크립트를 배울 때 가장 많이 사용했던 <code>console.log</code> 처럼 미리 만들어져있는 <code>document.getElementById()</code> 메소드를 사용하면 된다. </p>
<h3 id="getelementbyid">getElementById</h3>
<p>메소드 이름 그대로, 어떤 요소를 가져오겠다는 의미이다. 그래서 이 메소드의 파라미터로 우리가 접근하고자 하는 태그의 id값을 문자열로 전달해주면 해당되는 태그가 선택되는 원리이다.</p>
<pre><code class="language-javscsript">const myTag = document.getElementById(&#39;id&#39;);</code></pre>
<p>우리가 html을 배울 때 id 속성은 다른 태그들과 구분하기 위해 붙여주는 고유한 값이라 배웠으니까, id속성을 활용하면 우리가 필요한 태그만을 명확하게 선택할 수 있는 장점이 있다. </p>
<p>그렇기 때문에 자바스크립트로 딱 하나의 요소만을 선택할 땐 html 태그에 id 속성을 부여하고 <code>getElementById</code>로 불러주면 된다. </p>
<p>참고로, 존재하지 않는 태그를 선택하게 되면 <code>null</code> 이 출력된다. </p>
<h2 id="class로-태그-선택하기">Class로 태그 선택하기</h2>
<p>id는 고유한 값이라 하나의 태그를 선택할 땐 유용하지만 만약 여러 요소들을 동시에 선택해야 하는 경우에는 활용하기가 좀 어렵다.</p>
<p>css로도 여러 요소들을 선택할 땐 class 속성을 활용한다. </p>
<p>class로 속성을 선택할 땐 <code>getElementsByClassName</code>을 사용한다. </p>
<h3 id="getelementsbyclassname">getElementsByClassName</h3>
<p>한 가지 주의해야 할 점은 여러가지 속성을 선택하는 것이므로 Element&#39;s&#39;가 붙는다는 점!</p>
<pre><code class="language-javscsript">const myTags = document.getElementsByClassName(&#39;className&#39;);</code></pre>
<p>console.log로 출력해보면 className 클래스가 있는 모든 태그들이 대괄호로 감싸져서 배열의 형태로 선택되게 되는데, <code>HTMLcollection</code>이라고 붙으며 출력된다. </p>
<p>각각의 index도 있고, length 프로퍼티도 있어서 배열 같아 보이지만 완벽한 배열은 아니다. 배열의 메소드인 <code>splice</code>, <code>push</code>같은 것들은 사용할 수 없어 엄밀히 말하면 배열은 아니다. 하지만 대괄호 표기법으로 1번 인덱스에 접근하거나 <code>length</code> 프로퍼티를 사용할 수 있고, <code>for...of</code> 문도 사용할 수 있어 유사배열(Array-Like Object)이라 부른다. </p>
<p>요소들의 순서는 html 태그에서 봤을 때 깊이와는 상관없이 무조건 위에서부터 아래로 내려간다. </p>
<p>또, 클래스 이름이 한 번만 선언된 것에 접근하려 한다면 딱 그 태그만 선택될 거라고 생각할 수 있는데, 그렇지 않다. 출력해보면 요소 한 개가 들어있는 HTMLcollection이 선택되기 때문에 하나만 선택하려면 0번 인덱스에 접근해야 한다. </p>
<pre><code class="language-javscsript">console.log(myTags[0]);</code></pre>
<p><code>getElementsByClassName</code>으로 존재하지 않는 클래스에 접근하게 되면 null이 아닌 빈 HTMLcollection이 출력된다. </p>
<pre><code class="language-javscsript">console.log(myTags === null);  //false
console.log(myTags.length);  //0</code></pre>
<h2 id="태그-이름으로-태그-선택하기">태그 이름으로 태그 선택하기</h2>
<p><code>document.getElementByTagName(&#39;태그이름&#39;)</code> 메소드를 활용하면 태그  이름으로 태그를 선택할 수 있게 된다.</p>
<pre><code class="language-javscsript">const btns = document.getElementsByTagName(&#39;button&#39;);
// html문서 내의 모든 button 태그를 선택하게 됨</code></pre>
<p><code>document.getElementsByClassName(&#39;class&#39;)</code>메소드와 마찬가지로 태그 이름으로 요소를 찾는 경우에 여러 개의 요소가 선택될 수 있기 때문에 메소드 이름에 Element&#39;s&#39;가 있고, 실행결과 역시 HTMLCollection을 리턴한다.</p>
<p>참고로 css 선택자처럼 &#39;*&#39; 값을 전달하게 되면 모든 태그를 선택할 수도 있는데, </p>
<pre><code class="language-javscsript">const btns = document.getElementsByTagName(&#39;button&#39;);
const allTags = document.getElementsByTagName(&#39;*&#39;);</code></pre>
<p>...하지만 css에서도 <code>*</code>을 많이 사용하는걸 보지 못했듯이, 많이 사용되는 메소드는 아니다. </p>
<h2 id="css-선택자로-태그-선택하기">CSS 선택자로 태그 선택하기</h2>
<p>css선택자로 태그를 선택하면 보다 간편하게 태그를 선택할 수 있다. </p>
<h3 id="id">ID</h3>
<pre><code class="language-javscsript">const myTag = document.querySelector(&#39;#myNumber&#39;);
const myTag2 = document.getElementById(&#39;myNumber&#39;);</code></pre>
<p><code>myTag</code>와 <code>myTag2</code>는 서로 같은 동작을 하게 된다. 
id를 선택할 땐 #을 붙인다. </p>
<h3 id="class">Class</h3>
<pre><code class="language-javscsript">const myTag3 = document.querySelector(&#39;.color-btn&#39;);</code></pre>
<p>위 코드를 실행해보면 맨 처음 코드만 실행되게 된다. 이게 의도한 것이라면 상관없지만, 클래스나 태그 이름으로 여러 요소를 선택하고 싶을 땐 </p>
<pre><code class="language-javscsript">const myTags1 = document.querySelectorAll(&#39;.color-btn&#39;);
const myTags2 = document.getElementsByClassName(&#39;color-btn&#39;);
</code></pre>
<p>이렇게 해주면 된다. 출력을 확인해보면 Nodelist라는 유사 배열이 출력되는데, <code>querySelector</code>을 이용할 땐 Nodelist, <code>getElementsByClassName</code>을 이용할 땐 HTMLCollection이 사용된다. 그래도 내용은 같다!</p>
<h2 id="이벤트와-버튼-클릭">이벤트와 버튼 클릭</h2>
<pre><code class="language-javascript">// 이벤트(Event)와 버튼 클릭
const btn = document.querySelector(&#39;#myBtn&#39;);

// 이벤트 핸들링(Event Handling)
btn.onclick = function() { // 이벤트 핸들러(Event Handler)
    console.log(&#39;Hello Codeit!&#39;);
};</code></pre>
<p>이벤트 핸들링은 html에서도 사용할 두 싰는데, </p>
<pre><code class="language-html">&lt;button id=&quot;myBtn&quot; onclick=&quot;console.log(&#39;Hello Codeit!&#39;)&quot;&gt;Click!&lt;/button&gt;</code></pre>
<p>이렇게도 사용 가능하다. 근데 사실 잘 쓰지는 않는다. 실제로 동작시킬 코드들은 간단하지가 않아서 가독성이 매우 떨어진다. 또한 코드의 일관성이 떨어져서 나중에 유지보수가 어려워질 수 있다. </p>
<h2 id="유사-배열">유사 배열?</h2>
<ul>
<li>배열과 유사한 객체 ex) HTMLCollection, NodeList, DOMTokenList, ...<h3 id="특징">특징</h3>
</li>
</ul>
<ol>
<li>숫자 형태의 indexing이 가능하다.</li>
<li><code>length</code> 프로퍼티가 있다.</li>
<li>배열의 기본 메소드를 사용할 수 없다.</li>
<li><code>Array.isArray(유사배열)</code>의 리턴값은 false다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 메모]]></title>
            <link>https://velog.io/@anti_mang0/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A9%94%EB%AA%A8</link>
            <guid>https://velog.io/@anti_mang0/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%A9%94%EB%AA%A8</guid>
            <pubDate>Tue, 05 Dec 2023 15:08:02 GMT</pubDate>
            <description><![CDATA[<h2 id="자바스크립트에서--와--가-어떻게-다른지">자바스크립트에서 == 와 === 가 어떻게 다른지?</h2>
<p><img src="https://velog.velcdn.com/images/anti_mang0/post/a267cd6d-c525-4299-9e3a-2c86cbba20f9/image.png" alt=""></p>
<blockquote>
<p><code>==</code>는 Equal Operator이고, <code>===</code>는 Strict Equal Operator이다. </p>
</blockquote>
<h3 id="equal-operator">Equal Operator</h3>
<p>==는 a==b라고 할 때, 같은지 아닌지를 비교하여 같으면 true, 다르면 false라 한다. 그냥 값만 같으면 true라는 것.</p>
<h3 id="strict-equal-operator">Strict Equal Operator</h3>
<p>&quot;엄격하게&quot;같음을 비교할 때 사용하는 연산자이다. ===는 a===b라 할 때, <strong>데이터 타입</strong>도 같은지를 비교해 같으면 true, 다르면 false라고 한다. </p>
<h3 id="예시">예시</h3>
<pre><code>let a = 1;
let b = &#39;1&#39;;
console.log(a == b) //true
console.log(a === b) //false
---------------------------------
console.log(null==undefined) //true
console.log(null===undefined) //false</code></pre><p>a, b는 둘 다 값이 1로 같지만, 하나는 숫자, 하나는 문자열이므로 ===에서는 false가 출력된다. 
Null과 undefined 또한 값이 없다는걸로 공통점이 있지만, 값의 종류가 다르므로 ===에서는 false.</p>
<h2 id="얕은-복사shallow-copy와-깊은-복사deep-copy">얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)</h2>
<h3 id="shallow-copy">Shallow Copy</h3>
<p><img src="https://velog.velcdn.com/images/anti_mang0/post/4e78464e-c8fe-4a3d-9db0-17fe02b5d545/image.png" alt=""></p>
<blockquote>
<p>얕은 복사는 참조값의 복사를 나타낸다.</p>
</blockquote>
<pre><code>const obj = {a: 1};
const copyObj = obj;

copyObj.a = 2;

console.log(obj.a); // 2
console.log(obj === copyObj); //true</code></pre><p> <code>obj</code>라는 객체를 <code>copyObj.a</code>값을 변경하였더니 기준의 <code>obj.a</code>값도 같이 변경되었다. 마찬가지로 두 객체를 비교해봐도 true가 나온다. 이렇게 자바스크립트의 참조 타입은 Shallow Copy가 된다고 볼 수 있으며, 이는 데이터가 그대로 생성되는 것이 아닌 <strong>해당 데이터의 참조 값을 전달하여 한 데이터를 공유</strong>하는 것이다. </p>
<h3 id="deep-copy">Deep Copy</h3>
<p><img src="https://velog.velcdn.com/images/anti_mang0/post/3a51497b-f4b3-47b3-8322-8e7f295e1a27/image.png" alt=""></p>
<blockquote>
<p>깊은 복사는 얕은 복사처럼 참조값이 복사되는것이 아니라, 값만 복사되는 것을 의미한다.</p>
</blockquote>
<h4 id="spread-연산자를-통한-복사">Spread 연산자를 통한 복사</h4>
<p>객체, 배열을 복사하여 새로운 객체, 배열을 만드는 깊은 복사 방법. 이는 <code>Object.assign()</code>메소드와 같이 객체 안의 객체는 앝은 복사가 된다는 점이 동일. </p>
<pre><code>const obj = {
    a: 1,
};

let copy = {...obj};

console.log(obj === copy);//false</code></pre><p>깊은 복사가 이루어져 console 결과는 <code>false</code></p>
<h4 id="objectassign메소드를-통한-복사">Object.assign()메소드를 통한 복사</h4>
<blockquote>
<p>객체를 병합하는 메소드이다. </p>
</blockquote>
<pre><code>Object.assign(target, ...sources);</code></pre><ul>
<li>target : 병합 결과를 저장할 대상 객체</li>
<li>sources : 병합할 하나 이상의 소스 객체</li>
</ul>
<p>소스 객체의 속성을 대상 객체로 복사한다. 소스 객체는 여러 개가 될 수 있고, 순서에 따라 대상 객체의 속성이 덮어씌워질 수 있다. </p>
<pre><code>const obj = {
    a: 1,
};

let copy = Object.assign({}, obj);

console.log(obj === copy); //false</code></pre><p>copy값을 바꿔도 더 이상 obj에 영향을 주지 않는다.</p>
<p>하지만! 객체 안의 객체는 얕은 복사가 이루어진다. (???)</p>
<pre><code>const obj = {
    A: {
        a: 1,
    },
    B: 2,
};

let copy = Object.assign({}, obj);
copy.B = 3;

console.log(obj === copy); //false

copy.A.a = 4;

console.log(obj.A === copy.A, obj.A.a, copy.A.a)//true 4 4</code></pre><p>copy는 마치 깊은복사가 이뤄진 것 같지만, A와 같은 객체 안의 객체는 &#39;얕은 복사&#39;가 이루어졌다. 따라서, 객체 안에 또 다른 객체가 있는 경우 깊은 복사를 원할 땐 적절하지 않은 방법이다. </p>
<h3 id="jsonparse-jsonstringify">JSON.parse(), JSON.stringify()</h3>
<blockquote>
<p>이 방법은 객체 안의 또 다른 객체까지 <strong>전부 깊은 복사</strong>가 이루어진다.</p>
</blockquote>
<p>다음은 사용 방법이다.</p>
<pre><code>const obj = {
  A: {
    a: 1,
  },
  B: 2,
};

let copy = JSON.parse(JSON.stringify(obj));

copy.A.a = 4;

console.log(obj.A); // { a: 1 }
console.log(copy.A); // { a: 4 }
console.log(obj.A === copy.A);</code></pre><p>Object.assing() 메소드와 spread 문법과 다르게 모든 것이 깊은 복사가 되었다.</p>
<p>따라서, 특별한 경우가 아니라면 이 방법을 통해 깊은 복사하는 것을 추천한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Branch merge와 Git flow]]></title>
            <link>https://velog.io/@anti_mang0/Branch-merge%EC%99%80-Git-flow</link>
            <guid>https://velog.io/@anti_mang0/Branch-merge%EC%99%80-Git-flow</guid>
            <pubDate>Fri, 01 Dec 2023 06:35:01 GMT</pubDate>
            <description><![CDATA[<h2 id="branch-merge란">branch merge란</h2>
<p>현재 branch에서 다른 branch를 합칠 때 사용된다</p>
<p>특정 branch로 합치게 해달라고 요청하는 pull request로 세 가지 방식 중 하나를 선택할 수 있다.</p>
<ol>
<li>create  a merge commit</li>
<li>squash and merge</li>
<li>rebase and merge</li>
</ol>
<p>각각 방식마다 커밋 메세지, 커밋 그래프를 어떻게 유지해야 할 지와 연관되어 있기 때문에 이렇게 나누어 관리한다. </p>
<h2 id="mergecreate--a-merge-commit">Merge(create  a merge commit)</h2>
<p><img src="blob:https://velog.io/ed442cfd-cda2-4812-82da-191832bd239d" alt="업로드중.."></p>
<blockquote>
<p>일반적으로 많이 사용하는 merge방법이며 커밋 이력을 모두 남길 때 사용된다. 장점이자 단점은 모든 커밋과 분기했던 branch 히스토리가 남는다는 것.</p>
</blockquote>
<h3 id="fast-forward설정이란">Fast-forward설정이란?</h3>
<p><code>git merge</code>는 <code>-ff</code> 옵션이 기본으로 설정되어 있는데, 이는 base브랜치가 이후 변경 내용이 없는 최신 브랜치일 경우 병합한다는 커밋 없이 합치고, 그렇지 않은 경우 병합 커밋을 남기고 합한다. </p>
<p>github의 <code>merge and pull request</code> 는 <code>git merge -—no-ff</code> 옵션으로 base 브랜치가 최신 브랜치라 할지라도 커밋을 남기도록 강제한다.</p>
<h2 id="squash-and-merge">Squash and merge</h2>
<p><img src="blob:https://velog.io/ae93d01c-3b6e-45d2-a2ad-267576b01dee" alt="업로드중.."></p>
<blockquote>
<p><code>git merge</code>에 <code>-squash</code> 옵션을 추가한 방법이다.  분기했던 branch에 있던 내용 a, b, c커밋을 모두 합쳐 하나의 새로운 커밋을 만든다.</p>
</blockquote>
<p>지저분한 커밋 히스토리들을 하나로 합쳐서 기능상 의미있는 하나의 커맛만 남길 때 사용한다.  잘못 사용해 과도한 생략을 하게 되면, 추후 변경 파악이 힘들 수 있다. </p>
<p><a href="https://stackoverflow.com/questions/2427238/what-is-the-difference-between-merge-squash-and-rebase">Merge VS Squash and merge
</a></p>
<h2 id="rebase-and-merge">Rebase and merge</h2>
<blockquote>
<p>분기했던 branch의 기준을 최신 base로 정하고, merge하는 방법이다. 결과적으로는 <code>git merge -ff</code>과 같은 상황이 된다</p>
</blockquote>
<p>rebase하면 커밋들의 base가 변경되어 커밋해서 또한 변경될 수 있다. 이런 경우 <code>git push -f</code>해야 할 수 있다. 머지 커밋을 남길 필요가 없는 merge에 하면 좋다. 커밋 그래프가 하나의 라인으로 그려져 가독성이 뛰어나다. </p>
<h2 id="git-flow란">Git flow란?</h2>
<p><img src="blob:https://velog.io/7b06af9b-8121-492d-9222-938bb1ebe8c1" alt="업로드중.."></p>
<p>브랜치를 나누는 방법에 대한 분류 중 하나이다. Git flow의 특징은 브랜치를 5종류로 나눈다. </p>
<ol>
<li>main(master) : <strong>출시 가능한 프로덕션 코드</strong>를 모아두는 브랜치이다. Main 브랜치는 프로젝트 시작 시 생성되며, 개발 프로세스 전반에 걸쳐 유지된다. 배포된 각 버전을 Tag를 이용해 표시해둔다.</li>
<li>feature : <strong>하나의 기능을 개발하기 위한 브랜치</strong>이다. Develop 브랜치에서 생성하며, 기능이 개발 완료되면 다시 Develop 브랜치로 머지된다. 머지할때 주의점은 Fast-Forward로 머지하지 않고, Merge Commit을 생성하며 머지를 해주어야 한다. 이렇게해야 히스토리가 특정 기능 단위로 묶이게 된다.<ul>
<li>네이밍은 <strong><code>feature/branch-name</code></strong> 과 같은 형태로 생성한다.</li>
</ul>
</li>
<li>develop : <strong>다음 버전 개발을 위한 코드</strong>를 모아두는 브랜치이다. 개발이 완료되면, Main 브랜치로 머지된다.</li>
<li>release : <strong>소프트웨어 배포를 준비하기 위한 브랜치</strong>이다. Develop 브랜치에서 생성하며, 버전 이름 등의 소소한 데이터를 수정하거나 배포전 사소한 버그를 수정하기 위해 사용된다. 배포 준비가 완료되었다면 Main과 Develop 브랜치에 둘다 머지한다. 이때, Main 브랜치에는 태그를 이용하여 버전을 표시한다. Release 브랜치를 따로 운용함으로써, 배포 업무와 관련없는 팀원들은 병렬적으로 Feature 브랜치에서 이어서 기능을 개발할 수 있게된다.<ul>
<li>네이밍은 <strong><code>release/v1.1</code></strong> 과 같은 형태로 생성한다.</li>
</ul>
</li>
<li>hotfix : <strong>이미 배포된 버전에 문제</strong>가 발생했다면, Hotfix 브랜치를 사용하여 문제를 해결한다. Main 브랜치에서 생성하며, 문제 해결이 완료되면 Main과 Develop 브랜치에 둘다 머지한다. Release 브랜치와 마찬가지로 Hotfix 브랜치를 따로 운용함으로써, 핫픽스 업무와 관련없는 팀은 병렬적으로 기능 개발을 할 수 있다.<ul>
<li>네이밍은 <strong><code>hotfix/v1.0.1</code></strong> 과 같은 형태로 생성한다.</li>
</ul>
</li>
</ol>
<p>main, develop은 필수 브랜치이지만 나머지 브랜치는 유지 보수를 목적으로 하는 선택적 브랜치이다. 본인 프로젝트와 스타일에 따라 커스터마이징하여 브랜치 이용 가능하다.</p>
]]></description>
        </item>
    </channel>
</rss>