<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>just do it.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 31 May 2022 04:30:48 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. just do it.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/_seeul" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[TIL | 네이버 오픈 API 사용 시 utf-8로 인코딩하기]]></title>
            <link>https://velog.io/@_seeul/TIL-%EB%84%A4%EC%9D%B4%EB%B2%84-%EC%98%A4%ED%94%88-API-%EC%82%AC%EC%9A%A9-%EC%8B%9C-utf-8%EB%A1%9C-%EC%9D%B8%EC%BD%94%EB%94%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_seeul/TIL-%EB%84%A4%EC%9D%B4%EB%B2%84-%EC%98%A4%ED%94%88-API-%EC%82%AC%EC%9A%A9-%EC%8B%9C-utf-8%EB%A1%9C-%EC%9D%B8%EC%BD%94%EB%94%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 31 May 2022 04:30:48 GMT</pubDate>
            <description><![CDATA[<p>네이버 오픈 API를 사용해 토이프로젝트를 진행하는 중에 생각하지도 못한 곳에서 에러때문에 시간을 많이 썼다. 사실 API 도큐먼트를 잘 읽어봤어야 했는데 대충 읽고 일단 가져다 쓴 내 잘못이긴 하지만 ^^</p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/e292bb17-c151-4f63-8c0f-e097a5990973/image.png" alt=""></p>
<p>검색을 할때 query에 문자열을 그대로 넣는 것이 아니라 UTF-8로 인코딩해서 넣었어야 했다. 
포스트맨에서 API를 불러올땐 잘돼길래 그냥 썼는데 막상 프로젝트를 실행하니 400에러가 떴다. <img src="https://velog.velcdn.com/images/_seeul/post/4efdf69b-a903-43f7-9b1a-c911d044890f/image.png" alt="">
 친절하게 에러 코드도 나와있었는데...</p>
<p> 아무튼 쿼리부분을 그냥 한글로 써서 보내면 이렇게 요청이 간다.
<img src="https://velog.velcdn.com/images/_seeul/post/6fbc02d8-25f1-4357-b0c3-e26588db0f4b/image.png" alt=""></p>
<p>저 특수문자와 영어가 섞인 부분의 URI 영역을 인코딩해서 요청해야 한다. 자바스크립트에서 encodeURI를 사용하면 된다. </p>
<p>이렇게 작성해주었다니 잘 동작한다!</p>
<pre><code class="language-ts">export const getBookList = (query: string, sort: string, start = 1) =&gt; {
  return axios.get(encodeURI(`${BASE_URL}`), {
    params: {
      query,
      sort,
      start,
      display: 20,
    },
  });
};

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | React Router Dom Outlet]]></title>
            <link>https://velog.io/@_seeul/TIL-React-Router-Dom-outlet</link>
            <guid>https://velog.io/@_seeul/TIL-React-Router-Dom-outlet</guid>
            <pubDate>Tue, 24 May 2022 00:21:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/_seeul/post/e3a69195-4e68-483a-9773-bff1536a7830/image.png" alt=""></p>
<p>이번주 기업과제를 새롭게 시작하면서 역할을 분담했다.
나는 초기 레이아웃을 짜고, 광고관리 페이지를 진행하기로 했다
초기 레이아웃을 짜면서 팀원분이 알려주신 <a href="https://reactrouter.com/docs/en/v6/getting-started/overview">react router dom의 outlet</a>에 대해 정리해보려고 한다!</p>
<p>v6에 새롭게 추가된 Outlet은 react의 children과 유사하게 작동함으로서, 레이아웃 설정을 매우 간편하게 할 수 있다. </p>
<pre><code class="language-js">function App() {
  return (
    &lt;Routes&gt;
      &lt;Route path=&quot;/&quot; element={&lt;Layout /&gt;}&gt;
        &lt;Route path=&quot;invoices&quot; element={&lt;Invoices /&gt;} /&gt;
        &lt;Route path=&quot;activity&quot; element={&lt;Activity /&gt;} /&gt;
      &lt;/Route&gt;
    &lt;/Routes&gt;
  );
}

