<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_boku.log</title>
        <link>https://velog.io/</link>
        <description>Front-End Engineer</description>
        <lastBuildDate>Thu, 08 Dec 2022 00:04:45 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dev_boku.log</title>
            <url>https://velog.velcdn.com/images/dev_boku/profile/ba7332cf-56a0-45f6-9568-713ec428c6b5/image.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dev_boku.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_boku" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[누구나 자바스크립트 제너레이터 함수가 필요한 이유는 무엇인가요?]]></title>
            <link>https://velog.io/@dev_boku/%EB%88%84%EA%B5%AC%EB%82%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%95%A8%EC%88%98%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@dev_boku/%EB%88%84%EA%B5%AC%EB%82%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%95%A8%EC%88%98%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</guid>
            <pubDate>Thu, 08 Dec 2022 00:04:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 : <a href="https://jrsinclair.com/articles/2022/why-would-anyone-need-javascript-generator-functions/">https://jrsinclair.com/articles/2022/why-would-anyone-need-javascript-generator-functions/</a></p>
</blockquote>
<blockquote>
<p>티스토리 블로그 : <a href="https://dev-boku.tistory.com/entry/%EB%88%84%EA%B5%AC%EB%82%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%95%A8%EC%88%98%EA%B0%80-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94">티스토리</a></p>
</blockquote>
<p>제너레이터는 자바스크립트 언어의 이상한 부분입니다. 그리고 어떤 사람들은 제네레이터를 약간 수수께끼라고 생각합니다. 당신은 수십 년 동안 성공적인 개발자고, 제너레이터를 알 필요가 없다고 느꼈을 수도 있습니다. 만약 여러분이 제너레이터를 필요로 하지 않고 그렇게 오래 버텨왔다면 의문이 듭니다. 제너레이터는 무엇에 도움이 될까요?</p>
<p>제너레이터에는 재미있는 문법이 있습니다. 제너레이터에는 이상한 별표가 있는 함수로 정의하고, 화살표 함수로는 제너레이터를 정의할 수 없습니다. 제너레이터는 이해하기 힘든 <code>yield</code> 키워드도 가지고 있습니다. 만약 제너레이터가 하는 일에 익숙하지 않다면 코드를 읽기 힘들 수 있습니다.</p>
<p>문제 중 일부는 제너레이터가 저수준 구조라는 것입니다. 즉, 제너레이터는 도구를 만들기 위한 도구와 같으며 일상적인 문제를 해결하기 위해 만든 도구입니다. 하지만 제너레이터 함수를 따로따로 보면 왜 이런 기능이 필요한지 이해하기 어려울 수 있습니다.</p>
<p>그렇지만, 제너레이터는 상당히 강력한 구문입니다. 대부분의 도구들과 마찬가지로 모든 작업에 제네레이터가 필요하지 않을 수 있습니다.  그러나 특정 작업의 경우에는 삶을 훨씬 편하게 만듭니다. 도구를 더 잘 이해하면 그 도구가 어디에 유용한지 알게 됩니다. 마찬가지로 제네레이터를 잘 이해하면 언제 사용하지 _않을 때_인지 알게 됩니다.</p>
<p>그렇다면 제너레이터는 어디에 좋은 건가요?</p>
<h2 id="팀탐-그리고-지연-이터레이터-lazy-iterators">팀탐 그리고 지연 이터레이터 (lazy iterators)</h2>
<p>제너레이터에는 <em>많은</em> 용도가 있습니다. 그러나 가장 직접적이고 확실하게 적용해보는 건 _지연 이터레이터_를 만들어 보는 것입니다.</p>
<p>자바스크립트의 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols"><em>이터레이션 프로토콜</em></a>에 대해 이미 잘 알고 있기를 바랍니다. 이를 통해 자바스크립트 엔진에게 일부 객체가 <code>for...of</code> 루프 또는 _<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax">spread 문법</a>_으로 사용할 수 있단걸 알릴 수 있습니다.</p>
<p>우리가 할 수 있는 가장 간단한 일은 몇 가지 값을 생성하는 제너레이터 함수를 정의하는 것입니다. 그런 다음 <code>for...of</code> 루프를 사용하여 반복해서 처리할 수 있습니다.</p>
<pre><code class="language-js">function* culturalAchievements() {
    yield &#39;Amazing coffee&#39;;
    yield &#39;The Sydney Opera House&#39;;
    yield &#39;The invention of Wi-Fi&#39;;
}

for (achievement of culturalAchievements()) {
    console.log(`호주는 이것으로 유명합니다: ${achievement}`);
}

