<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Minsoftk</title>
    <link>https://minsoftk.tistory.com/</link>
    <description>개발자가 되기 위한 험한 길</description>
    <language>ko</language>
    <pubDate>Mon, 6 Jul 2026 04:24:08 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>MinsoftK</managingEditor>
    <image>
      <title>Minsoftk</title>
      <url>https://tistory1.daumcdn.net/tistory/3998262/attach/3bead0dc9a79468ba72867d7ddb5643a</url>
      <link>https://minsoftk.tistory.com</link>
    </image>
    <item>
      <title>[git] VSCode에서 vi모드 해제(pager, vim, log)</title>
      <link>https://minsoftk.tistory.com/91</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.&amp;nbsp; VScode에서 commit시 vi모드 해제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- `git commit` 명령어를 실행 시, 터미널에서 vi 모드로 열리는게 불편했다. 이를 VSCode에서 수정하도록 config 설정을 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1660019573544&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# PATH 등록이 되었는지 확인
code --verison

# 안되어있을 경우, MAC에선  Command + Shift + P
# Shell을 입력 후, Shell Command: Install 'code' command in PATH를 선택

# editor 변경
git config --global core.editor &quot;code --wait&quot;

# 정상등록 되었는지 확인
git config --global -e&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. git log default Pager 설정(vi 모드 해제)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- `git log` 명령어 작성 시, default로 vi 모드로 실행된다. cat처럼 바로 스크롤하면서 볼 수 있도록 아래의 명령어를 작성해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1660019720169&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global core.pager cat&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Alias 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- git 명령어 간소화&lt;/p&gt;
&lt;pre id=&quot;code_1660019493391&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git config --global alias.co checkout                                                                                        ✔  8s   12:47:40  

git config --global alias.br branch                                                                                                 ✔  12:50:39  

git config --global alias.st status                                                                                                 ✔  12:50:52  

git config --global alias.cm commit&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;</description>
      <category>TIL(Today I Learn)/Git</category>
      <category>git vi</category>
      <category>vscode</category>
      <category>vscode commit vi</category>
      <category>vscode commit 터미널</category>
      <category>vscode git alias</category>
      <category>vscode git log 터미널</category>
      <category>vscode log</category>
      <category>vscode pager</category>
      <category>vscode terminal</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/91</guid>
      <comments>https://minsoftk.tistory.com/91#entry91comment</comments>
      <pubDate>Tue, 9 Aug 2022 13:40:07 +0900</pubDate>
    </item>
    <item>
      <title>VScode 줄바꿈이 적용이 되지 않는 오류</title>
      <link>https://minsoftk.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 순간부터 VScode에서 Alt + Z를 사용해 줄 바꿈 하는 기능이 적용이 되지 않았다. 바로가기 키 설정을 막 바꾸다 보니 생기는 오류라고 생각했다. 그러다 점점 줄 바꿈 기능이 먹히지 않아 짜증이 극에 달하기 시작했다. 처음에는 키 바인딩 문제라고 생각해 바로가기 키가 겹치는 게 있는지 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 바로가기 키에 문제가 있지 않다고 판단했다. 문제가 발생했을 시점부터 확장 플러그인을 많이 설치했던 기억이 있어 확장 프로그램을 비활성화 시킨다음에 줄 바꿈 기능이 적용이 되는지 확인해봤다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;F1 key &amp;gt; developer 입력 후 색칠된 메뉴 찾아 클릭 &amp;gt; Alt + z 적용 여부 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekyx13/btrEeYCPxLF/wkcImv9eOPMPHSCTgNwtv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekyx13/btrEeYCPxLF/wkcImv9eOPMPHSCTgNwtv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekyx13/btrEeYCPxLF/wkcImv9eOPMPHSCTgNwtv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fekyx13%2FbtrEeYCPxLF%2FwkcImv9eOPMPHSCTgNwtv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;776&quot; height=&quot;552&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 적용이 된다면 익스텐션에 충돌이 일어나서 문제가 되는 것이라 생각한다. 하지만 그래도 적용이 되지 않는다면 나와 같은 경우일 확률이 높다. 이후, 확장 플러그인 문제는 아니라고 생각해 구글링만 1시간 넘게 했지만, 한국에서는 나와 같은 문제를 겪은 사람이 없는 것 같다. 도저히 찾을 수 없었지만, &lt;a href=&quot;https://github.com/microsoft/vscode/issues/108326&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;VSCode gthub issue&lt;/a&gt;에서 해당 문제를 찾을 수 있었다. 해당 글에서 @alexdima가 editor.accessibilitySupport라는 설정 때문에 문제가 발생할 수도 있다는 의견을 봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbz8pN/btrD8ibAPJ1/6LsxShshbpYRrqILUdcke0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbz8pN/btrD8ibAPJ1/6LsxShshbpYRrqILUdcke0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbz8pN/btrD8ibAPJ1/6LsxShshbpYRrqILUdcke0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbz8pN%2FbtrD8ibAPJ1%2F6LsxShshbpYRrqILUdcke0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1151&quot; height=&quot;484&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 읽고나서 혹시나 해서 나의 setting.json을 찾아봤다. F1 key &amp;gt; settings 입력 후 색칠된 메뉴 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zC6k7/btrEcQsvs6f/zRfX3tAmY53N3hKEbEjL5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zC6k7/btrEcQsvs6f/zRfX3tAmY53N3hKEbEjL5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zC6k7/btrEcQsvs6f/zRfX3tAmY53N3hKEbEjL5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzC6k7%2FbtrEcQsvs6f%2FzRfX3tAmY53N3hKEbEjL5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;472&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것저것 커스터마이징을 하다보니 왜 넣었는지도 모르는 설정들이 많이 들어가 있다.. 불필요하다 생각하는 설정들을 지워나가던 중 editor.accessibilitySupport가 on으로 설정돼있는 것을 확인할 수 있었다. 해당 설정을 주석처리를 해주니 Alt + Z로 줄 바꿈이 정상 동작되는 것을 확인할 수 있었다. 레퍼런스가 없어 굉장히 해결하기 난해해서 글을 작성해보았는데 나와 같은 오류가 있는 사람들에게 도움이 되었으면 좋겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coQfoS/btrEfB1Hw8K/86SMMQtwfJmVBlL5aGbfKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coQfoS/btrEfB1Hw8K/86SMMQtwfJmVBlL5aGbfKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coQfoS/btrEfB1Hw8K/86SMMQtwfJmVBlL5aGbfKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoQfoS%2FbtrEfB1Hw8K%2F86SMMQtwfJmVBlL5aGbfKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;449&quot; height=&quot;174&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주석을 생활화합시다...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Rerference :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/issues/108326&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/microsoft/vscode/issues/108326&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>vscode</category>
      <category>vscode 줄바꿈</category>
      <category>vscode 줄바꿈 오류</category>
      <category>자동줄바꿈</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/90</guid>
      <comments>https://minsoftk.tistory.com/90#entry90comment</comments>
      <pubDate>Wed, 8 Jun 2022 14:59:41 +0900</pubDate>
    </item>
    <item>
      <title>[JS] pushState로 인한 URL 변경 이벤트 감지하기</title>
      <link>https://minsoftk.tistory.com/89</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPA를 JavaScript로 구현하는 프로젝트를 진행하면서 url 변경 이벤트를 감지해야 하는 경우가 발생했다. 일반적으로는 pushState로 URL 변경 이후, router path에 해당하는 컴포넌트를 render 해준다. 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1649864517907&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const navigate = path =&amp;gt; {
  window.history.pushState({}, null, path);
  render(element, routes[path]);
};

const render = (elem, Component) =&amp;gt; {
	elem.innerHTML = Component;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 SPA를 구현하면서 우리는 URL 변경에 초점을 두고 개발을 진행하게 됐다. 즉, URL 변경이 일어나면 URL을 파싱 해 router에 해당하는 path의 컴포넌트를 렌더링 하게 했다. 하지만 Web API에서는 'popstate' 이벤트만을 제공하고 있었다. 왜 pushState, replaceState 이벤트는 존재하지 않는지 잘 모르겠다. 이는 라이브러리를 사용해 쉽게 해결할 수 있었다.&lt;/p&gt;
&lt;figure id=&quot;og_1649865501756&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;history-events&quot; data-og-description=&quot;Adds missing window.history events onpushstate, onreplacestate and onchangestate.. Latest version: 1.0.4, last published: 7 years ago. Start using history-events in your project by running &amp;#96;npm i history-events&amp;#96;. There are 5 other projects in the npm regis&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/history-events&quot; data-og-url=&quot;https://www.npmjs.com/package/history-events&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uj92p/hyN2EfvdSt/mFpqr1PfEipxFuVjOSkyOK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/history-events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/history-events&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uj92p/hyN2EfvdSt/mFpqr1PfEipxFuVjOSkyOK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;history-events&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Adds missing window.history events onpushstate, onreplacestate and onchangestate.. Latest version: 1.0.4, last published: 7 years ago. Start using history-events in your project by running `npm i history-events`. There are 5 other projects in the npm regis&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 라이브러리를 npm을 통해 설치 후, 아래와 같이 사용하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1649865742090&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const history = require('history-events');

window.addEventListener('changestate', ()=&amp;gt;{
 // write you want to do
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다른 방법 구상&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트가 끝난 이후, 라이브러리를 쓰는 방법 말고 다른 방법은 없을까 고민을 해보게 됐다. 다양한 방법들을 찾아보고 실패를 했다. 생각보다 레퍼런스가 없고, 방법들이 어려워 힘들었다. 같은 문제를 겪는 사람들에게 도움이 될까 작성해본다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Mutation Observer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM tree의 변경을 감지하는 이벤트이다. &lt;a href=&quot;https://phpcoder.tech/detect-url-change-in-javascript-without-refresh/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 글&lt;/a&gt;을 보고 시도를 해보게 됐다. DOM tree의 변경을 감지하는 객체였다. 이를 통해서 url 변경이 일어날 때마다 실행을 시키려 했다. 하지만 JS 파일이 실행이 되고, 1회밖에 감지를 하지 못했다. 감지를 지속해서 시키기 위해선 결국 일정한 이벤트 등록이 필요했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;setInterval&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;setInterval을 통해 계속 URL을 감지하는 방법이다. 물론 사용하면 안 된다. 웹 앱에서 계속 URL을 확인하는 방식이라, 규모가 커질수록 성능의 저하가 클 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CustomEvent&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 핸들러를 직접 만들어보는 것도 고민해봤다. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt;을 참고해서 만들어보려 했다. 브라우저의 이벤트를 직접 만드는 방법이라고 생각했지만, 기존의 이벤트를 활용한 커스터마이징 이벤트 핸들러를 만드는 방법이었다. 결국 url 변경을 감지해야 하는데, CustomEvent로는 불가능하다고 생각했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;pushState 이벤트 덮어쓰기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 좋은 방법이었다. 그 이유는 해당 프로젝트에서는 pushState만을 사용해서 url을 변경해줬기 때문에 해당 이벤트를 덮어 씌워서 원하는 동작을 하게 만들었다. &lt;a href=&quot;https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 글&lt;/a&gt;을 참고했다. 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1649866495808&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
        if (typeof history.onpushstate == &quot;function&quot;) {
            history.onpushstate({state: state});
        }
        // ... whatever else you want to do
        // maybe call onhashchange e.handler
        return pushState.apply(history, arguments);
    };
})(window.history);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;history-events 라이브러리도 코드를 완벽하게 이해하기 어렵지만, pushState, replaceState 이벤트가 발생하면 changestate 이벤트를 같이 발생시켜주는 방식으로 보인다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 추가해 pushState 함수를 사용하면 바뀐 URL로 렌더링을 하게 바꿔줬다. 하지만 2번을 클릭해야 렌더링이 정상적으로 되는 것을 확인할 수 있었다. `window.location`은 최신화가 되지 않았기 때문인데 정확한 이유는 알아내지 못했다. pushState는 Location 객체까지 변경을 시키지는 않는다고 이해를 하면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래와 같이 해줬을 때도 오류가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1649868368452&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(function (history) {
  var pushState = history.pushState;
  history.pushState = function (state) {
    if (typeof history.onpushstate == 'function') {
      history.onpushstate({ state: state });
    }
     // ... whatever else you want to do
    // maybe call onhashchange e.handler
	render(App());
    return pushState.apply(history, arguments);
  };
})(window.history);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 해결하기 위해서 pushState 함수를 사용할 때, 첫 번째 인수로 state를 전달할 수 있었다. 이를 통해 새로운 세션의 url 정보를 state를 통해 전달하고, 이를 pushState 함수 내에서 활용하는 방법을 생각했다. 전달된 state를 보고 currentPageUrl의 변수에 할당해 App에 인수로 넘겨줬다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예외처리가 발생해 까다로워지지만, 라이브러리를 사용하지 않아도 동작하게 만들 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649871633400&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// pushState 부분
history.pushState(
        { url: `/detail/${e.target.closest('li').dataset.postId}` },
        '',
        `/detail/${e.target.closest('li').dataset.postId}`
      );
    }
    
// pushState 이벤트 조작
(function (history) {
  var pushState = history.pushState;
  history.pushState = function (state) {
    if (typeof history.onpushstate == 'function') {
      history.onpushstate({ state: state });
    }
     // ... whatever else you want to do
    // maybe call onhashchange e.handler
    currentPageUrl = state?.url; // 옵셔널 체이닝
    if (currentPageUrl) render(App(currentPageUrl));
    return pushState.apply(history, arguments);
  };
})(window.history);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;느낀 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결하고 나니 처음부터 pushState를 할 때, 렌더링을 해주는 게 편했겠다는 생각을 했다. 단순하게 구현이 되기 때문이다. 무엇이 정답인지는 모르겠지만, 직접 구현을 해보면서 설계를 처음에 잘해야겠다는 생각을 했다. SPA의 동작 방식을 바꾸면 전체 페이지의 코드를 수정해야 했다. 팀 프로젝트인 만큼 다른 사람의 코드를 건들기도 어려웠다. 때문에 설계의 중요성을 깨달았다. best practice를 찾아보고 구현을 했으면 더 가독성이 좋은 앱으로 만들 수 있었겠지만, 새로운 방법을 통해 다양한 Web API와 라이브러리의 소스코드를 학습할 수 있었다. 프론트엔드가 진입장벽은 낮다지만 정말 알아야 하는 것이 많다는 생각을 한다... 꾸준한 학습으로 지식을 증진시켜나가야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Rerference :&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://phpcoder.tech/detect-url-change-in-javascript-without-refresh/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://phpcoder.tech/detect-url-change-in-javascript-without-refresh/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/History/pushState&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/API/History/pushState&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/34999976/detect-changes-on-the-url&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/34999976/detect-changes-on-the-url&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>history-events</category>
      <category>pushState</category>
      <category>pushstate url</category>
      <category>pushstate 이벤트</category>
      <category>url</category>
      <category>url 변경 이벤트</category>
      <category>url변경</category>
      <category>자바스크립트</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/89</guid>
      <comments>https://minsoftk.tistory.com/89#entry89comment</comments>
      <pubDate>Thu, 14 Apr 2022 03:18:52 +0900</pubDate>
    </item>
    <item>
      <title>[JS] CORS 깊게 이해하기</title>
      <link>https://minsoftk.tistory.com/88</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;22.06.07 CORS 정의 수정&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이전 &lt;a href=&quot;https://minsoftk.tistory.com/70&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;블로그 글&lt;/a&gt;에서 5. HTML 임베디드 요소의 &amp;lt;img&amp;gt; 태그의 내용을 정리할 때, 어트리뷰트 중 &lt;b&gt;&lt;a href=&quot;https://minsoftk.tistory.com/70&quot;&gt;crossorigin&lt;/a&gt;&lt;/b&gt; 어트리뷰트에 대해서 언급한 적이 있었다. 예전 면접에서 font-awesome의 아이콘을 쓰기 위해, 내 HTML에 스크립트를 추가해줘서 사용했다. 그런데 그 스크립트 태그 안에서 crossorigin이 무엇인지 설명할 수 있냐고 면접관님이 물어봤었다. CORS와 관련이 있는 것은 알았지만 CORS를 제대로 알지 못했기 때문에 설명할 수가 없었다. 그래서 굉장히 당황했던 기억이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이후 이를 이해하기 위해 많은 자료들을 참고해봤지만, 생각보다 이해가 쉽지 않았고 정확한 이해가 어려웠다. 기본이 많이 부족했기 때문에 이해가 어렵다고 생각해서 정리를 나중으로 미뤘고, 자바스크립트의 기본부터 제대로 공부를 하기 시작했다. 그리고 이제 비동기에 대한 공부를 하고 있는데, 이제야 CORS에 대한 내용을 제대로 정리할 수 있을 것 같아서 제대로 정리해보고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. CORS란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 MDN에 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;교차 출처 리소스 공유 글&lt;/a&gt;을 읽으면서 간략하게 다른 도메인에서 자원을 요청하는 경우, 보안상의 이유로 브라우저에서 HTTP 요청을 제한한다는 직관적인 이해만으로 넘어갔다. 그래서 하나하나 정확하게 어떤 의미인지 분석해보고자 한다. 아래는 MDN에서 CORS에 대한 정의를 하고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;교차 출처 리소스 공유(Cross-Origin Resource Sharing,&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/CORS&quot;&gt;CORS&lt;/a&gt;)는 추가&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/HTTP&quot;&gt;HTTP&lt;/a&gt;&amp;nbsp;헤더를 사용하여, 한&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/Origin&quot;&gt;출처&lt;/a&gt;에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다.&lt;br /&gt;&lt;/span&gt;&lt;/s&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span&gt;교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 HTTP 헤더를 기반으로한 매커니즘.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;22.06.07&amp;nbsp; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt;의 한글 번역본에서는 추가 HTTP 헤더를 사용한다고 되어있는데, 영어 원문을 보면 HTTP 헤더를 기반으로한 매커니즘이라고 해석된다. 추가 HTTP 헤더란 말이 부정확하다 생각해 수정했다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 출처란 용어에 대해서 정확한 이해가 필요할 것 같다. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/Origin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;출처&lt;/a&gt;란 사용하는 URL의 스킴(프로토콜), 호스트, 포트로 정의되는데 두 객체의 스킴, 호스트, 포트가 모두 일치하는 경우 &lt;b&gt;같은 출처&lt;/b&gt;를 가졌다고 말한다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스킴(프로토콜) : https&lt;/li&gt;