function Layout() {
  return (
    &lt;div&gt;
      &lt;GlobalNav /&gt;
      &lt;main&gt;
        &lt;Outlet /&gt;
      &lt;/main&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>이렇게 레이아웃 컴포넌트를 만들고, react-router-dom에서 Outlet 컴포넌트를 import한다. 고정할 컴포넌트들이나 스타일들을 설정해주고 routes안의 route에 레이아웃 컴포넌트로 감싸주면 그 밑의 route들은 Outlet 컴포넌트 위치에 위치하게 된다🌟</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 코드 리뷰, 프론트엔드 코드 짜는 습관]]></title>
            <link>https://velog.io/@_seeul/TIL-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@_seeul/TIL-%EC%BD%94%EB%93%9C-%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Wed, 18 May 2022 12:51:40 GMT</pubDate>
            <description><![CDATA[<p>오늘 준혁님이 게스트로 퓨저블의 대표님을 초대해주시고 코드리뷰를 진행했다. 코드 리뷰를 받은 내용과 코드를 짜는 습관에 대해 정리해보겠다. </p>
<h1 id="코드-리뷰">코드 리뷰</h1>
<blockquote>
<ol>
<li>router.tsx 의 내용은 최대한 간단하게 짜는 것이 좋음.</li>
<li>lazy 기능 구현시 <a href="https://github.com/jamiebuilds/react-loadable#readme">react-loadable</a> 라이브러리 추천해주심.</li>
<li>변하지 않는 함수일 경우 렌더링 최소화를 위해 useMemo를 사용할 것. (사실 엄청 큰 프로젝트가 아닌 이상 성능에 거의 차이는 없지만, 습관을 들이는 것이 좋다고 하심. 하지만 사람마다 다른 코드 취향일수도..)</li>
<li>컴포넌트 리턴 부분에 삼항 연산자를 최대한 안쓰는 것이 좋다. 가독성이 좋지 않기 때문에. 가독성을 위해 최대한 코드나 파일을 나누는 것이 좋음</li>
<li>프론트엔드 개발자는 수정을 최대한 빨리 할 수 있도록 코드를 짜야 한다. =&gt; 다른 사람들이 보았을 때 금방 코드가 읽히도록. 넘겨주는 props 최소화하기.(5개 미만으로..)</li>
<li>SEO 설정할 때 <a href="https://github.com/nfl/react-helmet#readme">react-helmet</a> 라이브러리 추천.</li>
<li>라이브러리 사용시 개발할 때만 필요한 것은 dev로 설치하기.</li>
<li>useEffect 부분이 너무 길어지면 따로 빼기. 프론트엔드는 가독성이 최고이다. </li>
<li>최대한 props명과 변수명 일치 시키기 =&gt; 코드 취향일 수 있으나 일치 시켜야 헷갈리지 않음.</li>
<li>return안에 depth가 깊어지지 않도록 신경쓰기</li>
<li>import 순서 지키기 =&gt; 이것 또한 가독성을 위해. 
보통 node modules package =&gt; type =&gt; utils or hooks =&gt; components =&gt; style 순으로 나열하신다고 하심.</li>
</ol>
</blockquote>
<p>🌟 전체적으로 가독성에 대한 이야기를 많이 해주신 것 같다. </p>
<h2 id="내-프로젝트-코드리뷰">내 프로젝트 코드리뷰...</h2>
<blockquote>
<p><a href="https://github.com/daseuls/Grip_Company_Assignment">프로젝트 repository</a></p>
</blockquote>
<ol>
<li>beautiful dnd 때문인지 return 부분 depth가 너무 깊어져 가독성이 좋지 않다. 따로 분리할 수 있는 것은 분리하는 것이 좋다.</li>
<li>삼항 연산자 때문에 가독성이 좋지 않음..</li>
</ol>
<h2 id="refactoring">refactoring</h2>
<p>가독성이 좋지 않은 MovieMain.tsx return 부분의 파일을 분리해보았다. </p>
<h3 id="리팩토링-전">리팩토링 전</h3>
<pre><code class="language-js">return (
    &lt;DragDropContext onDragEnd={() =&gt; {}}&gt;
      &lt;Container ref={parentObservedTarget}&gt;
        &lt;SearchBar setIsLoading={setIsLoading} /&gt;
        {movieList.Response === &quot;True&quot; ? (
          &lt;ul&gt;
            &lt;TotalContainer&gt;
              &lt;AiOutlineUnorderedList size={20} /&gt;
              &lt;MovieTotal&gt;Total {movieList.totalResults}&lt;/MovieTotal&gt;
            &lt;/TotalContainer&gt;
            &lt;Droppable droppableId=&quot;bookmarkLi&quot; isDropDisabled&gt;
              {(provided) =&gt; (
                &lt;MovieListSubContainer ref={provided.innerRef}&gt;
                  {movieList?.Search?.map((movie, i) =&gt; (
                    &lt;MovieItem key={`${i}${movie.imdbID}`} item={movie} /&gt;
                  ))}
                  &lt;div ref={setTarget}&gt;{!isLoading &amp;&amp; &lt;Loading /&gt;}&lt;/div&gt;
                  {provided.placeholder}
                &lt;/MovieListSubContainer&gt;
              )}
            &lt;/Droppable&gt;
          &lt;/ul&gt;
        ) : (
          &lt;NotFound error={movieList.Error} /&gt;
        )}
      &lt;/Container&gt;
    &lt;/DragDropContext&gt;
  );</code></pre>
<h3 id="리팩토링-후">리팩토링 후</h3>
<p>최선의 방법인지는 모르겠다. 왜냐면 MovieList라는 컴포넌트를 새로 만들면서 props로 3개를 넘겨주었기 때문이다. 그래도 확실히 짧아져서 보기엔 간편한듯 하기도 하구..? 하지만 아직도 삼항 연산자를 사용하게 될 수 밖에 없다. 삼항 연산자를 안쓰고 어떻게 조건부 렌더링을 해야하지?</p>
<pre><code class="language-js">  return (
    &lt;DragDropContext onDragEnd={() =&gt; {}}&gt;
      &lt;Container ref={parentObservedTarget}&gt;
        &lt;SearchBar setIsLoading={setIsLoading} /&gt;
        {movieList.Response === &quot;True&quot; ? (
          &lt;MovieList movieList={movieList} setTarget={setTarget} isLoading={isLoading} /&gt;
        ) : (
          &lt;NotFound error={movieList.Error} /&gt;
        )}
      &lt;/Container&gt;
    &lt;/DragDropContext&gt;
  );</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | Intersection Observer로 무한 스크롤 구현하기]]></title>
            <link>https://velog.io/@_seeul/TIL-Intersection-Observer%EB%A1%9C-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@_seeul/TIL-Intersection-Observer%EB%A1%9C-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 18 May 2022 00:37:47 GMT</pubDate>
            <description><![CDATA[<p>기업 과제로 무한 스크롤을 구현하기 위해 Web API인 Intersection Observer를 처음 사용하게 되었다. Intersection Observer에 대해 정리해보려 한다. </p>
<h1 id="interserction-observer-란">Interserction Observer 란?</h1>
<hr>
<blockquote>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">공식 문서</a></p>
</blockquote>
<p>Web에서 제공하는 API로 교차 관찰자라고 한다. 관찰 중인 요소가 사용자가 보는 화면 영역 내에 들어왔는지를 알려주는 API이다. 대상 요소가 상위 요소나 또는 최상위 요소인 뷰포트와 교차하는 변경 사항을 비동기식으로 관찰하고, 그에 따른 콜백함수를 정해 실행할 수 있다. </p>
<p>따라서 이런 기능을 구현할 때 사용할 수 있다. </p>
<ol>
<li>페이지를 스크롤 할 때 이미지나 컨텐츠를 느리게 로드하는 lazy Loading</li>
<li>스크롤할때 더 많은 콘텐츠를 불러오는 무한 스크롤</li>
</ol>
<h1 id="개념-및-사용법">개념 및 사용법</h1>
<hr>
<p>Intersection Observer API를 사용하면 다음 상황 중 하나가 발생할 때 실행시키는 콜백을 만들 수 있다. </p>
<ol>
<li>관찰할 대상이 뷰포트 또는 우리가 지정할 요소와 교차할때이다. 지정한 요소를 root 요소 또는 root라고 한다. 일반적으로 대상 요소의 스크롤이 가능한 바로 부모 대상 요소 또는 뷰포트를 대상으로 교차하는 것을 관찰할 것이다. 만약 뷰포트를 기준으로 교차를 관찰하려면 옵션에 null을 넣거나 아무것도 넣지 않으면 된다. </li>
<li>관찰자에게 처음으로 대상 요소를 관찰하라는 요청을 받을 때이다. </li>
</ol>
<p>대상 요소와 루트 간의 교차 정도는 교차 비율로 판단한다. 자식요소의 얼마만큼의 비율이 루트 요소에 교차가 되었는지를 정하고 정한 만큼이 교차가 되었을 때 우리가 지정한 콜백함수를 실행한다. 이것은 옵션의 threshold와 관련이 있다. 0.0부터 1.0사이의 값으로 표시한다. </p>
<h2 id="1-관찰자-생성하기">1. 관찰자 생성하기</h2>
<p>관찰자를 생성해보자 ! 생성하면서 우리는 관찰자의 옵션을 설정할 수 있다. </p>
<pre><code class="language-jsx">// option 설정
const options = {
    root: document.querySelector(&#39;#scollArea&#39;), // react의 경우 useRef를 이용해 설정도 가능.
    rootMargin: &#39;0px&#39;,
    threshold: 0.7,
}

// 관찰자 생성
let observer = new IntersectionObserver(callback, options)</code></pre>
<ol>
<li>root
⇒ 관찰할 대상이 교차할 요소이다. 지정하지 않거나 null일 경우 default 값은 뷰포트이고, 일반적으로 관찰할 대상의 스크롤이 가능한 상위 부모요소이다. </li>
<li>rootMargin
⇒ 루트 주변의 여백이다. margin 속성과 유사한 값을 가질 수 있다. default 값은 0이다. (ex. “10px 20px 30px 40px”) </li>
<li>threshold
⇒ 관찰할 대상과 root가 어느정도 교차할 때 콜백을 실행할 지에 대한 백분율을 나타내는 숫자이다. 관찰할 대상과 root가 50%가 교차할 때 콜백을 실행하고 싶다면 0.5라고 설정한다. </li>
</ol>
<h2 id="2-관찰할-요소-타겟팅하기">2. 관찰할 요소 타겟팅하기</h2>
<p>관찰자를 생성한 후 관찰할 대상 요소를 지정해야 한다. </p>
<pre><code class="language-jsx">// 관찰할 대상 요소 지정
const target = document.querySelector(&#39;#listItem&#39;); // react의 경우 useRef를 이용해 설정도 가능.

// 관찰자가 타겟을 관찰하도록 설정
observer.observe(target);</code></pre>
<p>이렇게 관찰할 대상 요소를 지정한 후 관찰하도록 설정을 하면 이 지정한 임계값(threshold)가 충족할 때마다 IntersectionObserver 첫번째 인자로 넣어준 콜백이 호출된다. </p>
<p>콜백함수를 설정할 때 인자로 entries를 넣어주고, 이 entrie를 통해 임계값이 충족되었는지 또는 타겟 요소의 정보나 관찰할 대상의 요소에 대한 정보를 확인할 수 있다. </p>
<p>entries는 배열이고, 배열안에는 내가 관찰하기로 설정한 대상 요소들이 들어있다. entries를 콘솔로 확인해보자</p>
<pre><code class="language-jsx">// 콜백 함수
const intersectionCallback = (entries) =&gt; {
    console.log(entries)
}</code></pre>
<p><img src="https://velog.velcdn.com/images/_seeul/post/32e667f9-3fdb-4743-9ef0-7fb0c1796bdd/image.png" alt=""></p>
<p>이러한 값들이 들어 있는 것을 알 수 있다. 하나씩 값을 살펴보자면</p>
<ul>
<li><code>boundingClientRect</code> : 관찰 대상의 사각형 정보를 반환한다.</li>
<li><code>intersectionRect</code> :  관찰 대상과 루트 요소의 교차하는 영역에 대한 사각형 정보를 반환한다.</li>
<li><code>intersectionRatio</code> : 관찰 대상이 루트 요소와 얼마나 교차하는지 (겹치는지)의 숫자를 0.0과 1.0 사이의 숫자로 반환한다. 이는 <code>intersectionRect</code> 영역과 <code>boundingClientRect</code> 영역의 비율을 의미한다.</li>
<li><code>isIntersecting</code> : 관찰 대상이 루트 요소와 교차 상태로 들어가거나(true) 교차 상태에서 나가는지(false) 여부를 나타내는 값(Boolean)이다. 보통 이 값이 true일 때 콜백 함수를 실행시킨다.</li>
<li><code>rootBounds</code> : 루트 요소에 대한 사각형 정보를 반환한다. 이는 옵션 rootMargin에 의해 값이 변경되고, 반약 별도의 루트 요소를 선언하지 않았다면 null을 반환한다.</li>
<li><code>target</code> : 관찰 대상을 반환한다.</li>
<li><code>time</code> : 문서가 작성된 시간을 기준으로 교차 상태 변경이 발생한 시간을 나타낸다.</li>
</ul>
<p>위의 값을 참고해서 콜백 함수를 작성해보자. 만약 관찰할 요소들을 여러개 지정해 주었다면 entries에는 2개 이상의 아이템이 들어있으므로 forEach를 통해 각 대상에 대해 콜백 함수를 실행한다. </p>
<pre><code class="language-jsx">const intersectionCallback = (entries) =&gt; {
    entries.forEach(entry =&gt; {}
}</code></pre>
<p>나는 하나의 타겟만 설정해주었으므로 다음과 <code>isIntersecting</code> 이 true가 되었을 때 콜백 함수를 설정해주었다. </p>
<pre><code class="language-jsx">const handleObserver: IntersectionObserverCallback = (entry) =&gt; {
    if (entry[0].isIntersecting &amp;&amp; !isLoading) {
      setTimeout(() =&gt; {
        getMoreMovieList();
      }, 1000);
    }
  };</code></pre>
<p>나는 무비 리스트들의 맨 끝에 빈 div를 넣고 루트 요소를 리스트가 들어있는 스크롤이 가능한 컨테이너로 설정했다. 따라서 리스트들의 맨 밑에 위치한 div가 교차하는 지에 따라 데이터를 새로 받아오는 함수를 구현했다. 데이터를 새로 받아서 기존의 무비 리스트 뒤에 추가 해주는 식으로 무비 리스트들이 계속 증가하여 보여질 수 있도록 작성했다. </p>
<p>전체 작성 코드!! (기존 코드에서 짜깁기해서 가져와서 빠진 부분이 있을 수 있습니다..🙏🏻)</p>
<pre><code class="language-jsx">import { useEffect, useRef } from &quot;react&quot;;

const MovieMain = () =&gt; {
    const [target, setTarget] = useState&lt;HTMLDivElement | null&gt;(null);

    const getMoreMovieList = async () =&gt; {
            // 데이터 받아 오는 함수
        }

// 콜백 함수
    const handleObserver: IntersectionObserverCallback = (entry) =&gt; {
        if (entry[0].isIntersecting &amp;&amp; !isLoading) {
         getMoreMovieList();
        }
      };

// 관찰자 생성
    useEffect(() =&gt; {
        let observer: IntersectionObserver;
        if (target) {
          observer = new IntersectionObserver(handleObserver, {
            root: parentObservedTarget.current,
            threshold: 1,
          });
          observer.observe(target);
        }
        return () =&gt; observer &amp;&amp; observer.disconnect();
      }, [handleObserver, target]);


    return (
          &lt;Container ref={parentObservedTarget}&gt;
            &lt;SearchBar setIsLoading={setIsLoading} /&gt;
            {movieList.Response === &quot;True&quot; ? (
              &lt;ul&gt;
              &lt;MovieListSubContainer&gt;
                {movieList?.Search?.map((movie, i) =&gt; (
                  &lt;MovieItem key={`${i}${movie.imdbID}`} item={movie} /&gt;
                ))}
                &lt;div ref={setTarget}&gt;{!isLoading &amp;&amp; &lt;Loading /&gt;}&lt;/div&gt;
              &lt;/MovieListSubContainer&gt;
              )}
          &lt;/ul&gt;
            ) : (
              &lt;NotFound error={movieList.Error} /&gt;
            )}
          &lt;/Container&gt;
      );
}

export default MovieMain;</code></pre>
<p>잘 작동한다! ㅎㅎㅎㅎ
<img src="https://velog.velcdn.com/images/_seeul/post/2839d94f-316b-4f85-a2b0-0448c9eec1ce/image.gif" alt=""></p>
<p>관련된 좋은 레퍼런스
<a href="https://medium.com/mesh-korea-fe-team-blog/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-intersection-observer-api-%EC%9E%AC%EC%82%AC%EC%9A%A9%EC%84%B1-%EB%86%92%EC%9D%B4%EA%B8%B0-ae47ea021719">리액트에서 Intersection Observer API 재사용성 높이기</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 0509 react + typescript 프로젝트 초기 세팅, styled-component, 린터 설정 (eslint, stylelint, prettier)]]></title>
            <link>https://velog.io/@_seeul/TIL-0509-react-typescript-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-styled-component-%EB%A6%B0%ED%84%B0-%EC%84%A4%EC%A0%95-eslint-stylelint-prettier</link>
            <guid>https://velog.io/@_seeul/TIL-0509-react-typescript-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-styled-component-%EB%A6%B0%ED%84%B0-%EC%84%A4%EC%A0%95-eslint-stylelint-prettier</guid>
            <pubDate>Tue, 10 May 2022 03:13:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/_seeul/post/fa540d6a-87fb-4b7f-8cf7-d4a9a0525323/image.png" alt=""></p>
<p>드디어 기업 개인 과제가 시작되었다 🥶
준혁님이 린터설정을 엄청나게 강조하셔서 오늘은 프로젝트 초기세팅과 린터설정을 했다. 준혁님이 만들어주신거 가져다가 쓸까 하다가 혼자 설정을 한번 해보고 싶어서 직접 설정을 해보았다. </p>
<p>이번에 개인 과제에서 사용할 기술들은 
<code>JavaScript</code>, <code>TypeScript</code>, <code>Styled-Component</code>, <code>Recoil</code> 로 정했다.</p>
<p>패키지 관리 툴은 <code>yarn</code>을 사용했다. </p>
<h1 id="1-cra-초기세팅-with-typescript">1. CRA 초기세팅 (with TypeScript)</h1>
<hr>
<blockquote>
<p><a href="https://create-react-app.dev/docs/adding-typescript/">CRA 공식문서</a></p>
</blockquote>
<pre><code>npx create-react-app my-app --template typescript
or
yarn create react-app 프로젝트명 --template typescript</code></pre><p>만약 기존 존재하는 프로젝트에 타입스크립트를 추가하고 싶다면 이렇게!</p>
<pre><code>npm install --save typescript @types/node @types/react @types/react-dom @types/jest
or
yarn add typescript @types/node @types/react @types/react-dom @types/jest</code></pre><h1 id="2-react-router-설치">2. React Router 설치</h1>
<hr>
<blockquote>
<p><a href="https://reactrouter.com/docs/en/v6/getting-started/installation">React Router 공식문서</a></p>
</blockquote>
<p>프로젝트에서 없어서는 안될 Router를 설치하자. 작년에 버전 6으로 업그레이드가 되었기 때문에 6버전을 써준다. </p>
<blockquote>
<p><a href="https://blog.woolta.com/categories/1/posts/211">6에서 달라진 점들이 잘 설명된 블로그</a></p>
</blockquote>
<pre><code>npm install react-router-dom@6
or 
yarn add react-router-dom@6</code></pre><pre><code class="language-javascript">import * as React from &quot;react&quot;;
import { Routes, Route, Link } from &quot;react-router-dom&quot;;
import &quot;./App.css&quot;;

function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;h1&gt;Welcome to React Router!&lt;/h1&gt;
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={&lt;Home /&gt;} /&gt;
        &lt;Route path=&quot;about&quot; element={&lt;About /&gt;} /&gt;
      &lt;/Routes&gt;
    &lt;/div&gt;
  );
}</code></pre>
<p>이런식으로 써주면 됨!</p>
<h1 id="3-styled-component-설치">3. Styled-Component 설치</h1>
<hr>
<p>나는 아직 css module보다는 Styled-component가 좋다... 조건부 스타일링을 할때 스타일 값안에 자바스크립트의 변수를 쓸 수 있는게 훨씬 편리하다.. (className으로 조건부 스타일링을 하는 게 미숙해서 그럴수도 😂😂)</p>
<p>styled-component로 만들었던 프로젝트를 css module로 바꾸면서 겪었던 어려움을 디스코드에 올렸었다. 
<img src="https://velog.velcdn.com/images/_seeul/post/b6b3906b-5175-46b5-8ee3-56d5eda599c2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/8e1f6c33-50f7-4345-8774-99504a229002/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/33f1747c-6de1-4eb6-a52d-529886e9cb11/image.png" alt=""></p>
<p>😭.....
state값을 스타일의 값으로 사용하는 방법말고 다른 방법을 사용했었으면, 다른 방법이 있었을 것이다.</p>
<p>준혁님이 Styled-component를 선호하지 않는 이유가 HTML의 시멘틱한 태그들을 안쓰게 되어서 HTML이 약해짐이었는데 이 부분을 좀 더 보완해서 신경쓰면서 styled-component를 사용해야겠다. </p>
<blockquote>
<p><a href="https://styled-components.com/docs/basics#installation">Styled Component 공식문서</a></p>
</blockquote>
<p>어쨌든 설치</p>
<pre><code>npm install --save styled-components
or
yarn add styled-components</code></pre><p>typeScript를 사용하는 경우라면,</p>
<pre><code>npm install --save @types/styled-components
or
yarn add -D @types/styled-components </code></pre><p>GlobalStyle을 위해 styled-reset 도 설치해주었다. </p>
<pre><code>npm install styled-reset
or
yarn add styled-reset</code></pre><h1 id="4-eslint-설정">4. ESlint 설정</h1>
<hr>
<blockquote>
<p><a href="https://eslint.org/docs/user-guide/getting-started">ESlint 공식문서</a></p>
</blockquote>
<pre><code>npm install eslint --save-dev
or 
yarn add eslint --dev</code></pre><p>ESlint 환경설정 파일이 생성되어 있지 않으므로 초기화를 해야한다.</p>
<pre><code>npm init @eslint/config
or
yarn create @eslint/config</code></pre><p>이렇게 해주면 config 파일이 생길 것이다. 여기서 내가 설정해주고 싶은대로 플러그인을 설치하거나 rules를 설정하면 된다. </p>
<p>나는 rule이 꽤 빡세다는 airbnb config를 설정해주었다.</p>
<pre><code>npm install eslint-config-airbnb
or
yarn add eslint-config-airbnb</code></pre><p>설치 후 .eslintrc 파일 extends에 &quot;airbnb&quot;, &quot;airbnb/hooks&quot;를 추가해준다. 역시 airbnb를 적용했더니 너무 warning이 많이 떠서 필요없는건 준혁님 <a href="https://github.com/miriyas/foundation-ts">foundation</a> 파일을 보면서 꺼주었다. (너무 warning이 많아서 프로젝트 시작 못할뻔..)</p>
<pre><code>{
 {
  &quot;extends&quot;: [&quot;airbnb&quot;, &quot;airbnb/hooks&quot;, &quot;react-app&quot;, &quot;prettier&quot;],
  &quot;env&quot;: {
    &quot;browser&quot;: true,
    &quot;jasmine&quot;: true,
    &quot;jest&quot;: true
  },
  &quot;settings&quot;: {
    &quot;import/extensions&quot;: [&quot;.js&quot;, &quot;.jsx&quot;, &quot;.ts&quot;, &quot;.tsx&quot;],
    &quot;import/resolver&quot;: {
      &quot;node&quot;: {
        &quot;extensions&quot;: [&quot;.js&quot;, &quot;.jsx&quot;, &quot;.ts&quot;, &quot;.tsx&quot;]
      }
    },
    &quot;react&quot;: {
      &quot;pragma&quot;: &quot;React&quot;,
      &quot;version&quot;: &quot;detect&quot;
    }
  },
  &quot;rules&quot;: {
    &quot;arrow-body-style&quot;: &quot;off&quot;,
    &quot;react/function-component-definition&quot;: [&quot;warn&quot;, { &quot;namedComponents&quot;: &quot;arrow-function&quot; }],
    &quot;react/jsx-one-expression-per-line&quot;: &quot;off&quot;,
    &quot;react/jsx-filename-extension&quot;: [&quot;error&quot;, { &quot;extensions&quot;: [&quot;.js&quot;, &quot;.jsx&quot;, &quot;.ts&quot;, &quot;.tsx&quot;] }],
    &quot;react/jsx-indent&quot;: &quot;warn&quot;,
    &quot;react/jsx-props-no-spreading&quot;: &quot;off&quot;,
    &quot;react/no-array-index-key&quot;: &quot;warn&quot;,
    &quot;react/require-default-props&quot;: &quot;off&quot;,
    &quot;react/jsx-wrap-multilines&quot;: &quot;off&quot;,
    &quot;react/jsx-uses-react&quot;: &quot;off&quot;,
    &quot;react/react-in-jsx-scope&quot;: &quot;off&quot;,
    &quot;import/prefer-default-export&quot;: &quot;off&quot;,
    &quot;import/no-unresolved&quot;: &quot;off&quot;,
    &quot;import/order&quot;: &quot;off&quot;,
    &quot;import/no-anonymous-default-export&quot;: &quot;off&quot;,
    &quot;import/no-extraneous-dependencies&quot;: [
      &quot;error&quot;,
      {
        &quot;devDependencies&quot;: [&quot;.storybook/**&quot;, &quot;src/stories/**&quot;]
      }
    ],
    // &quot;max-lines&quot;: [&quot;warn&quot;, 150],
    &quot;no-param-reassign&quot;: [&quot;error&quot;, { &quot;props&quot;: false }],
    &quot;no-use-before-define&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/no-use-before-define&quot;: [&quot;error&quot;],

    &quot;no-shadow&quot;: &quot;off&quot;,
    &quot;no-unused-expressions&quot;: [&quot;warn&quot;],
    &quot;@typescript-eslint/no-shadow&quot;: [&quot;error&quot;],
    &quot;@typescript-eslint/camelcase&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/unbound-method&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/no-non-null-assertion&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/no-unsafe-member-access&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/no-unsafe-assignment&quot;: &quot;off&quot;,
    &quot;@typescript-eslint/no-unused-vars&quot;: [&quot;warn&quot;, { &quot;argsIgnorePattern&quot;: &quot;^_&quot; }],
    &quot;prefer-const&quot;: [&quot;warn&quot;],
    &quot;prefer-destructuring&quot;: [&quot;error&quot;, { &quot;object&quot;: true, &quot;array&quot;: false }],
    &quot;lines-between-class-members&quot;: &quot;off&quot;,
    &quot;jsx-a11y/click-events-have-key-events&quot;: &quot;off&quot;,
    &quot;jsx-a11y/label-has-associated-control&quot;: [
      &quot;error&quot;,
      {
        &quot;labelComponents&quot;: [&quot;label&quot;],
        &quot;labelAttributes&quot;: [&quot;htmlFor&quot;],
        &quot;controlComponents&quot;: [&quot;input&quot;]
      }
    ],
    &quot;import/extensions&quot;: [
      &quot;error&quot;,
      &quot;ignorePackages&quot;,
      {
        &quot;js&quot;: &quot;never&quot;,
        &quot;jsx&quot;: &quot;never&quot;,
        &quot;ts&quot;: &quot;never&quot;,
        &quot;tsx&quot;: &quot;never&quot;
      }
    ]
  }
}
</code></pre><h1 id="5-stylelint-설정">5. Stylelint 설정</h1>
<hr>
<p>styled-component 공식문서의 <a href="https://styled-components.com/docs/tooling#stylelint">이곳</a>을 참고했다.</p>
<pre><code>npm install --save-dev \
  stylelint \
  stylelint-processor-styled-components \
  stylelint-config-styled-components \
  stylelint-config-recommended

or

yarn add \
 stylelint \
  stylelint-processor-styled-components \
  stylelint-config-styled-components \
  stylelint-config-recommended</code></pre><h1 id="6-prettier-설정">6. Prettier 설정</h1>
<hr>
<blockquote>
<p><a href="https://prettier.io/docs/en/install.html">prettier 공식문서</a></p>
</blockquote>
<p>prettier 설치</p>
<pre><code>npm install --save-dev --save-exact prettier
or 
yarn add --dev --exact prettier</code></pre><p>prettier eslint 플러그인 및 설정 패키지 설치</p>
<pre><code>npm install -D eslint-config-prettier eslint-plugin-prettier
or 
yarn add -D eslint-config-prettier eslint-plugin-prettier</code></pre><ul>
<li><code>eslint-plugin-prettier</code>: prettier 규칙을 생성하는 eslint 플러그인</li>
<li><code>eslint-config-prettier</code>: eslint와 prettier간 충돌나는 규칙을 비활성화해주는 eslint 설정</li>
</ul>
<p>.prettierrc.json 파일 생성 후 규칙 추가</p>
<pre><code>{
  &quot;jsxSingleQuote&quot;: false,
  &quot;semi&quot;: true,
  &quot;printWidth&quot;: 120,
  &quot;singleQuote&quot;: false,
  &quot;htmlWhitespaceSensitivity&quot;: &quot;css&quot;,
  &quot;endOfLine&quot;: &quot;lf&quot;
}
</code></pre><h1 id="7-recoil-설치">7. Recoil 설치</h1>
<blockquote>
<p><a href="https://recoiljs.org/docs/introduction/installation/">Recoil 공식문서</a></p>
</blockquote>
<pre><code>npm install recoil
or 
yarn add recoil</code></pre><p>초기세팅이랑 린터설정에 생각보다 시간을 많이 썼다. 그치만 초기세팅과 린터설정 또한 너무 중요하기에 이번 기회로 다시 한번 연습해보아서 좋았던 것 같다. 👍🏻 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 0506 각 경우에 따른 localStorage 저장]]></title>
            <link>https://velog.io/@_seeul/TIL-0506-%EA%B0%81-%EA%B2%BD%EC%9A%B0%EC%97%90-%EB%94%B0%EB%A5%B8-localStorage-%EC%A0%80%EC%9E%A5</link>
            <guid>https://velog.io/@_seeul/TIL-0506-%EA%B0%81-%EA%B2%BD%EC%9A%B0%EC%97%90-%EB%94%B0%EB%A5%B8-localStorage-%EC%A0%80%EC%9E%A5</guid>
            <pubDate>Sat, 07 May 2022 00:27:02 GMT</pubDate>
            <description><![CDATA[<h1 id="todo">TODO</h1>
<blockquote>
<p>☑️ 로그인하고 로컬스토리지에 저장하기</p>
</blockquote>
<p>로그인페이지를 맡게 되었다. UI는 굉장히 단순했기 때문에 금방 끝낼수 있었지만 각 경우의 수에 따라 로컬스토리지에 저장하는 것에 시간을 많이 쓴 것 같다. </p>
<p>먼저 우리팀은 유저의 닉네임을 받아서 로그인을 하기로 했다. 만약 유저가 닉네임을 입력시에 그 유저의 id가 없다면, 새로운 유저이기 때문에 빈 데이터구조를 만들어주어야 하고, 만약 로컬스토리지 안에 유저의 id가 있다면 기존의 유저이기 때문의 그 유저의 id를 메인페이지로 전달해서 TODO를 불러와야 한다.</p>
<p>위의 설명을 보면 두 가지의 경우이지만 아예 localStorage가 완전히 비어있을 경우까지 고려해야했다. 안그러면 데이터 구조를 map을 돌릴때 에러가 나기 때문에..</p>
<p>따라서 이렇게 작성했다.</p>
<pre><code class="language-javascript">  const onClickLoginBtn = () =&gt; {
    const item = JSON.parse(localStorage.getItem(&#39;todo&#39;))
    const newUser = {
      ...BASIC_DATA,
      userNickName: userName,
      id: `${new Date().getMilliseconds()}${userName}`,
      isLogined: true,
    }

    try {
      // 로컬스토리지가 완전히 비었을 때 (가장 최초의 회원)
      if (item === null) {
        localStorage.setItem(&#39;todo&#39;, JSON.stringify([newUser]))
        navigate(&#39;/&#39;, { state: { userId: `${new Date().getMilliseconds()}${userName}`, isNewUser: true } })
      } 
      // localStorage에 유저의 이름이 있을 때 (기존 회원)
      else if (item.map((el) =&gt; el.userNickName).includes(userName)) {
        const loginUser = item.find((el) =&gt; el.userNickName === userName)
        navigate(&#39;/&#39;, { state: { userId: loginUser.id, isNewUser: false } })
      } 
      // localStorage에 유저의 이름이 없을 때 (신규 회원)
      else {
        localStorage.setItem(&#39;todo&#39;, JSON.stringify([...item, newUser]))
        navigate(&#39;/&#39;, { state: { userId: `${new Date().getMilliseconds()}${userName}`, isNewUser: true } })
      }
    } catch (e) {
      console.log(e)
    }
  }</code></pre>
<p>가독성이 매우 안좋은 것 같은데 어떻게 리팩토링을 해야할까...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 0505 CSS Module 사용해보기]]></title>
            <link>https://velog.io/@_seeul/TIL-0505-CSS-Module-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@_seeul/TIL-0505-CSS-Module-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Sat, 07 May 2022 00:15:07 GMT</pubDate>
            <description><![CDATA[<h1 id="css-module-사용해보자">CSS module 사용해보자</h1>
<p>프로젝트를 그동안 진행할 때, 주로 styled component를 많이 썼다. 이유는 css in js 라이브러리로 자바스크립트 코드를 통해 쉽게 조건부 스타일링이 가능했기 때문이다. </p>
<p>하지만 styled component를 사용하면 HTML이 굉장히 약해진다고 한다. html 태그 위치에 우리가 정해준 스타일 컴포넌트가 자리하기 때문이다. styled component를 쓰며 div를 남발했던 과거의 나를 보며 그렇겠구나 생각이 들었다. </p>
<p>그래서 css module과 scss를 함께 사용하는 것을 권장하셨고, 이번 프로젝트엔 css module을 사용하기로 했다. </p>
<p>css module은 파일 확장자를 <code>.module.css</code>로 설정하면 된다. scss를 함께 사용할 것이라면 <code>.module.scss</code>라고 정해준다. </p>
<p>css module의 가장 큰 장점은 리액트 컴포넌트 파일에서 해당 css 파일을 불러올 때 css 파일에 선언한 클래스 이름들이 모두 고유해진다. css 클래스 이름이 만들어지는 과정에서 파일 경로, 파일 이름, 클래스 이름, 해쉬값 등이 사용될 수 있다. </p>
<p>실제로 css module을 사용하고 class이름을 확인해 보았다. </p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/bdf946e3-13c0-415c-ab42-7ad96a5f032e/image.png" alt=""></p>
<p>이렇게 되면 scss가 다른 컴포넌트라고 같은 class명을 가지고 있을 때 겪는 className 오염을 방지할 수 있다. </p>
<p>클래스 이름을 통해 조건부 스타일링을 해줄때는 이렇게 작성하면 되는데, </p>
<pre><code class="language-javascript">
&lt;p className={`${styles.warningMessage} ${isAvailableName ? styles.displayNone : &#39;&#39;}`}&gt;
 닉네임 형식에 맞지 않습니다
&lt;/p&gt;
</code></pre>
<p>조금 작성하기가 어렵다. 이럴때 classnames라는 라이브러리를 쓰면 좀 더 깔끔하게 작성할 수 있다. 이 라이브러리에는 bind 기능이 있다.</p>
<pre><code class="language-javascript">&lt;p className={cx(styles.warningMessage, isAvailableName ? styles.displayNone : &#39;&#39;)}&gt;
닉네임 형식에 맞지 않습니다
&lt;/p&gt;</code></pre>
<p>좀 더 깔끔해졌다.</p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/a2a583ec-c9c1-4130-a4d9-a61d20dceff6/image.png" alt=""></p>
<pre><code class="language-javascript">// X 이렇게 사용하기보다는
className={cx(&#39;title&#39;,&#39;bold&#39;)}

// O 이런식으로 사용해주기!!
className={cx(styles.title, styles.bold)}
</code></pre>
<h1 id="todo">TODO</h1>
<blockquote>
<p>☑️ 로그인 페이지 UI</p>
</blockquote>
<p>css module을 통해 UI를 구현했다. </p>
<pre><code class="language-javascript">    &lt;div className={styles.loginWrapper}&gt;
      &lt;p className={styles.loginTitle}&gt;닉네임을 입력해주세요&lt;/p&gt;
      &lt;input maxLength={15} onChange={onChangeInputValue} className={styles.loginInput} /&gt;
      &lt;p className={cx(styles.warningMessage, isAvailableName ? styles.displayNone : &#39;&#39;)}&gt;
        닉네임 형식에 맞게 입력해주세요.
      &lt;/p&gt;
      &lt;button
        disabled={!isAvailableName}
        type=&#39;button&#39;
        onClick={onClickLoginBtn}
        className={cx(styles.loginBtn, isAvailableName ? styles.ableBtn : styles.disableBtn)}
      &gt;
        Login
      &lt;/button&gt;
    &lt;/div&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 0504 팀프로젝트 시작]]></title>
            <link>https://velog.io/@_seeul/TIL-0504-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@_seeul/TIL-0504-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Fri, 06 May 2022 23:49:59 GMT</pubDate>
            <description><![CDATA[<p>프리온보딩과정이 시작되면서 팀프로젝트가 시작되었다. 첫 번째 팀과제는 준혁님이 직접 만들어두신 stylelint, eslint, prettier를 통해서 todolist를 만드는 것이다. </p>
<p>준혁님은 타입스크립트와 린터설정을 매우매우 강조하셨다.
(남들이 보기에도 좋은 코드를 짜기 위함일 것이다.)
확실히 린터를 설정하고 코드를 작성하니 내 코드가 이렇게 깔끔해지는구나..하고 느꼈다.</p>
<p>이번 과제의 핵심은 기능 구현이라기 보단 린터설정, 팀원과의 협업 능력 기르기가 아닐까 하는 생각이 든다.</p>
<hr>
<h1 id="todo">TODO</h1>
<blockquote>
<p>☑️ 팀원들과의 회의를 통해서 각자 기능 쪼개기 !</p>
</blockquote>
<p>사실 10명이서 todolist 프론트 부분을 쪼개려니 감이 안왔다. 페이지도 아무리 기능을 만들어봤자 3-4페이지가 다였는데 어떻게 쪼개지 하다가 각 컴포넌트나 큰 기능 단위로 쪼갰다. </p>
<p>일단 피그마에 어떤 기능들을 구현할지 그려보고, 각자 필수구현, 추가구현 기능을 정했다. (팀원 중 피그마 고수가 있으셔서 굉장히 수월하게 진행한 것 같다.)</p>
<p><img src="https://velog.velcdn.com/images/_seeul/post/0c53432a-6ded-4a54-975f-6124d0b4bb04/image.png" alt=""></p>
<p>오늘 회의만 거의 5-6시간을 진행한 것 같다. 팀원들 모두 열정적이라 좋았던 것 같다. 일단 데이터는 모두 localStorage에서 관리하기로 하고 데이터 구조도 작성했다. </p>
<pre><code class="language-json">[
  {
  id: new Date + useNickName,
  userNickName:’kang&#39;,
  isLogined: true,
  data: {
    category: [{ id: new date + categoryName, categoryName:&#39;카테고리명&#39;, color: “~~~” },
                           { id: 324832456카테고리명, categoryName:&#39;카테고리명2&#39;, color: “~~~” }],
    todoList: [
        {
          id:new date + todo,
           todo: &#39;과제하기&#39;, 
           categoryId: category.id, 
           date: &#39;2022/00/00&#39;, 
           isDone: true,
        },
    ]
  }
 }
]</code></pre>
<p>간단한 데이터 구조 만들어보는 툴도 좀 익혀놓을껄 하는 생각이 들었다.. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL | 원티드 프리온보딩 1일차]]></title>
            <link>https://velog.io/@_seeul/TIL-%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-1%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@_seeul/TIL-%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-1%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 03 May 2022 14:52:40 GMT</pubDate>
            <description><![CDATA[<h1 id="53-today-i-learned">5/3 Today I Learned.</h1>
<ol>
<li><p>input에 managed state사용하기.</p>
</li>
<li><p>key값을 index로 쓰면 말것.</p>
</li>
<li><p>리액트에서 돔을 직접 조작하지 말것. </p>
<pre><code class="language-javascript">ref.current.value = &#39;&#39; </code></pre>
<p>와 같은 코드는 큰 문제를 일으킬 수 있는 코드. useRef는 데이터를 바꿀 때 쓰는 것은 좋지 않다. 윈도우의 가로나 세로의 특정 값을 구할 때 사용하는 것이 좋음.</p>
</li>
<li><p><code>event.target.value</code> 보다는 <code>event.currentTarget.value</code>를 쓰는 것이 좋다. </p>
</li>
<li><p>setState 해줄 때 <code>prevState</code> 쓸것.</p>
</li>
<li><p>css에는 id말고 class 써주기. 정말 어떠한 의도가 있지 않는 한 class를 사용할 것.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[원티드 프리온보딩 코스를 지원하며]]></title>
            <link>https://velog.io/@_seeul/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%EC%BD%94%EC%8A%A4%EB%A5%BC-%EC%A7%80%EC%9B%90%ED%95%98%EB%A9%B0</link>
            <guid>https://velog.io/@_seeul/%EC%9B%90%ED%8B%B0%EB%93%9C-%ED%94%84%EB%A6%AC%EC%98%A8%EB%B3%B4%EB%94%A9-%EC%BD%94%EC%8A%A4%EB%A5%BC-%EC%A7%80%EC%9B%90%ED%95%98%EB%A9%B0</guid>
            <pubDate>Tue, 26 Apr 2022 23:36:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/_seeul/post/a64d5978-c10f-4998-8468-392e61496fb0/image.png" alt=""></p>
<p>원티드 프리온보딩 프론트엔드 코스를 지원하게 되었다. 지원하면서 간단한 숏에세이를 써보려 한다. </p>
<h1 id="1-원티드-프리온보딩-코스의-정책과-도입한-이유는-무엇일까">1) 원티드 프리온보딩 코스의 정책과 도입한 이유는 무엇일까?</h1>
<blockquote>
<p>원티드 프리온보딩 코스에서는 수강료 무료, 참가비 50만원을 받습니다. 
이후 코스 완주(1.참가기업 70% 이상 지원 2.과제 제출 3.동료피드백 4.출결)시 취업활동 지원금 50만원(제세공과 후)을 지급합니다.</p>
</blockquote>
<p>원티드에서 이러한 정책을 도입한 이유는 지원자들의 열정과 책임감을 보기 위함이라 생각한다. 원티드 프리온보딩에 참가한 기업들을 보았을 때 막 시작한 스타트업보다 어느정도 기반이 있고, 투자를 받은 회사들이 참가했다. 이러한 기업들이 참가한 만큼 지원하는 참가자의 책임감과 간절함을 보기위해 이러한 정책을 도입한 것이라 생각한다. 그래서 오히려 나는 더 이러한 정책이 긍정적이다. 함께 팀을 이루고 같이 과제를 하는 동기들을 만나는 과정에서 이러한 정책이 좀 더 나에게나 지원자들에게 좋은 영향을 미칠 것이라고 생각한다. 50만원이라는 금액이 많은 금액은 아니지만 그래도 취준생에게 적지만은 않은 금액이라 생각한다. 만약 선발이 된다면 나도 또한 한달동안 그 이상의 책임감을 갖고 열심히 코스에 임할 것이다.</p>
<h1 id="2-지원을-희망하는-기업-선정-이유">2) 지원을 희망하는 기업, 선정 이유</h1>
<h2 id="휴먼스케이프">휴먼스케이프</h2>
<p>누적 350억 투자를 받으며 성장가능성과 역량을 인정받은 스타트업으로서, 앞으로의 더 큰 성장가능성이 있다고 생각했다. 앞으로의 더 큰 성장을 통해 함께 하고 싶은 회사라는 생각이 들었으며, 마미톡과 레어노트라는 서비스를 출시한 것을 보고, 희귀질환과 임신 출산이라는 서비스가 관심이 많이 갔다. 모든 서비스가 그렇겠지만 사람들에게 긍정적이고 좋은 영향을 주는 서비스라고 생각했다. 또한 한국 뿐아니라 글로벌로 나아가는 성장 가능성이 더욱 더 함께 하고 싶은 생각이 들었다. </p>
<h2 id="매드업">매드업</h2>
<p>매드업은 디지털 마케팅 시장에서 급성장하고 있는 애드테크 스타트업이다. 기술과 데이터 기반의 마케팅 솔루션을 제공함으로서 급격하게 성장해온 점에서 관심이 갔다. 또한 데이터를 많이 다룰 수 있는 좋은 경험이 될 것같다. 프론트엔드 개발자로서 다양하고 많은 데이터를 접할 수 있는 기회가 있을 것 같아서 함께 하고 싶은 기업이다. </p>
<h2 id="그립컴퍼니">그립컴퍼니</h2>
<p>그립컴퍼니는 라이브 커머스 전문 앱으로 국내 라이브 커머스 브랜드 1위를 달성했다. 이에 머물지 않고 다양한 판매 상품과 그리퍼와 함꼐 고객 가치에 집중하며 성장하고 있는 기업이다. 최근 카카오에서 투자를 받으면서 그립컴퍼니의 앞으로의 성장 가능성이 얼마나 될까 궁금증이 생기게 되었다. 또한 온라인 쇼핑을 라이브로 진행함으로서 온라인 쇼핑의 새로운 서비스를 시작한다는 점에서 많은 관심이 갔다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redux | Redux 기초]]></title>
            <link>https://velog.io/@_seeul/Redux-Redux-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@_seeul/Redux-Redux-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Wed, 06 Oct 2021 12:41:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/_seeul/post/abd8cdf1-a009-48d6-b6eb-4267ddcff921/image.png" alt=""></p>
<h1 id="1-state와-render의-관계">1. state와 render의 관계</h1>
<hr>
<p>store안의 state ⇒ state에 직접 변경하면 안된다. 어떤 것을 통해 변경을 해야한다. </p>
<p>state를 만들면서 <code>reducer</code>를 만들어 공급해주어야 한다. </p>
<pre><code class="language-jsx">function reducer(oldState, action) {
    // ...
}

var store = Redux.createStore(reducer)  // 새로운 store생성 인자로 reducer를 준다.</code></pre>
<p>render는 store바깥에 있다. ⇒ 우리의 코드. UI를 만들어주는 우리가 짜는 코드.</p>
<p>state에 직접 접속하는게 불가능하기 때문에 앞단에 <code>dispatch</code>, <code>subscribe</code>, <code>getState</code> 함수가 있다. </p>
<pre><code class="language-jsx">function render() {
    var state = store.getState();   // store에서 state를 가져온다. 
    // ...
    document.querySelector(&#39;#app&#39;).innerHTML = `
        &lt;h1&gt;WEB&lt;h1&gt;
        ...
`</code></pre>
<p>render는 현재 state를 반영하여 보여준다. </p>
<p>state가 변경될때마다 render가 바뀌면 좋을것이다. 이 때 사용하는 것이 <code>subscribe</code>이다. </p>
<pre><code class="language-jsx">store.subscibe(render);
// 이렇게 store에 render를 subscribe하면 state가 변경될때마다 render가 갱신될것이다. </code></pre>
<h1 id="2-action과-reducer">2. action과 reducer</h1>
<hr>
<pre><code class="language-jsx">&lt;form onsubmit = &quot;
// ...
store.dispatch({type:&#39;create;, payload:{title:title, desc:desc}});
&quot;&gt;

// type안의 것이 action이고 이것을 dispatch에 전달</code></pre>
<p><code>dispatch</code>가 하는일은?</p>
<ul>
<li><code>reducer</code>를 호출해서 state값을 바꾼다.</li>
<li>이것이 끝난뒤 <code>subscribe</code>를 이용해서 render함수를 호출한다. 그러면 화면이 갱신된다.</li>
</ul>
<p><code>dispatch</code>는 <code>reducer</code>를 호출해서 현재의 state값과 action데이터를 전달한다. </p>
<pre><code class="language-jsx">function reducer(state, action){
    if(action.type === &#39;create&#39;){
        ...
        ...
    return Object.assign({}, state, {
        ...
        ...
        })
// return해주는 값이 새로운 state가 된다. </code></pre>
<p>dispatch는 state를 입력값으로 받고 action을 참조해서 새로운 state값을 만들어서 return하는 state가공자이다. </p>
<p>이렇게 state값이 변경되면 render가 다시 일어난다. dispatch가 subscribe를 모두 호출하면 render가 일어난다. (getState를 통해서)</p>
<p>store의 state에 직접 접근이 안되기 때문에getState를 통해 state를 가져오고 dispatch를 통해 값을 변경하고 subscribe를 통해 값이 변경됐을때 구동될 함수를 등록한다. 또 하나의 핵심은 reducer를 통해 state값을 변경한다.</p>
<h1 id="3-redux-적용">3. Redux 적용</h1>
<hr>
<h2 id="1-redux-설치">1) Redux 설치</h2>
<pre><code class="language-bash">npm install --save redux</code></pre>
<blockquote>
<p>💡<code>redux cdn</code>으로 직접 설치하지 않고 copy해서 사용할 수도 있다. copy한 것을 script에 추가하면 된다. </p>
</blockquote>
<h2 id="2-store-생성">2) store 생성</h2>
<p>리덕스를 이용한다는 것은 <strong>결국 store를 만들어서 store의 state를 바꾸는 것</strong>이다. </p>
<ul>
<li>첫번째로 store를 만든다. store를 만들면 자동으로 state라는 것이 생긴다. 그 다음에 reducer를 만들어서 그 함수에 주입해준다.</li>
</ul>
<pre><code class="language-jsx">function reducer(staet, action){ // --- (1)
    if(state === undefined){       // --- (2)
        return {color: &#39;yellow&#39;}     // --- (3)
    } 
} 

var store = Redux.createStore(reducer) // store 만들고, reducer 주입
console.log(store.getState()) // state값 가져오기 {color: yellow} 출력(초기값)</code></pre>
<blockquote>
<p>(1) 인자로 기존 staet값과 action을 받는다. 
(2) <code>state === undefined</code> 는 state의 초기값이 아직 setting이 되기 전, 최초의 초기화 단계라는 의미이다. 
(3) 여기서 리턴하는 것은 초기 state값을 의미한다. state 초기값은 바로 여기서 리턴하는 것이라는 것!</p>
</blockquote>
<ul>
<li><strong>reducer가 하는 역할</strong>은 dispatch에 의해서 action이 들어오게 되면 reducer가 그 action 값과 기존에 있었던 state의 값을 참조해서 <strong>새로운 state값을 만들어주는 것</strong>이다.</li>
<li>우리가 store를 처음 만들때 그 store의 <strong>state값의 초기값이 필요</strong>하다.</li>
<li>우리가 store를 만들면 내부적으로 state값이 생기고 이 <strong>state값을 가져오려면 getState 함수를 사용해야한다</strong>.</li>
<li>그리고 reducer를 통해 state값을 만들어줘야 하는데 그때에 <strong>reducer에 기존 state값이 <code>undefined</code>일때 리턴하는 값은 초기 state값</strong>이라 생각하면 된다. 초기화를 위해 최초로 실행되는 reducer에 대한 호출이기 때문에 우리가 원하는 초기값을 리턴해주면 이 리덕스의 store에는 그 초기값이 지정이 된다. 그래서 그렇게 저장된 state값을 getState를 통해 가져오고 변수에 할당해 우리의 컴포넌트에 할당해주면 그 초기 state를 사용할 수 있다.</li>
</ul>
<h2 id="3-reducer와-action을-이용해서-새로운-state값-만들기">3) reducer와 action을 이용해서 새로운 state값 만들기</h2>
<p>state값을 변경시키기 위해서는 어떻게 해야할까?</p>
<ul>
<li>state를 바꾸기 위해서는 action을 만든다. 그리고 이것을 dispatch에 제출한다. 그러면 dispatch가 reducer를 호출하는데 그때에 이전의 state값과 action의 값을 동시에 전달해 준다. 그러면 우리가 만들 reducer함수가 이것을 분석해서 최종적으로 값을 리턴해준다.</li>
</ul>
<pre><code class="language-jsx">store.dispatch({type: &#39;CHANGE_COLOR&#39;, color: &#39;red&#39;}) 
// 이 코드에 의해 store의 state값이 color를 red로 바꾸고 싶다면?</code></pre>
<p>store에 dispatch를 호출하게 되면은 dispatch는 우리가 store를 생성할 때 제공한 reducer라고 하는 함수를 호출하도록 약속되어있다. 그때 이전의 state값을 전달한 action을 인자로 준다. </p>
<pre><code class="language-jsx">console.log(state, action) 

// 처음엔 undefined, {type : &quot;@@redux/어쩌고&quot;} 이 출력
// 어떠한 버튼을 클릭한다면 {color: &#39;yellow&#39;} {type: &#39;CHANGE_COLOR&#39;, color: &#39;red&#39;} 이 출력

function reducer(staet, action){ 
    if(state === undefined){       
        return {color: &#39;yellow&#39;}   
    } 
    return {color: &#39;red&#39;}  // 어떠한 이벤트를 발생했을때 state값을 이것으로 바꿔준다. 
} </code></pre>
<ul>
<li><strong>reducer라는 것은 이전의 state와 action을 받아서 다음의 state값을 리턴해준다.</strong></li>
</ul>
<pre><code class="language-jsx">// 이렇게도 사용할 수 있다. 하지만 좋지 않은 방법이다. 

function reducer(staet, action){ 
    if(state === undefined){       
        return {color: &#39;yellow&#39;}   
    } 
    if(action.type === &#39;CHANGE_COLOR&#39;){
        state.color = &#39;red&#39;                 // state의 color를 &#39;red&#39;로 변경
    }
    return state                          // 그것을 return
}  </code></pre>
<p>위처럼 state를 color를 변경하고 그것을 리턴하는 것이 아닌 이 state를 복제하고 복제된 복사본을 변경해서 return 하는것이 좋다. 이유는 바로 불변성 때문이다. </p>
<ul>
<li>그럼 어떻게 복제를 하는 것이 좋을까?</li>
</ul>
<p>복제할 때 <code>Object.assign()</code>을 사용한다. 첫 번째 인자로는 빈 객체, 두 번째 인자로는 빈객체의 복제할 속성을 가진 객체를 주면 된다. 
<code>Object.assign({}, {name:&#39;daseul&#39;}, {city: &#39;seoul&#39;})</code>
이렇게 작성하면 여기 있는 객체의 name속성이 &#39;daseul&#39;이라는 값을 <code>assign</code>이 복제해준다. 그 뒤의 값도 복사가 된다. 즉 <strong>첫번째 인자에 두번째 인자를 복사하고 그 결과에 다시 세 번째 인자를 복사하는 것</strong>이다. </p>
<p>이렇게 되면 위의 코드는 <code>{name:&#39;daseul&#39;, city:&#39;seoul&#39;}</code>이라는 새로운 객체가 복사된다. 그것이 <code>assign</code>이다. 첫 번째 인자는 무조건 빈 객체를 주어야 한다. 왜냐하면 <code>Object.assign()</code>의 리턴값은 첫 번째 인자이기 때문이다. </p>
<pre><code class="language-jsx">// Object.assign()을 이용한 올바른 방법

function reducer(staet, action){ 
    if(state === undefined){       
        return {color: &#39;yellow&#39;}   
    } 
    if(action.type === &#39;CHANGE_COLOR&#39;){
        newState = Object.assign({}, state, { color: &#39;red&#39; }) 
        // state의 값이 첫번째 인자인 빈 객체에 복제되어 리턴되고 세번째 인자가 덮어씌워진다. 
    }
    return newState // 복제된 값 return! 
}  
</code></pre>
<p>이전에는 원본인 state를 직접 변경했는데 이제는 state를 복제하고 그 복제한 것의 color를 red로 준것을 리턴하게 된다. 그러면 이 reducer가 실행될 때마다 리턴되는 값이 새로운 state값이 되는데 각각의 state값이 완전히 독립되어 복제된 값들이 리턴된다.  </p>
<h2 id="4-state의-변화를-ui에-반영하기">4) state의 변화를 UI에 반영하기</h2>
<hr>
<p>위에서 reducer를 통해 state값을 변경해주었다. 그러면 이 변경된 state값을 우리의 UI에 반영해주려면 어떻게 해야할까?</p>
<ul>
<li>바로 render를 호출해주면 된다. state값이 바뀔 때마다 render를 호출해 화면에 그려준다.</li>
</ul>
<pre><code class="language-jsx">var store = Redux.createStore(reducer)

function red() {
    var state = store.getState()
    document.querySelector(&#39;#red&#39;).innerHTML = `
        &lt;div class=&quot;container&quot; id=&quot;component_red&quot;
        style=&quot;background-color:${state.color}&quot;&gt;
            &lt;h1&gt;red&lt;/h1&gt;
            &lt;input type=&quot;button&quot; value=&quot;fire&quot; onclick=&quot;
                store.dispatch({type: &#39;CHANGE_COLOR&#39;, color: &#39;red&#39;})
                &quot;&gt;
        &lt;/div&gt;
    `
}
red()</code></pre>
<p><code>red()</code>라는 UI를 바꿔주는 함수는 state값에 따라서 color를 바꿔서 UI를 변경해주는 함수이기 때문에 언제든지 호출할 수 있다. 일단 위의 코드에서 보듯 <code>red()</code>를 최초 한번은 호출을 해주었는데 그 이후에 state가 바뀔때마다 그러니까 dispatch를 호출할때마다 red함수를 호출하게 하려면 어떻게 해야할까?</p>
<p>⇒ <strong>subscribe에 render를 등록</strong>하면 된다. 그러면 dispatch가 state값을 바꾸고 난 다음에 이것을 호출하도록 약속되어 있기 때문이다. </p>
<pre><code class="language-jsx">var store = Redux.createStore(reducer)

function red() {
    var state = store.getState()
    document.querySelector(&#39;#red&#39;).innerHTML = `
        &lt;div class=&quot;container&quot; id=&quot;component_red&quot;
        style=&quot;background-color:${state.color}&quot;&gt;
            &lt;h1&gt;red&lt;/h1&gt;
            &lt;input type=&quot;button&quot; value=&quot;fire&quot; onclick=&quot;
                store.dispatch({type: &#39;CHANGE_COLOR&#39;, color: &#39;red&#39;})
                &quot;&gt;
        &lt;/div&gt;
    `
}
red()

store.subscribe(red) // !!!!</code></pre>
<p>store의 subscibe함수에 red함수를 인자로 넣어 호출해준다. 그러면 state가 바뀔때마다 red함수가 호출된다. </p>
<p>이렇게 Redux를 사용하게 되면 상태를 <code>중앙집중적</code>으로 관리할 수 있다. 각각의 부품들은 상태가 바뀌었을때 action을 store에 dispatch해주고 자신이 어떻게 변화되어야 하는지에 대한 코드를 작성하고 그것을 store에 subscribe하면 state가 바뀔때마다 통보를 받기 때문에 그때마다 자신의 모양을 바꿔줄수있는것이다.</p>
<h1 id="4-정리-">4. 정리 !</h1>
<hr>
<blockquote>
</blockquote>
<ul>
<li>reducer 함수가 하는 역할은 store의 state값을 변경해준다. 어떻게? action의 값과 이전의 state값을 이용해서 새로운 state 값을 리턴해주면 그 리턴된 값이 새로운 state값이 된다.
그리고 리턴하는 값은 원본을 바꾸는 것이 아니라 이전에 있었던 값을 복제한 결과를 리턴해야지만 우리가 리덕스를 사용하는 여러가지 효용들을 최대한으로 활용할 수 있다 ! <br/></li>
<li>원래 서로의 컴포넌트들은 자신의 상태가 변경되었을때, 자신에게 의존하고 있는 다른 컴포넌트들에게 그것을 직접 알려줘야했다. 하지만 redux를 사용하게 되면 모든 컴포넌트들이 rendering될 때 필요한 데이터를 담고 있는 stae를 만들고, 만약 action을 전달해 reducer를 통해 staet가 변경되면 모든 컴포넌트들에게 state가 변경되었음을 알리고 sate가 변경됨에 따라 subscribe에 포함되어 있는 함수들이 실행되면서 컴포넌트들이 재렌더링되기 때문에 컴포넌트들간의 의존성이 낮아지고 컴포넌트들은 각자 자신의 상태에만 집중할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[코어 자바스크립트 | 3. this]]></title>
            <link>https://velog.io/@_seeul/%EC%BD%94%EC%96%B4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-3.-this</link>
            <guid>https://velog.io/@_seeul/%EC%BD%94%EC%96%B4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-3.-this</guid>
            <pubDate>Wed, 06 Oct 2021 08:30:02 GMT</pubDate>
            <description><![CDATA[<h1 id="1-상황에-따라-달라지는-this">1. 상황에 따라 달라지는 this</h1>
<hr>
<p>자바스크립트에서 <code>this</code>는 기본적으로 <strong>실행 컨텍스트가 생성될 때 함께 결정</strong>된다. 실행 컨텍스트는 함수를 호출할 때 생성되므로, 바꿔 말하면 <code>this</code>는 <strong>함수를 호출할 때 결정</strong>된다고 할 수 있다. 함수를 <strong>어떤 방식으로 호출하느냐에 따라 값이 달라진다</strong>. </p>
<h2 id="1-전역-공간에서의-this">1) 전역 공간에서의 this</h2>
<p>전역 공간에서 <code>this</code>는 전역 객체를 가리킨다. <strong>개념상 전역 컨텍스트를 생성하는 주체가 바로 전역 객체</strong>이기 때문이다. </p>
<p>전역 객체는 자바스크립트 런타임 환경에 따라 다른 이름과 정보를 가지고 있다. 브라우저 환경에서 전역객체는 <code>window</code>이고, Node.js 환경에서는 <code>global</code>이다. </p>
<p>전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당한다. 변수이면서 객체의 프로퍼티이기도 한 셈이다. </p>
<pre><code class="language-jsx">var a = 1;
console.log(a);        // 1
console.log(window.a); // 1
console.log(this.a);   // 1</code></pre>
<p>⇒ 전역공간에서 선언한 변수 a에 1을 할당했을 뿐인데 window.a와 this.a는 모두 1이 출력된다. 전역 공간에서의 <code>this</code>는 전역객체를 의미하므로 두 값이 같은 값을 출력하는 것은 당연하지만, 그 값이 1인 것이 의아하다. 그 이유는 <strong>자바스크립트의 모든 변수는 실은 특정 객체의 프로퍼트로 동작하기 때문</strong>에다. </p>
<p><strong>전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.</strong></p>
<h2 id="2-메서드로서-호출할-때-그-메서드-내부에서의-this">2) 메서드로서 호출할 때 그 메서드 내부에서의 this</h2>
<h3 id="함수-vs-메서드">함수 vs. 메서드</h3>
<p>어떤 함수를 실행하는 방법은 여러가지가 있는데, 가장 일반적인 방법 두 가지는 <strong>함수로서 호출하는 경우</strong>와 <strong>메서드로서 호출하는 경우</strong>이다. </p>
<p>프로그래밍 언어에서 함수와 메서드는 미리 정의한 동작을 수행하는 코드 뭉치로, 이 둘을 구분하는 유일한 차이는 독립성에 있다. </p>
<p>함수는 그 자체로 독립적인 기능을 수행하는 반면, <strong>메서드는 자신을 호출한 대상 객체에 관한 동작을 수행</strong>한다. 자바스크립트는 상황별로 <code>this</code> 키워드에 다른 값을 부여하게 함으로써 이를 구현했다. </p>
<p><strong>어떤 함수를 객체의 프로퍼티에 할당한다고 해서 그 자체로서 무조건 메서드가 되는 것이 아니라 객체의 메서드로서 호출한 경우에만 메서드로 동작하고 그렇지 않으면 함수로 동작한다.</strong></p>
<pre><code class="language-jsx">var func = function(x){
    console.log(this, x);
};
func(1);                // Window{ ... } 1

var obj = {
    method: func
};
obj.method(2);          // { method:f } 2</code></pre>
<p>위의 예제에서 보듯이 &#39;함수로서의 호출&#39;과 &#39;메서드로서의 호출&#39;을 할때 <code>this</code>가 가리키는 것은 다른다. &#39;함수로서의 호출&#39;과 &#39;메서드로서의 호출&#39;을 어떻게 구분할까? 함수 앞에 점(<code>.</code>)이 있는지 여부만으로 간단하게 구분할 수 있다. </p>
<pre><code class="language-jsx">// 메서드로서의 호출 - 점 표기법, 대괄호 표기법

var obj = {
    method : function(x) { console.log(this,x) }
};

obj.method(1);   // { method: f } 1
obj[&#39;method&#39;](2) // { method: f } 2</code></pre>
<p>다시 말해 점 표기법이든 대괄호 표기법이든, 어떤 함수를 호출할 때 그 함수 이름(프로퍼티명) 앞에 객체가 명시돼 있는 경우에는 메서드로 호출한 것이고, 그렇지 않은 모든 경우에는 함수로 호출한 것이다. </p>
<h3 id="메서드-내부에서의-this">메서드 내부에서의 this</h3>
<p><code>this</code>에는 호출한 주체에 대한 정보가 담긴다. 어떤 함수를 메서드로서 호출하는 경우 호출 주체는 바로 함수명(프로퍼티명) 앞의 객체이다. 점 표기법의 경우 마지막 점 앞에 명시된 객체가 곧 <code>this</code>가 되는 것이다. </p>
<pre><code class="language-jsx">var obj = {
    methodA: function(){ console.log(this) },
    inner : {
        methodB : function(){ console.log(this) }
    }
};

obj.methodA();  // { methodA : f, inner: {...} } ( === obj )
obj[&#39;methodA&#39;]; // { methodA : f, inner: {...} } ( === obj )

obj.inner.methodB();        // { method: f } ( === obj.inner)
obj.inner[&#39;methodB&#39;]();     // { method: f } ( === obj.inner)
obj[&#39;inner&#39;].methodB();     // { method: f } ( === obj.inner)
obj[&#39;inner&#39;].[&#39;methodB&#39;](); // { method: f } ( === obj.inner)
</code></pre>
<h2 id="3-함수로서-호출할-때-그-함수-내부에서의-this">3) 함수로서 호출할 때 그 함수 내부에서의 this</h2>
<h3 id="함수-내부에서의-this">함수 내부에서의 this</h3>
<p>어떤 함수를 함수로서 호출할 경우에는 <code>this</code>가 지정되지 않는다. <code>this</code>에는 호출한 주체에 대한 정보가 담긴다. 그런데 함수로서 호출하는 것은 호출 주체(객체지향언어에서의 객체)를 명시하지 않고 개발자가 코드에 직접 관여해서 실행한 것이기 때문에 호출 주체의 정보를 알 수 없는 것이다. 2장에서 실행 컨텍스트를 활성화할 당시에 <code>this</code>가 지정되지 않은 경우 <code>this</code>는 전역 객체를 바라본다고 했다. 따라서 <strong>함수에서의 <code>this</code>는 전역 객체</strong>를 가리킨다. </p>
<p>더글라스 크락포드는 이를 명백한 설계상의 오류라고 지적한다. 그 이유를 알아보자.</p>
<h3 id="메서드-내부함수에서의-this">메서드 내부함수에서의 this</h3>
<pre><code class="language-jsx">var obj1 = {
    outer: function(){
        console.log(this);            // (1):obj1
        var innerFunc = function(){
            console.log(this);          // (2):전역객체(window) (3):obj2
        }
        innerFunc();                  // 🌈

        var obj2 = {
            innerMethod : innerFunc
        };
        obj2.innerMethod();           // 🌈
    }
}
obj1.outer();
</code></pre>
<ul>
<li>1번째 줄: 객체를 생성하는데, 이때 객체 내부에는 outer라는 프로퍼티가 있으며, 여기에는 익명함수가 연결된다. 이렇게 생성한 객체를 변수 obj1에 할당한다.</li>
<li>15번째 줄: obj1.outer를 호출한다.</li>
<li>2번째 줄: obj1.outer 함수의 실행 컨텍스트가 생성되면서 호이스팅하고, 스코프 체인 정보를 수집하고, <code>this</code>를 바인딩한다. 이 함수는 호출할 때 함수명인 outer앞에 점(<code>.</code>)이 있었으므로 메서드로서 호출한 것이다. 따라서 <code>this</code>에는 마지막 점 앞의 객체인 obj1이 바인딩된다.</li>
<li>3번째 줄: obj1 객체 정보가 출력된다.</li>
<li>4번째 줄: 호이스팅 된 변수 innerFunc는 outer스코프 내에서만 접근할 수 있는 지역변수이다. 이 지역변수에 익명 함수를 할당한다.</li>
<li>7번째 줄: innerFunc를 호출한다.</li>
<li>4번째 줄: innerFunc 함수의 실행 컨텍스트가 생성되면서 호이스팅, 스코프 체인 수집, <code>this</code> 바인딩 등을 수행한다. 이 함수를 호출할 때 함수명 앞에는 점(<code>.</code>)이 없다. 즉 함수로서 호출한 것이므로 <code>this</code>가 지정되지 않았고, 따라서 자동으로 스코프 체인상의 최상위 객체인 전역객체 (<code>Window</code>)가 바인딩 된다.</li>
<li>5번째 줄: <code>window</code> 객체 정보가 출력된다.</li>
<li>9번째 줄: 호이스팅된 변수 obj2 역시 스코프 내에서만 접근할 수 있는 지역변수이다. 여기에는 다시 객체를 할당하는데, 그 객체에는 innerMethod 라는 프로퍼티가 있으며, 여기에는 앞서 정의된 변수 innderFunc와 연결된 익명 함수가 연결된다.</li>
<li>10번째 줄: obj2 객체 정보가 출력된다.</li>
</ul>
<p>⇒ 7번째 줄에서는 outer 메서드 내부에 있는 함수(innerFunc)를 함수로서 호출했다. 반면 12번째 줄에서는 같은 함수(innerFunc)를 메서드로서 호출했다. 같은 함수임에도 7번째 줄에 의해 바인딩되는 <code>this</code>와 12번째 줄에 의해 바인딩 되는 <code>this</code>의 대상이 서로 달라진 것이다. </p>
<p>그러니까 <code>this</code> 바인딩에 관해서는 함수를 실행하는 당시의 주변 환경(메서드 내부인지, 함수 내부인지 등)은 중요하지 않고, 오직 해당 <strong>함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지 없는지가 관건</strong>인 것!!!</p>
<h3 id="메서드-내부-함수에서의-this를-우회하는-방법">메서드 내부 함수에서의 this를 우회하는 방법</h3>
<p>이렇게 하면 <code>this</code>에 대한 구분은 명확히 할 수 있지만, 그 결과 <code>this</code>라는 단어가 주는 인상과는 사뭇 달라져 버렸다. 호출 주체가 없을 때는 자동으로 전역객체를 바인딩하지 않고 호출 당시 주변환경의 <code>this</code>를 그대로 상속받아 사용할 수 있다면 좋겠다. 그게 훨씬 자연스러울뿐더러 자바스크립트 설계상 이렇게 동작하는 편이 스코프 체인과의 일관성을 지키는 설득력 있는 방식이었다. 변수를 검색하면 우선 가장 가까운 스코프의 L.E를 찾고 없으면 상위 스코프를 탐색하듯이, <code>this</code> 역시 현재 컨텍스트에 바인딩된 대상이 없으면 직전 컨텍스트의 <code>this</code>를 바라보도록 말이다. </p>
<p>아쉽게도 ES5까지는 자체적으로 내부함수에 <code>this</code>를 상속할 방법이 없지만 다행히 이를 우회할 방법이 없지는 않다. 그 중 대표적인 방법은 바로 변수를 활용하는 것이다. </p>
<pre><code class="language-jsx">var obj1 = {
    outer: function(){
        console.log(this)
        var innerFunc1 = function(){
            console.log(this)
        }
        innerFunc1();

      var self = this
        var innerFunc2 = function(){
      console.log(self)
    }
        innerFunc2()
    }
}
obj1.outer();</code></pre>
<p>위 예제의 innerFunc1 내부에서 <code>this</code>는 전역객체를 가리킨다. 한편 outer 스코프에서 self라는 변수에 <code>this</code>를 저장한 상태에서 호출한 innerFunc2의 경우 self에는 객체 obj가 출력된다. </p>
<h3 id="this를-바인딩하지-않는-함수">this를 바인딩하지 않는 함수</h3>
<p>ES6에서는 함수 내부에서 <code>this</code>가 전역객체를 바라보는 문제를 보완하고자, <code>this</code>를 바인딩하지 않는 화살표 함수를 새로 도입했다. 화살표 함수는 실행 컨텍스트를 생성할 때 <code>this</code> 바인딩 과정 자체가 빠지게 되어, 상위 스코프의 <code>this</code>를 그대로 활용할 수 있다. 내부함수를 화살표 함수로 바꾸면 위의 예제의 &#39;우회법&#39;이 불필요해진다. (아쉽게도 ES5환경에서는 화살표 함수를 사용할 수 없다.)</p>
<pre><code class="language-jsx">var obj = {
    outer: function(){
        console.log(this)         // (1) { outer: f }
        var innerFunc = () =&gt; {
            console.log(this)       // (2) { outer: f }
        }
        innerFunc()
    }
}
obj.outer();</code></pre>
<p>그 밖에도 call, apply 등의 메서드를 활용해 함수를 호출할 때 명시적으로 <code>this</code>를 지정하는 방법이 있다. </p>
<h2 id="4-콜백-함수-호출-시-그-함수-내부에서의-this">4) 콜백 함수 호출 시 그 함수 내부에서의 this</h2>
<p>함수 A의 제어권을 다른 함수(또는 메서드) B에 넘겨주는 경우 함수 A를 콜백 함수라 한다. 이때 함수 A는 함수 B의 내부 로직에 따라 실행되며, <code>this</code> 역시 함수 B 내부 로직에서 정한 규칙에 따라 값이 결정된다. 콜백 함수도 함수이기 때문에 기본적으로 <code>this</code>가 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백 함수에 별도로 <code>this</code>가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다. </p>
<pre><code class="language-jsx">setTimeout(function() { console.log(this); }, 300); // --------- (1)

[1, 2, 3, 4, 5].forEach(function(x) {               // --------- (2)
    console.log(this,x);
});

document.body.innerHTML += &#39;&lt;button id=&quot;a&quot;&gt;클릭&lt;/button&gt;&#39;;
document.body.querySelector(&#39;#a&#39;)
    .addEventListener(&#39;click&#39;, function(e){           // --------- (3)
            console.log(this, e);
    });</code></pre>
<p>(1): <code>setTimeout</code> 함수는 300ms 만큼 시간 지연을 한 뒤 콜백 함수를 실행하라는 명령이다. 0.3초 뒤 전역객체가 출력된다. </p>
<p>(2): <code>forEach</code> 메서드는 배열의 각 요소를 앞에서부터 차레로 하나씩 꺼내어 그 값을 콜백 함수의 첫 번째 인자로 삼아 함수를 실행하라는 명령이다. 전역객체와 배열의 각 요소가 총 5회 출력된다.</p>
<p>(3): <code>addEventListener</code>는 지정한 HTML 엘리먼트에 &#39;click&#39; 이벤트가 발생할 때마다 그 이벤트 정보를 콜백 함수의 첫 번째 인자로 삼아 함수를 실행하라는 명령이다. 버튼을 클릭하면 앞서 지정한 엘리먼트와 클릭 이벤트에 관한 정보가 담긴 객체가 출력된다.</p>
<p>⇒ (1)의 <code>setTimeout</code> 함수와 (2)의 <code>forEach</code> 메서드는 그 내부에서 콜백 함수를 호출할 때 대상이 될 this를 지정하지않는다. 따라서 콜백 함수 내부에서의 this는 전역객체를 참조한다. 한편 (3)의 <code>addEventListener</code> 메서드는 콜백 함수를 호출할 때 자신의 this를 상속하도록 정의돼 있다. 그러니까 메서드명의 점(.) 앞부분이 곧 this가 된다. </p>
<p>⇒ 이처럼 콜백 함수에서는 콜백 함수의 제어권을 가지는 함수(메서드)가 콜백 함수에서의 this를 무엇으로 할지 결정하며, 특별히 정의하지 않은 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라본다. </p>
<p>자바스크립트의 핵심 ! <strong>호출한 것(객체) === this</strong> !!</p>
<h2 id="5-생성자-함수-내부에서의-this">5) 생성자 함수 내부에서의 this</h2>
<p>생성자 함수는 어떤 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수이다. 객체지향 언어에서는 생성자를 클래스, 클래스를 통해 만든 객체를 인스턴스라고 한다. 프로그래밍적으로 &#39;생성자&#39;는 구체적인 인스턴스를 만들기 위한 일종의 틀이다. 자바스크립트늩 함수에 생성자로서의 역할을 함께 부여했다. new 명령어와 함께 함수를 호출하면 해당 함수가 생성자로서 동작하게된다. 그리고 어떤 함수가 생성자 함수로서 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이 된다. </p>
<p>⇒ 생성자 함수를 호출하면 우선 생성자의 <code>prototype</code> 프로퍼티를 참조하는 <code>__proto__</code> 라는 프로퍼티가 있는 객체를 만들고, 미리 준비된 공통 속성 및 개성을 해당 객체(<code>this</code>)에 부여한다. 이렇게 해서 구체적인 인스턴스가 만들어진다.  </p>
<pre><code class="language-jsx">var Cat = function (name, age) {
    this.bark = &#39;야옹&#39;
    this.name = name
    this.age = age
}

var choco = new Cat (&#39;초코&#39;, 7) // --- (1)
var nabi = new Cat (&#39;나비&#39;, 5)  // --- (2)
console.log(choco, nabi)

/* 결과
Cat { bark: &#39;야옹&#39;, name: &#39;초코&#39;, age: 7 }
Cat { bark: &#39;야옹&#39;, name: &#39;나비&#39;, age: 5 }
*/</code></pre>
<p>Cat이란 변수에 익명 함수를 할당했다. 이 함수 내부에서의 <code>this</code>에 접근해서 bark, name, age 프로퍼티에 각각 값을 대입한다. 그리고 new 명령어와 함께 Cat 함수를 호출해서 변수 choco, nabi에 각각 할당했다. choco와 nabi를 출력해보니 각각 Cat 클래스의 인스턴스 객체가 출력된다. 즉 (1)에서 실행한 생성자 함수 내부에서의 <code>this</code>는 choco 인스턴스를, (2)에서 실행한 생성자 함수 내부에서의 <code>this</code>는 nabi 인스턴스를 가리킴을 알 수 있다. </p>
<h1 id="2-명시적으로-this를-바인딩하는-방법">2. 명시적으로 this를 바인딩하는 방법</h1>
<hr>
<h2 id="1-call-메서드">1) call 메서드</h2>
<pre><code class="language-jsx">Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])</code></pre>
<p><code>call</code> 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다. 이때 <code>call</code> 메서드의 첫 번째 인자를 <code>this</code>로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 한다. 함수를 그냥 실행하면 <code>this</code>는 전역객체를 참조하지만 <code>call</code> 메서드를 이요하면 임의의 객체를 <code>this</code>로 지정할 수 있다. </p>
<pre><code class="language-jsx">var func = function (a, b, c) {
    console.log(this, a, b, c)
}

func(1, 2, 3)                  // Window{...} 1 2 3
func.call({ x: 1 }, 4, 5, 6)   // { x: 1 } 4 5 6</code></pre>
<p>메서드에 대해서도 마찬가지로 객체의 메서드를 그냥 호출하면 <code>this</code>는 객체를 참조하지만 <code>call</code> 메서드를 이용하면 임의의 객체를 <code>this</code>로 지정할 수 있다. </p>
<pre><code class="language-jsx">var obj = {
    a : 1, 
    method : function (x, y) {
        console.log(this.a, x, y)
    }
}

obj.method(2, 3)                // 1 2 3
obj,method.call({ a: 4 }, 5, 6) // 4 5 6</code></pre>
<h2 id="2-apply-메서드">2) apply 메서드</h2>
<pre><code class="language-jsx">Function.prototype.apply(thisArg[, argsArray])</code></pre>
<p><code>apply</code> 메서드는 <code>call</code> 메서드와 기능적으로 완전히 동일하다. <code>call</code> 메서드는 첫 번째 인자를 제외한 나머지 모든 인자들을 호출할 함수의 매개변수로 지정하는 반면, <code>apply</code> 메서드는 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다는 점에서만 차이가 있다. </p>
<pre><code class="language-jsx">var func = function (a, b, c) {
    console.log(this, a, b, c)
}
func.apply({ x: 1 }, [4, 5, 6])  // { x: 1 } 4 5 6

var obj = {
    a: 1, 
    method: function(x, y) {
        console.log(this.a, x, y)
    }
}

obj.method.apply({ a: 4 },[5, 6]) // 4 5 6</code></pre>
<h2 id="3-bind-메서드">3) bind 메서드</h2>
<pre><code class="language-jsx">Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])</code></pre>
<p><code>bind</code> 메서드는 ES5에 추가된 기능으로, <code>call</code>과 비슷하지만 즉시 호출하지는 않고 넘겨받은 <code>this</code> 및 인수들을 바탕으로 새로운 함수를 반환하기만 하는 메서드이다. 다시 새로운 함수를 호출할 때 인수를 넘기면 그 인수들은 기존 <code>bind</code> 메서드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록된다. 즉 <code>bind</code> 메서드는 함수에 <code>this</code>를 미리 적용하는 것과 부분 적용 함수를 구현하는 두 가지 목적을 모두 지닌다. </p>
<pre><code class="language-jsx">var func = function (a, b, c, d) {
    console.log(this, a, b, c, d)
}
func(1, 2, 3, 4)                    // Window{ ... } 1 2 3 4