// 호주는 이것으로 유명합니다: Amazing coffee
// 호주는 이것으로 유명합니다: The Sydney Opera House
// 호주는 이것으로 유명합니다: The invention of Wi-Fi</code></pre>
<p>그리고 표면적으로는 그것은 무의미해 보입니다. 배열을 사용하면 훨씬 적은 수고로 모든 작업을 수행할 수 있습니다. 하지만 아이러니하게도 제너레이터가 배열과 비슷하다는 것이 제너레이터를 매우 유용하게 만듭니다.</p>
<p>그 이유를 설명하기 위해 호주의 문화적 성취의 정점을 소개해야 합니다. 와이파이의 발명품이 아닙니다. 시드니 오페라 하우스도 아닙니다. 최상급 커피도 아닙니다. 틀림없이 호주의 가장 위대한 문화적 업적은 <a href="https://en.wikipedia.org/wiki/Tim_Tam"><em>팀탐(Tim Tam)</em></a>입니다.</p>
<p><img src="https://jrsinclair.com/assets/tim-tams.jpeg" alt="A plate of Tim Tams, with one in the centre broken open to show the biscuit and chocolate cream filling. Photograph by Bilby. Licensed under the Creative Commons Attribution-Share Alike 3.0 license."></p>
<p>팀탐은 &quot;두 개의 맥아 비스킷으로 구성되어 있으며 가볍고 단단한 초콜릿 크림으로 채워져 있고 질감이 있는 얇은 초콜릿 층으로 코팅되어 있습니다&quot;. 이 &quot;초콜릿 맛의 크리미한 벽돌&quot;이 우리의 비유 대상이 될 것 입니다. 팀탐은 처리하려는 데이터 항목을 나타냅니다.</p>
<p>그리고 우리는 <a href="https://firstwefeast.com/eat/2014/10/how-to-do-a-tim-tam-slam">팀탐 슬램(Tim Tam Slam)</a>이라는 의식을 통해 팀 탐을 &#39;처리&#39;합니다. 단계는 다음과 같습니다.</p>
<ol>
<li>하나의 팀탐을 선택합니다.</li>
<li>끝에서 2–5 mm 떨어진 한쪽 모서리에서 작은 덩어리를 물어보세요.</li>
<li>대각선 반대쪽 모서리에서 물기를 반복합니다.</li>
<li>물린 모서리 중 하나를 뜨거운 음료에 넣습니다. <a href="https://www.milo.com.au/"><em>밀로(Milo)</em></a>는 전통적이지만 커피, 차 또는 핫 초콜릿도 허용됩니다).</li>
<li>반대쪽 모서리에 입술을 대고 마치 빨대처럼 팀 탐을 통해 액체를 빨아들입니다.</li>
<li>액체가 입에 들어가는 즉시 팀탐 전체를 섭취하세요. 팀탐 형태가 무너지기 전에 이를 신속하게 수행하는 것이 중요합니다.</li>
<li>팀탐 더 이상 없을 때까지 또는 컨디션이 안좋다고 느낄 때까지 반복합니다.</li>
</ol>
<p>호주 가수 Natalie Imbruglia가 _Graham Norton Show_에서 시연하고 있습니다.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/VMbrlxTIVtI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>일부 사람들은 호주와 영국 악센트를 이해하기 어렵다고 생각할 수도 있습니다. 그런 경우라면 <a href="https://www.youtube.com/watch?v=lSnD5vs_35A"><em>Neil de Grasse Tyson이 최근 유튜브 비디오에서 자세히 설명하고 있습니다.</em></a></p>
<p>이제 컨디션이 나빠지기 전까지 최대 5개의 팀탐을 섭취할 수 있다고 칩시다. 이 과정을 자바스크립트를 사용하여 나타낸다면 다음과 같습니다.</p>
<pre><code class="language-js">const MAX_TIMTAMS = 5;

function slamTimTamsArray(timtams) {
    return timtams
        .map(biteArbitraryCorner)
        .map(biteOppositeCorner)
        .map(insertInBeverage)
        .map(drawLiquid)
        .map(insertIntoMouth)
        .slice(0, MAX_TIMTAMS);
}</code></pre>
<p>우리는 팀탐 슬램 과정을 일련의 논리적 단계로 설명했습니다. 그리고 이것은 좋은 일입니다. 그러나 이 함수를 작성하는 방식에는 심각한 문제가 있습니다. 원래 팀탐의 표준 상자에는 11개의 비스킷이 들어 있습니다. 상자를 배열처럼 처리하면 비스킷을 하나씩 꺼내서 모서리를 깨물고 새 상자에 넣습니다. 그런 다음 비스킷을 하나씩 차례로 가져와서 대각선으로 반대쪽 모서리를 깨물었습니다. 그리고 우리는 두 귀퉁이가 잘린 11개의 비스킷을 가지게 됩니다. 하지만 우리가 다음 단계를 시도할 때, 모든 것이 우스꽝스러워집니다. 거기서 우리는 11개의 비스킷을 음료에 넣을 것입니다.</p>
<p><code>.slice()</code>을 먼저 실행하도록 순서를 바꿔도 여전히 문제가 생깁니다. 한 번에 5장의 비스킷이 들어간 음료가 되어 버립니다. 또한 <a href="https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/#flow">_flow()_를 사용해서</a> <code>.map()</code> 연산의 모든 함수를 함께 구성할 수도 있습니다. 그것과 <code>.slice()</code>를 시작점으로 이동하는 것을 조합하면 상황이 개선됩니다.</p>
<pre><code class="language-ts">const flow = (...fns) =&gt; x0 =&gt; fns.reduce(
    (x, f) =&gt; f(x),
    x0
);

function slamTimTamsUsingFlow(timtams) {
    return timtams
        .slice(0, MAX_TIMTAMS)
        .map(flow(
            biteArbitraryCorner,
            biteOppositeCorner,
            insertInBeverage,
            drawLiquid,
            insertIntoMouth));
}</code></pre>
<p>이 접근 방식도 그리 나쁘지 않지만 첫 번째 시도만큼 깔끔하고 명료하지는 않습니다. 그러나 제너레이터는 지연되기 때문에 첫 번째 예제에서 깔끔한 시퀀스를 유지할 수 있는 방법을 제공합니다. 그러나 작동하려면 몇 가지 유틸리티 함수를 정의해야 합니다. 먼저 Array의 <code>.map()</code> 메서드에 대응하는 것을 정의합니다. 다음과 같이 표시됩니다.</p>
<pre><code class="language-js">const map = f =&gt; function*(iterable) {
  for (let x of iterable) yield f(x);
};</code></pre>
<p><code>function*()</code> 구문에 유의하십시오. 이 구문은 이 <code>map()</code> 함수가 제너레이터를 반환한다는 것을 의미합니다. 그리고 제너레이터는 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol"><em>이터러블 프로토콜</em></a>을 구현합니다. 이것은 우리가 반환 값을 가져와서 다른 <code>for...of</code> 구조에서 사용할 수 있음을 의미합니다. 그리고 아이템 수를 제한하는 또 다른 함수를 만들 수 있습니다.</p>
<pre><code class="language-js">const take = n =&gt; function*(iterable) {
  let i = 0;
  for (let x of iterable) {
    if (i &gt;= n) return;
    yield x;
    i++;
  }
};</code></pre>
<p><a href="https://jrsinclair.com/articles/2022/javascript-function-composition-whats-the-big-deal/#pipe"><em>pipe()</em></a>의 도움을 조금 받아서 이 두 가지 유틸리티 함수를 사용하면 문제를 해결할 수 있습니다.</p>
<pre><code class="language-js">const pipe = (x0, ...fns) =&gt; fns.reduce(
    (x, f) =&gt; f(x),
    x0
);