&lt;li&gt;호스트 : &lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;minsoftk.tistory.com&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;포트 : http의 기본 포트는 80이다. (따로 포트를 지정하지 않은 이상 80번 포트를 사용한다)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 위의 3개가 같다면 같은 출처(Same-origin)이라고 한다. 아래의 두 URL은 같은 출처이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;(https의 기본 포트는 443이다.)&lt;br /&gt;https://minsoftk.tistory.com/88:443&lt;br /&gt;https://minsoftk.tistory.com/70:443&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 출처가 아닌 A, B가 있다고 가정했을 때, A가 B에게 자원을 요청했을 때, &lt;b&gt;추가 http 헤더&lt;/b&gt;를 붙여 브라우저에게 A라는 출처에서 B라는 자원을 요청할 수 있다는 것을 브라우저에게 알려줘 B의 자원을 A가 가져올 수 있게 만드는 것이 CORS이고, 다른 출처끼리 자원을 공유하기 위해 권한을 부여하는 것을 CORS라고 정리할 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. CORS가 필요한 이유?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 위에서 출처(Origin)에 대해 이해를 할 수 있었다. 그런데 왜 교차 출처 리소스 공유(CORS)가 필요할까?라는 의문이 든다. 기본적으로 동일 출처 정책(Same Origin Policy)이라는 보안 정책이 있기 때문이다. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SOP&lt;/a&gt;란 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 보안 방식이다. 즉, 내 웹 페이지에서 다른 페이지의 리소스를 불러오는 것을 제한한다는 의미이다. 이런 SOP 보안 정책 때문에 CORS가 필요한 것인데, 또 SOP는 왜 필요한 것인가라는 의문이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. SOP가 필요한 이유?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://www.hackedu.com/blog/same-origin-policy-and-cross-origin-resource-sharing-cors&quot;&gt;글1&lt;/a&gt;,&amp;nbsp;&lt;a href=&quot;https://www.netsparker.com/whitepaper-same-origin-policy/&quot;&gt;글2&lt;/a&gt;에서 궁금증을 해결할 수 있었는데, 상당히 자세하게 설명이 돼 있다. 내가 이해한 바는 다음과 같다. 아래 예시는 SOP 보안 정책이 없는 경우를 가정한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;www.gooogle.com ('o'가 하나 더 붙었을 때의 경우, 악의적인 가짜 구글 사이트라 가정)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 위와 같은 가짜 페이지에서 정상적인 구글 페이지와 동일하게 콘텐츠를 로드해주는 iframe이 삽입돼 있다. 이를 통해서 악의적인 가짜 페이지에서 사용자가 개인정보를 입력했을 때, 악성 페이지에서는 사용자의 개인정보를 취득할 수 있고, 악의적으로 사용될 가능성이 있다.&amp;nbsp;그래서 SOP가 필요하다는 것인데, google.com(정상적인 페이지),&amp;nbsp; gooogle.com(악성 페이지)는 호스트가 다르다. 따라서 SOP 정책으로 gooogle.com(악성 페이지)과의 상호작용을 제한한다고 이해했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, google.com으로 정상적인 접속을 했을 경우에만 SOP 정책에 위반되지 않아, google.com 서버의 자원을 요청하고 리소스를 받아올 수 있다는 이야기로 이해할 수 있을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. crossorigin 어트리뷰트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 SOP가 왜 필요한지에 대해서 이해할 수 있었다. 그렇다면 이제 우리가 개발하는 웹 페이지에서 font-awesome의 리소스를 사용하기 위해, 추가한 스크립트 태그에서 crossorigin 어트리뷰트의 의미를 어느 정도 이해할 수 있을 것 같다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1640680734143&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;https://kit.fontawesome.com/(YOUR_private_key).js&quot; crossorigin=&quot;anonymous&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면, 우리가 개발하는 웹 페이지에서 font-awesome에 자원을 요청한다. SOP 정책에 위반되기에 CORS를 허용해줘야 한다. 따라서 crossorigin 어트리뷰트를 추가해준 것으로 이해할 수 있을 것 같다. 기본적으로 crossorigin 어트리뷰트를 명시하지 않으면 CORS요청은 할 수 없다고 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTML/Attributes/crossorigin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt;에서 설명하고 있다. 따라서 crossorigin을 반드시 명시해줘야 하고, crossorigin 어트리뷰트 값으로 'anonymous'를 주어서 CORS를 동작하게 한 것 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어트리뷰트의 값으로 anonymous를 줬는데, 이는 element의 CORS 요청의 &lt;span style=&quot;color: #ef5369;&quot;&gt;credentials flag&lt;/span&gt;가 'same-origin'으로 지정된다. (MDN)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 &lt;span style=&quot;color: #ef5369;&quot;&gt;credentials flag&lt;/span&gt;란 뭘까 의문이 생긴다...&amp;nbsp;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Request/credentials&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Request.credentials&lt;/a&gt;에 대한 이해가 필요한 것 같은데, 이를 이해하기 위해선&amp;nbsp;&lt;b&gt;cookie&lt;/b&gt;에 대해 정확한 이해가 필요할 것 같다. 또한 XHR의 withCredentials flag와는 무엇이 다른지에 대한 이해도 필요할 것 같다. 추후에 관련 내용의 포스팅도 추가할 예정이다. 지금은 CORS의 동작 방식중 하나겠구나로 추측만 하고 넘어가려 한다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;(아직 Font Awesome의 예시가 정확하게 어떤 방식으로 동작하는지 이해를 하지 못했다...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. CORS 동작 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CORS 동작하는 방식이 3가지가 있는데, &lt;b&gt;단순 요청(Simple Request)&lt;/b&gt;의 경우만을 이해해보고자 한다. &lt;span style=&quot;background-color: #dddddd;&quot;&gt;https://minsoftk.tistory.com&lt;span style=&quot;background-color: #ffffff;&quot;&gt; 도메인에서 임의의 웹 콘텐츠(https://foo.example)를 호출하길 원한다. 그러면 나의 웹 콘텐츠에서 아래와 같은 자바스크립트 코드가 사용될 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640690014599&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const xhr = new XMLHttpRequest();
const url = 'https://foo.example/resource/data/';

xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 브라우저가 &amp;nbsp;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;b&gt;Origin : https://minsoftk.tistory.com&lt;/b&gt;라는&lt;/span&gt; http 헤더를 서버로 전송하고, 서버에서는 아래와 같은 Access-Control-Allow-Origin 헤더를 다시 전송해준다. Origin과 Access-Control-Allow-Origin를 이용한 CORS 방식을 &lt;b&gt;단순 요청 방식&lt;/b&gt;이라고 한다. 해당 &lt;span style=&quot;background-color: #ffffff; color: #1b1b1b;&quot;&gt;리소스에 대한 접근을 허용하려면,&amp;nbsp;&lt;/span&gt;Access-Control-Allow-Origin&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b;&quot;&gt;&amp;nbsp;헤더에는 요청의&amp;nbsp;&lt;/span&gt;Origin&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b;&quot;&gt; 헤더에서 전송된 값이 포함되어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;Access-Control-Allow-Origin: * // 모든 도메인에서 접근할 수 있음
// or
Access-Control-Allow-Origin: https://minsoftk.tistory.com // minsoftk 도메인의 요청만 접근을 허용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 총 정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 정리하자면 ajax에 주로 사용되는 XMLHttpRequest(XHR)은 전체 페이지의 새로고침없이도 URL로부터 데이터를 받아올 수 있다. 따라서 ajax 프로그래밍에 주로 사용된다. 이를 활용해 우리가 만들 웹 사이트에서 다른 출처의 자원을 새로고침없이 받아올 수 있다. 이때 CORS가 필요한데, 이를 이해하기 위해 예전에 경험했던 Font Awesome을 경우를 예시로 이해해보고자 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 출처라는 용어와 SOP, CORS에 대해 먼저 정리를 했다. 그리고 CORS를 단순 요청 방식을 동작시켰다. CORS의 3가지 방식 중 하나인 &lt;b&gt;단순 요청&lt;/b&gt;의 경우를 살펴봤다. Font Awesome도 단순 요청처럼 CORS 허용을 해주는 역할로만 추측만 했을 뿐, 아직 어떤 동작인지 정확한 이해를 하지는 못했다. 이를 이해하기 위해 Cookie와 &lt;span style=&quot;color: #333333;&quot;&gt;credentials flag를 정확히 알아야 하고, XHR 요청의 withCredentials flag와는 뭐가 다른 지의 구별이 필요하다. 추후에 2탄으로 정리해볼 계획이다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;혹시 틀리거나 잘못된 내용이 있다면 댓글로 알려주세요. :)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  Reference:&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/API/XMLHttpRequest&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/Origin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Glossary/Origin&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.hackedu.com/blog/same-origin-policy-and-cross-origin-resource-sharing-cors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.hackedu.com/blog/same-origin-policy-and-cross-origin-resource-sharing-cors&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.netsparker.com/whitepaper-same-origin-policy/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.netsparker.com/whitepaper-same-origin-policy/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/24687313/what-exactly-does-the-access-control-allow-credentials-header-do&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/24687313/what-exactly-does-the-access-control-allow-credentials-header-do&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>cors</category>
      <category>crossorigin</category>
      <category>sop</category>
      <category>XMLHTTPRequest</category>
      <category>교차 출처 리소스 공유</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/88</guid>
      <comments>https://minsoftk.tistory.com/88#entry88comment</comments>
      <pubDate>Tue, 28 Dec 2021 20:37:13 +0900</pubDate>
    </item>
    <item>
      <title>[JS] this에 대해서</title>
      <link>https://minsoftk.tistory.com/86</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;this에 대한 이해&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;this&lt;/b&gt;란 객체의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자바스크립트에서 this에 대한 내용이 굉장히 헷갈렸다. 그 이유는 this바인딩이 상황에 따라 다르게 때문이었다. 함수를 정의할 때 this에 바인딩할 객체가 결정되는 것이 아니고, 함수를 호출할 때 함수를 어떻게 호출했는지에 따라 this에 바인딩할 객체가 결정된다. 굉장히 헷갈리는 부분이었고 나중에 화살표 함수에서도 this가 바인딩되는 방식이 달랐다. 화살표 함수에서는 함수 자체의 this 바인딩을 갖지 않는다. 그래서 상위 스코프의 this를 참한다. 이렇게 개발자가 함수를 어떻게 호출하냐에 this가 바인딩하는 위치가 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;생각해보면 굉장히 비효율적인 것 같다. 어떻게 호출되냐에 따라 this가 가리키는 객체가 달라진다는 것은 실수할 확률이 높기 때문이다. 아직은 경험이 적어 this로 인한 문제들을 마주치지는 못했지만 실수를 많이 생길 수밖에 없는 부분인 것 같다. 내용을 정리하면서 헷갈렸던 부분과 추가로 궁금한 점들을 적어봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;바인딩?&lt;br /&gt;식별자와 값을 연결하는 과정. 변수 선언이 바인딩 과정이다. 변수 선언은 변수와 변수가 확보한 메모리 공간을 바인딩한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 객체 리터럴, 생성자 함수에서의 this&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;객체 리터럴&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 리터럴 방식으로 생성했을 경우는 다음과 같다. this는 메서드를 호출한 객체, 즉 person을 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1639212840249&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person = {
  name: 'minsoftk',
  getName() {
    return this.name;
  },
};

console.log(person.getName());&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생성자 함수&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 함수의 경우는 다음과 같다. 여기에서의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1639213182441&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name) {
  this.name = name;
}

Person.prototype.getName = function () {
  return this.name;
};

const person = new Person('minsoftk');
console.log(person.getName());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 this는 상황에 따라 가리키는 대상이 다르게 되고, this 바인딩은 함수 호출 시점에 결정된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 함수를 호출하는 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 호출하는 방식에 따라 this 바인딩이 달라진다고 했는데, 함수를 호출하는 방식은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 함수 호출&lt;/li&gt;
&lt;li&gt;메서드 호출&lt;/li&gt;
&lt;li&gt;생성자 함수 호출&lt;/li&gt;
&lt;li&gt;Function.prototype.apply/call/bind&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;일반 함수 호출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 함수로 호출하는 경우에는 &lt;b&gt;전역 객체&lt;/b&gt;가 바인딩된다. this의 의미가 객체의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수이므로 일반 함수에서의 this는 큰 의미가 없다는 생각이 든다. 전역 객체를 가리키게 할 상황이 있을지 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메서드 호출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드를 호출했을 때, this는 메서드를 소유한 객체가 아닌 &lt;b&gt;메서드를 호출한 객체&lt;/b&gt;에 바인딩된다. 처음에는 이게 무슨 말인지 이해가 잘 가지 않았다. 결국 메서드를 소유한 객체가 메서드를 호출하니깐 해당 객체로 this가 바인딩되는 게 아닌가?라는 생각을 했다. 하지만 호출한 메서드가 서로 다른 객체의 메서드가 될 수 있는 경우도 있었다. 그 경우는 다음과 같다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639218812688&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name) {
  this.name = name;
}

Person.prototype.getName = function () {
  return this.name;
};

const me = new Person('minsoftk');

console.log(me.getName()); // minsoftk

Person.prototype.name = 'minsoftk2';

console.log(Person.prototype.getName()); // minsoftk2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 getName 메서드이지만, 어느 객체에서 호출하냐에 따라 해당 객체에 바인딩이 된다. 해당 객체에서는&amp;nbsp;&lt;b&gt;name&lt;/b&gt;이라는 프로퍼티 키의 값은 다를 수도 있다. 이런 경우를 생각 못해서 처음에 이해가 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;생성자 함수 호출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 함수 내부의 this에서는 생성할 인스턴스가 바인딩된다. 즉, 생성자 함수를 인스턴스를 생성했을 때, 해당 객체로 바인딩이 된다는 의미이다. 그런데 한 가지 의문이 생성자 함수도 function을 이용해서 객체를 생성하는 방식인데 &lt;b&gt;생성자 함수&lt;/b&gt;랑&amp;nbsp;&lt;b&gt;함수&lt;/b&gt;와 어떻게 구별을 하는 걸까?라는 의문이 생겼다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;new&lt;/b&gt;라는 연산자와 함께 사용하면 생성자 함수, new라는 연산자가 사용되지 않으면 일반 함수로 동작한다고 한다. 자바스크립트 엔진에서 구별하는 방식인 것 같다. 그래서 아래와 같이 일반 함수로 호출이 되었을 때는 undefined를 반환한다. (자바스크립트 함수에서는 return이 생략되었을 때 암묵적으로 &lt;b&gt;undefined&lt;/b&gt;를 반환한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 어떤 동작을 이해를 하려면 기본적인 내용들을 정확히 아는 게 중요했다. 함수에서도 반환문이 없을 때, 암묵적으로 undefined를 반환한다는 내용을 모르면 왜 이런 출력이 나오는지 이해하기가 어렵다. 일반 함수로 사용됐을 때는 return 반환문이 없으므로 undefined가 출력된다. 처음에 왜 undefined가 나오지? 생각하고 함수 파트를 다시 복습했다..&lt;/p&gt;
&lt;pre id=&quot;code_1639219632584&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name) {
  this.name = name;
}

const person1 = Person('minsoftk');

console.log(person1); // undefined
console.log(name); // minsoftk&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 생성자 함수로 호출이 됐을 때는, new라는 연산자가 붙고 인스턴스가 생성이 되게 된다. 생성된 인스턴스를 this가 가리키게 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Function.prototype.apply/call/bind 메서드에 의한 간접 호출&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;27장 배열에도 유사 배열 객체를 배열로 변환할 때 사용이 된다. 유사 배열 객체를 배열로 변환한다는 부분도 아직은 정확하게 이해를 하지 못해서 추후에 배열에 관련된 포스팅을 하면서 유사 배열 객체란 무엇인지 내용을 정리할 계획이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639222295377&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getThisBinding() {
  console.log(arguments); // [Arguments] { '0': 1, '1': 2, '2': 3 }
  return this;
}

const thisArg = 100;
console.log(getThisBinding.apply(thisArg, [1, 2, 3])); // [Number: 100]
console.log(getThisBinding.call(thisArg, 1, 2, 3)); // [Number: 100]
console.log(getThisBinding.bind(thisArg)()); // [Number: 100]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;apply, call을 쓰게 되면 getThisBinding이라는 함수의 this는 thisArg의 값으로 바인딩시켜준다. 또한 함수 객체의 arguments의 프로퍼티 값으로 객체를 전달해주게 된다. apply는 배열 형태로 전달해주고 call은 , 를 사용해서 인수로 넘겨주게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bind 같은 경우는 함수를 호출하지 않고 this로 사용할 객체만 전달한다. 따라서 호출 연산자 '( )'를 붙여줘서 함수를 호출해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 호출하는 방법에는 4가지가 있고, 각각의 경우 this 바인딩은 어떻게 되는지 공부해봤다. 공부를 하면 할수록 모르는 부분들도 많이 생겼고, 이를 어떻게 활용할 수 있는지에 대한 고민을 많이 하게 됐다. 따라서 이런 포스팅을 통해서 빈 개념들을 잘 메꿔가야겠다는 생각이 많이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6에서는 화살표 함수가 나오는데, 화살표 함수에서 this 바인딩이 또 달라진다. 이렇게 헷갈리는 this를 꼭 사용해야 되나?라는 질문을 받았는데 아직 내가 판단할 만큼의 this의 문제점을 경험해보지 못했다. 그래서 아직 판단이 되지는 않는다. 하지만 생성자 함수를 써야 한다면 인스턴스 생성을 해야 하고 인스턴스에서 this 사용은 불가피하다 생각한다. 그래서 this는 꼭 써야 되는 게 아닌가란 생각이 들었다. 하지만 이렇게 어렵게 쓸바엔 그냥 '객체 리터럴로 생성해서 편하게 사용하면 안 되나?'라는 생각은 강하게 들었다. 상황에 따라 달라질 것 같지만 가독성 측면에서는 지양해야 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;혹시 틀리거나 잘못된 내용이 있다면 댓글로 알려주세요. :)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;  Reference:&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;amp;mallGb=KOR&amp;amp;barcode=9791158392239&amp;amp;orderClick=LAG&amp;amp;Kc=&quot;&gt;모던 자바스크립트 Deep Dive - 이웅모 저 : 22장 this&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/js-this&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://poiemaweb.com/js-this&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>javascript this</category>
      <category>자바스크립트 this</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/86</guid>
      <comments>https://minsoftk.tistory.com/86#entry86comment</comments>
      <pubDate>Sat, 11 Dec 2021 22:51:00 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 프로토타입이란?</title>
      <link>https://minsoftk.tistory.com/85</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로토타입을 공부하면서 굉장히 헷갈리는 부분이 많았다. 내용을 다시 정리해보면서 내가 헷갈렸던 부분을 공유하고 제대로 공부해보고자 한다. 멘토님이 이런 개념들을 공부하고 나라면 어떻게 사용할 것인가? 에 대한 고민이 많이 필요하다고 했다. 공부를 하면서 해당 개념에 대한 나의 생각을 정리해놓는 것이 당연하다고 생각했다. 하지만 생각을 정리하기 위해선 개념들을 확실히 알아야 했다. 아직은 모든 개념들이 연결이 되지는 않지만, 반복적 학습을 통해서 개념들을 연결시키려고 노력하려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 프로토타입이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 프로토타입을 기반으로 상속을 구현한다. 여기서 &lt;b&gt;프로토타입&lt;/b&gt;이란 어떤 객체의 상위 객체의 역할을 하는 객체로서 다른 객체에게 공유 프로퍼티를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 이해하기 위해선 내부 슬롯, 내부 메서드를 이해해야 했다. 책에선 다음과 같이 설명한다. 내부 슬롯, 내부 메서드란 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티, 의사 메서드다.&amp;nbsp;굉장히 이해하기 어려웠는데 여러 번 읽어본 결과 내가 이해한 바는 이렇다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 &lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%98%EC%82%AC%EC%BD%94%EB%93%9C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;의사 코드에&lt;/a&gt; 대해서 한 번쯤은 들어봤는데, 동작은 하지 않지만 논리적인 흐름을 알기 위해 쓴 코드를 의사 코드라고 한다. 이처럼 ECMAScript의 사양을 설명하기 위해 내부 슬롯과 내부 메서드를 의사 코드로 사용한다는 의미로 해석했다. 그래서 이런 내부 슬롯과 내부 메서드를 가지게 되는데, 이를 프로퍼티 어트리뷰트라고 하고, 이는 JS엔진이 관리하는 프로퍼티의 내부 상태 값이다. 이는 표기를&amp;nbsp; [[ ... ]] 같이 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말이 어려워 이해가 어려웠지만, 다음과 같이 이해했다. 결국 자바스크립트 엔진이 우리가 객체의 프로퍼티를 생성해주면 자동으로 프로퍼티 어트리뷰트를 생성해주게 된다. 즉, 프로퍼티가 생성이 되면 자바스크립트 엔진이 [[Value]], [[Writable]] .. 와 같은 내부 슬롯을 생성해주게 된다. 이는 자바스크립트의 내부 로직이기 때문에 개발자가 직접 접근하지는 못하고 __proto__라는 접근자 프로퍼티를 사용해 [[prototype]]을 간접적으로 접근한다.&lt;/p&gt;