var bindFunc1 = func.bind({ x: 1 })
bindFunc1(5, 6, 7, 8);              // { x: 1 } 5 6 7 8

var bindFunc2 = func.bind({ x: 1 }, 4, 5)
bindFunc2(6, 7)                     // { x: 1 } 4 5 6 7
bindFunc2(8, 9)                     // { x: 1 } 4 5 8 9</code></pre>
<ul>
<li>6번째 줄에서 bindFunc1 변수에는 func에 <code>this</code>를 { x: 1 }로 지정한 새로운 함수가 담긴다.</li>
<li>이제 7번째 줄에서 bindFunc1을 호출하면 원하는 결과를 얻을 수 있게 된다.</li>
<li>한편 9번째 줄의 bindFunc2 변수에는 func에 <code>this</code>를 { x: 1 }로 지정하고, 앞에서부터 두 개의 인수를 각각 4, 5로 지정한 새로운 함수를 담았다.</li>
<li>이후 10번째 줄에서 매개변수로 6, 7을 넘기면 <code>this</code> 값이 바뀐 것을 제외하고는 최초 func함수에 4, 5, 6, 7을 넘긴 것과 같은 동작을 한다. 11번째 줄에서도 마찬가지이다.</li>
<li>6번째 줄의 <code>bind</code>는 <code>this</code>만을 지정한 것이고, 9번째 줄의 <code>bind</code>는 <code>this</code> 지정과 함께 부분 적용 함수를 구현한 것이다.</li>
</ul>
<h3 id="name-프로퍼티">name 프로퍼티</h3>
<p><code>bind</code> 메서드를 적용해서 새로 만든 함수는 한 가지 독특한 성질이 있다. 바로 name 프로퍼티에 동사 <code>bind</code>의 수동태인 &#39;bound&#39;라는 접두어가 붙는다는 점이다. 어떤 함수의 name 프로퍼티가 &#39;bound xxx&#39;라면 이는 곧 함수명이 xxx인 원본 함수에 <code>bind</code> 메서드를 적용한 새로운 함수라는 의미가 되므로 기존의 <code>call</code>이나 <code>apply</code>보다 코드를 추적하기에 더 수월해진 면이 있다. </p>
<pre><code class="language-jsx">var func = function (a, b, c, d) {
    console.log(this, a, b, c, d)
}
var bindFunc = func.bind({ x: 1 }, 4, 5)
console.log(func.name)                    // func
console.log(bindFunc.name)                // bound func</code></pre>
<h3 id="상위-컨텍스트의-this를-내부함수나-콜백-함수에-전달하기">상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기</h3>
<p>위에서 메서드의 내부함수에서 메서드의 <code>this</code>를 그대로 바라보게 하기 위한 방법으로 self 등의 변수를 활용한 우회법을 소개했는데, <code>call</code>, <code>apply</code> 또는 <code>bind</code> 메서드를 이요하면 더 깔끔하게 처리할 수 있다. </p>
<pre><code class="language-jsx">// 내부함수에 this 전달 - call

