<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyowon_lee.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 31 Oct 2021 16:58:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. hyowon_lee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyowon_lee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CORS(Cross-Origin Resource Sharing)]]></title>
            <link>https://velog.io/@hyowon_lee/CORSCross-Origin-Resource-Sharing</link>
            <guid>https://velog.io/@hyowon_lee/CORSCross-Origin-Resource-Sharing</guid>
            <pubDate>Sun, 31 Oct 2021 16:58:23 GMT</pubDate>
            <description><![CDATA[<h2 id="cors란">CORS란?</h2>
<p>Cross Origin Resource Sharing의 약자로 도메인 또는 포트가 다른 서버의 자원을 요청하는 매커니즘을 말한다. 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 <strong>브라우저에 알려주는</strong> 체제다.</p>
<h2 id="cors가-나오게-된-배경">CORS가 나오게 된 배경</h2>
<h3 id="동일-출처-정책same-origin-policy">동일 출처 정책(same-origin policy)</h3>
<p>예전에는 같은 도메인에서 모든 요청과 응답이 이뤄지는것이 당연했기 때문에 다른 서버로 요청을 보내는것을 보안상의 이유로 요청을 주고받을수 없게 했다.</p>
<p>웹이 단순 문서제공이 아니라 웹애플리케이션을 만들기 시작하면서 다른 서버로 요청을 주고받아야하는 경우가 많아졌기때문에 CORS가 나오게 되었다.</p>
<h2 id="cors-이슈">CORS 이슈</h2>
<p>동일 출처가 아닌경우 기본정책에 따라 다른서버에 요청한 데이터를 브라우저에서 차단하기 때문에 정상적으로 데이터를 받을 수 없게 되는것이다.</p>
<p>프로토콜, 서브도메인, 도메인, 포트 중 하나만 달라도 동일출처가 아니다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/4b863f41-500b-4b6a-9687-4c67b5925c33/image.png" alt=""></p>
<h3 id="해결방법">해결방법</h3>
<p>근본적인 해결방법은 서버에서 응답헤더에 프론트의 요청을 허용한다는 내용 넣어주는 것이다.</p>
<pre><code class="language-javascript">const express = require(&#39;express&#39;);
const cors = require(&#39;cors&#39;);

const app = express();

app.use(cors()); // CORS 미들웨어 추가</code></pre>
<p>express에서는 cors 미들웨어를 사용하면 된다.
위 코드를 적용하면 모든 요청에 대해 허가를 하게 된다. 
모든요청에 대해 허가하게되면 보안에 취약하기때문에 설정을 통해 일부 요청에대해서만  허가할 수 있다.</p>
<pre><code class="language-javascript">const corsOptions = {
    origin: &#39;http://localhost:3000&#39;, // 허락하고자 하는 요청 주소
    credentials: true, // true로 하면 설정한 내용을 response 헤더에 추가
};

app.use(cors(corsOptions)); // config 추가</code></pre>
<p>클라이언트에서 해결하는방법</p>
<ol>
<li><p>JSONP</p>
<p> 웹 브라우저가 css 같은 리소스파일은 동일출처정책에 영향받지않고 로딩이 가능하다. 이런 점을 이용해서 외부 서버에서 읽어온 js파일을 json으로 바꿔주는 편법이다. 리소스파일은 GET메서드로 읽어오기때문에 GET 방식의 API만 요청 가능하다.</p>
</li>
<li><p>프록시 서버 사용</p>
</li>
</ol>
<p>클라이언트에서 해결하는 방법은 공식적인 방법이 아닌 우회하는 방법이기때문에 서버에서 해결하는 것이 올바른 방법이다.</p>
<br>

<p><strong>참고</strong>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS">https://developer.mozilla.org/ko/docs/Web/HTTP/CORS</a>
<a href="https://www.npmjs.com/package/cors">https://www.npmjs.com/package/cors</a>
<a href="https://brunch.co.kr/@adrenalinee31/1">https://brunch.co.kr/@adrenalinee31/1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] transitionend 이벤트 활용하기]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-transitionend-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-transitionend-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Tue, 26 Oct 2021 11:46:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hyowon_lee/post/781bebde-7d0e-4bcf-a4fd-78453bf1b9fc/Oct-26-2021%2017-58-58.gif" alt=""></p>
<p>이번 팀 프로젝트에서 캐릭터를 랜덤으로 생성해주는 기능이 있었는데 스프라이트 이미지의 위치를 조정해서 눈과 입을 정할 수 있게 만들어 주었다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/077b28ac-89e7-4abf-8156-834ace9b1965/Oct-26-2021%2017-53-11.gif" alt=""></p>
<p>부드러운 전환효과를 주기위해서 transition 속성을 사용했는데 캐릭터 다시 만들기 버튼을 연속으로 클릭하는 경우 제대로 작동하지 않는 문제가 있었다.</p>
<p>이 문제를 transitionend 이벤트를 사용해서 해결하게 되어서 기록하고자한다.</p>
<blockquote>
<p><strong>transitionend 이벤트</strong>
transitionend 이벤트는 CSS transition 이 완료되면 발생한다. transition 속성이 제거되거나 display가 none으로 설정된 경우와 같이 완료 전에 transition이 제거된 경우에는 이벤트가 생성되지 않는다.</p>
</blockquote>
<p>!codepen[vfovetny-the-styleful/embed/OJjpYOY?default-tab=js%2Cresult]</p>
<p>위의 코드는 버튼을 클릭하면 active 클래스를 토글해준다.
active 클래스가 있으면 색깔과 크기가 변하면서 회전하는 css가 적용되어 있다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/af1f1cca-3491-49f3-9794-5be6edebf691/Oct-26-2021%2020-10-53.gif" alt=""></p>
<p>버튼을 트랜지션이 끝나기전에 누르게 되면 회전하던 박스가 회전 끝내지 못하는 문제가 있다.</p>
<p>이 문제를 해결하기 위해서는 트랜지션이 종료되기 전에 발생하는 클릭이벤트를 무시해줘야한다.</p>
<br>
첫번째 방법

<pre><code class="language-javascript">const box = document.querySelector(&#39;.box&#39;);
const button = document.querySelector(&#39;button&#39;);

const clickEvent = () =&gt; {
  button.onclick = null;
  box.textContent = &#39;회전하는중&#39;;
  box.classList.toggle(&#39;active&#39;);
};

button.onclick = clickEvent;

box.ontransitionend = () =&gt; {
  box.textContent = &#39;완료&#39;;
  button.onclick = clickEvent;
}</code></pre>
<p>클릭이벤트가 발생하면 바로 null을 할당해서 이벤트핸들러를 제거하고
transitionend 이벤트가 발생했을때 다시 이벤트핸들러를 등록해준다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/e9cc31c1-2cbe-4da6-9505-6199b1b291a2/Oct-26-2021%2020-11-51.gif" alt=""></p>
<p>이렇게 되면 첫번째 클릭이벤트가 발생한 이후에 발생한 발생한 클릭이벤트는 무시되고 버튼을 여러번 클릭해도 트랜지션이 종료된 후의 클릭에만 회전하게된다.</p>
<br>
두번째 방법

<pre><code class="language-javascript">const box = document.querySelector(&#39;.box&#39;);
const button = document.querySelector(&#39;button&#39;);
let isMoving = false;

button.onclick = () =&gt; {
  if (!isMoving) {
    box.textContent = &#39;회전하는중&#39;;
    box.classList.toggle(&#39;active&#39;);
  }
  isMoving = true;
};

box.ontransitionend = () =&gt; {
  isMoving = false;
  box.textContent = &#39;완료&#39;;
};</code></pre>
<p>isMoving 이라는 변수를 사용해서 isMoving이 false일때만 클래스를 토글해주는 방법이다. </p>
<p>우리 프로젝트에서는 두번째 방법을 적용하였다.</p>
<p>첫번째 방법을 사용하게 되면 키보드 이벤트에도 동일하게 이벤트핸들러를 제거했다가 다시 등록해줘야하기때문에 변수를 사용하는 방법이 더 좋다고 생각했다.</p>
<p>또 isMoving이라는 변수이름을 사용했기때문에 코드의 가독성도 좋다고 생각했다. </p>
<p>transition 속성을 자주 사용하는데 이런 이벤트를 알고 있다면 개발할때 유용하게 사용될것 같다.</p>
<br>
참고

<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/transitionend_event">https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/transitionend_event</a></p>
<p>모던 자바스크립트 Deep Dive</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] DOMContentLoaded 와 load]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-DOMContentLoaded-%EC%99%80-load</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-DOMContentLoaded-%EC%99%80-load</guid>
            <pubDate>Tue, 19 Oct 2021 01:15:00 GMT</pubDate>
            <description><![CDATA[<p>지난주동안 페어프로그래밍을 통해 여러가지 UI를 구현하게되었다. 아코디언 UI을 구현하던 중에 처음 로딩되었을때 펼쳐져있는 메뉴가 조금 잘리는 문제가 있었다. 내 화면에서는 정상적으로 나왔고 페어의 화면에서 잘려서 보였는데 미묘한 차이라서 처음에는 문제가 있는줄 몰랐다. </p>
<p>처음에는 단순히 scrollHeight가 안보이는 부분까지 요소의 높이를 구해주니까 <code>DOMContentLoaded</code> 이벤트가 발생했을때 scrollHeight로 펼쳐진 메뉴의 높이를 설정해주면 되겠다고 접근했다. 당연히 문제없이 동작할것이라고 생각했는데 잘려서 표시되니 원인을 알기 어려웠다.</p>
<p>그래서 혹시 setTimeout을 통해 시간을 늘려주면 괜찮을까 하고 시도해봤더니 정상적으로 표시되었다. </p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/a7e6f52d-22e1-488f-aa32-ef1655ccb42a/image.png" alt=""></p>
<p>왜 시간이 지난 후에는 scrollHeight를 정상적으로 계산해줄까 고민하다가 혹시 폰트에 따라서 달라지는것일까하는 생각을 했고 폰트를 적용하지 않았더니 높이 차이가 발생하는 것을 알게되었다.</p>
<p>load를 사용하면 폰트, 이미지 등이 모두 로드된 후에 발생하는 이벤트니까 정상적으로 보이겠다고 생각했고 load를 적용했더니 문제없이 작동하게되었다.</p>
<blockquote>
<p><code>DOMContentLoaded</code>
HTML 문서의 로드와 파싱이 완료되어 DOM 생성이 완료되었을 때 이벤트가 발생한다.</p>
</blockquote>
<p><code>load</code>
DOMContentLoaded 이벤트가 발생한 이후, 모든 리소스(이미지, 폰트 등)의 로딩이 완료되었을 때, 주로 window 객체에서 발생한다. </p>
<p>내 화면에서 제대로 표시됐던 이유는 캐시가 저장되어있어서 폰트가 적용된 높이가 구해진 상태였기 때문이였다. 이론을 알고있어도 문제상황에서 원인을 파악하고 내가 알고있는것을 적용하는 것은 어려운일이라고 생각했다. 구현을 완성시키기위해서 구현에만 치중될때가 있는데 결과를 완성하는 것도 중요하지만 공부하는 동안에는 이런 과정이 정말 중요하구나 느꼈다. </p>
<br>
참고

<p>모던 자바스크립트 Deep Dive</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] textContent 와 innerText]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-textContent-%EC%99%80-innerText</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-textContent-%EC%99%80-innerText</guid>
            <pubDate>Tue, 12 Oct 2021 11:59:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hyowon_lee/post/325a3e99-8df4-4cb6-a282-be9b0adcfa96/DOM-002.png" alt=""></p>
<p>특정 요소를 숨기기 위해 <code>display: none</code> 을 사용하면 리플로우가 일어난다. 리플로우 없는 다른 방법이 없을까 생각하다가 textContent는 리플로우가 발생하지 않는다는 생각이 났다. 찾아보다가 textContent 와 innerText 차이를 알게되어서 정리하게되었다.</p>
<p>우선 textContent로 텍스트를 조작하는 일은 리플로우가 발생한다.</p>
<blockquote>
<p><strong>리플로우(reflow)란?</strong>
브라우저 렌더링 과정에서 생성된 DOM이나 CSSOM를 변경 하게 되면 변경된 DOM과 CSSOM이 다시 렌더 트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 다시 렌더링 하는것을 리플로우, 리페인트라고 한다.</p>
</blockquote>
<h2 id="html-요소와-노드-객체">HTML 요소와 노드 객체</h2>
<p><img src="https://images.velog.io/images/hyowon_lee/post/5d7134d5-11e4-4561-adb0-2b5131dc489a/DOM-001.png" alt=""></p>
<p>HTML 요소는 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 요소 노드 객체로 변환된다. 이때 HTML 요소의 어트리뷰트는 어트리뷰트 노드로, HTML 요소의 텍스트 콘텐츠는 텍스트 노드로 변환된다.</p>
<p>이렇게 만들어진 노드 객체들은 HTML 요소의 중첩 관계에 의해 계층구조가 생긴다. 노드 객체들로 구성된 트리 자료구조를 DOM 이라 한다.</p>
<p>노드 객체도 자바스크립트의 객체이므로 프로토타입에 의한 상속을 받는다. 프로토타입 체인에 있는 모든 프로퍼티나 메서드를 사용 가능하다는  것이다. DOM이 제공하는 프로퍼티와 메서드를 DOM API라고 하고 DOM API를 사용하면 HTML의 구조나 내용, 스타일 등을 동적으로 변경할 수 있다.</p>
<h2 id="textcontent-와-innertext">textContent 와 innerText</h2>
<p>textContent 와 innerText는 프로퍼티이다.
setter와 getter 모두 존재하는 접근자 프로퍼티로서 요소 노드의 텍스트와 모든 자손 노드의 텍스트를 모두 취득하거나 변경한다.</p>
<blockquote>
<p><strong>접근자 프로퍼티란?</strong>
자체적으로 값을 갖지 않고 다른 데이터프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티</p>
</blockquote>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;body&gt;
    &lt;div id=&quot;foo&quot;&gt;
      Hello &lt;span style=&quot;text-transform: uppercase&quot;&gt;world!&lt;/span&gt;
    &lt;/div&gt;
    &lt;div id=&quot;bar&quot;&gt;
      Hello &lt;span style=&quot;text-transform: uppercase&quot;&gt;world!&lt;/span&gt;
    &lt;/div&gt;
  &lt;/body&gt;
  &lt;script&gt;
    const $foo = document.getElementById(&#39;foo&#39;);
    const $bar = document.getElementById(&#39;bar&#39;);

    console.log($foo.textContent); // Hello world!
    console.log($bar.innerText); // Hello WORLD!

    // HTML 마크업이 포함되어 있으면 문자열 그대로 텍스트로 취급된다.
    $foo.textContent = &#39;Hi &lt;span&gt;foo&lt;/span&gt;&#39;;
    $bar.innerText = &#39;Hi &lt;span&gt;bar&lt;/span&gt;&#39;;
  &lt;/script&gt;
&lt;/html&gt;
</code></pre>
<p>textContent 와 innerText 로 각각 id만 다르고 내용은 같은 foo와 bar의 텍스트를 가져오면 textContent는 css 는 고려되지않고 텍스트만 가져온다. innerText 는 css가 반영된 결과가 나오게 된다. 그 과정에서 리플로우가 발생하게 된다. </p>
<p>따라서 textContent로 단순히 텍스트를 가져올 때는 리플로우가 발생하지 않는다. </p>
<p>하지만 textContent로 텍스트를 변경할 때는 모든 자식 노드가 제거되고 할당한 문자열이 텍스트로 추가된다. 이것은 DOM을 조작하는 것이므로 리플로우가 발생하게 된다. innerText도 동일하다. </p>
<p>개념을 확실히 알고 구현하는 것이 중요하다고 생각했다.
<br></p>
<p>참고
모던 자바스크립트 Deep Dive
<a href="https://developer.mozilla.org/ko/docs/Web/API/Node/textContent">https://developer.mozilla.org/ko/docs/Web/API/Node/textContent</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 즉시 실행 함수]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-%EC%A6%89%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-%EC%A6%89%EC%8B%9C-%EC%8B%A4%ED%96%89-%ED%95%A8%EC%88%98</guid>
            <pubDate>Tue, 05 Oct 2021 01:00:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hyowon_lee/post/1ac327c7-4985-4444-bab9-7fce6d6abc68/%E1%84%8C%E1%85%A6%E1%84%86%E1%85%A9%E1%86%A8%E1%84%8B%E1%85%B3%E1%86%AF%20%E1%84%8B%E1%85%B5%E1%86%B8%E1%84%85%E1%85%A7%E1%86%A8%E1%84%92%E1%85%A2%E1%84%8C%E1%85%AE%E1%84%89%E1%85%A6%E1%84%8B%E1%85%AD_-001%20(3).png" alt=""></p>
<h2 id="즉시-실행-함수">즉시 실행 함수</h2>
<p>함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수(IIFE, Immediately Invoked Function Expression)라고 한다.</p>
<p>즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다. </p>
<pre><code class="language-javascript">
// 익명 즉시 실행 함수
(function () {
 var a = 3;
 var b = 5;
 return a * b;
}());


// 기명 즉시 실행 함수
(function foo() {
 var a = 3;
 var b = 5;
 return a * b;
}());

foo(); // ReferenceError: foo is not defined
</code></pre>
<p>기명 즉시 실행 함수의 경우 함수 이름이 함수 몸체에서만 유효한 식별자 이므로 함수를 다시 호출할 수 없다.</p>
<p>함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다.</p>
<h3 id="즉시실행함수를-그룹연산자괄호로-감싸는-이유">즉시실행함수를 그룹연산자(괄호)로 감싸는 이유</h3>
<pre><code class="language-javascript">function () { // SyntaxError: Function statements require a function name
 // ...
}();</code></pre>
<p>이 코드의 경우 자바스크립트 엔진이 함수 선언문으로 해석하는 문맥이다. 함수 선언문의 경우 함수 이름을 생략할 수 없어서 에러가 발생한다.</p>
<pre><code class="language-javascript">function foo() {
 // ...
}(); // SyntaxError: Unexpected token &#39;)&#39;</code></pre>
<p>이 코드의 경우 자바스크립트 엔진이 암묵적으로 수행하는 세미콜론 자동 삽입 기능에 의해 함수 선언문이 끝나는 위치에 세미콜론이 추가된다.</p>
<pre><code class="language-javascript">function foo() {};(); </code></pre>
<p>추가된 세미콜론 뒤에 괄호는 함수 호출 연산자가 아니라 그룹 연산자로 해석되고 그룹 연산자의 피연산자가 없기때문에 에러가 발생한다.</p>
<p>그룹 연산자로 즉시 실행 함수를 감싸는 이유는 함수를 평가해서 함수 객체를 생성하기 위해서다.</p>
<p>그룹 연산자 안의 함수는 자바스크립트 엔진이 함수 리터럴로 해석하고 평가하여 함수 객체로 생성한다. </p>
<pre><code class="language-javascript">
(function () {
 // ...
}());

(function () {
 // ...
})();

!function () {
 // ...
}();

+function () {
 // ...
}();</code></pre>
<p>따라서 위와 같이 값으로 평가되는 문맥이라면 함수 객체가 생성되고 호출할 수 있게 된다. 일반적으로는 그룹연산자와 함께 사용한다.</p>
<h3 id="즉시실행함수를-사용하는-이유">즉시실행함수를 사용하는 이유</h3>
<h4 id="전역변수-사용을-억제하기-위해서">전역변수 사용을 억제하기 위해서</h4>
<blockquote>
<p><strong>전역변수의 문제점</strong></p>
</blockquote>
<ul>
<li>전역 변수는 모든 코드가 전역변수를 참조하고 변경할 수 있기때문에 상태가 변경 될 수 있는 위험성이 높다.</li>
<li>생명주기가 어플리케이션의 생명주기와 동일하기때문에 메모리 리소스도 오랜 기간 소비한다.</li>
<li>스코프 체인의 종점에 위치하기 때문에 변수 검색 속도가 느리다</li>
<li>자바스크립트는 파일이 분리 되어있다해도 하나의 전역 스코프를 공유하기때문에 같은 스코프 내에 전역변수나 전역함수가 예상치 못한 결과를 가져올 수 있다.</li>
</ul>
<p>전역변수는 위와 같은 문제점이 있으므로 사용하지 않는 편이 좋다.
모든 코드를 즉시 실행 함수로 감싸면 모든 변수는 즉시 실행 함수의 지역 변수가 된다. 
변수의 충돌을 피할 수 있어 라이브러리 등에 자주 사용된다. </p>
<h4 id="정보-은닉을-위해서">정보 은닉을 위해서</h4>
<p>즉시 실행 함수는 클로저를 만들때 사용된다.</p>
<p>클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우를 말한다.</p>
<p>클로저는 상태가 의도치 않게 변경되지 않도록 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하여 상태를 안전하게 변경하고 유지하기 위해 사용한다.</p>
<h4 id="렉시컬-환경을-공유하는-클로저를-만들기-위해서">렉시컬 환경을 공유하는 클로저를 만들기 위해서</h4>
<pre><code class="language-javascript">// 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환한다.
const counter = (function () {
  // 카운트 상태를 유지하기 위한 자유 변수
  let counter = 0;
  // 함수를 인수로 전달받는 클로저를 반환
  return function (predicate) {
    // 인수로 전달받은 보조 함수에 상태 변경을 위임한다.
    counter = predicate(counter);
    return counter;
  };
})();
// 보조 함수
function increase(n) {
  return ++n;
}
// 보조 함수
function decrease(n) {
  return --n;
}
// 보조 함수를 전달하여 호출
console.log(counter(increase)); // 1
console.log(counter(increase)); // 2
// 자유 변수를 공유한다.
console.log(counter(decrease)); // 1
console.log(counter(decrease)); // 0
</code></pre>
<p>이 코드의 경우 고차 함수가 여러번 호출되면 함수 실행 컨텍스트가 여러개 생겨서 실행 컨텍스트 마다 참조하는 변수가 개별로 존재하게 된다. </p>
<p>increase 함수와 decrease 함수가 변수를 공유하기 위해서는 고차 함수가 단 한번만 호출되어야 하므로 즉시 실행 함수를 사용해야한다.</p>
<br>


<p><strong>참고</strong>
모던 자바스크립트 Deep Dive
<a href="https://dev.to/myk/8-what-is-iife-in-javascript-1bng">https://dev.to/myk/8-what-is-iife-in-javascript-1bng</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] GitHub로 협업하기 - Forking Workflow]]></title>
            <link>https://velog.io/@hyowon_lee/Git-GitHub%EB%A1%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0-Forking-Workflow</link>
            <guid>https://velog.io/@hyowon_lee/Git-GitHub%EB%A1%9C-%ED%98%91%EC%97%85%ED%95%98%EA%B8%B0-Forking-Workflow</guid>
            <pubDate>Sun, 03 Oct 2021 14:49:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hyowon_lee/post/6356c523-e11d-45f7-a24e-1321fc077480/image.png" alt=""></p>
<h2 id="forking-workflow">Forking Workflow</h2>
<ul>
<li>팀장의 저장소를 <code>Fork</code>해서 팀원마다 각자 저장소를 가지고 프로젝트를 진행하는 방식이다.</li>
<li>팀원은 각자의 저장소를 가지고있기때문에 자유롭게 작업이 가능하다.</li>
<li>팀원의 작업 내용은 <code>Pull requests</code>를 통해 팀장의 확인 후 반영된다.</li>
<li>팀장 저장소의 권한은 팀장만 가지고 있으면서 다른 사람의 커밋을 프로젝트에 적용이 가능하다.</li>
<li>팀장이 코드를 확인하고 머지하기 때문에 안전하게 협업이 가능하다.</li>
<li>오픈소스프로젝트에서 많이 사용하는 방식이다.</li>
</ul>
<p><img src="https://images.velog.io/images/hyowon_lee/post/de679003-7937-4969-8a7b-0014844637d6/image.png" alt=""></p>
<h2 id="gitflow-workflow">Gitflow Workflow</h2>
<p>Forking Workflow는 일반적으로 Gitflow Workflow를 기반으로 하는 분기 모델을 따른다.
Gitflow를 간단히 설명하자면 5가지의 브랜치로 프로젝트를 관리하는 것이다.</p>
<blockquote>
<p>master : 제품으로 출시될 수 있는 브랜치
develop : 다음 출시 버전을 개발하는 브랜치
feature : 기능을 개발하는 브랜치
release : 이번 출시 버전을 준비하는 브랜치
hotfix : 출시 버전에서 발생한 버그를 수정 하는 브랜치</p>
</blockquote>
<p><a href="https://danielkummer.github.io/git-flow-cheatsheet/index.ko_KR.html">여기</a>에서 git-flow 설치와 주요 명령을 볼 수 있다.</p>
<h2 id="협업하는방법">협업하는방법</h2>
<h3 id="1-팀장이-저장소를-만들고-프로젝트-설정">1. 팀장이 저장소를 만들고 프로젝트 설정</h3>
<p><img src="https://images.velog.io/images/hyowon_lee/post/81493f83-81ba-43e2-b214-f84d3de6de89/image.png" alt=""></p>
<p>팀장이 저장소를 만들고 로컬에 clone 한다.
<code>git clone {repo address}</code>
<code>git flow init</code> 을 통해 git flow를 사용하기위한 초기화를 해준다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/533f52be-4d75-4a9f-a459-bbe9d6f4a72a/image.png" alt=""></p>
<p>git flow에 필요한 브랜치가 생성이 되고 main 브랜치에서 자동으로 develop 브랜치로 이동하게 된다. </p>
<p>이 상태에서 원격저장소에 push를 한다.
<code>git push -u origin develop</code> </p>
<h3 id="2-팀원이-fork">2. 팀원이 Fork</h3>
<p><img src="https://images.velog.io/images/hyowon_lee/post/596d9ee6-6299-470f-9237-32f49627fe2d/image.png" alt=""></p>
<p>main 브랜치와 develop 브랜치가 있는 상태에서
팀장의 원격저장소를 가서 Fork 버튼을 누른다.
그러면 팀장의 원격저장소가 복사되어 팀원의 원격저장소가 생긴다.</p>
<p>팀원도 동일하게 자신의 원격저장소를 로컬에 clone하고
<code>git flow init</code> 을 해준다.</p>
<h3 id="3-issues에-각자-담당할-일을-등록">3. Issues에 각자 담당할 일을 등록</h3>
<p><img src="https://images.velog.io/images/hyowon_lee/post/9f83ebc1-f0d0-407f-b1d6-248b0763d75a/image.png" alt=""></p>
<p>팀원은 작업하기 전에 팀장의 원격저장소의 Issues에 각자 담당할 일을 등록한다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/c7b9c4bd-4389-4aad-bf25-e783d7f00aa1/image.png" alt=""></p>
<p>팀장은 <code>Projects</code>에서 <code>Create a project</code> 버튼을 클릭해서 Project를 만든다.</p>
<p>이때 템플릿을 선택할 수 있는데 <code>Automated kanban</code>를 선택하면 To Do, In Progress, Done 컬럼이 생성되고 이슈를 진행상황에 따라 확인 할 수 있다.</p>
<p>팀원이 등록한 이슈를 확인하고  Assignees, Labels, Projects 등을 지정해준다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/51580fbf-cfb8-46f0-8c7d-d80d1419f20f/image.png" alt="">
<img src="https://images.velog.io/images/hyowon_lee/post/fd399c77-7f41-4377-bb78-c186089cb24d/image.png" alt=""></p>
<h3 id="4-각자-맡은-기능을-개발하고-개인저장소에-push">4. 각자 맡은 기능을 개발하고 개인저장소에 Push</h3>
<p><code>git flow feature start 브랜치명</code> 으로 기능에 따라 브랜치를 새로 생성해서 개발한다. </p>
<p>커밋은 의미있는 단위이면서 정상적으로 동작하는 단위로 커밋한다.</p>
<p>기능 개발이 끝나면 <code>git flow feature finish 브랜치명</code> 명령을 입력하면 해당 브랜치를 develop 브랜치에 머지하고 삭제를 해준다. </p>
<p><code>git push -u origin develop</code> 로 자신의 원격 저장소로 push한다. </p>
<h3 id="5-pull-requests-생성">5. Pull requests 생성</h3>
<p><img src="https://images.velog.io/images/hyowon_lee/post/8b24acce-1e1c-4a02-9912-582829281d99/image.png" alt=""></p>
<p>자신의 원격 저장소로 push 하고나면 <code>Compare &amp; pull request</code> 버튼이 생기는 것을 볼 수 있다.</p>
<p>이 버튼이 생기지 않아도 Pull request로 직접 들어가서 생성이 가능하다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/4e9cd0fb-bae9-4460-83ea-fb3ef7cd7009/image.png" alt=""></p>
<p>❗️ 팀원의 develop 브랜치에서 팀장의 develop 브랜치로 보내야한다. </p>
<h3 id="6-팀장-코드-리뷰-및-merge">6. 팀장 코드 리뷰 및 Merge</h3>
<p><img src="https://images.velog.io/images/hyowon_lee/post/a9918b27-e060-4cf4-8b14-8f3df844af57/image.png" alt=""></p>
<p>팀장은 풀리퀘스트를 통해서 팀원이 작업한 내용을 볼 수 있고
<code>Files changed</code> 에서 코드리뷰를 할 수 있다.
<img src="https://images.velog.io/images/hyowon_lee/post/dd04c0ee-f695-4992-b539-7ad78dd3d6e1/image.png" alt=""></p>
<p>원하는 위치에 <code>+</code>를 누르면 코멘트를 추가할 수 있다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/e2117534-fbcb-4eb4-82b3-3571906a89d7/image.png" alt=""></p>
<p>수정사항이 없으면 <code>Approve</code> 를 선택하고 <code>Finish your review</code> 를 누르면 된다.</p>
<p>수정이 필요한 경우에는 <code>Request changes</code> 를 선택한다.</p>
<p>풀리퀘스트가 머지되기 전에는 팀원이 수정해서 푸시한게 자동으로 풀리퀘스트에 반영되기때문에 또 풀리퀘스트를 생성하지 않아도 된다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/e36110e2-3824-42a7-ad8f-f92a4d0f633f/image.png" alt="">
<img src="https://images.velog.io/images/hyowon_lee/post/c150ae78-8e16-40f7-b649-67d1e8e63573/image.png" alt=""></p>
<p><code>Resolve converstion</code> 를 누르면 대화가 접힌다</p>
<p><code>Merge pull request</code> 를 누르고 <code>Confirm merge</code> 를 누르면 현재 풀리퀘스트가 팀장의 develop 브랜치에 반영된다.</p>
<h3 id="7-pull-하기">7. Pull 하기</h3>
<p>팀장의 로컬 저장소를 최신화 하기 위해서 <code>git pull origin develop</code> 을 해준다.</p>
<p>다른 팀원은 팀장의 원격저장소의 내용을 pull 해야되기때문에 <code>git pull upstream develop</code> 을 해줘야한다.</p>
<p>이때 환경에 따라서 upstream이 자동으로 추가되지 않을 수 있다.</p>
<p><code>git remote -v</code> 로 upstream이 등록돼있는지 확인한다.</p>
<p>origin만 있는 경우에는 </p>
<p><code>git remote add upstream {팀장 원격저장소 주소}</code> 를 통해 upstream을 등록해주면된다.</p>
<hr/>

<p>참고</p>
<ul>
<li><a href="https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow">https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow</a></li>
<li><a href="https://woowabros.github.io/experience/2017/10/30/baemin-mobile-git-branch-strategy.html">https://woowabros.github.io/experience/2017/10/30/baemin-mobile-git-branch-strategy.html</a></li>
<li><a href="https://www.tomasbeuzen.com/post/git-fork-branch-pull/">https://www.tomasbeuzen.com/post/git-fork-branch-pull/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 함수형 프로그래밍]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Tue, 28 Sep 2021 11:53:01 GMT</pubDate>
            <description><![CDATA[<p>프로그래밍 패러다임마다 장단점이 존재하는데 각각의 특징과 장단점을 잘 알고 적절하게 사용할 줄 아는 것이 중요하기때문에 잘 몰랐던 함수형 프로그래밍에 대해 정리해보았다.</p>
<p><img src="https://images.velog.io/images/hyowon_lee/post/183ab1b6-869a-42ea-8395-3ee6caf87931/%E1%84%8C%E1%85%A6%E1%84%86%E1%85%A9%E1%86%A8%E1%84%8B%E1%85%B3%E1%86%AF%20%E1%84%8B%E1%85%B5%E1%86%B8%E1%84%85%E1%85%A7%E1%86%A8%E1%84%92%E1%85%A2%E1%84%8C%E1%85%AE%E1%84%89%E1%85%A6%E1%84%8B%E1%85%AD_-002.png" alt=""></p>
<h2 id="함수형프로그래밍이란">함수형프로그래밍이란?</h2>
<p>순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해서 불변성(immutability)을 지향하는 프로그래밍 패러다임이다. </p>
<h2 id="함수형프로그래밍의-특징">함수형프로그래밍의 특징</h2>
<h3 id="순수함수-pure-function">순수함수 (pure function)</h3>
<ul>
<li>동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수</li>
<li>어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과(side effect)가 없는 함수</li>
</ul>
<pre><code class="language-javascript">function add(a, b) {
  return a + b;
}

console.log(add(1, 2)); // 3
console.log(add(1, 2)); // 3</code></pre>
<p>순수 함수는 동일한 인수가 전달되면 언제나 동일한 값을 반환하기때문에 결과를 예측할 수 있고 테스트하기 편하다.</p>
<h3 id="일급객체">일급객체</h3>
<p>다음의 조건을 만족하는 객체를 일급 객체라고 한다.</p>
<ol>
<li>무명의 리터럴로 생성할 수 있다. 즉, 런타임에 생성이 가능하다.</li>
<li>변수나 자료구조(객체, 배열 등)에 저장할 수 있다.</li>
<li>함수의 매개변수에 전달할 수 있다.</li>
<li>함수의 반환값으로 사용할 수 있다.</li>
</ol>
<p>자바스크립트는 함수를 값과 동일하게 사용할 수 있기때문에 함수형 프로그래밍이 가능하다.</p>
<h3 id="고차함수-higher-order-function-hof">고차함수 (Higher-Order Function, HOF)</h3>
<ul>
<li>매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수</li>
</ul>
<pre><code class="language-javascript">// 외부에서 전달받은 f를 n만큼 반복 호출한다.
function repeat(n, f) {
  for (let i = 0; i &lt; n; i++) {
    f(i); // i를 전달하면서 f를 호출
  }
}

const logAll = function (i) {
  console.log(i);
};

// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logAll); // 0 1 2 3 4

const logOdds = function (i) {
  if (i % 2) console.log(i);
};

// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logOdds); // 1 3
</code></pre>
<p>함수를 매개변수로 전달할 수 있기때문에 유연한 구조를 갖게된다.
조건문과 반복문 대신 <code>map</code>,<code>reduce</code> 등 고차함수를 사용해서 코드의 가독성을 향상시킨다.</p>
<p>함수형 프로그래밍은 거의 모든 것을 순수 함수로 나누어 문제를 해결하는 기법으로, 작은 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해준다.</p>
<p>또 변경 가능한 상태를 원천적으로 배제하기 때문에 프로그래머는 잠금(Lock)과 동기화(Synchronize)와 같은 골치 아픈 스레드 관련 문제에서 벗어나 핵심 로직 구현에 집중할 수 있다.</p>
<p>하지만 UI어플리케이션에서는 많은 상태 변화가 일어나기때문에 함수형 프로그래밍만 이용하기는 어려운 부분이 있다. </p>
<p>자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이므로 필요할때 적절히 섞어서 사용하면 될 것 같다.</p>
<h4 id="참고">참고</h4>
<p>모던 자바스크립트 Deep Dive
<a href="https://mangkyu.tistory.com/111">https://mangkyu.tistory.com/111</a>
<a href="https://engineering.linecorp.com/ko/blog/functional-programing-language-and-line-game-cloud/#lazy-eval">https://engineering.linecorp.com/ko/blog/functional-programing-language-and-line-game-cloud/#lazy-eval</a>
<a href="https://www.youtube.com/watch?v=4ezXhCuT2mw">https://www.youtube.com/watch?v=4ezXhCuT2mw</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] Object.is 메서드]]></title>
            <link>https://velog.io/@hyowon_lee/JavaScript-Object.is-%EB%A9%94%EC%84%9C%EB%93%9C</link>
            <guid>https://velog.io/@hyowon_lee/JavaScript-Object.is-%EB%A9%94%EC%84%9C%EB%93%9C</guid>
            <pubDate>Tue, 14 Sep 2021 08:51:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/hyowon_lee/post/5df61ca8-9cf1-4271-bd31-e8bc19e8accb/%E1%84%8C%E1%85%A6%E1%84%86%E1%85%A9%E1%86%A8%E1%84%8B%E1%85%B3%E1%86%AF%20%E1%84%8B%E1%85%B5%E1%86%B8%E1%84%85%E1%85%A7%E1%86%A8%E1%84%92%E1%85%A2%E1%84%8C%E1%85%AE%E1%84%89%E1%85%A6%E1%84%8B%E1%85%AD_-001%20(1).png" alt=""></p>
<h2 id="자신과-일치하지-않는-유일한-값">자신과 일치하지 않는 유일한 값</h2>
<p>자바스크립트에서 <code>NaN</code> 은 <strong>산술 연산 불가(not-a-number)</strong>를 뜻한다.
동등 비교 연산자 <code>==</code> 와 일치 비교 연산자 <code>===</code> 로 <code>NaN</code>을 비교하면 둘다 <code>false</code> 를 반환한다.
<code>NaN</code> 은 자기자신을 비교했을때 일치하지 않는 유일한 값이다.</p>
<pre><code class="language-javascript">console.log(NaN == NaN); // false
console.log(NaN === NaN); // false</code></pre>
<p><code>0*&#39;string&#39;</code> 은 평가결과가 연산불가이므로 <code>NaN</code>이지만 비교한 결과는 false가 나온다.</p>
<pre><code class="language-javascript">console.log(0 * &#39;string&#39; == NaN); // false
console.log(0 * &#39;string&#39; === NaN); // false</code></pre>
<h2 id="0-과--0"><code>+0</code> 과 <code>-0</code></h2>
<p>자바스크립트에서는 <code>+0</code> 과 <code>-0</code>이 존재한다.
부호가 다르기때문에 일치하지 않는 값이여야 하지만 <code>+0</code> 과 <code>-0</code> 역시 우리가 예측한 값과는 다른 결과가 출력된다.</p>
<pre><code class="language-javascript">console.log(+0 == -0); // true
console.log(+0 === -0); // true</code></pre>
<p>그렇다면 어떻게해야 예측한 결과와 동일한 결과를 얻을 수 있을까?</p>
<h2 id="objectis-메서드">Object.is 메서드</h2>
<p>ES6에서 도입된 Object.is 메서드는 다음과 같이 예측 가능한 정확한 비교 결과를 반환한다. 그 외에는 일치 비교 연산자와 동일하게 동작한다.</p>
<pre><code class="language-javascript">console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(-0, +0)); // false</code></pre>
<p><code>Object.is</code> 메서드는 어떻게 비교하는지 궁금해서 mdn을 찾아보니 폴리필 코드를 볼 수 있었다.</p>
<p><strong>폴리필이란?</strong>
최신 사양의 기능을 지원하지 않는 브라우저를 위해 누락된 최신 사양의 기능을 구현하여 추가하는 것</p>
<p><code>Object.is</code> 메서드는 es6부터 도입됐기때문에 es6를 지원하지 않는 IE 브라우저는 <code>Object.is</code> 메서드를 사용하지 못한다.
따라서 IE 브라우저에서 <code>Object.is</code> 메서드를 사용하기 위해서는 폴리필이 필요하다.</p>
<pre><code class="language-javascript">
if (!Object.is) {
  Object.is = function(x, y) {
    if (x === y) {
      return x !== 0 || 1 / x === 1 / y;
   } else {
     return x !== x &amp;&amp; y !== y;
   }
  };
}
</code></pre>
<p>코드를 한줄씩 설명해보자면</p>
<p>먼저 <code>Object.is</code> 메서드가 존재하는지 체크한다.
<code>Object</code> 객체에 <code>is</code> 메서드가 존재하지 않는다면 <code>undefined</code>를 반환한다.
<code>undefined</code>는 <code>Falsy</code>한 값으로 부정연산자 <code>!</code> 의 결과는 <code>true</code>가 나온다.</p>
<p>if문 안으로 들어왔다면<code>Object</code> 객체에 <code>is</code> 메서드를 동적생성한다.</p>
<p>기본적으로는 일치비교연산자와 동일하게 동작하기때문에 일치비교연산자를 사용해서 비교한다.</p>
<p>일치비교연산자로<code>+0</code> 과 <code>-0</code> 을 비교하는 경우 <code>true</code>가 나오기때문에 예외 처리를 하기위해서 <code>return x !== 0 || 1 / x === 1 / y;</code> 논리연산자 표현식을 추가한다</p>
<p>연산자 우선순위에 따라서 연산을 하면 다음과 같은 과정을 통해 <code>false</code> 를 반환하게 된다.</p>
<pre><code class="language-javascript">//true -&gt; if문 안으로 들어간다
+0 === -0

// false -&gt; 0인지 확인한다. 0이 아닌경우는 단축평가에 의해서 true 반환
+0 !== 0 

//0인경우 나눗셈의 결과를 비교해서 반환
1 / +0  //Infinity 
1 / -0  //-Infinity
Infinity === -Infinity //false</code></pre>
<p>else 문에서는 <code>NaN</code> 과 <code>NaN</code>을 비교했을때를 처리해준다.
NaN은 자기자신과 일치하지않는 유일한 값이기때문에
<code>NaN !== NaN</code> 은 <code>true</code>임을 이용해서 <code>NaN</code> 을 판별한다.</p>
<pre><code class="language-javascript">NaN === NaN  //false
NaN !== NaN //true
true &amp;&amp; true //true</code></pre>
<p><code>NaN</code>을 확인하는 방법에는 <code>isNaN()</code>이나 <code>Number.isNaN()</code>도 있다.</p>
<p>폴리필 코드를 직접 추가하는 것 보다는
<code>Babel</code> 을 사용하는 것이 좋다.</p>
<h3 id="참고">참고</h3>
<p>모던 자바스크립트 Deep Dive
<a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is() - JavaScript | MDN</a></p>
]]></description>
        </item>
    </channel>
</rss>