function slamTimTamsWithGenerators(timtams) {
    return pipe(timtams,
        map(biteArbitraryCorner),
        map(biteOppositeCorner),
        map(insertInBeverage),
        map(drawLiquid),
        map(insertIntoMouth),
        take(MAX_TIMTAMS)
    );
}</code></pre>
<p>이제 배열 메서드 버전과 마찬가지로 팀탐 처리에 대한 제대로 된 설명을 할 수 있었습니다. 제너레이터는 지연되기 때문에 머그잔에 5개의 비스킷으로 끝나지 않을 것입니다. 단, 이 기능에는 문제가 있습니다. 현재 형식에서는 <code>slamTimTamsWithGenerators()</code>를 실행해도 아무 작업도 수행되지 않습니다. 이는 제너레이터가 너무 게을러서 <em>아무것도</em> 하지 않기 때문입니다. 즉, 값을 가져오기 위해 어떠한 행동도 취하지 않는 한 말입니다. 이를 수행하는 일반적으로 두 가지 방법이 있습니다.</p>
<ol>
<li>spread 구문을 사용하여 제너레이터 객체를 배열로 변환합니다.</li>
<li>값을 yield <em>하지 않고</em> 생성기를 반복합니다.</li>
</ol>
<p>두 번째 방법을 사용하면 배열 메서드 <code>.forEach()</code>와 매우 유사한 <code>forEach()</code> 유틸리티를 작성할 수 있습니다. 이것은 다음과 같습니다.</p>
<pre><code class="language-js">const forEach = effect =&gt; function(iterator) {
  for (let x of iterator) {
    effect(x);
  }
}</code></pre>
<p>이 유틸리티에는 별표 또는 <code>yield</code> 키워드가 없습니다. 단지 effect가 있고 이터레이터의 각 값으로 effect를 실행합니다. 이를 통해 다른 가상 함수 <code>eat()</code>를 파이프라인에 추가하면 새 유틸리티를 사용할 수 있습니다.</p>
<pre><code class="language-js">function slamTimTamsAndEat(timtams) {
    return pipe(timtams,
        map(biteArbitraryCorner),
        map(biteOppositeCorner),
        map(insertInBeverage),
        map(drawLiquid),
        map(insertIntoMouth),
        take(MAX_TIMTAMS),
        forEach(eat)
    );
}</code></pre>
<p>이제 우리 함수는 5개의 팀탐을 올바른 순서로 먹을 것입니다. 그러나 여전히 처리를 5개(즉, <code>MAX_TIMTAMS</code>)로 제한합니다.</p>
<p>이 &#39;지연&#39; 기능은 제너레이터 함수를 유용하게 만드는 첫 번째 기능입니다. 데이터를 처리하는 방식을 변경할 수 있게 해줍니다. 예를 들어, 한 번에 하나의 항목을 메모리에 로드하여 대용량 데이터 세트를 처리할 수 있습니다. 그리고 이것만으로도 제너레이터를 흥미롭게 만들기에 충분합니다. 그러나 지연에는 다른 이점이 있습니다.</p>
<h2 id="무한-이터레이터-infinite-iterators">무한 이터레이터 (infinite iterators)</h2>
<p>1990년대에 Arnotts는 팀탐의 광고 시리즈를 진행했습니다. 이들 중 첫 번째 시리즈는 케이트 블란쳇이 지니를 만나는 장면이었습니다. 그리고 그녀는 끊임없이 팀탐 상자를 바라는 캐릭터였습니다.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/I5bY2UVY7QI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p><a href="https://www.youtube.com/watch?v=-p7thvWWLL0">전체 광고 시리즈</a>는 무한한 팀탐 상자라는 개념에 초점을 맞췄습니다. 그리고 끊임없는 팀탐 상자와 마찬가지로 제너레이터는 무한 이터레이터를 만들 수 있습니다.</p>
<p>예를 들어 무한 시퀀스를 제공하는 제너레이터 함수를 만들 수 있습니다.</p>
<pre><code class="language-js">function* allTheOnes() {
    while (true) { 
        yield 1;
    }
}

console.log([...take(7)(allTheOnes())]);
// [ 1, 1, 1, 1, 1, 1, 1 ]</code></pre>
<p>이제 흥미로울 수도 있지만 아마도 그다지 유용하지 않을 것입니다. 그러나 반복하려는 값을 지정해서 좀 더 일반적으로 만들 수 있습니다.</p>
<pre><code class="language-js">function* repeat(val) {
    while (true) {
        yield val;
    }
}