var obj = {
    outer: function(){
        console.log(this)
        var innerFunc = function(){
            console.log(this)
        }
        innerFunc.call(this)
    }
}
obj.outer();</code></pre>
<pre><code class="language-jsx">// 내부함수에 this 전달 - bind

var obj = {
    outer: function(){
        console.log(this)
        var innerFunc = function(){
            console.log(this)
        }.bind(this)
        innerFunc()
    }
}
obj.outer();</code></pre>
<p>또한 콜백 함수를 인자로 받는 함수나 메서드 중에서 기본적으로 콜백 함수 내에서의 <code>this</code>에 관여하는 함수 또는 메서드에 대해서도 <code>bind</code> 메서드를 이용하면 <code>this</code> 값을 사용자의 입맛에 맞게 바꿀 수 있다. </p>
<pre><code class="language-jsx">vat obj = {
        logThis: function(){
            console.log(this)
        },
        logThisLater1: function(){
            setTimeout(this.logThis, 500)
        }, 
        logThisLater2: function(){
            setTimeout(this.logThis.bind(this), 1000)
        }
}
obj.logThisLater1() // Window { ... }
obj.logTHisLater2() // obj { logThis: f, ... }</code></pre>
<h2 id="4-화살표-함수의-예외사항">4) 화살표 함수의 예외사항</h2>
<p>ES6에 새롭게 도입된 화살표 함수는 실행 컨텍스트 생성 시 <code>this</code>를 바인딩하는 과정이 제외되었다. 즉 이 함수 내부에는 <code>this</code>가 아예 없으며, 접근하고자 하면 스코프체인상 가장 가까운 <code>this</code>에 접근하게 된다. </p>
<pre><code class="language-jsx">var obj = {
    outer: function(){
        console.log(this)
        var innerFunc = () =&gt; {
            console.log(this)
        }
        innerFunc()
    }
}
obj.outer()</code></pre>
<p>이렇게 화살표 함수를 사용하면 별도의 변수로 <code>this</code>를 우회하거나 <code>call</code>/<code>apply</code>/<code>bind</code> 를 적용할 필요가 없어 더욱 간결하고 편리하다. </p>
<h2 id="5-별도의-인자로-this를-받는-경우콜백-함수-내에서의-this">5) 별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)</h2>
<p>콜백 함수를 인자로 받는 메서드 중 일부는 추가로 <code>this</code>로 지정할 객체를 인자로 지정할 수 있는 경우가 있다. 이러한 메서드의 thisArg 값을 지정하면 콜백 함수 내부에서 <code>this</code> 값을 원하는 대로 변경할 수 있다. 이런 형태는 여러 내부 요소에 대해 같은 동작을 반복 수행해야 하는 배열 메서드에 많이 포진돼 있으며, 같은 이유로 ES6에 새로 등장한 Set, Map 등의 메서드에도 일부 존재한다. 그중 대표적인 배열 메서드인 forEach의 예를 살펴보겠다. </p>
<pre><code class="language-jsx">var report = {
    sum: 0, 
    count: 0, 
    add: function(){
        var args = Array.prototype.slice.call(arguments)
        args.forEach(function(entry){
            this.sum += entry
            ++this.count
        }, this)
    },
    average: function(){
        return this.sum / this.count
    }
}
report.add(60, 85, 90)
console.log(report.sum, report.count, report.average()) // 240 3 80</code></pre>
<ul>
<li>report 객체에는 sum, count 프로퍼티가 있고, add, average 메서드가 있다. 5번째 줄에서 add 메서드는 arguments를 배열로 변환해서 args 변수에 담고 6번쨰 줄에서는 이 배열을 순회하면서 콜백 함수를 실행하는데, 이때 콜백 함수 내부에서의 this는 forEach 함수의 두 번째 인자로 전달해준 this가 바인딩된다. 11번째 줄의 average는 sum 프로퍼티를 count 프로퍼티로 나눈 결과를 반환하는 메서드이다.</li>
<li>15번째 줄에서 60, 85, 95를 인자로 삼아 add 메서드를 호출하면 이 세 인자를 배열로 만들어 forEach 메서드가 실행된다. 콜백 함수 내부에서의 <code>this</code>는 add 메서드에서의 <code>this</code>가 전달된 상태이므로 add 메서드의 <code>this</code>(report)를 그대로 가리키고 있다. 따라서 배열의 세 요소를 순회하면서 report.sum 값 및 report.count 값이 차례로 바뀌고, 순회를 마친 결과 report.sum에는 240이 report.count에는 3이 담기게 된다.</li>
</ul>
<pre><code class="language-jsx">// 콜백 함수와 함께 thisArg를 인자로 받는 메서드