&lt;pre id=&quot;code_1638788922119&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var person = {
	name:'minsoftk',
}

console.log(Object.getOwnPropertyDescriptor(person,'name'));
// { value : &quot;Lee&quot;, writable: true, enumerable: true, configurable: true }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 getOwnPropertyDescriptor 메서드를 이용해서 name의 프로퍼티 어트리뷰트를 받아올 수도 있다. 즉, 프로퍼티 어트리뷰트란 'name'이라는 프로퍼티에 내부 슬롯이라는 &lt;b&gt;상태 값&lt;/b&gt;을 가지고 있는 것으로 이해했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 프로토타입을 왜 사용해야 할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성자 함수 &lt;/b&gt;이야기를 먼저 해보면, 생성자 함수를 쓰는 이유는 객체 리터럴로만 객체를 생성하기엔 비효율적이기 때문이다. 따라서 생성자 함수를 이용해서 인스턴스를 생성하는 방식으로 객체 리터럴로 객체를 생성하는 방식의 단점을 보완할 수 있다. 만약 아래와 같은 객체를 객체 리터럴로 10개를 생성해야 한다면? 굉장히 코드가 길어지고 비효율적이다. 생성자 함수를 통해서는 new 연산자를 이용해서 인스턴스를 간편하게 생성할 수 있으므로 효율적으로 객체를 생성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1639225317245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 객체 리터럴로 객체 생성
const person = {
  name: 'minsoftk',
  age: '11111',
  weight: '65',
  height: '176',

  getName() {
    return this.name;
  },
  getAge() {
    return this.age;
  },
  getWeight() {
    return this.weight;
  },
  getHeight() {
    return this.height;
  },
};

// 생성자 함수로 객체 생성
function Person(name, age, weight, height) {
  this.name = name;
  this.age = age;
  this.weight = weight;
  this.height = height;

  this.getName = function () {
    return this.name;
  };
  this.getAge = function () {
    return this.age;
  };
  this.getWeight = function () {
    return this.weight;
  };
  this.getHeight = function () {
    return this.height;
  };
}

const person = new Person('minsoftk', 30, 65, 176);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 프로토타입도 코드 재사용과 효율성을 위해서다. 만약 생성자 함수로 새로 생성되는 인스턴스에 만약 공통된 메서드가 포함된 경우를 생각해보면, 만약 데이터 프로퍼티가 다른 값들로 여러 개의 인스턴스들이 생성이 될때, 똑같은 메서드를 가진다고 생각하면 모든 인스턴스들이 메서드를 중복 생성하고 있다. 모든 인스턴스가 동일한 메서드를 중복 소유하는 것은 메모리를 불필요하게 낭비한다고 한다. 그래서 이를 위해 prototype에 해당 메서드를 등록해서 인스턴스들이 공유해서 사용할 수 있게 만들어준다. 그래서 자바스크립트는 프로토타입을 기반으로 상속을 구현한다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639032781100&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name, age, weight, height) {
  this.name = name;
  this.age = age;
  this.weight = weight;
  this.height = height;

  this.getName = function () {
    return this.name;
  };
  this.getAge = function () {
    return this.age;
  };
  this.getWeight = function () {
    return this.weight;
  };
  this.getHeight = function () {
    return this.height;
  };
}

const minsoftk = new Person('minsoftk', 30, 65, 176);
const nklcb = new Person('nklcb', 35,180, 55);
console.log(minsoftk.getName());
console.log(nklcb.getName());&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 아래와 같이 바꿔주게 된다면 Person라는 생성자 함수의 prototype에 getName, getAge 등등 메서드들이 등록이 된다. 따라서 인스턴스들은 prototype의 메서드를 참조하게 된다. 이 예제를 통해 프로토타입에 대한 이해를 할 수 있었다. 그러면 인스턴스를 생성할 때마다 해당 인스턴스들이 메서드를 prototype에서 참조를 하기 때문에 메모리 절약을 할 수가 있다. 어느 정도로 절약이 되는 건지는 감이 오지는 않으나 상속받아서 메서드를 사용한다는 점은 굉장히 효율적이라는 생각이 든다. 또 코드를 보다 보면 Person 생성자 함수와 프로토타입 메서드들을 묶어주고 싶다는 생각이 강하게 든다. 이럴 땐 전체를 Person이라는 즉시 실행 함수로 묶어줘서 생성자 함수를 반환하게 만들어 줄 수도 있다. 처음엔 굳이 이렇게까지 묶어야 하나 생각했지만, 코드가 굉장히 길어질 경우를 생각해보면 응집도가 높을수록 가독성이 좋기에 묶어 주는 것이 좋다고 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639032869089&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 프로토타입 메서드 생성
// 즉시실행함수로 응집성 높여줌

const Person = (function () {
  function Person(name, age, weight, height) {
    this.name = name;
    this.age = age;
    this.weight = weight;
    this.height = height;
  }
  Person.prototype.getName = function () {
    return this.name;
  };
  Person.prototype.getAge = function () {
    return this.age;
  };
  Person.prototype.getWeight = function () {
    return this.weight;
  };
  Person.prototype.getHeight = function () {
    return this.height;
  };
  return Person;
})();
const minsoftk = new Person('minsoftk', 30, 65, 176);
const nklcb = new Person('nklcb', 35, 180, 55);
console.log(Person.prototype.getName === minsoftk.getName);
console.log(minsoftk.getName());
console.log(nklcb.getName());&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 헷갈린 부분&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 프로토타입은 객체 간 상속을 구현하기 위해 사용한다. 중복되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드를&lt;span&gt;&amp;nbsp;&lt;/span&gt;상위 객체인 prototype에 넣어주게 된다면 인스턴스를 생성해도 하나의&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드를&lt;span&gt;&amp;nbsp;&lt;/span&gt;공유해서 쓸 수 있다. 만약 100개의 인스턴스를 생성해도 하나의&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드를&lt;span&gt;&amp;nbsp;&lt;/span&gt;공유해서 사용할 수 있다. 하지만 생성자&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 안에&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드를&lt;span&gt;&amp;nbsp;&lt;/span&gt;넣게 된다면, 모든 인스턴스들이 각각&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드를&lt;span&gt;&amp;nbsp;&lt;/span&gt;가지고 있기 때문에 재사용성 측면이나 메모리를 낭비하게 된다. 그런데 내가 헷갈렸던 부분은 프로토타입 객체에 대한 설명 부분이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책의 내용에서는 &quot;&lt;b&gt;모든 객체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결되어 있다. 즉, 객체와 프로토타입과 생성자 함수는 서로 연결되어있다.&lt;/b&gt;&quot; 이를 해석해서 작성하면 &quot;모든 객체는 하나의 [[prototype]]을 갖는다. 그리고 모든 프로토타입(객체의 프로토타입)은 생성자 함수와 연결되어 있다.&quot;인데 같은 프로토타입으로 용어가 쓰이다 보니 이해하는데 굉장히 어려웠다.&amp;nbsp; 이를 정확하게 이해하기 위해선 내부 슬롯인 [[prototype]]에 대해서 정확하게 이해를 하고 있어야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 객체는 프로토타입이라는 내부슬롯 [[prototype]]을 가지고 있다. 객체 생성 방식에 따라 프로토타입이 결정되고 [[prototype]]에 저장된다. 그리고 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입을 간접적으로 접근할 수 있다. 즉, 자기 프로퍼티의 [[prototype]]에는 상속을 받아오는 상위 객체인 프로토타입이 저장되어 있다. 이런 개념을 이해해야 각각의 프로토타입을 제대로 해석하고 이해할 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 함수를 공부하면서 this에 대한 내용도 공부가 필요했다. 함수를 호출하는 방식에 따라 this가 달라지기 때문이다. 아직은 this에 대한 이해가 많이 부족하기 때문에 this에 대한 내용도 프로토타입과 연관 지어서 따로 정리해볼 생각이다. 사소한 개념들이 다 연결이 되는데 이를 머릿속에서 정리하기란 굉장히 어려운 것 같다.&amp;nbsp;이해는 가지만 정리가 안되는 느낌이 강하다. 아직 정확하게 아는 것이 아니라는 의미인데, 유난히 프로토타입이 나에겐 어렵다. 용어적으로도 이해하기 어려워 그런 것 같다. 그럴 때마다 계속 반복해서 읽으면서 이해하려고 노력하는 방법밖에 없는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;혹시 틀리거나 잘못된 내용이 있다면 댓글로 알려주세요. :)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;  Reference:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;amp;mallGb=KOR&amp;amp;barcode=9791158392239&amp;amp;orderClick=LAG&amp;amp;Kc=&quot;&gt;모던 자바스크립트 Deep Dive 19장 프로토타입&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/js-prototype&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://poiemaweb.com/js-prototype&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>생성자 함수</category>
      <category>자바스크립트 프로토타입</category>
      <category>프로토타입</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/85</guid>
      <comments>https://minsoftk.tistory.com/85#entry85comment</comments>
      <pubDate>Mon, 6 Dec 2021 21:03:13 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 자바스크립트 변수 선언과 할당 동작 과정</title>
      <link>https://minsoftk.tistory.com/84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N6dx0/btrmg42KSSs/Iv9FzpyC9dVyYZjSy2MQ0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N6dx0/btrmg42KSSs/Iv9FzpyC9dVyYZjSy2MQ0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N6dx0/btrmg42KSSs/Iv9FzpyC9dVyYZjSy2MQ0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN6dx0%2Fbtrmg42KSSs%2FIv9FzpyC9dVyYZjSy2MQ0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;592&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;22.06.07 일부 내용 수정&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자바스크립트 변수 선언과 할당 동작 과정 이해&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;현재 자바스크립트를 배우고 있는데 느끼는 점이 굉장히 많다. 당연하다고 생각하던 것이 당연한 것이 아니었던 것이다.&amp;nbsp; 프로그래밍에 입문하면서 C, C++을 배웠었는데, 동작의 결과에 대해서는 당연하게 생각하고 왜 그런 동작을 하는지에 대한 고민을 해본 적이 별로 없었다. 또한 오류가 나도 해결하는 게 중요했지, 왜 오류가 나는지 고민을 해본 적이 별로 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번에 자바스크립트를 배우면서 동작 원리의 정확한 이해라는 방향성을 가지고 공부를 하면서 기본이 정말 중요하다는 생각을 하게 됐다. 과연 내가 혼자 공부를 했다면, 이런 방향성을 생각하면서 공부할 수 있었을까? 여기에서 정확한 이해라는 방향성이란 기본에 충실하는 것을 의미한다. 어느 분야든 올바른 방향성을 가질 수 있게 해주는 스승을 만나는 것은 참 중요한 것 같다. 당연하다고 생각하고 넘어갔던 자바스크립트에서 변수 선언과 할당 동작 과정에 대해 정리해보려 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. C와 JS에서의 변수 선언과 할당 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 C에서는 변수 선언과 할당 과정이 다음과 같다. int형을 정해준 변수 선언 방식(정적 타입)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;c에서의 변수 선언과 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1638082981101&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int a;
a = 1;
printf(&quot;%d&quot;, a); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 자바스크립트에선 다음과 같다. 데이터 타입에 관계없이 var를 활용해 변수를 선언한다.(동적 타입)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS에서의 변수 선언과 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1638083140386&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var a;
a = 1;
console.log(a); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 방식들을 해당 언어들만의 특징 정도로만 생각했고, 당연하게 받아들여야 하는 문법 정도로 생각했다. '자바스크립트에서 알아서 처리해주나 보다' 정도로만 이해하고 넘어갔다. 하지만 내 생각보다 복잡한 동작이 있었다. 이러한 동작을 이해하니 &lt;b&gt;호이스팅&lt;/b&gt;이라는 안티 패턴도 자연스럽게 이해할 수 있었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 용어에 대한 확실한 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연하게 생각하는 것들이란 무엇일까? 혹시 &quot;&lt;b&gt;변수란 무엇인가?&lt;/b&gt;&quot;라는 질문을 받았을 때, 명확하게 설명이 가능한지 모르겠다. 나는 변수에 대한 질문을 받았을 때, 머릿속으로는 떠오르지만 말로 나오지 않았다. 그리고 '변수가 변수지....'라고 생각을 했다. 하지만 어떤 개념을 이해한다는 것은 바로 용어를 정확히 이해하고 설명할 수 있어야 제대로 아는 것이라고 배우고 있는데, 굉장히 동의하는 부분이고 중요한 것 같다. 결국 나는 변수에 대해서도 제대로 알지 못했던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수란 &lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;하나의 값&lt;/span&gt;&lt;/b&gt;을 저장하기 위해 확보한 &lt;b&gt;메모리 공간 자체&lt;/b&gt; 또는 그 &lt;b&gt;메모리 공간을 식별하기 위해 붙인 이름&lt;/b&gt;이다. &lt;b&gt;식별자&lt;/b&gt;라고도 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&lt;b&gt;식과 문을 구별할 수 있는가?&quot;&lt;/b&gt;라는 비슷한 질문도 있다. &lt;b&gt;문은 프로그램의 최소 실행 단위이다.&lt;/b&gt; &lt;b&gt;표현식은 값으로 평가될 수 있는 문&lt;/b&gt;이다. 따라서 식은 문이다. 하지만 표현식인 문일 수도 있고, 표현식이 아닌 문일 수도 있다. 따라서 문이 값으로 평가가 될 수 있다면 표현식인 문이다. 처음엔 이런 용어들을 대수롭지 않게 생각했다. 대충 식과 문을 이해하고 넘어가서 개념이 많이 흔들리고 헷갈리는 것을 경험했다. 용어들의 정의를 확실히 알고 이해해야 더욱 깊은 내용들을 이해할 수 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1638785795702&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2 + 3 // 표현식 리터럴이 5로 평가가 된다.
var x; // 선언문은 표현식이 아니다. 값으로 평가가 될 수 없기 때문에
x = 10; // 할당문은 표현식인 문이다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 변수란 하나의 &lt;b&gt;값&lt;/b&gt;을 저장하기 위한 메모리 공간 자체라 했다. 표현식은 &lt;b&gt;값&lt;/b&gt;으로 평가가 가능하다. 따라서 표현식은 변수에 할당할 수가 있다. 하지만 표현식이 아닌 문은 변수에 저장할 수가 없다. 이런 용어의 확실한 정의를 바탕으로 자바스크립트 변수 선언과 할당 과정을 정리해보려 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 자바스크립트 변수 선언과 할당&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 선언을 했을 때, 자바스크립트에서는 어떻게 동작이 일어날까? 먼저, 자바스크립트에서는 런타임 이전에 변수 선언문을 실행 컨텍스트에 객체로 등록한다. 실행 컨텍스트라는 개념을 정확하게 이해하는데 굉장히 오랜 시간이 걸렸다. &lt;a href=&quot;https://poiemaweb.com/js-execution-context&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;실행컨텍스트&lt;/b&gt;&lt;/a&gt;란 자바스크립트 동작원리의 핵심 개념으로 식별자를 등록하고 식별자를 관리하는 스코프와 코드 실행 순서 관리를 구현한 자바스크립트의 내부 메커니즘이다. (Deep Dive 23장- 실행컨텍스트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행컨텍스트는 생략하고 변수 선언의 과정만을 살펴보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1638085332600&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var age;
age = 30;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;age라는 변수를 선언하게 되면, age라는 메모리 공간을 확보하고 undefined로 초기화를 하게 된다. 그러면 age라는 변수는 undefined 값을 가진 메모리 공간을 가리킨다. 아래 그림과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EW12Q/btrmg49udT4/vXvxJDfklYTAum5sgqP1J0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EW12Q/btrmg49udT4/vXvxJDfklYTAum5sgqP1J0/img.png&quot; data-alt=&quot;변수 선언&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EW12Q/btrmg49udT4/vXvxJDfklYTAum5sgqP1J0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEW12Q%2Fbtrmg49udT4%2FvXvxJDfklYTAum5sgqP1J0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;600&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;변수 선언&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;undefined 타입의 메모리 크기?&lt;br /&gt;&lt;br /&gt;undefined에 대한 메모리 공간의 크기는 얼마나 될까? 브라우저 엔진을 직접 까 보지 않는 이상 알 수 없다.&amp;nbsp;ECMAScript에 이에 대한 명세가 없기 때문에, 브라우저 엔진을 만드는 개발사의 자율이다. 따라서 브라우저 엔진마다 다를 수 있다고 한다.&lt;br /&gt;&lt;br /&gt;변수의 데이터 타입별로 memory size를 반환해주는 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://gist.github.com/zensh/4975495&quot;&gt;zensh의 github&lt;/a&gt;에서 찾을 수 있었다. 해당 글의 함수를 크롬 개발자 도구의 console에 입력해주고 직접 변수에 데이터 타입별로 값을 할당해주면서, 데이터 타입의 size를 확인해볼 수 있다. 하지만 값이 null과 undefined인 경우에는 제공을 하고 있지 않다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 age=30의 할당 문을 실행하면, 자바스크립트에서는 30이라는 &lt;b&gt;값&lt;/b&gt;을 할당하기 위해 새로운 메모리 공간을 확보하고 30이라는 값을 저장해준 뒤, age가 해당 메모리 공간을 가리키게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sQFkW/btrmrurAoCX/oeac43gtrbKK9XQeTVpMp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sQFkW/btrmrurAoCX/oeac43gtrbKK9XQeTVpMp0/img.png&quot; data-alt=&quot;값 할당&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sQFkW/btrmrurAoCX/oeac43gtrbKK9XQeTVpMp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsQFkW%2FbtrmrurAoCX%2Foeac43gtrbKK9XQeTVpMp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;600&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;값 할당&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1638087328738&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var age = 30;

// 아래 동작과 같다
var age;
age = 30;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 단축해서 써줘도 똑같은 동작이 일어나게 된다. 당시에는 메모리가 상당히 중요했기 때문에, 더 효율적인 방식으로 메모리를 관리할 수 있는 방식으로 만들어지게 됐다고 한다.&amp;nbsp;자바스크립트에서는 값의 변경은 재할당을 통해서만 이루어진다. 따라서 자바스크립트에서는 값을 재할당할 때, 새로운 메모리 공간을 확보하고 해당 메모리에 값을 할당해주게 된다. 또한 값을 할당하는 과정에서 얼마만큼의 메모리 공간을 확보할 것인지에 대한 데이터 타입에 대한 내용의 공부가 필요하다. 원시 타입과 객체에 대한 이해도 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C는 메모리 할당과 해제를 직접 관리해줘야 하고, 자바스크립트는 자바스크립트 엔진이 메모리 관리를 해주게 된다. 이를 가비지 콜렉터라고 한다. 가비지 콜렉터란 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제하는 기능이다. 변수 선언과 할당에서부터 공부할 내용이 벌써 3가지나 생겼다. 호이스팅에 대한 부분만 짚고 넘어가려 한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;호이스팅 (안티 패턴)&lt;/li&gt;
&lt;li&gt;데이터 타입 (값을 할당 시 얼마만큼의 메모리 공간을 확보할 것인가)&lt;/li&gt;
&lt;li&gt;가비지 콜렉터 (참조되지 않는 메모리 정리)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 변수 호이스팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 호이스팅이란 변수 선언문이 코드의 선두로 끌어올려진 것처럼 동작하는 자바스크립트 고유의 특징이다. 이러한 현상은 자바스크립트의 태생적 특징이라고 한다. 자바스크립트 창시자인 브랜던 아이크 씨의 생각이 많이 들어갔는데, 비개발자도 편리하게 사용할 수 있게, Error를 내지 않는 방향으로 고민을 하다 보니, 런타임 이전에 선언된 변수들을 실행컨텍스트에 미리 등록해 아래와 같은 코드도 Error를 내지 않게 만들었다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1638089302522&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(age); // undefined