console.log([...take(3)(repeat(&#39;팀탐&#39;))]);
// [ &#39;팀탐&#39;, &#39;팀탐&#39;, &#39;팀탐&#39; ]</code></pre>
<p>그래도 그다지 유용하지 않은 것 같습니다. 그러나 이것을 사용하여 다른 시퀀스를 만들 수 있습니다. <code>scanl()</code>이라는 함수를 정의했다고 가정합니다. Array의 <code>.reduce()</code> 메서드와 약간 비슷하게 작동합니다. 그러나 단일 값을 반환하는 대신 일련의 값을 생성합니다.</p>
<pre><code class="language-js">function* scanl(reducer, initalVal, iterator) {
  let b = initalVal;
  yield b;
  for (const x of iterator) {
    b = reducer(b, x);
    yield b;
  }
}</code></pre>
<p>그리고 <code>scanl()</code>을 사용하여 일련의 자연수를 생성할 수 있습니다.</p>
<pre><code class="language-js">const add = (a, b) =&gt; a + b;
const genNat = pipe(
    repeat(1),
    (ones) =&gt; scanl(add, 0, ones)
);</code></pre>
<p>하지만 사실 다음과 같이 작성하는 것이 더 쉽습니다.</p>
<pre><code class="language-js">function* genNat() {
  for (let i = 0; true; i++) yield i;
}</code></pre>
<p>여기서 요점은 양의 정수 지연 목록을 생성하는 가장 효과적인 방법을 보여주는 것이 아닙니다. <code>repeat()</code> 및 <code>scanl()</code>과 같은 도구를 사용하면 단순한 것에서 복잡한 무한 시퀀스를 만들 수 있습니다.</p>
<p>하지만 양의 정수의 무한 목록을 생성하는 것이 그다지 흥미롭지 않다는 점은 인정하겠습니다. 정말 도움이 되는 것을 해봅시다. 예를 들어, 암호화 또는 임의적인 모습을 만드는데 유용합니다. 우리는 일련의 소수를 생성할 것입니다.</p>
<p>이를 하기 위해서 헬퍼 함수가 두 개 더 필요합니다. 먼저 생성된 시퀀스를 필터링하려고 합니다.</p>
<pre><code class="language-js">function* filter(p, xs) {
  for (const x of xs) if (p(x)) yield x;
}</code></pre>
<p>그리고 두 번째 유틸리티 함수인 <code>pop()</code>은 다음과 같습니다.</p>
<pre><code class="language-js">const pop = (iterator) =&gt; {
  const result = iterator.next();
  if (result.done) return;
  return [result.value, iterator];
}</code></pre>
<p>이 <code>pop()</code> 함수는 제너레이터(및 일반적으로 이터레이터)의 약점을 드러냅니다. 약점은 변경 가능하다는 것입니다. 시퀀스에서 한 항목을 pop하면 더 이상 원래 시퀀스를 가져올 수 없습니다. 제너레이터로 작업할 때 주의해야 할 사항입니다. 하지만 지금은 이 두 가지 헬퍼 함수가 있으므로 소수 제너레이터를 함께 사용할 수 있습니다. 그리고 <a href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"><em>에라토스테네스의 체</em></a>라고 불리는 기법을 사용합니다. 알고리즘은 다음과 같이 작동합니다.</p>
<ol>
<li>2부터 시작하는 모든 자연수 목록으로 시작합니다.</li>
<li>목록의 첫 번째 요소를 선택한 다음 목록에서 해당 숫자의 배수를 모두 제거합니다.</li>
<li>2단계로 이동하여 목록의 다음 번호로 반복합니다.</li>
</ol>
<p>자바스크립트에서 이 작업을 수행하기 위해 두 가지 함수를 만듭니다. 하나는 숫자 목록을 걸러내는 작업을 수행하고 다른 하나는 모든 것을 시작하는 것입니다. 걸러내기 위한 체질(sieving) 함수는 다음과 같습니다.</p>
<pre><code class="language-js">function* sieve(nums) {
  const result = pop(nums);
  if (!result) return;
  const [n, rest] = result;
  yield n;
  yield* sieve(filter(x =&gt; ((x % n) !== 0), rest));
}</code></pre>
<p><code>yield*</code> 키워드에 주의해 주세요. 이터러블 객체가 있는 경우 <code>yield*</code>는 &quot;이 외의 이터러블에서 모든 것을 yield한다&quot;를 말합니다. 이를 통해 배열의 <code>.flatMap()</code>과 같은 작업을 수행할 수 있습니다.</p>
<p>이제 sieve 함수가 준비되었으므로 2부터 시작하는 모든 자연수 목록으로 시작해야 합니다. 또 다른 유틸리티 함수의 도움을 받아서 이를 생성할 수 있습니다.</p>
<pre><code class="language-js">function* drop(n, iterable) {
  let i = 0;
  for (const val of iterable) {
    if (i &gt;= n) yield val;
    else i++;
  }
}</code></pre>
<p>그리고 이제 이 모든 것을 하나로 합칠 수 있습니다.</p>
<pre><code class="language-js">const primes = () =&gt; sieve(drop(2, genNat()));
console.log([...take(9)(primes())]);
// [ 2, 3, 5, 7, 11, 13, 17, 19, 23 ]</code></pre>
<p>물론 소수를 생성하는 더 효율적인 다른 방법이 있습니다(아마도). 그러나 여기서의 요점은 소수에 관한 것이 아닙니다. 오히려 무한 시퀀스를 통해 문제에 대해 다르게 생각할 수 있는 방법을 보여줍니다. 또한 다음과 같은 애플리케이션에서 지연 및 무한 시퀀스를 사용할 수 있습니다.</p>
<ul>
<li>일련의 고유 식별자 생성</li>
<li>게임에서 가능한 모든 움직임을 생성합니다.</li>
<li>많은 순열 및 조합 중에서 특정 값(또는 값)을 찾습니다.</li>
</ul>
<h2 id="이런-모든-유틸리티-기능이-내장되어-있지-않은-이유는-무엇인가요">이런 모든 유틸리티 기능이 내장되어 있지 않은 이유는 무엇인가요?</h2>
<p>지금까지의 모든 예제를 통해 우리는 우리만의 작은 유틸리티 함수를 작성했습니다. 여기에는 <code>map()</code>, <code>take()</code>, <code>forEach()</code>, <code>filter()</code>, <code>scanl()</code> 및 <code>drop()</code>과 같은 함수가 포함됩니다. 또한 제너레이터에 배열과 같은 임베디드 메서드가 없는 것은 조금 번거롭습니다. 그렇게 느끼는 사람은 당신뿐만이 아닙니다. 이것이 ECMAScript 표준에 <a href="https://www.proposals.es/proposals/Iterator%20helpers"><em>이터레이터 헬퍼</em></a>를 추가하기 위한 2단계 TC39 제안이 있는 이유입니다.</p>
<p>그 사이에 스스로 헬퍼를 만들고 싶지 않다면 도움이 되는 라이브러리를 찾을 수 있습니다. 일반적인 예로 다음 두 가지가 있습니다.</p>
<ul>
<li><a href="https://www.npmjs.com/package/itertools"><em>Itertools</em></a> (인기 있는 Python 라이브러리 기반)</li>
<li><a href="https://github.com/ReactiveX/IxJS"><em>IxJS</em></a> (RxJS와 유사하지만 이터러블용).</li>
</ul>
<p>좀 더 가벼운 것을 찾고 있다면 제 개인 툴킷인 <a href="https://codesandbox.io/s/dynamonoodling-on-generators-xwidr?file=/src/Dynamo.ts">Dynamo</a>를 살펴볼 수 있습니다. 단, 여기서 사용하는 일반적인 자바스크립트가 아니라 타입스크립트로 작성되어 있다는 점을 유의해 주세요.</p>
<h2 id="메시지-전달">메시지 전달</h2>
<p>제너레이터의 지연은 매력적이고 유용합니다. 그러나 이것이 제너레이터가 할 수 있는 전부는 아닙니다. 제너레이터를 사용하면 한 쌍의 함수 간에 메시지를 양방향으로 전달할 수 있습니다. 솔직히 말하면 함수는 이미 이 작업을 수행할 수 있습니다. <em>매개 변수를 제공해서 호출_된 함수에 메시지를 전달합니다. 그런 다음 _호출</em> 함수는 반환 값을 통해 다시 메시지를 받습니다. 그러나 그것은 일회성입니다. 처음에는 한 방향으로 하나의 메시지를 받고 마지막에는 다른 방향으로 메시지를 받습니다. 하지만 제너레이터를 사용하면 많은 메시지를 주고받을 수 있습니다.</p>
<p>가장 일반적인 예는 <code>async/await</code> 구문을 모방하는 것입니다. 예를 들어 Node 코드를 작성한다고 가정합니다. 우리가 작성하는 함수는 다음과 같아야 합니다.</p>
<ul>
<li>파일에서 설정정보를 읽습니다.</li>
<li>fetch 호출을 만들어 인증 토큰을 얻습니다.</li>
<li>일부 데이터를 얻기 위해 토큰으로 또 다른 fetch를 호출합니다.</li>
</ul>
<p><code>async/await</code>를 사용하면 다음과 같이 보일 수 있습니다.</p>
<pre><code class="language-js">const getData = async () =&gt; {
  const cfg = await readConfig();
  const authDetails = extractAuthDetails(cfg);
  const token = await fetchAuthToken(authDetails);
  const data = await secureFetch(DATA_URL, token);
  return data;
};</code></pre>
<p>그러나 <code>async/await</code>가 있기 전에는 제너레이터를 사용하여 다음과 같이 할 수 있었습니다.</p>
<pre><code class="language-js">const getData = asyncDo(function*() {
  const cfg = yield readConfig();
  const authDetails = extractAuthDetails(cfg);
  const token = yield fetchAuthToken(authDetails);
  const data = yield secureFetch(DATA_URL, token);
  return data;
});

const promiseForData = getData();</code></pre>
<p>그리고 그것은 <code>async/await</code> 버전처럼 보입니다. 그렇지 않나요? 하지만 제대로 작동하려면 약간의 추가 작업이 필요합니다. 추가 작업은 다음과 같습니다.</p>
<pre><code class="language-js">const asyncDo = (runTasks) =&gt; (...args) =&gt; {
  // runTasks()는 예를 들어 getData()와 같은 제너레이터 함수가 될 것으로 예상하고 있습니다.
  // 먼저 제너레이터 객체를 얻기 위해 실행합니다.
  const generator = runTasks(...args);
  // 다음으로 제너레이터 함수에서 생성된 Promise를 확인하는 재귀 함수를 만듭니다.
  const resolve = (next) =&gt; {
    // 모든 재귀 함수에서 작업이 완료되었는지 확인해야 합니다. 
    // 여기에서 제너레이터 결과에서 반환된 `done` 속성을 확인합니다.
    if (next.done) return Promise.resolve(next.value);
    // 우리는 `next.value`가 항상 promise라고 가정합니다. 
    // 아직 완료하지 않은 경우 값을 가져오고 .next()를 사용해서 제너레이터로 다시 전달합니다.
    return next.value.then(data =&gt; resolve(generator.next(data)));
  }
  // resolve()를 호출하여 프로세스 전체를 시작합니다.
  return resolve(generator.next());
};</code></pre>
<p>이건 깔끔합니다. 하지만 아마 그렇게 유용하지 않을 것입니다. 우리 대부분은 <code>async/await</code>를 모방할 필요가 없습니다. 하지만 그렇게 말해도 코드를 오래된 브라우저에서 작동시키기 위해 아마 Babel(또는 유사한 것)을 사용하고 있을 것입니다. 이 경우 트랜스파일러는 이런 제너레이터를 사용해서 <code>async/await</code>을 작동하게 합니다. 그리고 제너레이터는 매우 저수준이기 때문에 <code>.next()</code>에서는 할 수 없는 방법으로 이 yield 패턴을 만질 수 있습니다. 이를 통해 작성자는 <code>async/await</code>를 넘어서는 흥미로운 라이브러리를 만들 수 있습니다. 예를 들어, Kyle Simpson의 _<a href="https://github.com/getify/CAF">CAF (Cancellable Async Flows)</a>_가 있습니다.</p>
<blockquote>
<p>CAF [...] 는 비동기 함수처럼 처리하지만 토큰을 통한 외부 취소를 지원하는 <code>function*</code> 제너레이터용 래퍼입니다. 이렇게 해서 동기로 보이는 취소 가능한 비동기 로직의 흐름을 표현할 수 있습니다. 여전히 취소 가능한 비동기 처리가 (아직) 필요하지 않을 수 있습니다. 그래도 promise를 조작하는 것 외에도 제너레이터의 메시지 전달에는 많은 것이 있습니다. 예를 들어 오류 처리를 단순화하는 데 사용할 수 있습니다.</p>
</blockquote>
<h3 id="오류-처리를-추상화하기-위해-전달되는-메시지">오류 처리를 추상화하기 위해 전달되는 메시지</h3>
<p>이전에 <a href="https://jrsinclair.com/articles/2019/elegant-error-handling-with-the-js-either-monad/"><em>둘 중 하나를 사용해서 오류를 처리하는 방법</em></a>에 대해 쓴 적이 있습니다. Either 구조를 사용해서 실패할 수 있는 작업의 결과를 나타낼 수 있습니다. 규칙에 따라 <code>Left</code>라는 클래스를 사용해서 실패를 나타냅니다. 그리고 <code>Right</code>라는 클래스를 사용해서 성공을 나타냅니다. 다음은 두 개의 Either 클래스의 단순화된 버전입니다.</p>
<pre><code class="language-js">class Left {
  constructor(val) { this._val = val; }
  map() { return this; }
  flatMap() { return this; }
  isLeft() { return true; }
}

class Right {
  constructor(val) { this._val = val; }
  map(fn) { return new Right(fn(this._val)); }
  flatMap(fn) { return fn(this._val); }
  isLeft() { return false; }
}

// 편의를 위한 생성자 함수
const right = x =&gt; new Right(x);
const left = x =&gt; new Left(x);</code></pre>
<p>이제 해당 기사에서 CSV 파일을 구문 분석하는 예를 살펴보았습니다. 그리고 단일 행을 구문 분석하기 위해 다음과 같은 함수를 생각했습니다.</p>
<pre><code class="language-js">function processRowChained(headers, row) {
  return right(row)
    .map(splitFields)
    .flatMap(zipRow(headers))
    .flatMap(addDateStr);
}</code></pre>
<p>이것은 Either를 반환하는 함수입니다. 그러나 제너레이터와 메시지 전달을 사용하면 <code>yield</code>를 사용해서 Either를 약간 덮어쓸 수 있습니다. 다음과 같이 보입니다.</p>
<pre><code class="language-js">const processRow = eitherDo(function* (headers, row) {
  const fieldData = splitFields(row);
  const rowObj = yield zipRow(headers)(fieldData);
  const withDateStr = yield addDateStr(rowObj);
  return withDateStr;
});</code></pre>
<p>이 경우 제너레이터 함수가 항상 Either를 생성할 것으로 예상합니다. 그리고 <code>eitherDo</code> 함수는 그렇게 작동합니다.</p>
<pre><code class="language-js">// eitherDo()는 함수를 반환하는 함수입니다.
const eitherDo = (genFn) =&gt; (...args) =&gt; {
  // 전달된 인수를 사용해서 제너레이터 함수를 호출하여 메시지 전달을 시작합니다.
  const generator = genFn(...args);
  // 다음으로 제너레이터에서 처음 생성된 값을 가져옵니다.
  let next = generator.next();

  // `done` 응답을 받을 때까지 계속 값을 처리합니다.
  do {
    // 반환 값이 Either가 아닌 일반 값이라고 가정하므로 Right로 래핑합니다.
    if (next.done) return right(next.value);

    // Left를 만나면 나머지는 모두 건너뛰고 Left 구조를 반환합니다.
    if (next.value.isLeft()) return next.value;

    // 아직 여기에 있는 경우 제네레이터에서 Right를 얻었으므로
    // 여기서 값을 추출하여 제너레이터 함수로 전달합니다.
    next = generator.next(next.value._val);
  } while (!next.done);
}</code></pre>
<p>결국 우리는 <code>processRow()</code>에서 Either 값을 다시 얻습니다. <code>processRow()</code>은 <code>processRowChained()</code>와 같은 일을 합니다. 그러나 이런 코드 스타일은 특히 연결된(chained) 메서드 호출에 익숙하지 않은 일부 사용자에게 더 편안하게 느껴질 수 있습니다.</p>
<h2 id="마무리">마무리</h2>
<p>제너레이터에 익숙하지 않다면 처음에는 조금 이상하게 보일 수 있습니다. 그리고 제너레이터는 매우 저수준 언어이라서 다양한 애플리케이션에 사용할 수 있습니다. 그렇기 때문에 당신이 매일 제너레이터가 필요한지 알기 어려울 수 있습니다. 그러나 지금까지 살펴본 것처럼 제너레이터는 다음과 같은 작업에 도움이 됩니다.</p>
<ul>
<li>대용량 데이터 세트를 효율적으로 처리</li>
<li>무한 시퀀스 작업</li>
<li>두 함수 사이에 메시지를 전달</li>
</ul>
<p>이제 제너레이터를 알 필요가 없다고 느꼈을 수도 있습니다. 여러분이 하고 있는 일이 제너레이터에 적합하지 않을 수도 있습니다. 그러나 만일을 대비해서 도구 상자(toolbox)에 넣어두면 편리합니다. 그리고 살펴보기 시작하면 많은 곳에서 은밀히 작동하는 제너레이터를 찾을 수 있습니다. 그리고 가끔 라이브러리 코드를 파헤쳐야 할 수도 있습니다. 이러한 경우 제너레이터가 어떻게 작동하는지 이해해 두면 좋습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] 전문가처럼 타입스크립트 infer 사용하기]]></title>
            <link>https://velog.io/@dev_boku/%EC%A0%84%EB%AC%B8%EA%B0%80%EC%B2%98%EB%9F%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-infer-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_boku/%EC%A0%84%EB%AC%B8%EA%B0%80%EC%B2%98%EB%9F%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-infer-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 23 Oct 2022 14:20:14 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 : <a href="https://levelup.gitconnected.com/using-typescript-infer-like-a-pro-f30ab8ab41c7">https://levelup.gitconnected.com/using-typescript-infer-like-a-pro-f30ab8ab41c7</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 : <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-%EC%A0%84%EB%AC%B8%EA%B0%80%EC%B2%98%EB%9F%BC-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-infer-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] 문 vs 표현식]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-%EB%AC%B8-vs-%ED%91%9C%ED%98%84%EC%8B%9D</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-%EB%AC%B8-vs-%ED%91%9C%ED%98%84%EC%8B%9D</guid>
            <pubDate>Wed, 05 Oct 2022 13:24:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_boku/post/900e92ff-ed5a-496e-a46b-daa330219dab/image.PNG" alt=""></p>
<blockquote>
<p>원문 : <a href="https://www.joshwcomeau.com/javascript/statements-vs-expressions/">https://www.joshwcomeau.com/javascript/statements-vs-expressions/</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 : <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-%EB%AC%B8-vs-%ED%91%9C%ED%98%84%EC%8B%9D">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] JavaScript 패키지 매니저 비교 - npm, Yarn 또는 pnpm?]]></title>
            <link>https://velog.io/@dev_boku/JavaScript-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80-%EB%B9%84%EA%B5%90-npm-Yarn-%EB%98%90%EB%8A%94-pnpm</link>
            <guid>https://velog.io/@dev_boku/JavaScript-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80-%EB%B9%84%EA%B5%90-npm-Yarn-%EB%98%90%EB%8A%94-pnpm</guid>
            <pubDate>Sun, 18 Sep 2022 12:57:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_boku/post/69ccbdfd-40fe-4ffd-a26e-fdf6154464c2/image.png" alt=""></p>
<blockquote>
<p>원문 : <a href="https://doppelmutzi.github.io/packageManagers/">https://doppelmutzi.github.io/packageManagers/</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다: <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-JavaScript-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80-%EB%B9%84%EA%B5%90-npm-Yarn-%EB%98%90%EB%8A%94-pnpm">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] React에 SOLID 원칙 적용하기]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-React%EC%97%90-SOLID-%EC%9B%90%EC%B9%99-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-React%EC%97%90-SOLID-%EC%9B%90%EC%B9%99-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 26 Jul 2022 06:24:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 : <a href="https://medium.com/dailyjs/applying-solid-principles-in-react-14905d9c5377">https://medium.com/dailyjs/applying-solid-principles-in-react-14905d9c5377</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 : <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-React%EC%97%90-SOLID-%EC%9B%90%EC%B9%99-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] Ecma 인터네셔널에서 ECMAScript 2022를 승인했습니다. 새로운 기능은 무엇인가요?]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Ecma-%EC%9D%B8%ED%84%B0%EB%84%A4%EC%85%94%EB%84%90%EC%97%90%EC%84%9C-ECMAScript-2022%EB%A5%BC-%EC%8A%B9%EC%9D%B8%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4.-%EC%83%88%EB%A1%9C%EC%9A%B4-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Ecma-%EC%9D%B8%ED%84%B0%EB%84%A4%EC%85%94%EB%84%90%EC%97%90%EC%84%9C-ECMAScript-2022%EB%A5%BC-%EC%8A%B9%EC%9D%B8%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4.-%EC%83%88%EB%A1%9C%EC%9A%B4-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94</guid>
            <pubDate>Sun, 10 Jul 2022 02:27:32 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 : <a href="https://2ality.com/2022/06/ecmascript-2022.html">https://2ality.com/2022/06/ecmascript-2022.html</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 : <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-Ecma-%EC%9D%B8%ED%84%B0%EB%84%A4%EC%85%94%EB%84%90%EC%97%90%EC%84%9C-ECMAScript-2022%EB%A5%BC-%EC%8A%B9%EC%9D%B8%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4-%EC%83%88%EB%A1%9C%EC%9A%B4-%EA%B8%B0%EB%8A%A5%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] Reduce에 대한 10가지 필수 JavaScript 트릭 및 팁]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Reduce%EC%97%90-%EB%8C%80%ED%95%9C-10%EA%B0%80%EC%A7%80-%ED%95%84%EC%88%98-JavaScript-%ED%8A%B8%EB%A6%AD-%EB%B0%8F-%ED%8C%81</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Reduce%EC%97%90-%EB%8C%80%ED%95%9C-10%EA%B0%80%EC%A7%80-%ED%95%84%EC%88%98-JavaScript-%ED%8A%B8%EB%A6%AD-%EB%B0%8F-%ED%8C%81</guid>
            <pubDate>Tue, 14 Jun 2022 04:14:46 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 : <a href="https://javascript.plainenglish.io/10-must-know-javascript-tricks-tips-about-reduce-1368766d99da">https://javascript.plainenglish.io/10-must-know-javascript-tricks-tips-about-reduce-1368766d99da</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 : <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-Reduce%EC%97%90-%EB%8C%80%ED%95%9C-10%EA%B0%80%EC%A7%80-%ED%95%84%EC%88%98-JavaScript-%ED%8A%B8%EB%A6%AD-%EB%B0%8F-%ED%8C%81">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] 자바스크립트 번들러 만들기]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B2%88%EB%93%A4%EB%9F%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B2%88%EB%93%A4%EB%9F%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 16 May 2022 14:45:50 GMT</pubDate>
            <description><![CDATA[<h1 id="자바스크립트-번들러-만들기">자바스크립트 번들러 만들기</h1>
<p><img src="https://velog.velcdn.com/images/dev_boku/post/e16c022a-e52c-4be6-85b7-a18621d5c55a/image.png" alt=""></p>
<blockquote>
<p>원문: <a href="https://cpojer.net/posts/building-a-javascript-bundler">https://cpojer.net/posts/building-a-javascript-bundler</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다:  <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%B2%88%EB%93%A4%EB%9F%AC-%EB%A7%8C%EB%93%A4%EA%B8%B0">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Top 75 LeetCode Questions] Two Sum (with JS)]]></title>
            <link>https://velog.io/@dev_boku/Top-75-LeetCode-Questions-Two-Sum-with-JS</link>
            <guid>https://velog.io/@dev_boku/Top-75-LeetCode-Questions-Two-Sum-with-JS</guid>
            <pubDate>Thu, 05 May 2022 13:00:36 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>LeetCode에는 문제가 무수히 많기 때문에 어떤 것부터 풀어봐야할지 어려움이 많습니다. 그래서 서칭을 하던 도중 블라인드에 Facebook 엔지니어가 정리해준 <a href="https://www.teamblind.com/post/New-Year-Gift---Curated-List-of-Top-75-LeetCode-Questions-to-Save-Your-Time-OaM1orEU">75가지 LeetCode 주요 질문 리스트</a>가 눈에 띄었고 이를 풀어보기로 결정했습니다. 저는 프론트엔드 엔지니어이기 때문에 이 문제들을 Javascript로 풀어보도록 하겠습니다.</p>
<blockquote>
<p>링크 : <a href="https://leetcode.com/problems/two-sum/">https://leetcode.com/problems/two-sum/</a></p>
</blockquote>
<h1 id="문제">문제</h1>
<pre><code>정수 배열 nums와 정수 target이 주어지면 두 숫자를 합한 값이 target 값이 되는 두 숫자의 인덱스를 반환하여 대상에 합산되도록 합니다.

각 입력에 정확히 하나의 솔루션이 있다고 가정하고, 동일한 요소를 두 번 사용하지 않을 수 있습니다.

어떤 순서로든 답변을 반환할 수 있습니다.</code></pre><h1 id="풀이">풀이</h1>
<h3 id="1-브루트포스-brute-force">1) 브루트포스 (Brute Force)</h3>
<ul>
<li>시간복잡도 : O(n^2)<pre><code class="language-js">/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
  for (let first = 0; first &lt; nums.length; first++) {
      for (let second = first + 1; second &lt; nums.length; second++) {
          if (nums[first] + nums[second] === target) {
              return [first, second];
          }
      }
  }
};
};</code></pre>
</li>
</ul>
<h3 id="2-hash-table-2번-사용">2) Hash Table 2번 사용</h3>
<ul>
<li>시간복잡도 : O(n)<pre><code class="language-js">/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
  const map = new Map();
  for (let i = 0; i &lt; nums.length; i++) {
      map.set(nums[i], i);
  }
  for (let i = 0; i &lt; nums.length; i++) {
      let complement = target - nums[i];
      if (map.has(complement) &amp;&amp; map.get(complement) !== i) {
          return [i, map.get(complement)];
      }
  }
  return null;
};</code></pre>
</li>
</ul>
<h3 id="3-hash-table-1번-사용">3) Hash Table 1번 사용</h3>
<ul>
<li>시간복잡도 : O(n)<pre><code class="language-js">/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
  const map = new Map();
  for (let i = 0; i &lt; nums.length; i++) {
      let complement = target - nums[i];
      if (map.has(complement)) {
          return [i, map.get(complement)];
      }
      map.set(nums[i], i);
  }
  return null;
};</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] Remix: 리액트의 음에 양을]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Remix-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%9D%8C%EC%97%90-%EC%96%91%EC%9D%84</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Remix-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%9D%8C%EC%97%90-%EC%96%91%EC%9D%84</guid>
            <pubDate>Sat, 23 Apr 2022 07:35:28 GMT</pubDate>
            <description><![CDATA[<h1 id="remix-리액트의-음에-양을">Remix: 리액트의 음에 양을</h1>
<blockquote>
<p>원문 : <a href="https://kentcdodds.com/blog/remix-the-yang-to-react-s-yin">https://kentcdodds.com/blog/remix-the-yang-to-react-s-yin</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다 <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-Remix-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%9D%8C%EC%97%90-%EC%96%91%EC%9D%84">티스토리</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역] Remixing React Router]]></title>
            <link>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Remixing-React-Router</link>
            <guid>https://velog.io/@dev_boku/%EB%B2%88%EC%97%AD-Remixing-React-Router</guid>
            <pubDate>Sun, 10 Apr 2022 07:43:35 GMT</pubDate>
            <description><![CDATA[<h1 id="remixing-react-router">Remixing React Router</h1>
<blockquote>
<p>원문 : <a href="https://remix.run/blog/remixing-react-router">https://remix.run/blog/remixing-react-router</a></p>
</blockquote>
<blockquote>
<p>블로그를 이전했습니다. <a href="https://dev-boku.tistory.com/entry/%EB%B2%88%EC%97%AD-Remixing-React-Router">티스토리</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>