Array.prototype.forEach(callback[, thisArg])
Array.prototype.map(callback[, thisArg])
Array.prototype.filter(callback[, thisArg])
Array.prototype.some(callback[, thisArg])
Array.prototype.every(callback[, thisArg])
Array.prototype.find(callback[, thisArg])
</code></pre>
<h1 id="3-정리">3. 정리</h1>
<hr>
<p><strong>다음 규칙은 명시적 this 바인딩이 없는 한 늘 성립한다.</strong></p>
<ol>
<li>전역공간에서의 <code>this</code>는 전역객체(브라우저에서는 window, Node.js에서는 global)를 참조한다.</li>
<li>어떤 함수를 메서드로서 호출한 경우 <code>this</code>는 메서드 호출 주체(메서드명 앞의 객체)를 참조한다.</li>
<li>어떤 함수를 함수로서 호출한 경우 <code>this</code>는 전역객체를 참조한다. 메서드의 내부함수에서도 같다.</li>
<li>콜백 함수 내부에서의 <code>this</code>는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따르며, 정의하지 않은 경우에는 전역객체를 참조한다.</li>
<li>생성자 함수에서의 <code>this</code>는 생성될 인스턴스를 참조한다.</li>
</ol>
<p><strong>다음은 명시적 this의 바인딩이다. 위 규칙에 부합하지 않는 경우에는 다음 내용을 바탕으로 this를 예측할 수 있다.</strong> </p>
<ol>
<li><code>call</code>, <code>apply</code> 메서드는 <code>this</code>를 명시적으로 지정하면서 함수 또는 메서드를 호출한다. </li>
<li><code>bind</code> 메서드는 <code>this</code> 및 함수에 넘길 인수를 일부 지정해서 새로운 함수를 만든다. </li>
<li>요소를 순회하면서 콜백 함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자로 <code>this</code>를 받기도 한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 공통 원소 구하기 (Two Pointers Algorithm)]]></title>
            <link>https://velog.io/@_seeul/Algorithm-%EA%B3%B5%ED%86%B5-%EC%9B%90%EC%86%8C-%EA%B5%AC%ED%95%98%EA%B8%B0-Two-Pointers-Algorithm</link>
            <guid>https://velog.io/@_seeul/Algorithm-%EA%B3%B5%ED%86%B5-%EC%9B%90%EC%86%8C-%EA%B5%AC%ED%95%98%EA%B8%B0-Two-Pointers-Algorithm</guid>
            <pubDate>Fri, 01 Oct 2021 09:38:52 GMT</pubDate>
            <description><![CDATA[<p>10 / 1</p>
<h1 id="📚-문제">📚 문제</h1>
<hr>
<blockquote>
<p>*<em>공통 원소 구하기 *</em><br />
A, B 두 개의 집합이 주어지면 두 집합의 공통 원소를 추출하여 오름차순으로 출력하는 프로그램을 작성하세요</p>
</blockquote>
<blockquote>
<p>스스로 해결 여부 
⭕️ 👏🏻</p>
</blockquote>
<h1 id="🔍-문제-접근">🔍 문제 접근</h1>
<hr>
<ol>
<li>두 집합을 오름차순으로 정렬한다.</li>
<li>각 집합의 인덱스를 가리킬 포인터 두개를 만든다.</li>
<li>반복하면서 어떤 조건을 만족했을때 포인터를 이동시켜서 result값을 구한다.</li>
</ol>
<blockquote>
<p>어제 한 회사의 알고리즘 면접을 보면서 이중 for문을 사용하는 것보다 <code>two pointers</code> 알고리즘을 이용하는 것이 시간복잡도가 더 낮다는 설명을 들었다. 그도 그럴것이 <code>이중 for문</code>은 두 배열의 모든 경우의 수를 계산하게 된다. 하지만 두개의 포인터를 사용하여 어떤 조건을 만족했을 때 어떤 것을 취하고 포인터를 이동시키면 굳이 모든 경우의 수를 따질 필요가 없다. <code>이중 for문</code>을 사용한다면 <code>n^2</code>의 경우의 수를 계산한다면 <code>two pointer</code>는 <code>n * 2</code>의 경우의 수만 계산하기 때문! (맞나..?)</p>
</blockquote>
<h1 id="👩🏻💻-코드">👩🏻‍💻 코드</h1>
<hr>
<pre><code class="language-javascript">const getCommonElement = (arr1, arr2) =&gt; {
  const sortedArr1 = arr1.sort((a, b) =&gt; a - b)
  const sortedArr2 = arr2.sort((a, b) =&gt; a - b)

  let result = []
  let p1 = 0
  let p2 = 0
  while (p1 &lt; arr1.length &amp;&amp; p2 &lt; arr2.length) {
    if (sortedArr1[p1] === sortedArr2[p2]) {
      result.push(sortedArr1[p1])
      p1++
    } else if (sortedArr1[p1] &lt; sortedArr2[p2]) {
      p1++
    } else if (sortedArr1[p1] &gt; sortedArr2[p2]) {
      p2++
    }
  }
  return result
}

getCommonElement([1, 3, 9, 5, 2], [3, 2, 5, 7, 8])
// [ 2, 3, 5 ]
getCommonElement([1, 3, 11, 5, 2, 13, 39, 23], [3, 11, 5, 9, 8, 23, 39, 2])
// [ 2, 3, 5, 11, 23, 39 ]</code></pre>
<h1 id="🕵🏻♀️-문제-풀이">🕵🏻‍♀️ 문제 풀이</h1>
<hr>
<ol>
<li>먼저 인자로 들어온 두 배열을 <code>sort</code>메서드를 통해 오름차순으로 정렬한다.</li>
<li>결과를 담을 빈 배열 result를 만들어준다.</li>
<li>각 배열의 인덱스를 담당할 <code>pointer</code>두개를 만들어준다. 0부터 시작한다.</li>
<li><code>p1</code> 포인터가 <code>arr1</code>의 배열의 길이보다 작을때, 또 <code>p2</code> 포인터가 <code>arr2</code>의 배열의 길이보다 작을때 둘다를 만족시킬때까지 반복해준다.(두 포인터를 모두 돌때까지)</li>
<li>만약 정렬한 <code>arr1</code>의 배열의 <code>p1</code>의 값이 <code>arr2</code>의 배열의 <code>p2</code>값과 같다면 result에 둘중의 하나 값을 담는다.(둘다 어차피 같은 값이니까)</li>
<li>그다음 <code>p1</code>이나 <code>p2</code> 둘중 하나의 값을 <code>1</code>증가시킨다. 
(<em>처음 풀때 이 부분을 처리를 안해줬더니 무한루프가 돌았다. 이 부분을 처리를 안하게 되면 처음 값이 같게 될때 그 값을 담고나서 포인터가 이동하지 않기 때문에 계속 그 자리에 머물면서 result값에 담기만 하기 때문에 무한 루프가 돌았던 것!!</em>)</li>
<li>만약 한쪽의 배열의 값이 다른 배열의 값보다 작게되면 그 작은 값의 포인터를 <code>1</code>증가시킨다. 오름차순으로 되어있기때문에 작을때 증가시켜야 그 다음 커진 원소와 비교가 되기 때문</li>
<li>두개의 포인터가 끝날때까지 이 조건들을 반복한다!</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 두 배열 합치기]]></title>
            <link>https://velog.io/@_seeul/Algorithm-%EB%91%90-%EB%B0%B0%EC%97%B4-%ED%95%A9%EC%B9%98%EA%B8%B0</link>
            <guid>https://velog.io/@_seeul/Algorithm-%EB%91%90-%EB%B0%B0%EC%97%B4-%ED%95%A9%EC%B9%98%EA%B8%B0</guid>
            <pubDate>Wed, 29 Sep 2021 09:40:07 GMT</pubDate>
            <description><![CDATA[<p>9 / 29</p>
<h1 id="📚-문제">📚 문제</h1>
<hr>
<blockquote>
<p>*<em>두 배열 합치기 *</em><br>
오름차순으로 정렬이 된 두 배열이 주어지면 두 배열을 오름차순으로 합쳐 출력하는 프로그램을 작성하세요. 첫번째 줄에 첫번째 배열의 크기 n이 주어진다. 두번째 줄에 n개의 배열 원소가 오름차순으로 주어진다. 세번째 줄에 두번째 배열의 크기 m이 주어진다.
네 번째 줄에 M개의 배열 원소가 오름차순으로 주어진다. 각 리스트의 원소는 int형 변수의 크기를 넘지 않는다.<br/>
sort를 사용하게 되면 시간 복잡도가 n log n이 된다 . 따라서 sort를 사용하지 않고 풀어보자</p>
</blockquote>
<blockquote>
<p>스스로 해결 여부
❌</p>
</blockquote>
<h1 id="🔍-문제-접근">🔍 문제 접근</h1>
<hr>
<p>한시간 정도 혼자 풀다가 잘못풀었다는것을 알고 강의를 보고 다시 풀었다 😅</p>
<blockquote>
<ul>
<li>처음 내가 접근했던 방법</li>
</ul>
</blockquote>
<ol>
<li>1씩 증가하는 <code>i</code>를 통해 반복문을 만든다. <code>i</code>는 두 배열중 길이가 작은 배열의 길이만큼 값이 증가한다.</li>
<li>각각 두 배열의 <code>i</code>번째를 비교해서 만약 <code>arr1[i]</code>값이 <code>arr2[i]</code>보다 작거나 같으면 빈 배열에 <code>arr1[i]</code>를 먼저 넣고, <code>arr2[i]</code>값을 그 뒤에 넣는다. 그 반대의 경우라면 <code>arr2[i]</code>의 값을 먼저 넣고, <code>arr1[i]</code>을 넣는다.</li>
<li>그 다음 길이가 긴 배열의 남은 요소드을 그 뒤에 붙여준다.</li>
<li>이것을 n &lt; m 일때의 경우와, n &gt; m 일때의 경우로 나누어서 작업해줌.</li>
<li>될 것같았으나 완전 잘못 접근함.. 밑에 코드를 보면 알 수 있다.</li>
</ol>
<pre><code class="language-javascript">const getOneArray = (n, arr1, m, arr2) =&gt; {
  let result = []
  // n이 m보다 작을때
  if (n &lt;= m) {
    for (let i = 0; i &lt; n; i++) {
      if (arr1[i] &lt;= arr2[i]) {
        result.push(arr1[i])
        result.push(arr2[i])
      } else {
        result.push(arr2[i])
        result.push(arr1[i])
      }
    }
    for (let j = n; j &lt; m; j++) {
      result.push(arr2[j])
    }
    return result
    // m이 n보다 작을때
  } else {
    for (let i = 0; i &lt; m; i++) {
      if (arr1[i] &lt;= arr2[i]) {
        result.push(arr1[i])
        result.push(arr2[i])
      } else {
        result.push(arr2[i])
        result.push(arr1[i])
      }
    }
    for (let j = m; j &lt; n; j++) {
      result.push(arr1[j])
    }
    return result
  }
}

console.log(getOneArray(3, [1, 3, 5], 5, [2, 3, 6, 7, 9]))
// [ 1, 2, 3, 3, 5, 6, 7, 9 ]
console.log(getOneArray(4, [1, 3, 5, 10], 5, [2, 3, 6, 7, 9]))
// [ 1, 2, 3, 3, 5, 6, 7, 10, 9 ] &lt;= 이 테스트에서 오류가 나는것을 볼 수 있다.
console.log(getOneArray(5, [2, 3, 6, 7, 9], 3, [1, 3, 5]))
// [ 1, 2, 3, 3, 5, 6, 7, 9 ]</code></pre>
<h1 id="👩🏻💻-코드">👩🏻‍💻 코드</h1>
<hr>
<blockquote>
<ul>
<li>강의를 보고 다시 푼 방법</li>
</ul>
</blockquote>
<ol>
<li><code>two pointers</code>라는 알고리즘으로 각 배열의 포인터를 정해주고(포인터는 인덱스를 의미하는 숫자가 됨) 각각의 포인터가 어떤 조건을 만족시킬때마다 증가시킨다.</li>
<li>이번 문제에서는 <code>p1</code>, <code>p2</code> 변수를 두어서 각 배열의 포인터를 각각 분리해준다. 0부터 시작한다.</li>
<li>이 포인터는 배열의 길이보다 작다. 두 배열의 길이가 다르기 때문에 조건을 나누어줄것이다.</li>
<li>각 포인터가 두 배열의 크기보다 작을때를 둘다 만족할 때의 경우 만약 <code>arr1[p1]</code>이 <code>arr[p2]</code>보다 작으면 result에 <code>arr1[p1]</code>을 넣어주고 포인터에 1을 증가시킨다. 왜냐면 그래야 다음 포인터가 가리키는 값이랑 비교를 할 수 있기 때문!!</li>
<li>이렇게 비교를 하면서 작은 값을 result에 넣어주고, 어떤 포인터의 값이 끝나면 조건을 만족시키지 않을 것이다. 그럼 남은 배열의 값들을 그대로 넣어주어야 하기 때문에 밑에 조건을 추가해준다.</li>
<li>그리고 result값을 리턴해주면 끝!</li>
<li>배열에서 인덱스 값에 접근할때 그 안의 변수를 넣은뒤 증가 시키는 방법을 새롭게 알게되었다.</li>
</ol>
<pre><code class="language-javascript">const getOneArray = (n, arr1, m, arr2) =&gt; {
  let result = []
  let p1 = 0
  let p2 = 0
  while (p1 &lt; n &amp;&amp; p2 &lt; m) {
    if (arr1[p1] &lt;= arr2[p2]) {
      result.push(arr1[p1++])
    } else {
      result.push(arr2[p2++])
    }
  }
  while (p1 &lt; n) {
    result.push(arr1[p1++])
  }
  while (p2 &lt; m) {
    result.push(arr2[p2++])
  }
  return result
}

console.log(getOneArray(3, [1, 3, 5], 5, [2, 3, 6, 7, 9])) 
// [ 1, 2, 3, 3, 5, 6, 7, 9 ]
console.log(getOneArray(4, [1, 3, 5,10], 5, [2, 3, 6, 7, 9]))
// [ 1, 2, 3, 3, 5, 6, 7, 9, 10 ]
console.log(getOneArray(5, [2, 3, 6, 7, 9],3, [1, 3, 5] ))
// [ 1, 2, 3, 3, 5, 6, 7, 9 ]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React | React의 state가 불변성을 가져야하는 이유]]></title>
            <link>https://velog.io/@_seeul/React-React%EC%9D%98-state%EA%B0%80-%EB%B6%88%EB%B3%80%EC%84%B1%EC%9D%84-%EA%B0%80%EC%A0%B8%EC%95%BC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@_seeul/React-React%EC%9D%98-state%EA%B0%80-%EB%B6%88%EB%B3%80%EC%84%B1%EC%9D%84-%EA%B0%80%EC%A0%B8%EC%95%BC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Fri, 24 Sep 2021 11:46:35 GMT</pubDate>
            <description><![CDATA[<h1 id="spread-operator를-사용하여-setstate하기">spread operator를 사용하여 setState하기</h1>
<p>리액트에서 state값이 객체인 경우 setState를 통해 상태값을 업데이트 시킬때, spread operator를 사용해서 기존의 state값은 유지시키고 그것을 복사해서 업데이트한 값으로 상태를 바꿔준다. 이는 리액트에서 불변성을 지켜야 하는 이유와 관련이 깊다. </p>
<pre><code class="language-jsx">const onChange = (e) =&gt; {
    const { name, value } = e.target

    setInputs({
      ...inputs,            // 이 부분 
      [name]: value,        
    })
  }</code></pre>
<h1 id="불변성이란">불변성이란</h1>
<p>불변성은 어떤 값을 직접적으로 변경하지 않고 새로운 값을 만들어내는 것이다. </p>
<p>코어자바스크립트 1장 데이터타입에서 살펴보았듯이 원시 타입은 괜찮지만 객체 타입의 불변성을 지키는 것은 고려해야 할 부분이 있다. </p>
<p>코어자바스크립트 1장을 참고하면, 만약 원시타입이 아닌 객체타입의 데이터를 어떠한 변수에 할당하고 그 변수를 다른 변수에 다시 할당했다면, <strong>배열의 복사가 이루어지는 것이 아니라 같은 참조값을 갖게 된다. 그래서 만약 사본을 수정하면 원본도 함께 수정이 되어버린다.</strong> </p>
<p>React로 넘어와보자. </p>
<p>React가 화면을 업데이트하는 과정은 다음과 같다. </p>
<blockquote>
<ol>
<li><code>setState</code> 호출 (혹은 부모로부터 props를 전달 받는다.)</li>
<li><code>shouldComponentUpdate</code>를 실행했는데 <code>fasle</code>를 리턴하면 여기서 멈추고, <code>true</code>를 리턴하면 다음 단계로 이동.</li>
<li>가상 DOM과 실제 DOM을 비교해서 변경사항이 있으면 화면을 다시 그린다. </li>
</ol>
</blockquote>
<blockquote>
<p>여기서 <code>shouldComponentUpdate</code>는? <br/></p>
</blockquote>
<ul>
<li>각각의 컴포넌트들은 <code>shouldComponentUpdate</code>라는 메소드를 가지고 있고 이것은 <code>state</code>가 변경되거나 부모 컴포넌트로부터 새로운 <code>props</code>를 전달받을 때 실행됩니다. React는 이 메소드(<code>shouldComponentUpdate</code>)의 반환 값에 따라서 re-render를 할지에 대한 여부를 결정하게 됩니다.</li>
<li>기본적으로 <code>shouldComponentUpdate</code> 메소드는 <code>true</code>를 반환합니다. 하지만 React 개발자는 re-render를 원하지 않는 경우에, 이 return value를 <code>false</code>로 오버라이드 할 수 있습니다.</li>
</ul>
<p>특정 컴포넌트가 업데이트를 할 필요가 없다는 것을 어떻게 판단할 수 있을까? 가장 간단한 방법은 컴포넌트가 갖고 있는 데이터(props, state)의 이전 이후 값을 완전히 비교하는 것이다. </p>
<p><strong>불변성이 지켜지지 않으면 객체 내부의 값이 새로워져도 바뀐것을 감지하지 못한다</strong>. </p>
<h1 id="spread-operator의-한계">spread operator의 한계</h1>
<p>추가로 전개 연산자(spread operator)을 사용하여 객체나 배열 내부의 값을 복사할 때는 <strong>얕은 복사</strong>를 하게 된다. 즉 <strong>내부의 값이 완전히 새로 복사되는 것이 아니라 가장 바깥쪽에 있는 값만 복사</strong>된다. 따라서 내부의 값이 객체 혹인 배열이라면 내부의 값 또한 따로 복사해 주어야 한다. </p>
<p>배열 혹은 객체의 구조가 정말 복잡해진다면 이렇게 불변성을 유지하면서 업데이트 하는 것도 까다로워진다. 이렇게 복잡한 상황인 경우 <strong><code>immer</code></strong>라는 라이브러리의 사용으로 편하게 작업이 가능하다. </p>
<p>즉 다음과 같은 이유로, 우리가 state를 바꾸고 돔을 다시 만들려면, 새로운 객체나 배열을 만들어 새로운 참조값을 만들고 react에게 이 값은 이전과 다른 참조값임을 알려야 한다. </p>
<p>따라서 기존의 state값은 변하지 않도록 불변하게 만들고 새롭게 복사한 객체로 업데이트를 시켜 이전과 다른 값임을 알려야 한다. </p>
<p>이렇게 state값을 포함한 변수도 불변성을 갖게 해야 다른 버그나 예외사항이 일어나지 않는다. </p>
<h1 id="immutable-variable을-만드는-방법">immutable variable을 만드는 방법</h1>
<p>React에서 <code>immutable variable</code>을 만드는 여러가지 방법이 있다. </p>
<ol>
<li>자바스크립트 표준 함수 ES6 Object.assign() 또는 object-rest-spread</li>
<li>자바스크립트 라이브러리 immutable-js </li>
<li>react공식 문서에서 추천하는 패키지인 immutability-helper</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[CS | polyfill, transpiler]]></title>
            <link>https://velog.io/@_seeul/CS-polyfill-transpiler</link>
            <guid>https://velog.io/@_seeul/CS-polyfill-transpiler</guid>
            <pubDate>Thu, 23 Sep 2021 08:49:42 GMT</pubDate>
            <description><![CDATA[<h1 id="1-polyfill">1. polyfill</h1>
<hr>
<p>JS는 각 버전별로 문법과 동작이 매우 급변하는데, 브라우저 개발사가 항상 이에 맞게 최신 버전으로 업데이트를 하지만 소수의 사용자만이 제때 업데이트를 한다. 또한 각 브라우저들 마다 약간씩 API의 지원 범위가 차이가 나는데 이 모든 걸 개발자들이 신경 쓰기 어려운 것이 현실이다.</p>
<p>이를 위해 <code>polyfill</code>이 생겼는데, <code>polyfill</code>은 모던 브라우저에서만 지원하던 API들을 이전 버전의 브라우저에서도 동작하게끔 도와준다 !</p>
<p>아래의 예를 보고 이해해보자.</p>
<pre><code class="language-jsx">&#39;use strict&#39;

/* http://www.ecma-international.org/ecma-262/6.0/#sec-number.isnan */

module.exports = function isNaN(value) {
    return value !== value;
};</code></pre>
<p>is-nan <code>es-shim</code>에서 가져온 코드이다.</p>
<p>(참고로 <code>es-shim</code>은 크로스 브라우징에 대응하기 위한 라이브러리이다.)</p>
<p><code>polyfill</code>을 사용하면 isNAN을 지원하지 않더라도, 미리 구현된 코드를 통해 모던 브라우저와 같은 결과를 낼 수 있게 도와준다!</p>
<p>여기서 의문이 하나든다. 이렇게 하위 호환성을 위한 코드가 늘어나면 코드의 전체 크기가 커져 로딩이 오래 걸리지 않을까? </p>
<p>정답은 맞다.</p>
<p>실제로 로딩 시간은 길어진다. 하지만 속도를 제외하고 생산성과 유지보수의 측면에서 바라본다면 손해보단 이득이 크다. </p>
<p>그렇다면 <code>polyfill</code>코드의 크기를 줄여보는 것은 어떨까? <a href="https://medium.com/hackernoon/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423">이 글</a>에서는 코드를 빌드하는 시점에서 코드를 분석해서 사용할 코드에 대해서만 <code>polyfill</code>을 추가했다고 한다. 하지만 이러한 노력에도 불구하고 매우 적은 용량이 감소했고 이미 <code>polyfill</code>의 최적화 방법들이 훌륭하다고 말한다. </p>
<p>마지막으로 모든 코드가 <code>polyfill</code>이 가능하거나 동일한 결과를 보장할 수 없을 수도 있다고 한다. 따라서 개발자들은 사용하려는 함수가 어떻게 구현됐는지 가능하면 알아야 한다.</p>
<p>크로스 브라우징을 위한 <code>es-shim</code> 링크이다. </p>
<ul>
<li><a href="https://github.com/es-shims/es6-shim">ES6</a></li>
<li><a href="https://github.com/es-shims/es5-shim">ES5</a></li>
</ul>
<h1 id="2-transpiler">2. transpiler</h1>
<hr>
<p>class, const, let 등 API와 관련 없이 아예 새로운 문법을 사용하고 싶을 때는 어떻게 해야 할까? 이러한 상황에서 사용해야 하는 것이 바로 <code>transplier</code>이다. </p>
<p>transform + compiler를 합친 단어로 새로운 문법이 사용된 코드를 이전 문법으로 변환해주는 작업을 담당한다. </p>
<pre><code class="language-jsx">class Person {

  constructor(name) {
    this.name = name
  }

  showName() {
    console.log(name)
  }
}

const msLee = new Person(&#39;Daseul Lee&#39;)
msLee.showName()</code></pre>
<p>위 class 키워드는 es6에서 지원하는 문법이다. 이를 대표적인 <code>transpiler</code>인 <code>babel</code>로 가장 흔하게 변환하는 es6 ⇒ es5로 변환해본다면 아래와 같이 변경된다. </p>
<pre><code class="language-jsx">&quot;use strict&quot;;

function _instanceof(left, right) { if (right != null &amp;&amp; typeof Symbol !== &quot;undefined&quot; &amp;&amp; right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError(&quot;Cannot call a class as a function&quot;); } }

function _defineProperties(target, props) { for (var i = 0; i &lt; props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (&quot;value&quot; in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var Person =
/*#__PURE__*/
function () {
  function Person(name) {
    _classCallCheck(this, Person);

    this.name = name;
  }

  _createClass(Person, [{
    key: &quot;showName&quot;,
    value: function showName() {
      console.log(name);
    }
  }]);

  return Person;
}();

var msLee = new Person(&#39;Daseul Lee&#39;);
msLee.showName();</code></pre>
<p>(굉장히 복잡해 보인다. 변환 코드는 우리가 다 이해할 필요는 없다^^.. 아마도?)</p>
<h1 id="3-polyfill과-transpiler의-차이">3. polyfill과 transpiler의 차이</h1>
<hr>
<p><code>polyfill</code>과 <code>transpiler</code>는 비슷하면서 다르다. 둘 다 최신 기능을 구 버전의 실행환경에서 동작 가능하게 바꿔준다는 점이다. 하지만 <code>polyfill</code>은 오롯이 API에서만 구 버전 지원을 도와주고 <code>transpiler</code>는 신규 문법을 구 버전으로 바꿔주는 역할을 한다. </p>
<h3 id="📚-reference">📚 reference</h3>
<p><a href="https://wangchunsik.tistory.com/12">https://wangchunsik.tistory.com/12</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | k번째 큰 수]]></title>
            <link>https://velog.io/@_seeul/Algorithm-k%EB%B2%88%EC%A7%B8-%ED%81%B0-%EC%88%98</link>
            <guid>https://velog.io/@_seeul/Algorithm-k%EB%B2%88%EC%A7%B8-%ED%81%B0-%EC%88%98</guid>
            <pubDate>Mon, 20 Sep 2021 10:43:00 GMT</pubDate>
            <description><![CDATA[<p>9 / 20</p>
<h1 id="📚-문제">📚 문제</h1>
<hr>
<blockquote>
<p><strong>k번째 큰 수</strong> <br/>
현수는 1부터 100사이의 자연수가 적힌 N장의 카드를 가지고 있습니다. 같은 숫자의 카드가 여러장 있을 수 있습니다. 현수는 이 중 3장을 뽑아 각 카드에 적힌 수를 합한 값을 기록하려고 합니다. 3장을 뽑을 수 있는 모든 경우를 기록합니다. 기록한 값 중 K번째로 큰 수를 출력하는 프로그램을 작성하세요. 만약 큰 수부터 만들어진 수가 25 23 24 24 22 20 19 ...이고 K값이 3이라면 K번쨰 큰 값은 22입니다.
첫 줄에 자연수 N과 K가 입력되고, 그 다음 주에 N개의 카드값이 입력된다.
첫 줄에 K번째 수를 출력합니다. K번쨰 수가 존재하지 않으면 -1를 출력합니다.</p>
</blockquote>
<blockquote>
<p>스스로 해결 여부 
⭕️ 👏🏻</p>
</blockquote>
<h1 id="🔍-문제-접근">🔍 문제 접근</h1>
<ol>
<li>3장을 뽑아 모든 합을 기록해야 하므로 3중 for문을 이용해 모든 합을 구해 배열에 담는다.</li>
<li>중복된 숫자를 거른다.</li>
<li>그 중 k-1의 인덱스를 구한다.</li>
</ol>
<h1 id="👩🏻💻-코드">👩🏻‍💻 코드</h1>
<pre><code class="language-javascript">const getNumber = (n, k, arr) =&gt; {
  let sum = []
  for (let i = 0; i &lt; arr.length; i++) {
    for (let j = i + 1; j &lt; arr.length; j++) {
      for (let z = j + 1; z &lt; arr.length; z++) {
        sum.push(arr[i] + arr[j] + arr[z])
      }
    }
  }
  sum.sort((a, b) =&gt; b - a)
  const uniqueSum = new Set(sum)
  const uniqueArr = [...uniqueSum]
  return uniqueArr[k - 1]
}

console.log(getNumber(10, 3, [13, 15, 34, 23, 45, 65, 33, 11, 26, 42]))</code></pre>
<h1 id="🕵🏻♀️-문제-풀이">🕵🏻‍♀️ 문제 풀이</h1>
<ol>
<li>빈 <code>sum</code>이라는 배열을 만든다.</li>
<li>인자로 주어진 숫자들 중 3개를 뽑은 모든 경우의 합을 구해야 하기 때문에 삼중 for문을 통해 모든 합을 구한다. 이때, 더해야 하는 index는 서로 중복되면 안되기 때문에 첫번째 for문 i는 0부터 시작하고 그 다음 j는 i+1, z는 j+1로 설정한다.</li>
<li>각 인덱스의 합들을 구해 <code>sum</code>에다 요소를 넣는다.</li>
<li><code>sum</code>을 <code>sort</code>메서드를 통해 내림차순으로 정렬한다.</li>
<li><code>Set</code>이라는 인스턴스를 통해 중복을 제거한다. 제거한 값을 배열로 바꾸어준다.</li>
<li>k번째로 큰 수를 구해야 하기 때문에 새로운 배열의 k-1 번째 값을 리턴한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 졸업 선물]]></title>
            <link>https://velog.io/@_seeul/Algorithm-%EC%A1%B8%EC%97%85-%EC%84%A0%EB%AC%BC</link>
            <guid>https://velog.io/@_seeul/Algorithm-%EC%A1%B8%EC%97%85-%EC%84%A0%EB%AC%BC</guid>
            <pubDate>Sat, 18 Sep 2021 03:45:21 GMT</pubDate>
            <description><![CDATA[<p>9 / 18</p>
<h1 id="📚-문제">📚 문제</h1>
<blockquote>
<p>졸업선물 <br />
선생님은 올해 졸업하는 반 학생들에게 졸업선물을 주려고 합니다. 학생들에게 인터넷 쇼핑몰에서 각자 원하는 상품을 골라 그 상품의 가격과 배송비를 제출하라고 했습니다. 선생님이 가지고 있는 예산은 한정되어 있습니다.
현재 예산으로 최대 몇 명의 학생에게 선물을 사줄 수 있는지 구하는 프로그램을 작성하세요. 선생님은 상품 하나를 50% 할인해서 살 수 있는 쿠폰을 가지고 있습니다. 배송비는 할인에 포함되지 않습니다. <br>
첫번째 인자에 학생수와 예산이 주어진다. 두 번째 인자부터 n줄까지 각 학생들이 받고 싶은 상품의 가격과 배송비가 입력된다. 상품 가격은 짝수로 입력된다.</p>
</blockquote>
<blockquote>
<p>스스로 해결 여부 
⭕️ 👏🏻</p>
</blockquote>
<h1 id="🔍-문제-접근">🔍 문제 접근</h1>
<ol>
<li>학생의 선물 가격과 배송비를 합한 총 가격을 계산한다.</li>
<li>계산 후 각 상품 가격과 배송비가 입력된 배열을 포함한 배열을 for문을 통해 돌면서 sum이라는 변수에 누적을 한다.</li>
<li>예산보다 sum이 작거나 같을때 num에 1씩 더한다.</li>
</ol>
<h1 id="👩🏻💻-코드">👩🏻‍💻 코드</h1>
<pre><code class="language-javascript">const getMaxStudentNumber = (budget, arr) =&gt; {
  let sum = 0
  let num = 0
  let sumArr = []
  for (let j = 0; j &lt; arr.length; j++) {
    sumArr.push(arr[j][0] / 2 + arr[j][1])
  }
  sumArr.sort((a, b) =&gt; a - b)
  console.log(sumArr)
  for (let i = 0; i &lt; sumArr.length; i++) {
    sum += sumArr[i]
    if (sum &lt;= budget) {
      num++
    }
  }
  return num
}
console.log(
  getMaxStudentNumber(28, [
    [6, 6],
    [4, 3],
    [10, 3],
    [4, 5],
    [2, 2],
  ])
) //4</code></pre>
<h1 id="🕵🏻♀️-문제-풀이">🕵🏻‍♀️ 문제 풀이</h1>
<ol>
<li>처음에 문제 접근의 방법으로 푸니 만약 모든 상품 가격과 배송비를 더한 값의 배열의 순서가 달라지면 결과가 달라지는 것을 알았다. (왜냐하면 순서대로 각 배열을 접근하면서 sum의 누적할때마다 num이 1이 증가하는데 만약 합이 큰 숫자가 앞에서 먼저 나와버리면 num의 값이 달라질 수 있기 때문)</li>
<li>그래서 모든 상품 가격과 배송비를 더한 값의 배열을 새로 만든뒤 그 배열을 오름차순으로 정렬했다. 이렇게 되면 작은 수부터 큰 수 순서대로 나오기 때문에 최대한의 num의 값을 구할 수 있기 때문이다.</li>
<li>이 배열을 처음 문제 접근한 방법대로 for문에 누적을 시키고 만약 예산보다 값이 작거나 같을때 num을 1씩 증가시킨다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithm | 멘토링 ]]></title>
            <link>https://velog.io/@_seeul/Algorithm-%EB%A9%98%ED%86%A0%EB%A7%81</link>
            <guid>https://velog.io/@_seeul/Algorithm-%EB%A9%98%ED%86%A0%EB%A7%81</guid>
            <pubDate>Fri, 17 Sep 2021 03:01:05 GMT</pubDate>
            <description><![CDATA[<p>9 / 17</p>
<h1 id="📚-문제">📚 문제</h1>
<blockquote>
<p>멘토링 <br/>
현수네 반 선생님은 반 학생들의 수학점수를 향상시키기 위해 멘토링 시스템을 만들려고 한다. 멘토링은 멘토(도와주는 학생)와 멘티(도움을 받는 학생)가 한 짝이 되어 멘토가 멘티의 수학공부를 도와주는 것이다. 선생님은 M번의 수학테스트 등수를 가지고 멘토와 멘티를 정한다. 만약 A학생이 멘토이고, B학생이 멘티가 되는 짝이 되었다면 A학생은 M번의 수학테스트에서 모두 B학생보다 등수가 앞서야 한다. M번의 수학성적이 주어지면 멘토와 멘티가 되는 찍을 만들 수 있는 경우가 총 몇가지 인지 출력하는 프로그램을 작성하세요.<br>
인자로 수학테스트 결과가 학생 번호로 주어진다. 학생번호가 제일 앞에서부터 1등, 2등, ...n등 순으로 표현된다.</p>
</blockquote>
<blockquote>
<p>스스로 해결 여부 <br />
⭕️ 👏🏻 (두시간에 걸쳐서 간신히 풀었다ㅜㅜ....)</p>
</blockquote>
<h1 id="🔍-문제-접근">🔍 문제 접근</h1>
<ol>
<li>최대한 어렵지 않게 접근하려고 했다. 어렵고 복잡하게 접근할수록 더 코드가 복잡해지기에..
(지금 푼 코드도 사실 복잡한 것 같긴하지만...)</li>
<li>배열이 주어지면 각 숫자는 학생의 이름이다. 그리고 순서는 학생의 등수이다. 다행히 학생이름이 숫자이기에 for문을 통해 접근할 수 있었다. i는 멘토가 될 학생이다. 또 j는 멘티가 될 학생이다.</li>
<li>각각의 역할을 부여했을때, 모든 수학 성적에서 i의 등수가 j의 등수보다 작을때의 경우의 수를 구한다.</li>
</ol>
<h1 id="👩🏻💻-코드">👩🏻‍💻 코드</h1>
<pre><code class="language-javascript">const getMentoringNumberOfCase = (arr) =&gt; {
  let num = 0
  for (let i = 1; i &lt; arr[0].length + 1; i++) {
    for (let j = 1; j &lt; arr[0].length + 1; j++) {
      const arr1 = []
      for (let z = 0; z &lt; arr.length; z++) {
        if (arr[z].indexOf(i) &lt; arr[z].indexOf(j)) {
          arr1.push(true)
        } else {
          arr1.push(false)
        }
      }
      if (arr1.every((el) =&gt; el === true)) {
        num++
      }
    }
  }
  return num
}

console.log(
  getMentoringNumberOfCase([
    [3, 4, 1, 2],
    [4, 3, 2, 1],
    [3, 1, 4, 2],
  ])
) // 3
console.log(
  getMentoringNumberOfCase([
    [1, 3, 2, 4, 5],
    [5, 3, 1, 2, 4],
    [3, 5, 2, 1, 4],
  ])
) // 4</code></pre>
<h1 id="🕵🏻♀️-문제-풀이">🕵🏻‍♀️ 문제 풀이</h1>
<ol>
<li>i와 j를 학생의 이름으로 구분한 후 이중 for문을 통해 각각 멘토일때와 멘티일때를 비교한다.</li>
<li>그 안의 for문을 통해 각 수학성적등수의 경우를 비교한다.</li>
<li>만약 z번째의 수학성적등수중 i의 등수가 j의 등수보다 작으면 (i가 더 시험을 잘보면) arr1이라는 값에 true를 넣고, 만약 그렇지 않으면 false를 넣는다.
(이 과정에서 모든 수학성적등수의 모든 값이 조건을 만족했을때의 경우의 수를 구하기 위해 이것저것 생각해봤는데 달리 방법이 생각나지 않았다..)</li>
<li>따라서 arr1의 모든 요소가 true일때 num에 1씩 더해주고, num의 값을 리턴했다.</li>
<li>여기서 배열의 every라는 메소드를 처음 사용했는데 이 메소드는 배열의 모든 요소가 어떤 조건을 만족하면 true를 반환한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[코어 자바스크립트 | 2. 실행 컨텍스트]]></title>
            <link>https://velog.io/@_seeul/%EC%BD%94%EC%96%B4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-2.-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@_seeul/%EC%BD%94%EC%96%B4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-2.-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 16 Sep 2021 02:25:08 GMT</pubDate>
            <description><![CDATA[<h1 id="1-실행-컨텍스트란">1. 실행 컨텍스트란?</h1>
<hr>
<p>실행 컨텍스트(execution context)는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체로, 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념이다. </p>
<p>자바스크립트는 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고(호이스팅), 외부 환경 정보를 구성하고, this 값을 설정하는 등의 동작을 수행한다. </p>
<p>본격적으로 실행 컨텍스트를 살펴보기전 스택(stack)과 큐(queue)의 개념을 살펴보자.</p>
<blockquote>
<p>스택 ⇒ 출입구가 하나뿐인 깊은 우물 같은 데이터 구조. 선입후출
큐 ⇒ 양쪽이 모두 열려있는 파이프의 데이터 구조. 선입선출</p>
</blockquote>
<p><img src="https://images.velog.io/images/_seeul/post/05ae1b5a-2a85-4066-b110-33870d21fcc2/image.png" alt=""></p>
<p>앞서 실행 컨텍스트를 실행할 코드에 제공할 환경 정보들을 모아놓은 객체라고 했다. 동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하고, 이를 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장한다. 우리가 흔히 실행 컨텍스트를 구성하는 방법은 함수를 실행하는 것뿐이다. 예제를 보자.</p>
<blockquote>
<pre><code class="language-jsx">// -----------------------------  (1)
var a = 1;
function outer(){
    function inner(){
        console.log(a); // undefined
        var a = 3;
    }
    inner(); // ------------------- (2)
    console.log(a); // 1
}
outer(); // --------------------- (3)
console.log(a); // 1</code></pre>
</blockquote>
<pre><code>
1. 자바스크립트 코드를 실행하는 순간 (1) 전역 컨텍스트가 콜 스택에 담긴다. 최상단의 공간은 코드 내부에서 별도의 실행 명령이 없어도 브라우저에서 자동으로 실행하므로 자바스크립트 파일이 열리는 순간 전역 컨텍스트가 활성화된다고 이해하면 된다. 
2. 전역 컨텍스트와 관련된 코드들을 순차로 실행하다가 (3)에서 outer 함수를 호출하면 자바스크립트 엔진은 outer에 대한 환경 정보를 수집해서 outer 실행 컨텍스트를 생성한 후 콜 스택에 담는다. 콜 스택의 맨 위에 outer 실행 컨텍스트가 놓인 상태가 됐으므로 전역 컨텍스트와 관련된 코드의 실행을 일시중단하고 대신 outer 실행 컨텍스트와 관련된 코드, 즉 outer 함수 내부의 코드들을 순차로 실행한다. 
3. 다시 (2)에서 inner 함수의 실행 컨텍스트가 콜 스택의 가장 위에 담기면 outer 컨텍스트와 관련된 코드의 실행을 중단하고 inner 함수 내부의 코드를 순서대로 진행할 것이다. 
4. inner 함수 내부에서 a 변수에 값 3을 할당하고 나면 inner 함수의 실행이 종료되면서 inner 실행 컨텍스트가 콜 스택에서 제거된다. 그러면 아래에 있던 outer 컨텍스트가 콜 스택의 맨 위에 존재하게 되므로 중단했던 (2)의 다음 줄부터 이어서 실행한다. a변수의 값을 출력하고 나면 outer 함수의 실행이 종료되어 outer 실행 컨텍스트가 콜 스택에서 제거되고, 콜 스택에는 전역 컨텍스트만 남아 있게 된다. 그런 다음 실행을 중단했던 (3)의 다음 줄부터 이어서 실행한다. 
5. a변수의 값을 출력하고 나면 전역 공간에 더는 실행할 코드가 남아 있지 않아 전역 컨텍스트도 제거되고, 콜 스택에는 아무것도 남지 않은 상태로 종료된다. 

![](https://images.velog.io/images/_seeul/post/a52cbb7a-815b-49b3-941f-546d38bb10af/image.png)

스택 구조를 잘 생각해보면 한 실행 컨텍스트가 콜 스택의 맨 위에 쌓이는 순간이 곧 현재 실행할 코드에 관여하게 되는 시점임을 알 수 있다! 

어떤 실행 컨텍스트가 활성화될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는 데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장한다. 여기에 담기는 정보들을 다음과 같다.

`VariableEnvironment` : 현재 컨텍스트 내의 식별자에 대한 정보 + 외부 환경 정보. 
선언 시점의 LexicalEnvirionment의 스냅샷으로, 변경 사항은 반영되지 않음
`LexicalEnvironment` : 처음에는 VariableEnvironment와 같지만 변경 사항이 실시간으로 반영됨.
`ThisBinding` : this 식별자가 바라봐야 할 대상 객체.

![](https://images.velog.io/images/_seeul/post/43bbab02-9509-4fb8-87ea-351df9488b60/image.png)

위의 그림은 활성화된 실행 컨텍스트의 수집 정보이다. 

# 2. VariableEnvironment

---

&gt;`VariableEnvrionment`에 담기는 내용은 `LexicalEnvironment`와 같지만 최초 실행 시의 스냅샷을 유지한다는 점이 다르다. 실행 컨텍스트를 생성할 때 `VariableEnvironment`에 정보를 먼저 담은 다음, 이를 그대로 복사해서 `LexicalEnvironment`를 만들고, 이후에는 `LexicalEnvironment`를 주로 활용하게 된다. 

# 3. LexicalEnvironment

---

&gt;`LexicalEnvironment`는 &#39;사전적인&#39;이 어울리는 표현이다. &quot;현재 컨텍스트의 내부에는 a,b,c와 같은 식별자들이 있고 그 외부 정보는 D를 참조하도록 구성돼있다&quot;라는, 컨텍스트를 구성하는 환경 정보들을 사전에서 접하는 느낌으로 모아놓은 것이다. 

## 1) environmentRecord와 호이스팅

environmentRecord에는 현재 컨텍스트와 관련된 코드의 **식별자 정보**들이 저장 !
- 컨텍스트를 구성하는 함수에 지정된 **매개변수 식별자**
- ****선언한 함수가 있을 경우 **그 함수 자체**
- **var로 선언된 변수의 식별자**

⇒ 컨텍스트 내부 전체를 처음부터 끝까지 쭉 훑어나가며 **순서대로** 수집.

변수 정보를 수집하는 과정을 모두 마쳤더라도 아직 코드들은 실행되기 전의 상태. 코드가 실행 전임에도 불구하고 자바스크립트 엔진은 이미 해당 환경에 속한 코드의 변수명들을 모두 알고있다. 

&#39;자바스크립트 엔진은 식별자들을 최상단으로 끌어올려놓은 다음 코드를 실행한다&#39;고 생각해도 문제가 없다!

여기서 호이스팅이라는 개념이 등장

⇒ 호이스팅이란 &#39;끌어올리다&#39;라는 의미로, 변수 정보를 수집하는 과정을 더욱 이해하기 쉬운 방법으로 대체한 가상의 개념이다. 자바스크립트 엔진이 실제로 끌어올리지는 않지만 편의상 끌어올린 것으로 간주하는 것.

### **매개 변수와 변수에 대한 호이스팅**

&gt;```jsx
function a (x) {  // 수집 대상 1 (매개변수)
    console.log(x)  // (1) -- 1 출력(예상)
    var x           // 수집 대상 2 (변수 선언)
    console.log(x)  // (2) -- undefined 출력(예상)
    var x = 2       // 수집 대상 3 (변수 선언)
    console.log(x)  // (3) -- 2 출력(예상)
}
a(1);</code></pre><p>우선 호이스팅이 되지 않았을 때, (1), (2), (3)에서 어떤 값들이 출력될지를 예상해보자.</p>
<p>(1)에는 함수 호출 시 전달한 1이 출력되고,</p>
<p>(2)에는 선언된 변수 x에 할당한 값이 없으므로 undefined가 출력되고</p>
<p>(3)에는 2가 출력될 것 같다.</p>
<p>실제로는 어떤 결과가 나오고 왜 그렇게 되는지 알아보자!</p>
<blockquote>
<pre><code class="language-jsx">function a(){
    var x;         // 수집 대상 1의 매개변수 선언 부분
    var x;         // 수집 대상 2의 변수 선언 부분
    var x;         // 수집 대상 3의 변수 선언 부분
    x = 1          // 수집 대상 1의 할당 부분
    console.log(x) // (1) -- 1 출력
    console.log(x) // (2) -- 1 출력
    x = 2          // 수집 대상 3의 할당 부분
    console.log(x) // (3) -- 2 출력
}
a(1)</code></pre>
</blockquote>
<pre><code>
(1)은 1, (2)는 2, (3)은 2라는 결과가 나온다. (2)에서 undefined가 아닌 1이 출력된다는 건 호이스팅 개념을 이해하고 있어야한다. 

### **함수 선언의 호이스팅**

&gt;```jsx
function a() {
    console.log(b);  // (1) -- undefined 출력(예상)
    var b = &#39;bbb&#39;;   // 수집 대상 1 (변수 선언)
    console.log(b);  // (2) -- &#39;bbb&#39; 출력(예상)
    function b(){};  // 수집 대상 2 (함수 선언)
    console.log(b);  // (3) -- b함수 출력(예상)
}
a();</code></pre><p>출력 결과를 미리 예상해보자. (1)에는 b의 값이 없으니 undefined가 나올 것 같다. (2)는 &#39;bbb&#39;, (3)은 b함수가 출력될 것같다. 실제로도 그럴지 한번 보자!</p>
<blockquote>
<pre><code class="language-jsx">function a(){
    var b           // 수집 대상 1. 변수는 선언부만 끌어올린다. 
    function b(){}  // 수집 대상 2. 함수 선언은 전체를 끌어올린다. 
    console.log(b)  // (1) -- 함수 b 출력
    b = &#39;bbb&#39;       // 변수의 할당부는 원래 자리에 남겨둔다. 
    console.log(b)  // (2) -- &#39;bbb&#39; 출력
    console.log(b)  // (3) -- &#39;bbb&#39; 출력
}
a()</code></pre>
</blockquote>
<pre><code>
해석의 편의를 위해 한 가지 더 바꿔보자. 호이스팅이 끝난 상태에서의 함수 선언문은 함수명으로 선언한 변수에 함수를 할당한 것처럼 여길 수 있다.

&gt;```jsx
function a(){
    var b           // 수집 대상 1. 변수는 선언부만 끌어올린다. 
    var b = function b(){}  // 바뀐 부분!!! 🌟🌟
    console.log(b)  // (1) -- 함수 b 출력
    b = &#39;bbb&#39;       // 변수의 할당부는 원래 자리에 남겨둔다. 
    console.log(b)  // (2) -- &#39;bbb&#39; 출력
    console.log(b)  // (3) -- &#39;bbb&#39; 출력
}
a()</code></pre><h3 id="함수-선언문과-함수-표현식">함수 선언문과 함수 표현식</h3>
<p><strong>둘 다 함수를 새롭게 정의할 때 쓰이는 방식</strong></p>
<ol>
<li><strong>함수 선언문</strong> ⇒ function 정의부만 존재하고 별도의 할당 명령이 없는 것을 의미<ul>
<li>반드시 함수명의 정의되어 있어야 함 <br></li>
</ul>
</li>
<li><strong>함수 표현식</strong> ⇒ 정의한 function을 별도의 변수에 할당하는 것 의미 <ul>
<li>함수명이 정의되어 있지 않아도 됨</li>
<li>함수명을 정의한 함수 표현식 ⇒ &quot;기명 함수 표현식&quot;</li>
<li>함수명을 정의하지 않은 함수 표현식 ⇒ &quot;익명 함수 표현식&quot;</li>
</ul>
</li>
</ol>
<blockquote>
<pre><code class="language-jsx">function a () { ... } // 함수 선언문. 함수명 a가 곧 변수명
a() // 실행 ok
var b = function() { ... } // 익명 함수 표현식. 변수명 b가 곧 함수명
b() // 실행 ok
var c = function d () { ... } // 기명 함수 표현식. 변수명은 c, 함수명은 d
c() // 실행 ok
d() // 에러 !!</code></pre>
</blockquote>
<pre><code>
함수 선언문과 함수 표현식의 실질적인 차이를 살펴보자 !

&gt;```jsx
console.log(sum(1, 2))
console.log(multiply(3, 4));
function sum (a, b) {             // 함수 선언문 sum
    return a + b;
}
var multiply = function (a, b) {  // 함수 표현식 multiply
    return a + b
}</code></pre><p>호이스팅을 마친 최종 상태를 바로 확인해보자</p>
<blockquote>
<pre><code class="language-jsx">var sum = function sum (a, b) {   // 함수 선언문은 전체를 호이스팅한다. 
    return a + b;
}
var multiply                      // 변수는 선언부만 끌어올린다. 
console.log(sum(1, 2))            // 3출력
console.log(multiply(3, 4));      // Error! &#39;multiply is not a function&#39;
multiply = function (a, b) {      // 변수의 할당부는 원래 자리에 남겨 놓는다.
    return a + b
}</code></pre>
</blockquote>
<pre><code>
sum함수는 선언 전에 호출해도 아무 문제없이 실행된다. 어떻게 작성해도 오류를 내지 않는다는 면에서 초급자들이 자바스크립트를 좀 더 쉽게 접근할 수 있게 해주는 측면도 있지만, 반대로 큰 혼란을 일으키는 원인이 되긴도 한다. 

함수 선언문보다는 함수 표현식이 어떻게 보면 더 안전하다고 생각하면 된다. 

## 2) 스코프, 스코프 체인, outerEnvironmentReference

**스코프란 식별자에 대한 유효범위이다**. 어떤 경계 A의 외부에서 선언한 변수는 A의 외부뿐 아니라 A의 내부에서도 접근이 가능하지만, A의 내부에서 선언한 변수는 오직 A의 내부에서만 접근할 수 있다. 

자바스크립트는 특이하게도 ES5까지는 전역공간을 제외하면 오직 함수에 의해서만 스코프가 생성된다. 이러한 **&#39;식별자의 유효범위&#39;를 안에서부터 바깥으로 차례로 검색해나가는 것을 스코프 체인**이라고 한다. 그리고 이를 가능케 하는 것이 바로 `LexicalEnvironment`의 두 번째 수집 자료인 `outerEnvironmentReference`이다. 

### 스코프 체인

`outerEnvironmentReference`는 현재 호출된 함수가 선언될 당시의 `LexicalEnvironment`를 참조한다. 과거 시점인 &#39;선언될 당시&#39;에 주목하자. &#39;선언하다&#39;라는 행위가 실제로 일어날 수 있는 시점이란 콜 스택 상에서 어떤 실행 컨텍스트가 활성화된 상태일 때뿐이다. 어떤 함수를 선언(정의)하는 행위 자체도 하나의 코드에 지나지 않으며, 모든 코드는 실행 컨텍스트가 활성화 상태일 때 실행되기 때문이다. 

예를들어 A함수 내부에 B함수를 선언하고, 다시 B함수 내부에 C함수를 선언했다고 가정하자!

함수 C의 `outerEnvironmentReference`는 함수 B의 `LexicalEnvironment`를 참조한다.
⇒ 함수 B의 `LexicalEnvironment` 에 있는 `outerEnvironmentReference`는 다시 함수 B가 선언되던 때 A의 `LexicalEnvironment`를 참조할것이다. 
⇒ 이처럼 `outerEnvironmentReference` 는 연결리스트 형태를 띈다.
⇒ &#39;선언 시점의`LexicalEnvironment`&#39;를 계속 찾아 올라가면 마지막엔 전역 컨텍스트의 `LexicalEnvironment`가 있을 것이다.  
⇒ 또한 각 `outerEnvironmentReference` 는 오직 자신이 선언된 시점의 `LexicalEnvironment` 만 참조하고 있으므로 가장 가까운 요소부터 차례대로만 접근할 수 있고 다른 순서로 접근하는 것은 불가능할 것이다. 
⇒ 이런 구조적 특성 덕분에 여러 스코프에서 동일한 식별자를 선언한 경우에는 무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근 가능하게 된다. 

![](https://images.velog.io/images/_seeul/post/e90aa798-e90b-4376-a5d4-4e273dc3ea97/image.png)

&gt;```jsx
var a = 1                     
var outer = function () {     
    var inner = function () {   
        console.log(a)            
        var a = 3                 
    }
    inner()
    console.log(a)
}
outer()
console.log(a)</code></pre><p>다음 코드를 보자 ! </p>
<ol>
<li>전역 컨텍스트 활성화. 전역 컨텍스트의 <code>environmentRecord</code>에 { a, outer } 식별자 저장. 전역 컨텍스트는 선언 시점이 없으므로 <code>outerEnvironmentReference</code>에는 아무것도 담기지 않는다. (this : 전역 객체)</li>
<li>1번째과 2번째 줄 : 전역 스코프에 있는 변수 a에 1을, outer에 함수를 할당.</li>
<li>10번째 줄 : outer함수 호출. 이에 따라 전역 컨텍스트의 코드는 10번째 줄에서 임시중단. outer 실행 컨텍스트가 활성화 되어 2번째 줄로 이동</li>
<li>2번째 줄: outer 실행 컨텍스트의 <code>environmentRecord</code>에 { inner } 식별자 저장. <code>outerEnvironmentReference</code>에는 outer함수가 선언될 당시의 <code>LexicalEnvironment</code>가 담긴다. 
outer 함수는 전역 공간에서 선언됐으므로 전역 컨텍스트의 <code>LexicalEnvironment</code>를 참조복사한다. 이를 [ Global, { a, outer } ]라고 표기하자. 첫 번째는 실행 컨텍스트의 이름, 두 번째는 <code>environmentRecord</code> 객체이다. (this : 전역 객체)</li>
<li>3번째 줄 : outer 스코프에 있는 변수 inner에 함수를 할당.</li>
<li>7번째 줄 : inner 함수 호출. 이에 따라 outer 실행 컨텍스트의 코드는 7번째 줄에서 임시 중단되고, inner 실행 컨텍스트가 활성화되어 3번째줄로 이동.</li>
<li>3번째 줄 : inner 실행 컨텍스트의 <code>environmentRecord</code>에 { a } 식별자 저장. <code>outerEnvironmentReference</code>에는 inner 함수가 선언될 당시의 <code>LexicalEnvironment</code>가 담긴다. inner 함수는 outer 함수 내부에서 선언됐으므로 outer 함수의 <code>LexicalEnvirionment</code>, 즉 [ outer, { inner } ]를 참조복사. (this : 전역객체)</li>
<li>4번째 줄 : 식별자 a에 접근하고자 함. 현재 활성화 상태인 inner 컨텍스트의 <code>environmentRecord</code>에서 a를 검색. a가 발견됐는데 여기에는 아직 할당된 값 없음 (undefined 출력)</li>
<li>5번째 줄 : inner 스코프에 있는 변수 a에 3을 할당.</li>
<li>6번째 줄 : inner 함수 실행 종료. inner 실행 컨텍스트가 콜 스택에서 제거되고, 바로 아래의 outer 실행 컨텍스트가 다시 활성화되면서, 앞서 중단했던 7번째 줄의 다음으로 이동. </li>
<li>8번째 줄 : 식별자 a에 접근하고자 한다. 이때 자바스크립트 엔진은 활성화된 실행 컨텍스트의 <code>LexicalEnvironment</code>에 접근한다. 첫 요소의 <code>environmentRecord</code>에서 a가 있는지 찾아보고, 없으면 <code>outerEnvirionmentReference</code>에 있는 <code>environmentRecord</code>로 넘어가는 식으로 계속해서 검색. 예제에서는 두 번째, 즉 전역 <code>LexicalEnvironment</code>에 a가 있으니 그 a에 저장된 값 1을 반환.</li>
<li>9번째 줄 : outer 함수 실행이 종료. outer 실행 컨텍스트가 콜 스택에서 제거되고, 바로 아래의 전역 컨텍스트가 다시 활성화되면서, 앞서 중단했던 10번째 줄의 다음으로 이동.</li>
<li>11번째 줄 : 식별자 a에 접근하고자 함. 현재 활성화 상태인 전역 컨텍스트의 <code>environmentRecord</code>에서 a를 검색. 바로 a를 찾을 수 있음 (1 출력). 이로써 모든 코드의 실행 완료. 전역 컨텍스트가 콜 스택에서 제거되고 종료.</li>
</ol>
<p><img src="https://images.velog.io/images/_seeul/post/5fbd091d-53b2-4b6d-8f49-b6b6d44b298d/image.png" alt=""></p>
<blockquote>
<p>정리 !
<strong>environmentRecord</strong> 
⇒ 컨텍스트 내부의 식별자 정보.
<strong>outerEnvironmentReference</strong> 
⇒ 외부 Scope의 주소 참조. 현재 호출된 함수가 선언될 당시의 LexicalEnvironment참조.
<strong>스코프</strong> 
⇒ 식별자에 대한 유효범위.
<strong>스코프 체인</strong> 
⇒ &#39;식별자의 유효범위&#39;를 안에서부터 바깥으로 차례로 검색해 나가는 것. 이를 가능하게 하는 것이 outerEnvironmentReference. </p>
</blockquote>
<h1 id="4-this">4. this</h1>
<hr>
<p>실행 컨텍스트의 thisBinding에는 this로 지정된 객체가 저장된다. 실행 컨텍스트 활성화 당시에this가 지정되지 않은 경우 this에는 전역 객체가 저장된다. </p>
<p>그 밖에는 함수를 호출하는 방법에 따라 this에 저장되는 대상이 다르다. </p>
<h1 id="5-마지막-정리">5. 마지막 정리</h1>
<hr>
<blockquote>
<p><strong>1. 실행 컨텍스트</strong> 
⇒ 실행할 코드에 제공할 환경 정보들을 모아놓은 객체. 실행 컨텍스트의 객체는 활성화 되는 시점에 VariableEnvironment, LexicalEnvironment, ThisBinding의 세 가지 정보를 수집.
⇒ 실행 컨텍스트를 생성할 때는 VariableEnvironment와 LexicalEnvironment가 동일한 내용으로 구성되지만 LexicalEnvironment는 함수 실행 도중에 변경되는 사항이 즉시 반영되는 반면 VariableEnvironment는 초기 상태를 유지.
⇒ VariableEnvironment와 LexicalEnvironment는 매개변수명, 변수의 식별자, 선언한 함수의 함수명 등을 수집하는 environmentRecord와 바로 직전 컨텍스트의 LexicalEnvironment 정보를 참조하는 outerEnvironmentReference로 구성.
<br />
<strong>2. 호이스팅</strong>
⇒ 코드 해석을 좀 더 수월하게 하기 위해 environmentRecord의 수집 과정을 추상화한 개념으로, 실행 컨텍스트가 관여하는 코드 집단의 최상단으로 이들을 &#39;끌어올린다&#39;고 해석하는 것. 
⇒ 변수 선언과 값 할당이 동시에 이뤄진 문장은 &#39;선언부&#39;만을 호이스팅 하고, 할당 과정은 원래 자리에 남아있게 되는데, 여기에서 함수 선언문과 함수 표현식의 차잉가 발생.
<br />
<strong>3. 스코프</strong>
⇒ 스코프는 변수의 유효범위를 뜻함.
⇒ outerEnvironmentReference는 해당 함수가 선언된 위치의 LexicalEnvironment를 참조. 코드 상에서 어떤 변수에 접근하려고 하면 현재 컨텍스트의 LexicalEnvironment를 탐색해서 발견되면 그 값을 반환하고, 발견하지 못할 경우 다시 outerEnvironmentReference에 담긴 LexicalEnvironment를 탐색하는 과정을 거친다. 전역 컨텍스트의 LexicalEnvironment까지 탐색해도 해당 변수를 찾지 못하면 undefined를 반환.
<br />
<strong>4. 전역변수와 지역변수</strong> 
⇒ 전역 컨텍스트의 LexicalEnvironment에 담긴 변수를 전역변수라 하고, 그 밖의 함수에 의해 생성된 실행 컨텍스트의 변수들은 모두 지역변수. 안전한 코드 구성을 위해 가급적 전역변수의 사용은 최소화 하는 것이 좋음
<br />
<strong>5. this</strong>
⇒ 실행 컨텍스트를 활성화하는 당시에 지정된 this가 지정. 함수를 호출하는 방법에 따라 그 값이 달라지는데, 지정되지 않은 경우에는 전역 객체가 저장.</p>
</blockquote>
<h3 id="📚-reference">📚 Reference</h3>
<ul>
<li>코어 자바스크립트</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>