var age;
age = 30;

console.log(age); // 30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 첫 번째 줄의 console문은 age가 선언이 되지 않았기 때문에 참조 에러가 발생해야 맞다. 하지만 undefined가 출력이 된다. 자바스크립트에서는 &lt;b&gt;런타임 이전에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;변수 선언문들이 미리 실행이 된다. 따라서 age라는 변수가 선언이 되고, undefined로 초기화가 되는 과정이&amp;nbsp;&lt;b&gt;런타임 이전&lt;/b&gt;에 일어나게 된다. 따라서 런타임이 진행되면서 첫 번째 줄의 console문에서 초기화된 undefined가 출력이 되는 것이다. 이런 현상을&amp;nbsp;&lt;b&gt;변수 호이스팅&lt;/b&gt;이라고 한다. (함수 호이스팅도 존재) 이전에는 최상단으로 끌어올리는 효과라고만 암기를 했지만, 배경과 이유를 배우고 나니 호이스팅이라는 현상의 이해가 쉬웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수가 선언이 되지 않았는 데 사용하면 안 되는 것은 어느 언어나 명확한 문제이지만, 자바스크립트의 태생적 특징(브랜던 아이크 씨의 생각들) 때문에 오류를 발생시키지 않는 것뿐이라고 한다. 따라서 이러한 호이스팅 현상은 피해야 하는 &lt;b&gt;안티 패턴&lt;/b&gt;이지만, 자바스크립트가 오류를 발생시키지 않는다고 이해하면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 기본적인 동작 원리를 제대로 이해하면 호이스팅과 같은 현상이 왜 일어나는지 자연스럽게 이해를 할 수 있었다. 어떻게 보면 너무 당연한 부분이라 생각할 수 있지만, 이러한 동작을 자세하게 설명하는 것은 굉장히 어려웠다.&amp;nbsp; 그 이유는 용어에 대한 정의가 명확하지 않았기 때문이다. 용어를 정확하게 이해하고 이를 바탕으로 실행컨텍스트, 클로저의 내용으로 개념을 확장해야만 어려운 개념도 풀어서 이해할 수 있다는 것을 깨달았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;혹시 틀리거나 잘못된 내용이 있다면 댓글로 알려주세요. :)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;  Reference:&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&amp;amp;mallGb=KOR&amp;amp;barcode=9791158392239&amp;amp;orderClick=LAG&amp;amp;Kc=&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;모던 자바스크립트 Deep Dive 4장 변수&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/js-data-type-variable&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://poiemaweb.com/js-data-type-variable&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL(Today I Learn)/JavaScript</category>
      <category>JavaScript</category>
      <category>JS 기본적인 동작 원리</category>
      <category>JS 변수 선언과 할당</category>
      <category>변수</category>
      <category>실행컨텍스트</category>
      <category>자바스크립트 변수</category>
      <category>자바스크립트 변수 선언 할당</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/84</guid>
      <comments>https://minsoftk.tistory.com/84#entry84comment</comments>
      <pubDate>Sun, 28 Nov 2021 20:06:27 +0900</pubDate>
    </item>
    <item>
      <title>백준 2170번 - 선긋기</title>
      <link>https://minsoftk.tistory.com/83</link>
      <description>&lt;figure id=&quot;og_1637657561951&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2170번: 선 긋기&quot; data-og-description=&quot;첫째 줄에 선을 그은 횟수 N(1 &amp;le; N &amp;le; 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y(-1,000,000,000 &amp;le; x &amp;lt; y &amp;le; 1,000,000,000)가 주어진다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2170&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2170&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bN6P8X/hyMsofhBxU/GUvEgOfvkNajHa9K9PdvD0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2170&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2170&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bN6P8X/hyMsofhBxU/GUvEgOfvkNajHa9K9PdvD0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2170번: 선 긋기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에 선을 그은 횟수 N(1 &amp;le; N &amp;le; 1,000,000)이 주어진다. 다음 N개의 줄에는 선을 그을 때 선택한 두 점의 위치 x, y(-1,000,000,000 &amp;le; x &amp;lt; y &amp;le; 1,000,000,000)가 주어진다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;선긋기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌표가 겹치는 경우와 포함하는 경우들을 생각하면서 경우를 나눴다. 즉, 다음 선이 이전 선에 포함될 수도 있고, 겹치지 않을 수도 있다. 다음 선이 이전 선에 포함이 되는 경우는 생각하지 않아도 되는 경우이다.(생각해보면 당연 이전 선이 더 큰 범위이기 때문) 이렇게 경우를 나눠서 생각해보면 된다. 이렇게 선의 좌표를 구해주고 마지막엔 선의 길이를 구해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1637657549569&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, arr) {
	let answer = 0;
	// 연결된 선을 구해야 하므로 시작을 기준으로 sort를 해준다.
	arr.sort((a, b) =&amp;gt; a[0] - b[0]);

	// 처음 좌표의 왼쪽, 오른쪽 좌표 입력
	let left = arr[0][0];
	let right = arr[0][1];

	// 1번 인덱스부터 비교한다.
	for (let i = 1; i &amp;lt; n; i++) {
		// 이전 좌표 x,y  다음 선의 좌표 x2,y2 라 가정.
		// x2가 y보다 작거나 같을 때, y2가 y보다 클 때 겹치는 모든 경우를 처리해줄 수 있다.
		// x2,y2가 x,y에 포함되는 경우는 생각하지 않아도 된다. 포함이 되기 때문.
		// y 좌표를 옮겨준다.
		if (arr[i][0] &amp;lt;= right &amp;amp;&amp;amp; arr[i][1] &amp;gt; right) {
			right = arr[i][1];
		}
		// 좌표들이 겹치지 않을 때
		else if (arr[i][0] &amp;gt; right) {
			// 이전 좌표들의 거리를 먼저 더해준다.
			answer += right - left;
			right = arr[i][1];
			left = arr[i][0];
		}
	}
	// 끝나고나서 구해진 마지막 좌표의 합을 구해준다.
	answer += right - left;
	return answer;
}
console.log(solution(n, arr));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/Boj</category>
      <category>BOJ</category>
      <category>백준</category>
      <category>백준 2170번</category>
      <category>백준 선긋기</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/83</guid>
      <comments>https://minsoftk.tistory.com/83#entry83comment</comments>
      <pubDate>Tue, 23 Nov 2021 17:56:16 +0900</pubDate>
    </item>
    <item>
      <title>Pollyfill이란? Babel이란?</title>
      <link>https://minsoftk.tistory.com/82</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;21.11.22 내용 수정 &amp;amp;&amp;amp; 프로젝트 내용 추가&amp;nbsp;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Polyfill?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 접근성과 Web Vitals에 대한 공부를 하다가 이해가 안 가는 개념이 있었다. First Input Delay(FID)라는 최초 입력 지연의 최적화를 공부하면서 Total Blocking Time(TBT)의 시간을 줄여야 FID도 줄일 수 있는데, 그 최적화 방법 중에서 사용하지 않는 polyfills를 줄여야 한다는 말이 있었다. 전혀 감이 오지 않아서 pollyfill에 대한 검색을 해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &lt;a href=&quot;https://polyfill.io/v3/&quot;&gt;pollyfill.io&lt;/a&gt;의 공식 레퍼런스이다. 해당 사이트에선 기능이나 사용자의 브라우저에 따라 폴리필 스크립트를 제공해주는 서비스 사이트이다. 아래 글은 해당 사이트에서 Pollyfill에 대해서 말해주고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세계적으로 다양한 브라우저와 브라우저 버전을 사용하고 있으며, 각 브라우저에는 나머지 기능 집합이 약간씩 다릅니다. 이것은 브라우저용 개발을 어려운 작업으로 만들 수 있습니다. 인기 있는 브라우저의 최신 버전은 이전 브라우저에서 할 수 없는 많은 작업을 수행할 수 있지만 여전히 이전 브라우저를 지원해야 할 수도 있습니다. Polyfill.io를 사용하면 누락된 기능을 polyfill로 다시 생성하여 다양한 브라우저를 더 쉽게 지원할 수 있습니다. 지원하는 브라우저와 지원하지 않는 브라우저에서 최신 기능을 사용할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 정리하자면 개발자는 스크립트에 새로운 함수를 추가하거나 수정해서 스크립트가 최신 표준을 준수할 수 있게 작업할 수 있다. 이렇게 변경된 표준을 준수할 수 있게 기존 함수의 동작 방식을 수정하거나, 새롭게 구현한 함수의 스크립트를 &quot;폴리필(polyfill)&quot;이라 부른다. 폴리필(polyfill)은 말 그대로 구현이 누락된 새로운 기능을 메꿔주는(fill in) 역할을 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그렇다면 Polyfill이 왜 필요한가?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저마다 지원할 수 있는 기능이 다르기 때문이다. &lt;a href=&quot;https://roseline.oopy.io/dev/javascript-back-to-the-basic/history-of-javascript&quot;&gt;자바스크립트의 역사&lt;/a&gt;를 읽어보면 왜 이런 이슈들이 발생하는지 이해할 수 있다. 즉, 크롬에서는 동작하는 기능들이 인터넷 익스플로러에서는 동작하지 않는 현상이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 &lt;b&gt;크로스 브라우징&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 가지 예로 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/CSS/object-fit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;object-fit&lt;/a&gt;이라는 CSS 속성은 크롬과 파이어폭스 같은 최신 버전의 엔진에서는 정상적으로 적용이 된다. 하지만 IE에서는 적용이 되지 않는다. &lt;a href=&quot;https://caniuse.com/?search=object-fit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;can i use&lt;/a&gt; 사이트를 확인해보면, 내가 사용할 기능들을 브라우저 별로 지원 여부를 알려준다. 굉장히 고마운 사이트...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1251&quot; data-origin-height=&quot;845&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bruB1K/btrlImoi0vW/5qfGNH6MA3wUpTq3tOs0s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bruB1K/btrlImoi0vW/5qfGNH6MA3wUpTq3tOs0s0/img.png&quot; data-alt=&quot;can i use&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bruB1K/btrlImoi0vW/5qfGNH6MA3wUpTq3tOs0s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbruB1K%2FbtrlImoi0vW%2F5qfGNH6MA3wUpTq3tOs0s0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1251&quot; height=&quot;845&quot; data-origin-width=&quot;1251&quot; data-origin-height=&quot;845&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;can i use&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 팀 프로젝트를 진행하면서 겪은 문제는 다음과 같다. 왼쪽 화면은 크롬에서의 실행 화면인데, 화면에 꽉 찬 비디오가 재생이 되고 있다. 반면에 오른쪽 IE 환경에서는 왼쪽과 오른쪽에 검정 여백이 생긴 것이 보인다. 이는 IE에서는 object-fit 속성을 지원하지 않기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1SdgS/btrlGIr5MhR/73c1DFEO4ndu1lUgmshgNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1SdgS/btrlGIr5MhR/73c1DFEO4ndu1lUgmshgNK/img.png&quot; data-alt=&quot;project&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1SdgS/btrlGIr5MhR/73c1DFEO4ndu1lUgmshgNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1SdgS%2FbtrlGIr5MhR%2F73c1DFEO4ndu1lUgmshgNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;315&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;project&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 지원을 하지 않는다는 것을 알아도 내가 진행하고 있는 프로젝트에서 object-fit과 비슷한 기능을 어떻게 구현할지 굉장히 어려웠다. 여러 Reference를 참고해도 내 프로젝트 상황과는 달랐기에 적용하기가 쉽지 않았다. 이럴 때 polyfill을 사용해서 간단하게 해결할 수 있었다. 기존의 IE 문법으로 object-fit이란 문법을 구현한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/fregante/object-fit-images&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;이 github&lt;/a&gt;에서 내가 필요한 object-fit의 pollyfill을 제공하고 있었다. 아래 그림처럼 내가 사용할 태그에 맞게 상황에 따른 버전을 선택해서 Usage에 설명된 대로 해주면 된다. 다만 처음 pollyfill을 사용해 본 경험상 내 프로젝트에 적용하는 것도 생각보다 쉽지는 않았다. 모듈을 설치했는데도 적용이 되지 않아 한참 헤맸다. 해당 모듈을 import를 제대로 못한 문제였는데, 간단한 문제였지만 처음 접하다보니 어려웠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;707&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzXfoy/btrlNdq1jn7/NWZMO1nVJEkhNnkDrAWN9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzXfoy/btrlNdq1jn7/NWZMO1nVJEkhNnkDrAWN9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzXfoy/btrlNdq1jn7/NWZMO1nVJEkhNnkDrAWN9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzXfoy%2FbtrlNdq1jn7%2FNWZMO1nVJEkhNnkDrAWN9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1114&quot; height=&quot;707&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;707&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 폴리필 사용을 고민했다. 익숙하지 않기도 했고, 프로젝트에서 Object-fit 속성이 한 번밖에 사용되지&amp;nbsp;&amp;nbsp;않았기 때문에. Pollyfill을 사용하는 것은 성능 관점에서 비효율적인 것 아닌가 생각했다. 하지만 프로젝트 사이트 특성상 이미지를 많이 사용하기에 추후에 사이트의 확장성과 재사용성 관점에서 Object-fit-pollyfill을 사용해도 괜찮다고 생각해서 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Babel이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pollyfill을 공부하면서 바벨이라는 개념과 굉장히 많이 헷갈렸다. 바벨이란 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Babel은 트랜스파일러이다. ES6에서 쓰이는 최신 문법을 쓸 수 없기 때문에 ES5로 문법을 바꿔주는 역할을 한다. 하지만 Pollyfill은 변경된 표준을 준수할 수 있게 기존 함수의 동작 방식을 수정하거나 새롭게 구현을 해서 누락된 새로운 기능을 메꿔주는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 ES6에서 새롭게 등장한 Promise와 같이 ES5에서 변환할 수 있는 대상이 없는 경우엔 에러가 발생하기 때문에 이 경우엔 &lt;b&gt;Pollyfill&lt;/b&gt;이 사용된다. (예제를 보고 싶다면 reference에 pollyfill 예제라 메모한 사이트들을 참고해 보길 바란다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 프로젝트의 경우에서는 다음과 같은 화살표 함수가 사용됐다. 이는 ES6 문법인데 IE에서는 지원을 하지 않는다. 따라서 ES6 문법을 ES5로 변환해주어 동작하게 만들어 준다. 이를 Babel이 담당한다.&lt;/p&gt;
&lt;pre id=&quot;code_1637548877104&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ES6
const removeClassName = () =&amp;gt; {
  btn.classList.remove('is-active');
  list.classList.remove('is-active');
  title.classList.remove('is-active');
};

// ES5

var removeClassName = function () {
  btn.classList.remove('is-active');
  list.classList.remove('is-active');
  title.classList.remove('is-active');
};&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리한 내용들이 막상 프로젝트를 진행하면서는 생각이 잘 나지 않았다. 구현에만 힘을 쓰다보니 생각을 잘 못했던 것 같다. 굉장히 안좋은 버릇이고, 더 좋은 방법들을 생각해보는 연습을 하려고 노력하고 있다. 또한 Pollyfill을 공부하면서 Babel과 헷갈렸는데, 결국은 Babel과 Pollyfill과는 하는 역할이 다르지만 웹의 호환성을 관점에서 바라보면 큰 차이가 없는 기능들이라는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크로스 브라우징을 해결해보는 경험은 이전에 없었는데 한번 쯤은 꼭 필요한 것 같다. 크로스브라우징을 해결하면서 polyfill과 babel에 대해서 알게 됐고, IE가 왜 문제가 많은지 알 수 있었다. IE를 왜 아직도 사용하고 있는지는 아직도 모르겠지만, 생각보다 IE를 쓰는 곳은 많았다. ** 증권의 입사지원 페이지가 IE에서만 접속이 되던 기억이 있다.. 웹 팩이라는 개념도 정리하면서 Postcss와 Package.json에 대한 개념들도 정리해볼 계획이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 틀리거나 잘못된 내용이 있다면 댓글로 알려주세요. 감사합니다. :)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  Reference:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills&quot;&gt;https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://polyfill.io/v3/&quot;&gt;https://polyfill.io/v3/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/polyfills&quot;&gt;https://ko.javascript.info/polyfills&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://okchangwon.tistory.com/3&quot;&gt;https://okchangwon.tistory.com/3&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@kwonh/Babel-%ED%8F%B4%EB%A6%AC%ED%95%84polyfill-babelpreset-env&quot;&gt;https://velog.io/@kwonh/Babel-%ED%8F%B4%EB%A6%AC%ED%95%84polyfill-babelpreset-env&lt;/a&gt; (pollyfill 예제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://iancoding.tistory.com/175&quot;&gt;https://iancoding.tistory.com/175&lt;/a&gt; (pollyfill 예제)&lt;/p&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>Babel</category>
      <category>pollyfill</category>
      <category>크로스 브라우징</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/82</guid>
      <comments>https://minsoftk.tistory.com/82#entry82comment</comments>
      <pubDate>Sun, 7 Nov 2021 15:22:17 +0900</pubDate>
    </item>
    <item>
      <title>백준 14503번 : 로봇 청소기 (JavaScript)</title>
      <link>https://minsoftk.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1635687507451&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;14503번: 로봇 청소기&quot; data-og-description=&quot;로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N&amp;times;M 크기의 직사각형으로 나타낼 수 있으며, 1&amp;times;1크기의 정사각형 칸으로 나누어&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/14503&quot; data-og-url=&quot;https://www.acmicpc.net/problem/14503&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/susZr/hyMa7w0wPL/Dmgzkgy9JebHhhrfMKV1Pk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14503&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/14503&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/susZr/hyMa7w0wPL/Dmgzkgy9JebHhhrfMKV1Pk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;14503번: 로봇 청소기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N&amp;times;M 크기의 직사각형으로 나타낼 수 있으며, 1&amp;times;1크기의 정사각형 칸으로 나누어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;접근 방법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제에서 왼쪽 방향으로 회전하는 부분을 현재 청소기의 방향을 기준으로 좌표를 미리 구했다. 아래 코드처럼 0 : 북일 경우에는 왼쪽 방향인 서쪽 방향을 체크해야 한다. 따라서 현재 좌표에서 바라보고 있는 방향을 기준으로 왼쪽의 좌표를 구했다. 0,1,2,3 각각 방향의 왼쪽 좌표를 미리 선언해놨다.&lt;/li&gt;
&lt;li&gt;뒤로 한칸을 가야되는 경우도 미리 0,1,2,3 방향에 따라 뒤로 한칸의 좌표를 미리 구해놨다.&lt;/li&gt;
&lt;li&gt;만약 청소기가 0:북 방향을 바라볼 때, 왼쪽을 탐색 해야 된다면, turn[0]을 참조한다.&lt;/li&gt;
&lt;li&gt;만약 청소기가 0:북 방향을 바라볼 때, 뒤를 탐색 해야 된다면, back[0]을 참조한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1635687652245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 0 1 2 3 북 동 남 서
// 왼쪽 회전
let turn = [
		[0, -1],
		[-1, 0],
		[0, 1],
		[1, 0],
	];
// 후진
let back = [
    [1, 0],
    [0, -1],
    [-1, 0],
    [0, 1],
];​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;막혔던 부분&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모두 조건대로 잘 구해줬다고 생각했다. 하지만 반례를 찾는 부분에서 시간이 굉장히 오래걸렸다. 나중에 문제를 잘못 해석해서 코드가 제대로 구현이 되지 않았다. 헷갈린 문장은 아래와 같다. 아래 문장을 보고 &lt;b&gt;후진해야되는 좌표가 만약 청소가 되어 있다면 가지 못하는걸로 생각했다.&amp;nbsp;&lt;/b&gt;하지만 청소가 되어 있어도 벽이 아니라면 후진을 할 수 있다. 이 조건을 잘못 해석해서 굉장히 오랜시간 고민을 했다. 문제를 잘 해석하는 능력도 중요하다고 생각했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 구현&lt;/h2&gt;
&lt;pre id=&quot;code_1635688119904&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, m, robot, arr) {
	let answer = 1; // 로봇이 던져진 곳은 청소한 것으로 치므로 1로 선언
	let check = Array(n);
	for (let i = 0; i &amp;lt; check.length; i++) check[i] = Array(m).fill(0);

	// 0 1 2 3 북 동 남 서
	// 왼쪽 회전
	let turn = [
		[0, -1],
		[-1, 0],
		[0, 1],
		[1, 0],
	];
	// 후진
	let back = [
		[1, 0],
		[0, -1],
		[-1, 0],
		[0, 1],
	];

	let queue = []; // 로봇이 탐색하는 위치를 저장
	let path = robot[2]; // 로봇이 바라보는 방향을 저장

	// 로봇의 좌표를 queue에 넣는다.
	queue.push([robot[0], robot[1]]);
	// 로봇이 청소한 곳의 좌표를 방문 체크.
	check[robot[0]][robot[1]] = 1;

	// queue가 빌때까지 반복
	while (queue.length) {
		// 청소할 공간 탐색
		let front = queue.shift();
		let k = 0; // 4방향을 모두 탐색했을 때의 조건을 만들기 위한 변수
		let temp = path; // 4방향 모두 청소가 되어있을 때, 원래의 방향이 필요하다. 방향을 저장
		for (let i = 0; i &amp;lt; 4; i++) {
			// 왼쪽으로 회전 시켰을 때의 좌표값 xx, yy
			let xx = front[0] + turn[path][0];
			let yy = front[1] + turn[path][1];
			// 왼쪽으로 돌았을 때, -1을 해줘서 방향을 변경해준다. 북 -&amp;gt; 서
			path = path - 1;
			if (path === -1) path = 3;

			// 만약 청소할 수 있고 벽이 아니라면
			if (
				xx &amp;gt;= 0 &amp;amp;&amp;amp;
				yy &amp;gt;= 0 &amp;amp;&amp;amp;
				xx &amp;lt; n &amp;amp;&amp;amp;
				yy &amp;lt; m &amp;amp;&amp;amp;
				check[xx][yy] === 0 &amp;amp;&amp;amp;
				arr[xx][yy] !== 1
			) {
				// 회전한 방향을 queue에 넣어주고, 방문체크
				queue.push([xx, yy]);
				check[xx][yy] = 1;
				// 해당 칸을 청소 했으므로 +1을 해준다.
				answer++;
				// 한칸 씩을 탐색하기 위해서 break를 해준다.
				break;
			}
			k++;
		}

		// k가 4일 경우는, 모두 탐색했는데도 청소안한 곳을 못찾은 것이다.
		if (k === 4) {
			// 원래의 방향을 저장하고 있는 temp를 활용해 후진 좌표를 구한다.
			let back_x = front[0] + back[temp][0];
			let back_y = front[1] + back[temp][1];

			// 만약 후진 했을 때도 벽이라면 break를 해준다. 그러면 queue는 비어있는 상태다.
			// 경로를 하나씩만 넣어서 탐색했기 때문이다.
			if (arr[back_x][back_y] === 1) break;
			else {
				// 벽이 아니라면 후진한 칸을 방문체크해주고, queue에 넣어준다.
				check[back_x][back_y] = 1;
				queue.push([back_x, back_y]);
			}
		}
	}
	return answer;
}
console.log(solution(n, m, robot, arr));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/Boj</category>
      <category>로봇청소기</category>
      <category>백준</category>
      <category>백준 17140</category>
      <category>백준 자바스크립트</category>
      <category>자바스크립트</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/81</guid>
      <comments>https://minsoftk.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 31 Oct 2021 22:58:35 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 타겟 넘버 (DFS)(Java, JS)</title>
      <link>https://minsoftk.tistory.com/79</link>
      <description>&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43165&quot;&gt;타겟 넘버&lt;/a&gt;&lt;/h1&gt;
&lt;figure id=&quot;og_1634259468536&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 타겟 넘버&quot; data-og-description=&quot;n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다. -1+1+1+1+1 = 3 +1-1+1+1+&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43165&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43165&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PJCK0/hyLXt3jVWT/iWvfTTFXG7N0kNkgEtEKc1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/mFRaT/hyLXyjhey0/xDlZRBFAn3IVG9sRSxVMMK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43165&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43165&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PJCK0/hyLXt3jVWT/iWvfTTFXG7N0kNkgEtEKc1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/mFRaT/hyLXyjhey0/xDlZRBFAn3IVG9sRSxVMMK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 타겟 넘버&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다. -1+1+1+1+1 = 3 +1-1+1+1+&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n개의 음이 아닌 정수가 있습니다. 이 수를 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 return 하도록 solution 함수를 작성해주세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제한사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어지는 숫자의 개수는 2개 이상 20개 이하입니다.&lt;/li&gt;
&lt;li&gt;각 숫자는 1 이상 50 이하인 자연수입니다.&lt;/li&gt;
&lt;li&gt;타겟 넘버는 1 이상 1000 이하인 자연수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;내 풀이&amp;nbsp;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DFS - JavaScript&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(numbers, target) {
    let answer = 0;
    let sum = 0; 
    let cnt = 0; // target을 만드는데 성공한 가지 수 저장 변수
    
    // DFS 시작
    function DFS(L, sum){
        if (L === numbers.length) { // 만약 Level이 0 ~ numbers.length - 1 이후일 때.
            if (sum === target){ // sum과 target이 같다면 가지 수 +1
                cnt++;
            }
        }else {
            // 이진트리 부모에서 numbers[L]을 더해주는 왼쪽 자식 생성
            // index엔 L을 넣어준다. for문 써야되는 순열이나 조합이랑 구별 잘하기.
            DFS(L+1, sum + numbers[L]);
            
            // 루트 노드에서 number[L] 만큼의 값을 빼서 오른쪽 자식 노드 생성
            DFS(L+1, sum - numbers[L]);    
            
            // 이후에 이진 트리에서 if문에 설정한 L까지 모든 조건을 탐색한다.
        }
    }
    
    // Level은 0부터 시작, 타겟넘버와 비교를 위한 sum을 0으로 입력
    DFS(0, 0);
    answer = cnt;
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DFS - JAVA&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;class Solution {
    int answer = 0;

    public int solution(int[] numbers, int target) {
        DFS(0,0,numbers,target);
        return answer;
    }

    private void DFS(int L, int sum, int[] numbers, int target)
    {
        if (L == numbers.length)
        {
            if (sum == target)
            {
                answer++;
                return ;
            }
        }
        else
        {
            int temp;
            temp = sum + numbers[L];
            DFS(L + 1, temp, numbers, target);
            temp = sum - numbers[L];
            DFS(L + 1, temp, numbers, target);
        }

    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/Programmers</category>
      <category>dfs</category>
      <category>Java</category>
      <category>JavaScript</category>
      <category>타겟넘버</category>
      <category>프로그래머스</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/79</guid>
      <comments>https://minsoftk.tistory.com/79#entry79comment</comments>
      <pubDate>Fri, 15 Oct 2021 09:59:20 +0900</pubDate>
    </item>
    <item>
      <title>[JS - 알고리즘] 03. 투포인터 알고리즘(슬라이딩 윈도우)</title>
      <link>https://minsoftk.tistory.com/78</link>
      <description>&lt;h1&gt;투 포인터 알고리즘, 슬라이싱 윈도우&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 문자열과 해싱이나 1차원 배열 같은 경우 구현 문제들이었다.(물론 효율적으로 풀어야 되는 문제들도 있었다.) 현재 투 포인터 알고리즘 카테고리를 학습하면서 수학적인 사고가 필요한 부분들이 많아졌다. 이전엔 문제에 주어진대로 풀다 보니 시간 복잡도를 생각하지 못했다. O(N&lt;sup&gt;3&lt;/sup&gt;)까지 쓰면서 문제를 해결에만 집중했다. 하지만 알고리즘 스터디와 공부를 진행하다 보니 어려운 문제를 굉장히 수학적인 방법으로 간단하게 푸는 방식을 보면서, 알고리즘이 왜 중요한지 알 수 있었다. 이제는 O(N&lt;sup&gt;3&lt;/sup&gt;)을 어떻게 O(N)으로 풀어낼 것인가를 조금이나마 고민하게 됐다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;N의 조건이 100,000 정도가 넘어갈 때, 시간복잡도가 N&lt;sup&gt;2&lt;/sup&gt;이 되면 문제가 생길 수도 있다. (&lt;a href=&quot;https://jeleedev.tistory.com/70&quot;&gt;참고&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;따라서 더욱 효율적으로 문제를 해결하기 위해서 사용하는 방법들이 있다. &lt;a href=&quot;https://blog.fakecoding.com/archives/algorithm-slidingwindow/&quot;&gt;슬라이싱 윈도우란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;투 포인터와 슬라이싱 윈도우는 구간을 훑으면서 지나간다는 공통점이 있으나, 슬라이딩 윈도우는 어느 순간에도 그 구간의 넓이가 동일하다는 차이점이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 최대 매출&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(nums, k) {
    let max = 0;
    let sum = 0;
    let start = 0,
        end = 0;
    for (let i = 0; i &amp;lt; nums.length; i++) {
        sum += nums[i];
        end++;
        
        // 만약 end, start 거리가 k 보다 커지면
        if (end - start &amp;gt; k) {
            // start의 값을 빼주고 idx ++
            sum -= nums[start];
            start++;
            max = Math.max(max, sum);
        }
    }
    return max;
}

console.log(solution([12, 15, 11, 20, 25, 10, 20, 19, 13, 15], 3));
console.log(solution([1, 2, 3, 5, 6, 7, 1, 3, 9], 5));
console.log(solution([12, 34, 56, 72, 93, 121, 33, 11, 23, 52], 4));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 매출액의 종류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(nums, k) {
    let answer = [];
    let arr = [];
    let start = 0,
        end = 0;
    let max = 0;
    for (let i = 0; i &amp;lt; nums.length; i++) {
        arr.push(nums[i]);
        end++;
        if (end - start &amp;gt;= k &amp;amp;&amp;amp; start &amp;lt;= nums.length - k) {
            let set = new Set();
            for (let x of arr) {
                set.add(x);
            }
            answer.push(set.size);
            arr = arr.slice(1, arr.length);
            start++;
        }
    }
    return answer;
}

console.log(solution([20, 12, 20, 10, 23, 17, 10], 4));
console.log(solution([1, 2, 3, 2, 2, 3, 3, 3, 3, 2], 3));&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution2(nums, k) {
    let answer = [];
    let nh = new Map();
    let len = nums.length;
    for (let i = 0; i &amp;lt; k - 1; i++) {
        nh.set(nums[i], (nh.get(nums[i]) || 0) + 1);
    }

    let left = 0;
    for (let right = k - 1; right &amp;lt; nums.length; right++) {
        //k 개수에 맞게 right idx값 해시에 입력
        nh.set(nums[right], (nh.get(nums[i]) || 0) + 1);
        //size를 answer에 넣는다. 중복되지 않는다.
        answer.push(nh.size);
        //left idx 값을 해쉬에서 빼준다.
        nh.set(nums[left], nh.get(nums[left]) - 1);
        //만약 빼고 나서 val 값이 0이라면 해시에서 제거한다.
        if (nh.get(nums[left]) === 0) nh.delete(nums[left]);
        left++;
    }
    return answer;
}
console.log(solution([20, 12, 20, 10, 23, 17, 10], 4));
console.log(solution([1, 2, 3, 2, 2, 3, 3, 3, 3, 2], 3));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 연속 부분 수열-1&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(nums, m) {
    let start = 0, end=0,
        sum = 0,
        answer = 0;
    while (start &amp;lt;= end &amp;amp;&amp;amp; end &amp;lt;= nums.length) {
        if (sum === k) {
            cnt++;
            sum -= nums[start];
            start++;
        } else if (sum &amp;gt; k &amp;amp;&amp;amp; start &amp;lt;= end) {
            // 만약 1 1 1 3 100 경우?
            //앞에 원소 빼준다.
            sum -= nums[start];
            start++;
        } else {
            //뒤에 원소 추가 해준다.
            sum += nums[end];
            end++;
        }
    }
    return answer;
}

console.log(solution([1, 2, 1, 3, 1, 1, 1, 2], 6));
console.log(solution([1, 1, 1, 1, 1, 1], 3));
console.log(solution([1, 2, 1, 2, 1, 2, 1], 3));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;풀이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;for문을 이용해 right를 돌리는 방식을 사용하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(nums, m) {
    let left = 0,
        sum = 0,
        answer = 0;

    for (let right = 0; right &amp;lt; nums.length; right++) {
        // 0부터 시작하므로 right idx를 이용해 sum에 더해준다.
        sum += nums[right];
        // sum 값이 m 보다 커졌을 때
        while (sum &amp;gt; m) {
            //left idx 값을 빼주고, +1 증가
            sum -= nums[left++];
        }
        // 만약 sum이 m 일때, answer 증가
        if (sum === m) answer++;
    }
    return answer;
}

console.log(solution([1, 2, 1, 3, 1, 1, 1, 2], 6));
console.log(solution([1, 1, 1, 1, 1, 1], 3));
console.log(solution([1, 2, 1, 2, 1, 2, 1], 3));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 연속 부분 수열-2&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 어려웠던 문제. 정확한 이해를 바탕으로 다른 곳에서도 사용할 줄 알아야 한다.&lt;/li&gt;
&lt;li&gt;sum에 nums[i]를 차례대로 누적해나간다. 그러다 i번째에서 만약 &lt;code&gt;(sum-m)&lt;/code&gt;의 key값이 존재한다면, key의 value만큼 m=3을 만드는 방법이, &lt;code&gt;+nums[i]&lt;/code&gt;를 한 부분에도 value만큼 존재한다는 의미이다.&lt;/li&gt;
&lt;li&gt;즉 m=3 인 경우, for문을 돌면서 sum = 6 이 됐을 때, (key=3, value=2)가 해시에 있다면 &lt;code&gt;(sum-m = 3)&lt;/code&gt;을 만족한다. 해시의 3인 key값을 조회하고 value 값인 2를 추가로 더해준다. 이는 +nums[i]를 sum에 더했을 때 일어난 경우다. 따라서 반대쪽으로도 m=3을 만들어주는 2가지 방법이 존재한다는 의미이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(nums, m) {
    let answer = 0,
        sum = 0;

    let hash = new Map();
    for (let i = 0; i &amp;lt; nums.length; i++) {
        sum += nums[i];
        if (sum === m) answer++;
        
        // 만약 sum - m에 key를 가진다면, (sum - m) key의 value만큼 
        // sum에서도 m을 만드는 방법이 존재한다는 의미. 이 부분이 생각하기 어렵다.
        if (hash.has(sum - m)) answer += hash.get(sum - m);
        hash.set(sum, (hash.get(sum) || 0) + 1);
    }
    return answer;
}

console.log(solution([1, 2, 3, -3, 1, 2], 3));
console.log(solution([-1, 0, 1], 0));
console.log(solution([-1, -1, -1, 1], 0));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 연속 부분 수열 3&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연속된 부분 수열이기 때문에 &lt;code&gt;right - left + 1&lt;/code&gt; 을 쓰게 된다면, 해당 숫자를 포함한 수열까지 포함하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(nums, m) {
    let left = 0,
        sum = 0,
        answer = 0;

    for (let right = 0; right &amp;lt; nums.length; right++) {
        // sum에 right idx 값 더해주며 +1 증가시킨다.
        sum += nums[right];
        // sum이 m보다 커지면 left idx값 빼주고, 증가시킨다.
        while (sum &amp;gt; m) {
            sum -= nums[left++];
        }
        // 현재 sum &amp;lt;= m을 만족하는 상태, 그러면 nums[right]를 더했을 때 만족한다는 의미다.
        // 이는 nums[right] 값도 m보다 작다는 의미이고, 현재까지의 sum도 m보다 작다는 의미이다.
        // 따라서 아래의 식이 만족하게 된다. 연속부분수열이라 가능한 부분
        answer += right - left + 1;
    }
    return answer;
}

console.log(solution([1, 3, 1, 2, 3], 5)); //10
console.log(solution([1, 1, 1, 1, 1, 1], 3)); //15
console.log(solution([1, 1, 2, 2, 1, 2, 1, 3, 2], 5)); //22&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 연속된 자연수의 합&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(num) {
    let sum = 0,
        answer = 0,
        len = 0;

    // 나누기를 했을때 소수점 없애기 위해 parseInt를 사용.
    len = parseInt(num / 2) + 1;
    let arr = [];

    // 1번 idx부터 1을 입력해준다.
    for (let i = 1; i &amp;lt;= len; i++) {
        arr[i] = i;
    }

    // 1부터 시작
    let left = 1;
    for (let right = 1; right &amp;lt;= len; right++) {
        sum += arr[right];

        // 만약 sum이 num보다 커졌을때 left값 빼주고 인덱스 증가시킨다.
        while (sum &amp;gt; num) {
            sum -= arr[left++];
        }

        // num과 sum이 같다면 answer++ 
        if (sum === num) {
            answer++;
        }
    }

    return answer;
}

console.log(solution(15));
console.log(solution(45678));
console.log(solution(98765));&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 알고리즘을 학습하면서 &lt;code&gt;연속 부분 수열 2번&lt;/code&gt; 다음으로 가장 수학적인 사고가 반영되지 않았나 싶다. N을 표현하는 가짓수를 표현하기 위해 연속된 숫자 1, 2를 먼저 뽑았다면 &lt;code&gt;cnt=2&lt;/code&gt;이다. 그다음 N에서 cnt를 뺀다. 그러면 &lt;code&gt;N - (1 + 2)&lt;/code&gt; 과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 입력된 숫자의 개수 &lt;code&gt;cnt = 2&lt;/code&gt; 나누었을 때 나누어 떨어진다면, 연속된 숫자 1, 2가 해당 &lt;code&gt;N- (1 + 2)&lt;/code&gt;를 나눠가질 수 있다. 따라서 &lt;code&gt;N= 15&lt;/code&gt;일 때 연속된 숫자에 &lt;code&gt;N- (1 + 2) / 2 = 6&lt;/code&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 1, 2에 각각 6을 더한다면 &lt;code&gt;7 + 8 = 15&lt;/code&gt; 가 된다. 이런 방식으로 다음과 같이 짤 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution2(n) {
    let answer = 0;

    // 1부터 시작한다. cnt = 1
    cnt = 1;
    // 1부터 시작하기에 N에서 1을 먼저 빼준다.
    n--;

    // n이 0보다 클때만 
    while (n &amp;gt; 0) {
        // cnt가 2부터 시작한다.
        cnt++;

        // 이미 1은 빼져 있는 상태
        // 따라서 cnt = 2인 경우, n에서 cnt를 빼준다.
        n -= cnt;
        // 나누어 떨어진다면 1, 2가 N-(1+2)를 나눠가질 수 있다.
        if (n % cnt == 0) answer++;
    }
    return answer;
}
console.log(solution(15));
console.log(solution(45678));
console.log(solution(98765));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 모든 아나그램 찾기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;left는 이제 비교하지 않으므로 s[left] key의 value 값을 1 감소시킨다.&lt;/code&gt; 이 부분이 이해하기 힘들었다. 해시의 응용문제.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;function solution(s, m) {
    let answer = 0;
    let hash = new Map();

    // 부분 문자열을 hash에 -1로 저장하기
    // 슬라이딩 윈도우를 이용하여 아나그램을 찾는다.
    for (let x of m) {
        hash.set(x, (hash.get(x) || 0) - 1);
    }

    /* 부분 문자열의 길이 - 1을 해시에 넣는다.(이땐 value를 +1로 set을 한다.) 
    동작 후, value가 0이 되는 key값은 제거해준다.
    key의 vlaue가 0인 경우는 아나그램 조건인 부분 문자열 하나를 충족했다는 의미이다.
    */
    let len = m.length - 1;
    for (let i = 0; i &amp;lt; len; i++) {
        //  1~(비교할 문자열의 길이 -1) 해시에 등록
        hash.set(s[i], (hash.get(s[i]) || 0) + 1);
        if (hash.get(s[i]) === 0) hash.delete(s[i]);
    }

    /* 3번째 문자를 추가했을 때, 아나그램을 만족했다면 모든 해시 key의 value가 0이 된다.
    size=0인 경우, 아나그램 부분 문자열 개수 추가를 해준다.
    */
    let left = 0;
    for (let right = len; right &amp;lt; s.length; right++) {
        // 부분문자열 마지막 개수를 해시에 등록
        hash.set(s[right], (hash.get(s[right]) || 0) + 1);
        // 만약 해시의 value가 0이 되었다면, 해시에서 삭제해준다.
        // 삭제해주는 이유는 0도 size에 포함되기 때문에 1로 카운트 된다. size가 0일때, 아나그램을 만족한다.
        if (hash.get(s[right]) === 0) hash.delete(s[right]);
        if (hash.size === 0) answer++;

        // left는 이제 비교하지 않으므로 s[left] key의 value 값을 1 감소시킨다.         
        hash.set(s[left], (hash.get(s[left]) || 0) - 1);
        if (hash.get(s[left]) === 0) hash.delete(s[left]);
        left++;
    }
    return answer;
}

console.log(solution('bacacbcba', 'abc'));
console.log(solution('bacaAacba', 'abc'));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/JavaScript 알고리즘</category>
      <category>hash</category>
      <category>슬라이딩윈도우</category>
      <category>아나그램</category>
      <category>알고리즘</category>
      <category>연속부분수열</category>
      <category>투포인터</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/78</guid>
      <comments>https://minsoftk.tistory.com/78#entry78comment</comments>
      <pubDate>Mon, 11 Oct 2021 04:11:21 +0900</pubDate>
    </item>
    <item>
      <title>[JS - 알고리즘] 02. 1차원 배열</title>
      <link>https://minsoftk.tistory.com/77</link>
      <description>&lt;h1&gt;1차원 배열&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;01. 수열 축소&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/slice&quot;&gt;slice&lt;/a&gt; : &lt;code&gt;slice()&lt;/code&gt; 메서드는 어떤 배열의 &lt;code&gt;begin&lt;/code&gt;부터 &lt;code&gt;end&lt;/code&gt;까지(&lt;code&gt;end&lt;/code&gt; 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt;음수 인덱스는 배열의 끝에서부터의 길이를 나타냅니다. &lt;code&gt;slice(-2)&lt;/code&gt; 는 배열에서 마지막 두 개의 엘리먼트를 추출합니다.&lt;code&gt;begin&lt;/code&gt;이 배열의 길이보다 큰 경우에는, 빈 배열을 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt;이 &lt;code&gt;undefined&lt;/code&gt;인 경우에는, 0번 인덱스부터 &lt;code&gt;slice&lt;/code&gt; 합니다.&lt;/li&gt;
&lt;li&gt;0을 시작으로 하는 추출 시작점에 대한 인덱스를 의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt;예를 들어, &lt;code&gt;slice(1,4)&lt;/code&gt;는 두번째 요소부터 네번째 요소까지 (1, 2 및 3을 인덱스로 하는 요소) 추출합니다.&lt;code&gt;end&lt;/code&gt;가 생략되면 &lt;code&gt;slice()&lt;/code&gt;는 배열의 끝까지(&lt;code&gt;arr.length&lt;/code&gt;) 추출합니다.&lt;/li&gt;
&lt;li&gt;만약 &lt;code&gt;end&lt;/code&gt; 값이 배열의 길이보다 크다면, &lt;code&gt;silce()&lt;/code&gt;는 배열의 끝까지(&lt;code&gt;arr.length&lt;/code&gt;) 추출합니다.&lt;/li&gt;
&lt;li&gt;음수 인덱스는 배열의 끝에서부터의 길이를 나타냅니다. 예를들어 &lt;code&gt;slice(2,-1)&lt;/code&gt; 는 세번째부터 끝에서 두번째 요소까지 추출합니다.&lt;/li&gt;
&lt;li&gt;추출을 종료 할 0 기준 인덱스입니다. &lt;code&gt;slice&lt;/code&gt; 는 &lt;code&gt;end&lt;/code&gt; 인덱스를 제외하고 추출합니다.&lt;/li&gt;
&lt;li&gt;반환 값&lt;/li&gt;
&lt;li&gt;추출한 요소를 포함한 새로운 배열.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(s, m) {
    let answer;
    for (let i = m; i &amp;gt; 0; i--) {
        for (let j = 1; j &amp;lt; s.length; j++) {
            s[j - 1] = s[j] - s[j - 1];
        }
    }
    //0에서 m번만큼의 길이로 잘라준다.
    s = s.slice(0, s.length - m);
    console.log(s);

    return answer;
}

console.log(solution([5, 3, 7, 9, -2], 1));
console.log(solution([5, 3, 7, 9, -2], 2));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;02. 제곱수 정렬&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오름차순 정렬한 배열이기 때문에, left, right 투 포인터를 사용해 절대값이 더 큰 숫자를 제곱해준 다음에 새로운 배열에 넣어준다. 그러면 sort()를 할 필요가 없다. sort를 최대한 사용하지 않으려는 이유는 &lt;a href=&quot;https://jeleedev.tistory.com/70&quot;&gt;시간복잡도&lt;/a&gt; 때문이다.&lt;/li&gt;
&lt;li&gt;N의 제한 조건이 10만이 넘어간다면 최대한 O(n)으로 짜주자.&lt;/li&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;function solution(s) {
    let answer;
    let left = 0,
        right = s.length - 1;
    let arr = Array(s.length).fill(0);
    let pos = s.length - 1;

    //left보다 right가 클 경우에만 loop
    while (left &amp;lt;= right) {

        //절대값이 left가 더 큰 경우
        if (Math.abs(s[left]) &amp;gt; Math.abs(s[right])) {
            // 큰 값을 찾았을 때, pos idx에 값을 넣어주고
            //left idx는 증가시켜주고, pos idx는 감소시켜 준다.
            arr[pos] = s[left] * s[left];
            left++;
            pos--;

          // 절대값이 right가 더 큰 경우, 
        } else if (Math.abs(s[left]) &amp;lt; Math.abs(s[right])) {
            arr[pos] = s[right] * s[right];
            right--;
            pos--;
        } else {
            arr[pos] = s[right] * s[right];
            right--;
            pos--;
        }
    }
    console.log(arr);
    return answer;
}

console.log(solution([-4, -1, 0, 3, 10])); //[0, 1, 9, 16, 100]
console.log(solution([-7, -3, 2, 3, 11])); //[4, 9, 9, 49, 121]&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;03. 수열의 높이 조정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열을 탐색하면서 최댓값과 최솟값을 찾는다. 연속된 수열이 아니기에 사용된 수열의 값을 &lt;code&gt;arr&lt;/code&gt;에 저장해준다.&lt;/li&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lua&quot;&gt;&lt;code&gt;function solution(s, m) {
    let answer;
    let arr = Array(1000).fill(0);
    let max = -2147000000;
    let min = 2147000000;

    //최대값과 최소값을 찾아준다.
    for (let i = 0; i &amp;lt; s.length; i++) {
        if (max &amp;lt; s[i]) max = s[i];
        if (min &amp;gt; s[i]) min = s[i];
    }

    // 사용되는 값을 +1 해준다.
    for (let i = 0; i &amp;lt;= max; i++) {
        arr[s[i]] += 1;
    }

    // 입력 받은 m만큼 명령 수행
    for (let i = m; i &amp;gt; 0; i--) {
        // min === max일 경우 다 같은 경우이므로 return 0.
        if (min === max) return 0;

           // 가장 큰 값이 1일때, max-1의 값을 max 값으로 만들어줘야 한다.
        // max 값의 변화를 위해서 증감연산자를 사용
        if (arr[max] === 1) {
            arr[max]--;
            max--;
            arr[max]++;
        } else {
            // max 값의 idx가 1이 아니면 1보다 큰 경우밖에 없다.
            // 위와는 달리 max의 값이 변화하지 않았다.
            arr[max]--;
            arr[max - 1]++;
        }
        // 가장 작은 값이 1일때, min + 1의 값을 min 값으로 만들어줘야 한다.
        // min 값의 변화를 위해서 증감연산자를 사용
        if (arr[min] === 1) {
            arr[min]--;
            min++;
            arr[min]++;
        } else{ 
            // min 값의 idx가 1이 아니면 1보다 큰 경우밖에 없다.
            // 위와는 달리 min의 값이 변화하지 않았다.
            arr[min]--;
            arr[min + 1]++;
        }
    }
    // 높이값 return
    return max - min;
}

console.log(solution([2, 1, 3, 7, 5], 2));
console.log(solution([69, 42, 68, 76, 40, 87, 14, 65, 76, 81], 50));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;04. 가장 높은 증가수열&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 높은 차를 누적하는 문제.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(arr) {
    let answer = 0;
    let height = 0;

    for (let i = 1; i &amp;lt; arr.length; i++) {
        // 증가하는 수열이라면 height에 저장한다.
        if (arr[i - 1] &amp;lt; arr[i]) {
            height += arr[i] - arr[i - 1];
        } else {
            //증가하는 수열이 아닐때, 최대값을 answer에 집어넣는다.
            answer = Math.max(answer, height);
            height = 0;
        }
    }
    //for문이 끝나고 나서도 최대값을 저장해줘야 한다.
    answer = Math.max(answer, height);
    return answer;
}

console.log(solution([5, 2, 4, 7, 7, 3, 9, 10, 11]));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 가장 긴 수열&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function solution(nums) {
    let answer;
    let minus_cnt = 1;
    let plus_cnt = 1;
    let p_max = -2147000000;
    let m_max = -2147000000;


    for (let i = 1; i &amp;lt; nums.length; i++) {
        // 증가수열일때 증가cnt를 + 1
        if (nums[i - 1] &amp;lt; nums[i]) {
            plus_cnt++;
        } else { // 증가가 아닐 경우, 길이가 최대라면 p_max에 저장하고 cnt를 1로 초기화
            p_max = Math.max(p_max, plus_cnt);
            plus_cnt = 1;
        }
        // 감소수열일때 감소cnt를 +1
        if (nums[i - 1] &amp;gt; nums[i]) {
            minus_cnt++;
        } else { // 감소가 아닐 경우, 길이가 최대라면 m_max에 저장하고 cnt를 1로 초기화
            m_max = Math.max(m_max, minus_cnt);
            minus_cnt = 1;
        }
        // if문에서 plus_cnt가 증가하고 나온 경우일수도 있다.
        // 따라서 최대값을 또 한번 정해준다.
        p_max = Math.max(p_max, plus_cnt);
        m_max = Math.max(m_max, minus_cnt);
        answer = Math.max(p_max, m_max);
    }

    return answer;
}

console.log(solution([5, 3, 6, 7, 9, 8, 5, 3, 1, 2]));
console.log(
    solution([1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15])
);&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 바이토닉 수열&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바이토닉 수열이란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연속적으로 증가하는 수열과 감소하는 수열이 함께 존재하는 것을 바이토닉 수열이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(nums) {
    let answer = 'YES';
    let n = nums.length;
    let i = 0;
    // 증가하는 수열이면 i를 계속 증가
    while (i + 1 &amp;lt; n &amp;amp;&amp;amp; nums[i] &amp;lt; nums[i + 1]) i++;
    // 증가하고 나서도 i가 0이거나 수열 끝에 다다르면 바이토닉 수열이 아니다.
    if (i === 0 || i === n - 1) answer = 'NO';

    // 감소하는 수열이면 i를 계속 증가
    while (i + 1 &amp;lt; n &amp;amp;&amp;amp; nums[i] &amp;gt; nums[i + 1]) i++;
    // 만약 i가 nums의 끝에 다다르지 않는다면 바이토닉 수열이 아니다.
    if (i !== n - 1) answer = 'NO';

    return answer;
}

console.log(solution([1, 2, 3, 4, 5, 3, 1]));
console.log(solution([1, 3, 4, 5, 5, 6, 4, 3]));
console.log(solution([1, 2, 3, 4, 5]));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 거리두기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음에 생각하는 것이 좀 어려웠다. ch라는 임시 배열을 활용해 O(n)의 시간복잡도로 풀어낸다.&lt;/li&gt;
&lt;li&gt;사람이 있는 곳을 만나면 ch 배열에서 0으로 바꿔준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;// - 앞에서부터 한번, 뒤에서부터 한번 쭉 2번 탐색을 해준다.
// - distance를 0으로 바꾼다. 0을 만나면 ++ -&amp;gt; 왼쪽 사람으로부터 떨어진 거리
// - 왜 distance를 1000으로 주는가? 1000 distance 설정을 해야 시작 부분에서 사람이 없을 경우에 1000으로 설정이 되서 나중에 거리 값을 측정할 때 min값으로 변경이 되게 된다.
function solution(nums) {
    let answer;

    // 임시 저장공간 ch배열 생성
    let ch = Array(nums.length).fill(0);

    // nums를 탐색하면서 사람이 있는 곳은 값을 0으로 설정해준다.
    // 처음 시작할 때 사람이 없는 경우가 있으므로, 초기 distance 1000이 입력된다.
    // 그래서 다시 되돌아올 때, min연산으로 거리 값을 제대로 입력해줄 수 있다.
       let distance = 1000;
    for (let i = 0; i &amp;lt; nums.length; i++) {
        if (nums[i] === 1) {
            ch[i] = 0;
            distance = 1;
        } else {
            ch[i] = distance;
            distance++;
        }
    }

    // 이번엔 배열의 끝에서부터 다시 처음으로 탐색한다.
    // 마찬가지로 distance를 1000으로 해준다.
    distance = 1000;
    for (let i = nums.length - 1; i &amp;gt;= 0; i--) {
        if (nums[i] === 1) {
            ch[i] = 0;
            distance = 1;
        } else {
            // 기존의 ch배열에 입력된 distance 값과 비교해서 최소값을 입력
            ch[i] = Math.min(distance, ch[i]);
            distance++;
        }
    }

    answer = -10;
    for (let x of ch) {
        // 요소들 중에서 가장 큰 값이 거리이다.
        answer = Math.max(x, answer);
    }
    return answer;
}

console.log(solution([1, 0, 0, 0, 1, 0, 0, 1, 0, 1]));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 빈도수 구하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해시를 이용해서 간단하게 풀 수가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;function solution(arr, k) {
    let hash = new Map();

    // x 요소가 해시에 존재한다면, 해시에 값 등록
    for (let x of arr) {
        // 만약 기존의 해시에 값이 존재한다면, value 값을 +1
        if (hash.has(x)) {
            hash.set(x, hash.get(x) + 1);
        } else { // 만약 기존의 해시에 값이 없다면, 해시에 등록
            hash.set(x, (hash.get(x) || 0) + 1);
        }
    }

    // sort의 compare 파라미터를 이용해 해시의 value 값을 기준으로 정렬시킨다.
    let temp = [...hash].sort((a, b) =&amp;gt; b[1] - a[1]);

    // 정렬된 value 기준으로 k개만큼 answer 배열에 넣어준다.
    let answer = [];
    for (let i = 0; i &amp;lt; k; i++) {
        answer.push(temp[i][0]);
    }

    return answer;
}

console.log(solution([1, 1, 1, 2, 2, 3], 2));
console.log(solution([3, 3, 3, 5, 1, 1, 1, 7, 2, 2], 3));&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 아나그램&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;undefined와 null은 자동으로 Number로 형변환된다.&lt;/li&gt;
&lt;li&gt;자세한 내용은 &lt;a href=&quot;https://kamang-it.tistory.com/entry/JavaScript09undefined%EC%99%80-null-%EA%B7%B8%EB%A6%AC%EA%B3%A0-NaN-%EC%9D%B4%EC%83%81%ED%95%9C-%EC%82%BC%EA%B0%81%EA%B4%80%EA%B3%84-feat-boolean%EA%B9%8C%EC%A7%80-4%EA%B0%81-%EA%B4%80%EA%B3%84&quot;&gt;이곳&lt;/a&gt;을 참고&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;console.log(typeof null); //object
console.log(typeof undefined); //undefined
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN

console.log(undefined || 0); // 0
console.log(null || 0); // 0

console.log(undefined || 10); //10
console.log(null || 5); //5

console.log(null || true); // true
console.log(undefined || true); // true

console.log(null || false); // false
console.log(undefined || false); // false&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;function solution(str1, str2) {
    let answer = 'YES';
    let temp;
    let hash = new Map();
    let hash2 = new Map();

    // hash에 str1를 등록한다.
    for (let i = 0; i &amp;lt; str1.length; i++) {
        // hash.get(str1[i])d에 값이 없다면 undefined, undefined || 0 연산은 0이 나온다. 
        hash.set(str1[i], (hash.get(str1[i]) || 0) + 1);
    }

    // hash2에 str2를 등록한다.
    for (let i = 0; i &amp;lt; str2.length; i++) {
        hash2.set(str2[i], (hash2.get(str2[i]) || 0) + 1);
    }

    // hash2가 key 값을 가지고 있고, val 값이 똑같다면 continue,
    // 다르면 NO를 출력
    for (let [key, val] of hash) {
        if (hash2.has(key)) {
            if (val === hash2.get(key)) {
                continue;
            } else {
                answer = 'NO';
                break;
            }
        }
    }
    return answer;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 문자열 구분하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 1번째 방법
function solution(s) {
    let answer, i;

    // s[0]의 문자 길이만큼 for문 실행
    for (i = 0; i &amp;lt; s[0].length; i++) {
        let hash = new Map();
        let flag = true;

        // s가 가지고 있는 요소의 개수만큼 실행
        for (let j = 0; j &amp;lt; s.length; j++) {
            // 각각의 요소에서 s[0]의 길이인 i 만큼 substring을 실시한다.
            let x = s[j].substring(0, i + 1);
            // 만약 hash에 substring한 key가 있다면 false하고 탈출!
            if (hash.has(x)) {
                flag = false;
                break;
            }
            // key값이 없다면 hash에 key를 등록한다.
            hash.set(x, 1);
        }

        // 2번째 for문이 끝나고도 flag가 true라면 첫번째부터 일치하지 않으므로 break
        if (flag) break;
    }

    // se  se   se  까지 일치하는 것이므로 +1을 해준다.
    answer = i + 1;
    return answer;
}

console.log(solution(['seeasue', 'sesseysu', 'semeas']));
console.log(solution(['ackky', 'kabck', 'yokkcs']));
console.log(solution(['longlong', 'longtong', 'longbig']));
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2번째 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 2번째 방법
function solution2(s) {
    let answer, i;
    for (i = 0; i &amp;lt; s[0].length; i++) {
        // set 자료형을 이용한다.
        let set = new Set();
        for (let j = 0; j &amp;lt; s.length; j++) {
            // s의 요소들을 i번째까지 substring하고 set에 등록한다.
            let x = s[j].substring(0, i + 1);
            set.add(x);
            // 만약 set의 size가 1이 아니라면 일치하지 않는 경우이다.
            if (set.size !== 1) return i + 1;
        }
    }
    return 1;
}


console.log(solution(['seeasue', 'sesseysu', 'semeas']));
console.log(solution(['ackky', 'kabck', 'yokkcs']));
console.log(solution(['longlong', 'longtong', 'longbig']));&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/JavaScript 알고리즘</category>
      <category>1차원배열</category>
      <category>hash table</category>
      <category>JS</category>
      <category>js hash</category>
      <category>JS알고리즘</category>
      <category>set</category>
      <category>자바스크립트</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/77</guid>
      <comments>https://minsoftk.tistory.com/77#entry77comment</comments>
      <pubDate>Sun, 10 Oct 2021 01:53:28 +0900</pubDate>
    </item>
    <item>
      <title>[JS - 알고리즘] 01. 문자열 해싱</title>
      <link>https://minsoftk.tistory.com/76</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;21.10.28 오타, 내용 수정&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 문자열 해싱&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;01. 문자열 압축&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 접근:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 idx와 그 다음 idx 값이 같을 때, cnt의 개수를 for문으로 구해주고 answer에 str[i]와 String(cnt)를 붙여주는 방식으로 하려 했다. 하지만 계속 원치 않는 문자열이 추가가 됐다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;풀이 :
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어느 부분에서 오류가 발생하는지 생각하기 어려웠다. 그 이유는 입력받은 문자열에서 직접 몇 번째 idx에 접근하는지를 처리하려고 하니 어려웠던 것 같다. 대신 cnt만 세주고 문자가 달라질 때, 새로운 문자열에 넣는 방식으로 생각하니 for문에서 처리하는 로직이 간단해졌다. &lt;b&gt;JS에서는 새로운 배열에 필요한 값만 넣는다고 생각하면 쉽다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = '';

    for (let i = 0; i &amp;lt; str.length; i++) {
        let cnt = 1;
        if (str[i] === str[i + 1]) {
            for (let j = i + 1; j &amp;lt; str.length; j++) {
                if (str[i] === str[j]) cnt++;
            }
            console.log('cnt', cnt);
            if (cnt &amp;gt; 1) {
                answer += str[i];
                answer += cnt;
                i += cnt;
                cnt = 1;
            }
        } else answer += str[i];
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;hsp&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = '';
    str = str + ' ';
    let cnt = 1;
    for (let i = 0; i &amp;lt; str.length - 1; i++) {
        if (str[i] === str[i + 1]) {
            // 문자열이 앞 뒤가 같을 때 cnt++을 해준다.
            cnt++;
        } else {
            // str[i] 와 str[i + 1]이 달라질 때, 현재의 i번 idx까지 같은 Char
            answer += str[i];
            if (cnt &amp;gt; 1) answer += String(cnt);
            cnt = 1;
        }
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;02. 숫자만 추출 (정규식, parseInt())&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions&quot;&gt;정규식&lt;/a&gt;을 만드는 두 가지 방법이 있다. 정규식 리터럴(슬래쉬 &quot;/&quot;로 감싸는 패턴)을 사용하는 방법은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;let re = /ab+c/;
let re = new RegExp(&quot;ab+c&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;02.1. 정규식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt; : &lt;code&gt;/a*/&lt;/code&gt; 에서의 특수 문자 &lt;code&gt;*&lt;/code&gt;는 0개 이상의 'a' 문자가 등장함을 나타냅니다. 이와는 다르게, 패턴 &lt;code&gt;/a \*/ 는&lt;/code&gt; &lt;code&gt;*&lt;/code&gt;이 특별하지 않다는 것을 나타내며, 'a*'와 같은 문자열과 대응될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; : 입력의 시작 부분에 대응. 만약 다중행 플래그가 참으로 설정되어 있다면, 줄 바꿈 문자 바로 다음 부분과도 대응됩니다. &lt;code&gt;/^A/&lt;/code&gt; 는 &quot;an A&quot; 의 'A'와는 대응되지 않습니다, 그러나 &quot;An E&quot; 의 'A'와는 대응된다. 그리고 &lt;code&gt;[^abc]&lt;/code&gt; 패턴안에서의 &lt;code&gt;^&lt;/code&gt; 는 부정셋을 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; : &lt;code&gt;/t$/&lt;/code&gt; 는 &quot;eater&quot; 의 't'에는 대응되지 않습니다, 그러나 &quot;eat&quot; 과는 대응됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; : 앞의 표현식이 0회 이상 연속으로 반복되는 부분과 대응됩니다. {0,} 와 같은 의미입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt; : 앞의 표현식이 1회 이상 연속으로 반복되는 부분과 대응됩니다. &lt;code&gt;{1,}&lt;/code&gt; 와 같은 의미입니다. 예를 들어, &lt;code&gt;/a+/&lt;/code&gt; 는 &quot;candy&quot;의 'a'에 대응되고 &quot;caaaaaaandy&quot; 의 모든 'a'들에 대응되지만, &quot;cndy&quot; 내의 어느 부분과도 대응되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; : 앞의 표현식이 0 또는 1회 등장하는 부분과 대응됩니다. &lt;code&gt;{0,1}&lt;/code&gt; 와 같은 의미입니다. 예를 들어, &lt;code&gt;/e?le?/&lt;/code&gt; 는 &quot;angel&quot;의 'el' 에 대응되고, &quot;angle&quot;의 'le' 에 대응되고 또한 &quot;oslo&quot; 의 'l'에도 대응됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.&lt;/code&gt; : 개행 문자를 제외한 모든 단일 문자와 대응됩니다. 예를 들어, &lt;code&gt;/.n/&lt;/code&gt;는 &quot;nay, an apple is on the tree&quot;에서 'an'과 'on'에 대응되지만, 'nay' 에는 대응되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions#special-character-set&quot;&gt;[xyz]&lt;/a&gt; : 문자셋(Character set) 입니다. 이 패턴 타입은 괄호 안의 어떤 문자(&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals#Unicode_escape_sequences&quot;&gt;이스케이프 시퀀스&lt;/a&gt;까지 포함)와도 대응됩니다. 점(&lt;code&gt;.&lt;/code&gt;) 이나 별표 (&lt;code&gt;*&lt;/code&gt;) 같은 특수 문자는 문자셋 내부에서는 특수 문자가 아닙니다. 따라서 이스케이프시킬 필요가 없습니다. 하이픈을 이용하여 문자의 범위를 지정해줄 수 있습니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 패턴 &lt;code&gt;[a-d]&lt;/code&gt; 는 패턴 &lt;code&gt;[abcd]&lt;/code&gt; 와 똑같이 동작하며, &quot;brisket&quot;의 'b' 에 일치하고, &quot;city&quot;의 'c' 에 일치합니다. 패턴 &lt;code&gt;/[a-z.]+/&lt;/code&gt;와 &lt;code&gt;/[\w.]+/&lt;/code&gt; 는 &quot;test.i.ng&quot; 전체 문자열이 일치합니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions#special-negated-character-set&quot;&gt;[^xyz]&lt;/a&gt; : 부정 문자셋(negated character set) 또는 보충 문자셋(complemented character set)입니다. 괄호 내부에 등장하지 않는 어떤 문자와도 대응됩니다. 하이픈을 이용하여 문자의 범위를 지정할 수 있습니다. 일반적인 문자셋에서 작동하는 모든 것은 여기에서도 작동합니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 패턴&lt;code&gt;[^abc]&lt;/code&gt;는 패턴&lt;code&gt;[^a-c]&lt;/code&gt;와 동일합니다. 두 패턴은 &quot;brisket&quot;의 'r', &quot;chop.&quot;의 'h' 에 대응됩니다.&lt;/li&gt;
&lt;li&gt;[\b] : 백스페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;\b : 단어 경계, 단어 경계는 다른 '단어 문자'가 앞이나 뒤에 등장하지 않는 위치에 대응됩니다. 단어의 경계는 대응 결과에 포함되지 않는다는 사실에 주의하세요. 다른 말로는, 단어의 경계에 대응되는 문자열의 길이는 항상 0입니다. (패턴 &lt;code&gt;[\b]&lt;/code&gt;와 혼동하지 마세요.)&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&lt;mark&gt;이해하기가 좀 어려움. &lt;/mark&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;02.2. 정규식에 쓰이는 메소드&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;exec : 대응되는 문자열을 찾는 &lt;code&gt;RegExp&lt;/code&gt; 메소드입니다. 정보를 가지고 있는 배열을 반환합니다. 대응되는 문자열을 찾지 못했다면 null을 반환합니다.&lt;/li&gt;
&lt;li&gt;test : 대응되는 문자열이 있는지 검사하는 &lt;code&gt;RegExp&lt;/code&gt; 메소드 입니다. true 나 false를 반환합니다.&lt;/li&gt;
&lt;li&gt;match : 대응되는 문자열을 찾는 &lt;code&gt;String&lt;/code&gt; 메소드입니다. 정보를 가지고 있는 배열을 반환합니다. 대응되는 문자열을 찾지 못했다면 null을 반환합니다.&lt;/li&gt;
&lt;li&gt;search : 대응되는 문자열이 있는지 검사하는 &lt;code&gt;String&lt;/code&gt; 메소드 입니다. 대응된 부분의 인덱스를 반환합니다. 대응되는 문자열을 찾지 못했다면 -1을 반환합니다.&lt;/li&gt;
&lt;li&gt;replace : 대응되는 문자열을 찾아 다른 문자열로 치환하는 &lt;code&gt;String&lt;/code&gt; 메소드입니다.&lt;/li&gt;
&lt;li&gt;split : 정규식 혹은 문자열로 대상 문자열을 나누어 배열로 반환하는 &lt;code&gt;String&lt;/code&gt; 메소드입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;02.3. &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/parseInt&quot;&gt;parseInt()&lt;/a&gt;&lt;/h4&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;parseInt(string, radix);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인풋 값 &lt;code&gt;string&lt;/code&gt; 이 &quot;0&quot;으로 시작한다면, radix 는 8(8진)이거나, 10(십진)입니다. 정확히 이 선택된 radix 는 구현 의존적적입니다. ECMAScript 5 는 10(십진)이 사용되는 것을 명시하지만, 모든 브라우저가 아직 이렇게 되지 않습니다. 이러한 이유로 &lt;b&gt;항상 &lt;code&gt;parseInt&lt;/code&gt;를 사용할 때는 radix 값을 명시해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 접근:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정규식 사용 없이 숫자만 사용하기 위해서 if문에 a-z, A-Z 조건문을 일일이 쓰려 했다. 하지만 정규식을 공부하고 나니 굉장히 쉽게 처리할 수 있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = '';
    for (let x of str) {
        if (!isNaN(x)) answer += x;
    }
    return pasrseInt(answer);
}

function solution2(str) {
    let answer = str.replace(/[^0-9]/g, ' ');
    return pasrseInt(answer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;03. 접미사 정렬&lt;/h3&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;arr.sort([compareFunction])&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort&quot;&gt;sort()&lt;/a&gt; : &lt;b&gt;정렬한 배열&lt;/b&gt;. 원 배열이 정렬되는 것에 유의하세요. 복사본이 만들어지는 것이 아닙니다. 파라미터 &lt;code&gt;compareFunction&lt;/code&gt;이 생략되면 유니코드 순서에 따라서 오름차순으로 정렬된다. (&lt;a href=&quot;https://hianna.tistory.com/409&quot;&gt;참고&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;문자열일 경우에만 정렬이 된다. 숫자일 경우에는 compareFunction을 추가해줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;answer.sort((a, b) =&amp;gt; a - b);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 원리는 compare 함수의 형식을 살펴봐야 한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compareFunction(a, b)&lt;/code&gt;이 0보다 작은 경우 a를 b보다 낮은 색인으로 정렬합니다. 즉, a가 먼저옵니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compareFunction(a, b)&lt;/code&gt;이 0보다 큰 경우, b를 a보다 낮은 인덱스로 소트합니다.&lt;/li&gt;
&lt;li&gt;즉, compare함수가 &lt;code&gt;-1&lt;/code&gt;을 return시 a가 b보다 낮은 색인 인식. &lt;code&gt;1&lt;/code&gt;을 return 했을 때, a가 b보다 큰 색인으로 인식.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;function compare(a, b) {
  if (a &amp;lt; b by some ordering criterion) {
    return -1;
  }
  if (a &amp;gt; b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = [];
    for (let i = 0; i &amp;lt; str.length; i++) {
        answer.push(str.substring(i, str.length));
        answer.sort((a, b) =&amp;gt; a - b);
    }
    return answer;
}
console.log(solution('kseaedu'));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;04. 회문 문자열&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;function solution(str) {
    let left = 0,
        right = str.length - 1;
    str = str.toLowerCase();
    console.log(str);
    while (left &amp;lt; right) {
        if (str[left] === str[right]) {
            left++;
            right--;
        } else return 'NO';
    }
    return 'YES';
}
console.log(solution('gaaaooaaaG'));&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;li&gt;split(' ', 3) : 처음 3개의 문자열을 반환한다. 주어진 문자열을 &lt;code&gt;separator&lt;/code&gt;마다 끊은 부분 문자열을 담은 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array&quot;&gt;Array&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;let answer = 'YES';
str = str.toLowerCase();
if (str.split('').reverse().join('') != str) return 'NO';
return answer;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;05. 특정 문자 뒤집기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;function solution(str) {
    str = str.split('');
    const isAlpha = /[a-zA-Z]/;
    let left = 0,
        right = str.length - 1;
    while (left &amp;lt; right) {
        if (!isAlpha.test(str[left])) left++;
        if (!isAlpha.test(str[right])) right--;
        if (isAlpha.test(str[left]) &amp;amp;&amp;amp; isAlpha.test(str[right]))         {
            let temp = str[left];
            str[left] = str[right];
            str[right] = temp;
            left++;
            right--;
        }
    }
    return str;
}
console.log(solution('a#b!GE*T@S'));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;06. 회문 문자열2&lt;/h3&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;str.substring(indexStart[, indexEnd])&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;indexStart : 반환 문자열의 시작 인덱스&lt;/li&gt;
&lt;li&gt;indexEnd : 옵션. 반환 문자열의 마지막 인덱스 (포함하지 않음.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 코드에서 문제점은 while문을 빠져나가는 명령어가 필요했는데, &quot;NO&quot;인 경우에 대해 생각을 해주지 못했다. 따라서 &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt; idx 변경도 없기 때문에 무한 루프에 빠져버렸다. 따라서 아래 풀이와 같이 substring한 문자열을 각각 비교해줘서 해결할 수 있었다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = 'NO';
    let left = 0,
        right = str.length - 1;
    while (left &amp;lt; right) {
        if (str[left] === str[right]) {
            left++;
            right--;
        } else {
            let temp = str.substring(left, right);
            let temp2 = str.substring(left + 1, right + 1);
            if (
                temp === temp.split('').reverse().join('') ||
                temp2 === temp2.split('').reverse().join('')
            ) {
                return 'YES';
            } else return 'NO';
        }
    }
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;07. 공통 문자가 없는 단어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;indexOf : &lt;b&gt;배열&lt;/b&gt;에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고 존재하지 않으면 -1을 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = 0;
    str.sort((a, b) =&amp;gt; a.length - b.length);
    for (let i = 0; i &amp;lt; str.length - 1; i++) {
        for (let j = i + 1; j &amp;lt; str.length; j++) {
            if (isUniq(str[i], str[j])) {
                let temp = str[i].length * str[j].length;
                answer = Math.max(temp, answer);
            }
        }
    }
    function isUniq(short, long) {
        for (let x of short) {
            if (long.indexOf(x) &amp;gt; 0) return false;
        }
        return true;
    }
    return answer;
}
console.log(solution(['skudy', 'kstue', 'time', 'back', 'good']));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;08. 학급 회장&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set은 하나의 값만을 가지게 만드는 자료형.&lt;/li&gt;
&lt;li&gt;Map은 key-value를 가지는 자료형&lt;/li&gt;
&lt;li&gt;for ... of : String, Array &lt;a href=&quot;https://velog.io/@manudeli/%EC%A0%9C%EB%84%A4%EB%A0%88%EC%9D%B4%ED%84%B0generator-%EC%9D%B4%ED%84%B0%EB%9F%AC%EB%B8%94iterable%EC%9D%B4%EB%9E%80&quot;&gt;iterable&lt;/a&gt;한 객체를 포함해서 loop를 돌 수 있다. (in은 )&lt;/li&gt;
&lt;li&gt;null check 관련글 &lt;a href=&quot;https://helloworldjavascript.net/pages/160-null-undefined.html&quot;&gt;https://helloworldjavascript.net/pages/160-null-undefined.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;undefined와 &lt;code&gt;||&lt;/code&gt;연산을 했을 때 정리하기. (&lt;a href=&quot;https://negabaro.github.io/archive/js-isEmpty&quot;&gt;null, undefined&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;has(key) : key를 가지고 있는지 확인해주는 메소드.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contacts.has('Jessie') // true&lt;/code&gt; : key값을 가지는지 확인하는 메소드.&lt;/li&gt;
&lt;li&gt;[...hash].sort((a,b) =&amp;gt; b[1] -a[1]) : 이와 같이 hash안의 key와 value들을 정렬할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;function solution(str) {
    let answer = '';
    let hash = new Map();
    for (let x of str) {
        console.log(hash.get(x));
        hash.set(x, (hash.get(x) || 0) + 1);
        //undefined가 나왔을 땐, 0으로 입력된다.
    }
    let max = Number.MIN_SAFE_INTEGER;
    for (let [key, val] of hash) {
        if (val &amp;gt; max) {
            max = val;
            answer = key;
        }
    }
    hash.get(max);
    return answer;
}
console.log(solution('BACBACCACCBDEDE'));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로그래머스 문제 (숫자 문자열과 영단어)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;join('')&lt;/code&gt; 메서드는 배열의 모든 요소를 연결해 하나의 문자열로 만듭니다. 파라미터를 주지 않으면 기본값은 &lt;code&gt;,&lt;/code&gt;가 들어간다.&lt;/li&gt;
&lt;li&gt;요소가 &lt;code&gt;undefined&lt;/code&gt; 또는 &lt;code&gt;null&lt;/code&gt;이면 빈 문자열로 변환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution(s) {
    let answer = 0;
    let arr = s;
    const numbers =['zero','one','two','three','four','five','six','seven','eight','nine','ten'];
    for (let i = 0; i &amp;lt; 11; i++){
        arr = arr.split(numbers[i]).join(i);
    }
    answer = parseInt(arr)
    return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;09. 아나그램(Anagram)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Map 메소드 (Hash table)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;const contacts = new Map()
contacts.set('Jessie', {phone: &quot;213-555-1234&quot;, address: &quot;123 N 1st Ave&quot;})
contacts.has('Jessie') // true
contacts.get('Hilary') // undefined
contacts.set('Hilary', {phone: &quot;617-555-4321&quot;, address: &quot;321 S 2nd St&quot;})
contacts.get('Jessie') // {phone: &quot;213-555-1234&quot;, address: &quot;123 N 1st Ave&quot;}
contacts.delete('Raymond') // false
contacts.delete('Jessie') // true
console.log(contacts.size) // 1

/* for문에서의 이용 */
for (let [key, val] of hash) {
    console.log(hash.size);
    console.log(hash2.get(key));
    if (hash2.has(key)) {
        if (val === hash2.get(key)) {
            continue;
        } else {
            answer = 'NO';
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(str1, str2) {
    let answer = 'YES';
    let temp;
    let hash = new Map();
    let hash2 = new Map();

    for (let i = 0; i &amp;lt; str1.length; i++) {
        hash.set(str1[i], (hash.get(str1[i]) || 0) + 1);
    }
    for (let i = 0; i &amp;lt; str2.length; i++) {
        hash2.set(str2[i], (hash2.get(str2[i]) || 0) + 1);
    }

    for (let [key, val] of hash) {
        if (hash2.has(key)) {
            if (val === hash2.get(key)) {
                continue;
            } else {
                answer = 'NO';
                break;
            }
        }
    }
    return answer;
}
console.log(solution('abaCC', 'Caaab'));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;09.1 Filter&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function solution(arr) {
    return arr.filter((val) =&amp;gt; {
        // 참 거짓을 return 해야한다.
        for (let i = 2; i * i &amp;lt;= val; i++) {
            if (val % i == 0) return false;
            else return true;
        }
    });
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 문자열 구분하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Array.prototype.slice()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;slice()&lt;/code&gt; 메서드는 어떤 배열의 &lt;code&gt;begin&lt;/code&gt;부터 &lt;code&gt;end&lt;/code&gt;까지(&lt;code&gt;end&lt;/code&gt; 미포함)에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt; Optional음수 인덱스는 배열의 끝에서부터의 길이를 나타냅니다. &lt;code&gt;slice(-2)&lt;/code&gt; 는 배열에서 마지막 두 개의 엘리먼트를 추출합니다.&lt;code&gt;begin&lt;/code&gt;이 배열의 길이보다 큰 경우에는, 빈 배열을 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt;이 &lt;code&gt;undefined&lt;/code&gt;인 경우에는, 0번 인덱스부터 &lt;code&gt;slice&lt;/code&gt; 합니다.&lt;/li&gt;
&lt;li&gt;0을 시작으로 하는 추출 시작점에 대한 인덱스를 의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;end&lt;/code&gt; Optional예를 들어, &lt;code&gt;slice(1,4)&lt;/code&gt;는 두번째 요소부터 네번째 요소까지 (1, 2 및 3을 인덱스로 하는 요소) 추출합니다.&lt;code&gt;end&lt;/code&gt;가 생략되면 &lt;code&gt;slice()&lt;/code&gt;는 배열의 끝까지(&lt;code&gt;arr.length&lt;/code&gt;) 추출합니다.&lt;/li&gt;
&lt;li&gt;만약 &lt;code&gt;end&lt;/code&gt; 값이 배열의 길이보다 크다면, &lt;code&gt;silce()&lt;/code&gt;는 배열의 끝까지(&lt;code&gt;arr.length&lt;/code&gt;) 추출합니다.&lt;/li&gt;
&lt;li&gt;음수 인덱스는 배열의 끝에서부터의 길이를 나타냅니다. 예를들어 &lt;code&gt;slice(2,-1)&lt;/code&gt; 는 세번째부터 끝에서 두번째 요소까지 추출합니다.&lt;/li&gt;
&lt;li&gt;추출을 종료 할 0 기준 인덱스입니다. &lt;code&gt;slice&lt;/code&gt; 는 &lt;code&gt;end&lt;/code&gt; 인덱스를 제외하고 추출합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Array.prototype.splice()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;splice()&lt;/code&gt; 메서드는 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 배열의 내용을 변경합니다.&lt;/p&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;array.splice(start[, deleteCount[, item1[, item2[, ...]]]])&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;start&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;배열의 변경을 시작할 인덱스입니다. 배열의 길이보다 큰 값이라면 실제 시작 인덱스는 배열의 길이로 설정됩니다. 음수인 경우 배열의 끝에서부터 요소를 세어나갑니다(원점 -1, 즉 -n이면 요소 끝의 n번째 요소를 가리키며 &lt;code&gt;array.length - n&lt;/code&gt;번째 인덱스와 같음). 값의 절대값이 배열의 길이 보다 큰 경우 0으로 설정됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCount&lt;/code&gt; Optional&lt;code&gt;deleteCount&lt;/code&gt;를 생략하거나 값이 &lt;code&gt;array.length - start&lt;/code&gt;보다 크면 &lt;code&gt;start&lt;/code&gt;부터의 모든 요소를 제거합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;deleteCount&lt;/code&gt;가 0 이하라면 어떤 요소도 제거하지 않습니다. 이 때는 최소한 하나의 새로운 요소를 지정해야 합니다.&lt;/li&gt;
&lt;li&gt;배열에서 제거할 요소의 수입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item1, item2, *...*&lt;/code&gt; Optional&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/splice#%EB%B0%98%ED%99%98_%EA%B0%92&quot;&gt;반환 값&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;제거한 요소를 담은 배열. 하나의 요소만 제거한 경우 길이가 1인 배열을 반환합니다. 아무 값도 제거하지 않았으면 빈 배열을 반환합니다.&lt;/li&gt;
&lt;li&gt;배열에 추가할 요소입니다. 아무 요소도 지정하지 않으면 &lt;code&gt;splice()&lt;/code&gt;는 요소를 제거하기만 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내 풀이&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;function solution(s, m) {
    let answer;
    for (let i = m; i &amp;gt; 0; i--) {
        for (let j = 1; j &amp;lt; s.length; j++) {
            s[j - 1] = s[j] - s[j - 1];
        }
    }
    s = s.slice(0, s.length - m);
    console.log(s);

    return answer;
}

console.log(solution([5, 3, 7, 9, -2], 1));
console.log(solution([5, 3, 7, 9, -2], 2));&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Set 자료형&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;var mySet = new Set();

mySet.add(1); // Set { 1 }
mySet.add(5); // Set { 1, 5 }
mySet.add(5); // Set { 1, 5 }
mySet.add('some text'); // Set { 1, 5, 'some text' }
var o = {a: 1, b: 2};
mySet.add(o);

mySet.add({a: 1, b: 2}); // o와 다른 객체를 참조하므로 괜찮음

mySet.has(1); // true
mySet.has(3); // false, 3은 set에 추가되지 않았음
mySet.has(5);              // true
mySet.has(Math.sqrt(25));  // true
mySet.has('Some Text'.toLowerCase()); // true
mySet.has(o); // true

mySet.size; // 5

mySet.delete(5); // set에서 5를 제거함
mySet.has(5);

mySet.size; // 4, 방금 값을 하나 제거했음
console.log(mySet);// Set {1, &quot;some text&quot;, Object {a: 1, b: 2}, Object {a: 1, b: 2}}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/JavaScript 알고리즘</category>
      <category>Set 자료형</category>
      <category>문자열 압축</category>
      <category>문자열해싱</category>
      <category>알고리즘</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/76</guid>
      <comments>https://minsoftk.tistory.com/76#entry76comment</comments>
      <pubDate>Fri, 8 Oct 2021 00:37:18 +0900</pubDate>
    </item>
    <item>
      <title>HTML, CSS 기본기 다지기(CSS)(6)</title>
      <link>https://minsoftk.tistory.com/75</link>
      <description>&lt;h1&gt;6. HTML 기본기 다지기&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17. Grid&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flex 박스의 기본적인 컨셉은 1차원의 개념이다. 따라서 &lt;code&gt;wrap&lt;/code&gt;으로 다음 줄로 넘어간 요소들에 대한 정렬을 주로 다뤘다.&lt;/li&gt;
&lt;li&gt;grid의 기본 개념은 2차원으로 시작한다.&lt;/li&gt;
&lt;li&gt;하나의 그리드는 &lt;code&gt;columns&lt;/code&gt;, &lt;code&gt;rows&lt;/code&gt;로 구성된다. 각 행과 열 사이에 공백이 있는데, 이를 &lt;code&gt;gutters&lt;/code&gt;, &lt;code&gt;gap&lt;/code&gt;이라고 표현한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Table&lt;/code&gt;을 레이아웃에 사용하면 안된다!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.1. grid-template-rows, grid-template-columns (Container 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;width를 설정해도 기본적으로 border 값이 알맞지 않게 나올 수 가 있는데, 이는 border 값을 가지고 있기 때문이다.&lt;/li&gt;
&lt;li&gt;grid-template-row , columns를 적용한 곳에서만 css 적용이 된다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1fr 1fr 1fr&lt;/code&gt;로 설정을 한다면 1:1:1 비율로 공간을 나눠 가진다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2fr 1fr&lt;/code&gt;경우를 직접 작성해서 비교해보자.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grid-template-rows: repeat(4,1fr)&lt;/code&gt; 로도 작성할 수 있다.&lt;/li&gt;
&lt;li&gt;HTML 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;1&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;2&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;3&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;4&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;5&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    grid-template-columns: 100px 150px 100px;
    grid-template-rows: 100px 100px 100px;
    /* grid-template-rows: repeat(4,100px); */
}

.item {
    background-color: paleturquoise;
    border: 3px solid blue;
    font-size: 30px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.2. grid-template-areas (Container 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;areas 설정할 수 있는데, 꼭 사각형을 가지도록 설정해줘야 한다.&lt;/li&gt;
&lt;li&gt;각각 class 이름을 추가해주고, 각각의 이름을 Container에서 영역을 설정 해준다. 빈 공간을 원한다면 &lt;code&gt;.&lt;/code&gt;을 추가해서 빈 영역으로 만들어 준다.&lt;/li&gt;
&lt;li&gt;HTML 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
            &amp;lt;div class=&quot;item header&quot;&amp;gt;header&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item main&quot;&amp;gt;main&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item sidebar&quot;&amp;gt;sidebar&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item footer&quot;&amp;gt;footer&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(3,1fr);


}

.item {
    background-color: paleturquoise;
    border: 3px solid blue;
    font-size: 30px;
}

.header {
    grid-area: hd;
}

.main {
    grid-area: ma;
}

.sidebar {
    grid-area: sb;
}

.footer {
    grid-area: ft;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.3. row-gap&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid-row-gap이라고 현재는 사용하진 않는다. (deprecated)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    grid-template-rows: repeat(3, 1fr);
    row-gap: 20px;
    column-gap: 10rem;
    /* 단축속성으로 사용 가능 */
    /* gap: 20px 10rem; */
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.4. grid-auto-rows, grid-auto-columns&lt;/h3&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;

    /* 내부에 아이템이 있건 없건 template을 만들어 놓는다. 그런데 템플릿을 넘치게 됐을 때 
    넓이, 높이를 설정하고 싶을 때를 위해 auto 명령어를 사용한다. */
    grid-template-rows: 100px 150px 80px;
    grid-template-columns: 1fr 1fr 1fr;

    /* item이 template을 흘러 넘칠때 설정이 된다. */
    grid-auto-rows: 100px;
    grid-auto-columns: 50px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.5. grid-auto-flow&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid의 아이템들이 어떻게 흘러갈 것 인지에 대한 속성. &lt;code&gt;row&lt;/code&gt; 값이 기본 값이다.&lt;/li&gt;
&lt;li&gt;row는 주축 방향으로 흐르게 한다. 반대로 column일 경우엔, 교차축 방향으로 item들이 흐른다.&lt;/li&gt;
&lt;li&gt;각각 요소들에 span으로 공간을 차지하게 했을 때, 만약 크기가 grid 컨테이너에 담지 못한다면 다음 줄로 내려버린다. 그 때 &lt;code&gt;dense'&lt;/code&gt; 명령어를 추가해주게 된다면 빈 공간에 담길 수 있는 이후 item들이 대신 들어와 담기게 된다.&lt;/li&gt;
&lt;li&gt;HTML 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;1&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;2&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;3&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;4&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;5&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    grid-template-rows: 100px 100px 100px;
    grid-template-columns: repeat(3, 1fr);

/* 교차축에 방향으로 흘러가게 됨. */
/*    grid-auto-flow: row; */

/* 차지할 수 있는 요소들이 대신 들어가게 된다. */
    grid-auto-flow: row dense;
}

.item {
    background-color: paleturquoise;
    border: 3px solid blue;
    font-size: 30px;
}

/* 2칸을 차지하겠다. */
.item:nth-child(2) {
    grid-column: span 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;17.6. grid (단축 속성)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명시적인 표현 : grid-template-~~&lt;/li&gt;
&lt;li&gt;암시적인 표현 : grid-auto-~~&lt;/li&gt;
&lt;li&gt;(명, 명), (명, 암), (암, 명) 사용이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;

    /* 
    grid-template-rows: 1fr 2fr;
    grid-template-columns: 100px 200px; */

    /* row / column (앞 뒤를 명시적으로 쓸 수 있다.) */
    /* grid: 1fr 2fr / 100px 200px; */

    /* auto-flow를 써줄 때 row에 써 넣으면 row, column에 써 넣으면 column으로 설정이 된다. */
    grid: auto-flow 1fr 2fr / 100px 200px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.7. justify-items, align-items (item 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;남는 공간이 있어야지 사용이 가능하다. 기본 값은 &lt;code&gt;stretch&lt;/code&gt;를 가진다.&lt;/li&gt;
&lt;li&gt;Container에서 &lt;code&gt;justify-items&lt;/code&gt;, &lt;code&gt;align-items&lt;/code&gt;를 사용해서 각각의 요소를 컨트롤 할 수 가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    width: 100%;
    height: 500px;

    display: grid;
    grid-template-rows: repeat(3, 100px);
    grid-template-columns: repeat(3, 100px);

    justify-items: center;
    align-items: end;
}

.item {
    width: 50px;
    height: 50%;
    background-color: paleturquoise;
    border: 3px solid blue;
    font-size: 30px;
}

.item:nth-child(1) {
    width: 50px;
    height: 50px;
    justify-self: center;
    /* self를 사용하면 하나의 정렬만 바꿀 수 있다. */
    align-self: center;
}

.item:nth-child(2) {
    width: 50px;
    justify-self: end;
    align-self: start;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.8. grid-row (item 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;grid-row-start&lt;/code&gt;, &lt;code&gt;grid-row-end&lt;/code&gt;에 대한 내용.&lt;/li&gt;
&lt;li&gt;몇번째 선인지에 대한 내용을 확인해야 한다.&lt;/li&gt;
&lt;li&gt;명시적으로 선언한 grid에만 선에 번호가 붙는다.&lt;/li&gt;
&lt;li&gt;1부터 -1까지로 지정하면 처음부터 끝까지라는 의미가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/minsoftk/TIL/blob/master/zero-base/img/css9.png?raw=true&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;1&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;2&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;3&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;4&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;5&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;6&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;item&quot;&amp;gt;7&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CSS 파트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;
    display: grid;
    width: 100%;
    height: 500px;

    display: grid;
    grid-template-rows: repeat(3, 100px);
    grid-template-columns: repeat(3, 100px);
}

.item {
    background-color: paleturquoise;
    border: 3px solid blue;
    font-size: 30px;
}

.item:nth-child(1) {
    background-color: coral;

    grid-row-start: 1;
    grid-row-end: -1;
    /* grid: 1 / -1 */
    /* grid: 1 / span 2  -&amp;gt; 1부터 2칸을 차지  */
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.9. grid-areas (item 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 요소에서 단축 속성을 이용해서 다음과 같이 영역을 설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.item:first-child{
    grid-row: 4 / span 2;
    grid-column: 2 / -1;

    /* row-start, col-start, row-end, col-end */
    grid-area: 4 / 2 / span2 / -1;
}    &lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.10. order (item 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;order가 같을 경우에는 코드 순서가 먼저인 것을 앞으로 꺼내 준다.&lt;/li&gt;
&lt;li&gt;기본 값은 &lt;code&gt;0&lt;/code&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.item:nth-child(5) {
    order: -1;
}
.item:nth-child(3) {
    order: -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.11. z-index (item 속성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flexbox에서 쓰던 것과 유사하다. (12.6 참고-HTML 기본기 다지기(5))&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.12. Grid 단위 (fr, min-content, max-content)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fraction : col은 100px을 차지하고 나머지를 전부 1:1로 나눠가진다. 다른 단위와도 혼합해서 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;

    display: grid;
    grid-template-rows: repeat(3, 200px);
    /* grid-template-columns: 100px 1fr 1fr; */

    /* min-content vs max-content */
    /* min : 쪼개진 단어보다 작아질 수가 없는 크기만큼 */
    /* max : 한줄에 볼 수 있는 형태까지 늘린다. */
    grid-template-columns: min-content 1fr 1fr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;17.13. Grid 단위 - auto-fill, auto-fit&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;grid-auto-rows, gird-template-rows 사용점의 차이? (아래 코드에서)&lt;/li&gt;
&lt;li&gt;auto-fill, auto-fit이 남은 공간을 채워주는 동작은 똑같다. auto-fill은 화면을 줄이거나 키울때 100px보다 작게 되면은 1fr으로 나눠가진다. 하지만 100px이 들어갈 공간이 생기게 되면, 요소가 col에 하나 추가 된다. 즉, 100px 기준으로 요소가 채워지고 1fr 유지하다가 또 100px이 채워지거나 빠졌을 때, 다시 1fr로 설정이 된다.&lt;/li&gt;
&lt;li&gt;auto-fit 같은 경우 아이템 수가 적어졌을 때, 그리드에서 남는 공간이 생긴다. 이 남는 공간을 채워주고 싶을 때 사용한다.&lt;/li&gt;
&lt;li&gt;남는 공간을 어떻게 활용할지의 차이가 있다.&lt;/li&gt;
&lt;li&gt;auto-fill&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;

    display: grid;
    /* 화면이 줄어들거나 늘어날 때 자동으로 채워준다. */
    grid-template-columns: repeat(auto-fill, 100px);
    /* grid-template-columns: repeat(auto-fill, minmax 100px, 1fr); */

    /* 암시적으로 auto-fill로 새로 row가 생겨도 크기를 똑같이 지정해준다. */
    grid-auto-rows: 50px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;auto-fit&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.container {
    border: 5px dashed orange;

    display: grid;
    /* 화면이 줄어들거나 늘어날 때 자동으로 채워준다. */
    grid-template-columns: repeat(auto-fit, 100px);
    /* grid-template-columns: repeat(auto-fill, minmax 100px, 1fr); */

    /* 암시적으로 auto-fill로 새로 row가 생겨도 크기를 똑같이 지정해준다. */
    grid-auto-rows: 50px;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL(Today I Learn)</category>
      <category>flexbox</category>
      <category>Grid</category>
      <category>grid auto-fill</category>
      <category>grid auto-fit</category>
      <category>grid-auto-row</category>
      <category>grid-template-row</category>
      <author>MinsoftK</author>
      <guid isPermaLink="true">https://minsoftk.tistory.com/75</guid>
      <comments>https://minsoftk.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 5 Oct 2021 12:51:33 +0900</pubDate>
    </item>
  </channel>
</rss>