<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Daniel's Note</title>
    <link>https://daniel-park.tistory.com/</link>
    <description>실리콘밸리 스타트업에서 일하다 보니, 어느덧 6년차 개발자가 되었습니다.
프론트, 프로트콜, 백엔드, 경험 등 여러가지를 다루어보려고 합니다!</description>
    <language>ko</language>
    <pubDate>Fri, 21 Aug 2026 12:16:31 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Daniel(빡일)</managingEditor>
    <image>
      <title>Daniel's Note</title>
      <url>https://tistory1.daumcdn.net/tistory/3892786/attach/d1b9480fc52948d3a9e47fc2f05e4a62</url>
      <link>https://daniel-park.tistory.com</link>
    </image>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 47 에러처리</title>
      <link>https://daniel-park.tistory.com/99</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.4 throw문&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0L0a9/btr8LOdEuT6/9UFY8kyqLCauEY1JpAt8o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0L0a9/btr8LOdEuT6/9UFY8kyqLCauEY1JpAt8o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0L0a9/btr8LOdEuT6/9UFY8kyqLCauEY1JpAt8o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0L0a9%2Fbtr8LOdEuT6%2F9UFY8kyqLCauEY1JpAt8o0%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정보 전달용이 아닌 개인 스터디 레코딩용 포스트입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.1 에러 처리의 필요성&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발자라면 비지니스 로직을 잘 짜는 것도 중요하지만 에러를 잘 핸들링 하는 것도 능력이라고 생각한다. 에러가 발생하지 않는 코드는 없기 때문인데, 에러를 &quot;잘&quot; 파악하기 위한 처리가 필요하다. 발생한 에러에 대해 대처하지 않으면 프로그램이 종료될 수 있다. 사실 이것보다 무서운건 &quot;그냥&quot; 지나가는 것인데, 파급 효과를 알 수 없기 때문에 그 중요성이 더 크다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.2 try... catch... finally문&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 에러 처리를 구현하는 방법은 크게 두 가지가 있다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;querySelector나 Array#find 메서드처럼 예외적인 상황이 발생하면 반환하는 값(Null || -1)을 if 문이나 단축 평가 또는 옵셔널 체이닝 연산자를 통해 확인해서 처리하는 방법&lt;/li&gt;
&lt;li&gt;에러 처리 코드를 미리 등록해 두고 에러가 발생하면 에러 처리 코드로 점프하도록 하는 방법 (try...catch..finally가 해당)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.3 Error 객체&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Error &lt;/b&gt;생성자 함수는 에러를 상세히 설명하는 에러 메세지를 인수로 전달하는 에러 객체를 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Error 생성자 함수가 생성한 에러 객체는 message 프로퍼티와 stack 프로퍼티를 갖는다. message 프로퍼티의 값은 Error 생성자 함수에 인수로 전달한 에러메세지이고, stack 프로퍼티 값은 에러를 발생시킨 콜스택의 호출 정보를 나타내는 문자열이다(디버깅 목적).&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 144px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;생성자 함수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;인스턴스&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;Error&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;일반적 에러 객체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;SyntaxError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;자바스크립트 문법에 맞지 않는 문을 해석할 떄&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;ReferenceError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;참조할 수 없는 식별자를 참조했을때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;TypeError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;피연산자 또는 인수의 데이터 타입이 유요하지 않을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;RangeError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;숫자값의 허용 범위를 벗어났을 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;URIError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;encodeURI 또는 decodeURI 함수에 부적절한 인수를 전달했을 때&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;EvalError&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;eval 함수에서 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.4 throw문&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러를 발생시키려면 try 코드 블록에서 throw 문으로 에러 객체를 던져야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;throw 문의 표현식은 어떤 값이라도 상관없지만 일반적으로 에러 객체를 지정한다. 에러를 던지면 catch 문의 에러 변수가 생성되고 던져진 에러 객체가 할당되어 catch 코드 블록이 실행되기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 47-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681027111202&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
 throw new Error('something wrong')
} catch(error) {
 console.log(error)
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;47.5 에러의 전파&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;45장 &quot;프로미스&quot;의 45.1.2절 &quot;에러 처리의 한계&quot;에서 살펴본 것처럼 에러는 호출자(caller) 방향으로 전파된다. 즉, 콜 스택의 아래 방향(실행 중인 실행 컨택스트가 푸시되기 직전에 푸시된 실행 컨택스트 방향)으로 전파된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 47-02]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681027261254&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const foo = () =&amp;gt; {
 throw Error('foo')  //4
}

const bar = () =&amp;gt; {
 foo(); //3
}

const baz = () =&amp;gt; {
 bar(); //2
}

try {
 baz(); //1
} catch(err) {
 console.error(err)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1에서 baz 함수를 호출하면 2에서 bar 함수 3에서 foo 그리고 4에서 에러를 throw한다. 이때 foo 함수가 throw한 에러는 다음과 같이 호출자에게 전파되어 전역에서 캐치된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boHp36/btr8OViNLdc/9qhoJWuyNrqQuoqgb9pl91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boHp36/btr8OViNLdc/9qhoJWuyNrqQuoqgb9pl91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boHp36/btr8OViNLdc/9qhoJWuyNrqQuoqgb9pl91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboHp36%2Fbtr8OViNLdc%2F9qhoJWuyNrqQuoqgb9pl91%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;400&quot; height=&quot;432&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;throw된 에러를 캐치하지 않으면 호출자 방향으로 전파된다. 따라서 throw된 에러를 캐치하여 적절히 대응해야 프로그램에 타격을 줄이면서 코드의 실행 흐름을 복구할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setTimeout이나 프로미스 후속 처리 메서드의 콜백 함수는 호출자가 없기 때문에 주의가 필요하다. 이 두 가지 함수들은 태스크 큐나 마이크로태스크 큐에 일시 저장되었다가 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 푸시되어 실행된다. 이때 콜 스택에 푸시된 콜백 함수의 실행 컨택스트는 콜 스택의 가장 하부에 존재하게 되기 때문에 에러를 전파할 호출자가 존재하지 않는다.&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/99</guid>
      <comments>https://daniel-park.tistory.com/99#entry99comment</comments>
      <pubDate>Sun, 9 Apr 2023 17:05:02 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 45 Promise</title>
      <link>https://daniel-park.tistory.com/98</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rJCYo/btr8Mqi7hGk/Q5CufJ3kVEtKDtjLiutV2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rJCYo/btr8Mqi7hGk/Q5CufJ3kVEtKDtjLiutV2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rJCYo/btr8Mqi7hGk/Q5CufJ3kVEtKDtjLiutV2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrJCYo%2Fbtr8Mqi7hGk%2FQ5CufJ3kVEtKDtjLiutV2K%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정보 전달용이 아닌 개인 스터디 레코딩용 포스트입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.0 Preface&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JS는 비동기 처리를 위해 콜백 함수를 사용한다. 하지만 Callback Hell로 가독성이 지옥으로 가버리거나 에러 핸들링의 어려움이 있다. 이 단점을 극복하기 위해 ES6에서는 비동기 처리를 위해 Promise  (약속)을 도입했다. 비동기 처리 시점을 명확하게 표현하게 되면서 코드의 가독성을 끌어올릴 수 있게 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.1 비동기 처리를 위한 콜백 패턴의 단점&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;45.1.1 Callback Hell&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;비동기 함수를 호출하면 함수 내부의 비동기로 동작하는 코드가 완료되지 않았다 하더라도 기다리지 않고 즉시 종료된다. 즉, 비동기 함수 내부의 비동기로 동작하는 코드는 비동기 함수가 종료된 이후에 완료된다. 따라서 비동기 함수 내부의 코드에서 처리 결과를 외부로 반환하거나 상위 스코프의 변수에 할당하면 기대한 대로 동작하지 않는다.&quot;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 45-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681019472236&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const get = url =&amp;gt; {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();
  
  xhr.onload = () =&amp;gt; {
    if (xhr.status === 200) {
     return JSON.parse(xhr.response)
    } else {
     console.log(`${xhr.status} ${xhr.statusText}`)
    }
  }
}


const response = get('https://jsonplaceholder.typicode.com/posts/1');
console.log(response)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 예시는 JS를 배우는 단계에서 꽤나 헷갈려하기도 하고 찾아보는 부분이 아닐까 싶다. &amp;nbsp;console.log에 반환 값을 찍으면 &lt;b&gt;undefined&lt;/b&gt;가 찍힌다. get 함수 내부의 onload 이벤트 핸들러가 비동기로 동작하기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;get 함수는 반환문이 생략되었으므로 암묵적으로 undefined를 반환하게 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;비동기 함수 get이 호출되면 함수 코드를 평가하는 과정에서 get 함수의 실행 컨텍스트 생성, 실행 컨택스트 스택에 푸시&lt;/li&gt;
&lt;li&gt;함수 코드 실행 과정에서 xhr.onload 이벤트 핸들러 프로퍼티에 이벤트 핸들러 바인딩&lt;/li&gt;
&lt;li&gt;get 함수 종료시 get 함수의 실행 컨텍스트가 콜 스택에서 팝&lt;/li&gt;
&lt;li&gt;곧바로 console.log(response) 출력&lt;/li&gt;
&lt;li&gt;console.log 실행 컨텍스트가 생성되어 실행 컨텍스트 스택에 푸시
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;console.log가 호출되기 직전에 load 이벤트가 발생했더라도 xhr.onload 이벤트 핸들러 프로퍼티에 바인딩한 이벤트 핸들러는 먼저 실행되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;서버로부터 응답이 도착해야 xhr 객체에서 load 이벤트 발생
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;xhr.onload 핸들러 프로퍼티에 바인딩한 이벤트 핸들러는 load 이벤트가 발생하면 태스크 큐에 저장되어 대기하다가, 콜 스택이 비면 이벤트 루프에 의해 콜 스택으로 푸시되어 실행.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 비동기 함수는 처리 결과를 외부에 반환할 수 없고, 상위 스코프의 변수에 할당할 수 없다. 처리 결과에 대한 후속 처리는 비동기 함수 내부에서 수행해야 하는데 콜백 함수를 전달하는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 45-02] 진정한 callback hell&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681020976330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const get = (url, callback) =&amp;gt; {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();
  
  xhr.onload = () =&amp;gt; {
    if (xhr.status === 200) {
     callback(JSON.parse(xhr.response))
    } else {
     console.log(`${xhr.status} ${xhr.statusText}`)
    }
  }
}


const url = get('https://jsonplaceholder.typicode.com/');


// 그나마 귀여운...
get(`${url}/posts/1`, ({userId}) =&amp;gt; {
  console.log(userId);
  
  get(`${url}/users/${userId}`, userInfo =&amp;gt; {
   console.log(userInfo)
  })
})

// going to the hell
get('/step1', a =&amp;gt; {
 get(`/step2/${a}`, b =&amp;gt; {
  get(`/step3/${b}`, c =&amp;gt; {
   get(`/step4/${c}`, d =&amp;gt; {
    console.log(d)
   })
  })
 })
})&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;45.1.2 에러 처리의 한계&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 45-03]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681021116990&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try {
 setTimeout(() =&amp;gt; { throw new Error('Error!'); }, 1000)
} catch (e) {
 // 캐치 불가
 console.error('캐치한 에러', e)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비동기 함수인 setTimeout이 호출되면&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;setTimeout 함수의 실행 컨택스트 생성되어 콜스택에 푸시&lt;/li&gt;
&lt;li&gt;setTimeout은 비동기 함수이므로 콜백 함수 호출을 기다리지 않고 즉시 종료되어 콜 스택에서 제거&lt;/li&gt;
&lt;li&gt;타이머가 만료되면 setTimeout 함수의 콜백 함수는 태스크 큐로 푸시되고 콜 스택이 비어졌을 때 이벤트 루프에 의해 콜 스택으로 푸시되어 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, setTimeout 함수의 콜백 함수가 실행될 때 setTimeout 함수는 이미 콜 스택에서 제거된 상태이다. setTimeout 함수의 콜백 함수를 호출한 caller가 setTimeout 함수가 아님을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러는 호출자(caller) 방향으로 전파된다. 다시 말하면, 콜 스택의 아래 방향(실행 중인 실행 컨텍스트가 푸시되기 직전에 푸시된 실행 컨택스트 방향)으로 전파된다. 하지만 위의 예시와 같이 setTimeout 함수의 콜백 함수를 호출한 것은 setTimeout이 아니기 때문에, catch 블록에서 잡을 수 없다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.2 Promise 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise&lt;/b&gt; 생성자 함수는 비동기 처리를 수행할 콜백 함수를 인수로 resolve, reject 함수를 전달 받는다. 그리고 &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;&lt;b&gt;[예제 45-04]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681022513098&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const promise = new Promise((reoslve, reject) =&amp;gt; {
 if(성공) {
  resolve('result')
 } else (
  reject('failure')
 )
})&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 72px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;&lt;b&gt;프로미스의 상태 정보&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;&lt;b&gt;상태 변경 조건&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;pending&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;비동기 처리가 아직 수행되지 않은 상태&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;프로미스가 생성된 직후 기본 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;fulfilled&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;비동기 처리가 수행된 상태(성공)&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;resolve 함수 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;rejected&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;비동기 처리가 수행된 상태(실패)&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 18px;&quot;&gt;reject 함수 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPXjTo/btr8204xqae/Ugp2hgOXJDFydEonQCGrM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPXjTo/btr8204xqae/Ugp2hgOXJDFydEonQCGrM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPXjTo/btr8204xqae/Ugp2hgOXJDFydEonQCGrM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPXjTo%2Fbtr8204xqae%2FUgp2hgOXJDFydEonQCGrM1%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;259&quot; data-origin-width=&quot;1644&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.3 Promise 후속 처리 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로미스의 비동기 처리 상태가 변화하면 이에 따른 후속 처리를 해야 한다. 예를 들어 fullfilled 상태가 되면 처리 결과로 어떤 로직을 사용할테고, reject가 되어도 에러 처리를 해야 한다. 이를 then, catch, finally를 통해 실행한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.4 Promise 에러 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 45-05]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681023475960&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const wornUrl = 'https://jsonplaceholder.typicode.com/XXX/1'

promiseGet(wrongUrl)
 .then(res =&amp;gt; console.log(res))
 .catch(err =&amp;gt; console.error(err))
 
 // 내부적으로는 아래와 같이 처리 됨.
 promiseGet(wrongUrl)
 .then(res =&amp;gt; console.log(res))
 .then((undefined, err =&amp;gt; console.error(err))&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.5 Promise Chainning&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 처리를 위한 콜백 패턴에 Callback HEEEEELLL이 발생하는 문제가 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제 45-02를 아래 예제처럼 프로미스를 연속적으로 호출하는 Promise Chainning을 통해 해결 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 45-06]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681023733342&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const url = 'https://jsonplaceholder.typicode.com'

promiseGet(`{url}/posts/1`)
 .then(({userId}) =&amp;gt; promiseGet(`{url}/users/${userId}`))
 .then(userInfo =&amp;gt; console.log(userInfo))
 .catch(err =&amp;gt; console.error(err))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 후속 처리 메서드의 콜백 함수가 프로미스가 아닌 값을 반환하더라도 그 값을 암묵적으로 resolve, reject하여 프로미스를 생성해 반환한다. &amp;nbsp;Promise Chainning을 통해 비동기 처리 결과를 전달받아 후속 처리를 하므로 비동기 처리를 위한 콜백 패턴에서 발생하던 callback hell이 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.6 Promise의 정적 메서드&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;45.6.2 Promise.all&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all&lt;/b&gt;은 여러 개의 비동기 처리를 모두 병렬 처리할 때 사용하는데 인수로 전달받은 배열의 모든 프로미스가 모두 fulfilled 상태가 되어야 종료한다. 따라서 Promise.all 메서드가 종료하는 데 걸리는 시간은 가장 늦게 fulfilled 상태가 되는 프로미스의 처리 시간보다 조오금 더 길다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 모든 프로미스가 fulfilled 상태가 되면 resolve된 처리 결과를 모두 배열에 저장해 새로운 프로미스를 반환한다. 이때 첫 번째 프로미스가 가장 나중에 fulfilled 상태가 되어도 첫 번째 프로미스 처리 결과부터 차례대로 배열에 저장해 그 배열을 resolve하는 새로운 프로미스를 반환한다. 즉, 처리 순서가 보장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인수로 전달받은 배열의 프로미스가 하나라도 reject 상태가 되면 나머지 프로미스가 fulfilled 상태가 되는 것을 기다리지 않고 즉시 종료한다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;45.6.3 Promise.race&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.all &lt;/b&gt;메서드처럼 모든 프로미스가 fulfilled 상태가 되는 것을 기다리는 것이 아니라 가장 먼저 fulfilled 상태가 된 처리 결과를 resolve 한다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;45.6.4 Promise.allSettled&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Promise.allSettled&amp;nbsp;&lt;/b&gt;메서드는 프로미스를 요소로 갖는 배열 등의 이터러블을 인수로 전달받는다. 그리고 전달받은 프로미스가 모두 setteled 상태가 되면 처리 결과를 배열로 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 45-07]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681024732008&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Promise.allSettled([
 new Promise(resolve =&amp;gt; setTimeout(() =&amp;gt; resolve, 2000)),
 new Promise((_, reject) =&amp;gt; setTimeout(() =&amp;gt; reject(new Error('ERR')), 1000))
]).then(console.log)

/*
[
 {status: &quot;fulfilled&quot;, value:1},
 {status: &quot;rejected&quot;, reason: Error: ERR at &amp;lt;anonymous&amp;gt;...},
]
*/&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;+ Promise.any&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.7 마이크로태스크 큐&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로미스의 후속 처리 메서드도 비동기로 동작하므로 1-&amp;gt;2-&amp;gt;3 순으로 출력될 것처럼 보이지만 2-&amp;gt;3-&amp;gt;1 순으로 출력된다.&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;&lt;b&gt;&lt;b&gt;[예제 45-08]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681024804619&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTimeout(() =&amp;gt; console.log(1), 0);

Promise.resolve()
 .then(() =&amp;gt; console.log(2))
 .then(() =&amp;gt; console.log(3))&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;45.8 fetch&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;fetch &lt;/b&gt;함수는&lt;b&gt; XMLHttpRequest&lt;/b&gt;&amp;nbsp;객체와 마찬가지로 HTTP 요청 전송 기능을 제공하는 클라이언트 사이드 WEB API다. &lt;b&gt;XMLHttpRequest&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천하는 Reference: &lt;a href=&quot;https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke&lt;/a&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;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/98</guid>
      <comments>https://daniel-park.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 9 Apr 2023 16:26:22 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 43 Ajax</title>
      <link>https://daniel-park.tistory.com/97</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chpvo1/btr5Qnwp4QB/eGFk4eGVqCNVlCk9jg5xG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chpvo1/btr5Qnwp4QB/eGFk4eGVqCNVlCk9jg5xG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chpvo1/btr5Qnwp4QB/eGFk4eGVqCNVlCk9jg5xG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchpvo1%2Fbtr5Qnwp4QB%2FeGFk4eGVqCNVlCk9jg5xG0%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;43.1 Ajax란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ajax(Asynchronous Javascript and XML)란 자바스크립트를 사용하여 &lt;i&gt;브라우저가 서버에게 비동기 방식으로 데이터를 요청&lt;/i&gt;하고, &lt;i&gt;서버가 응답한 데이터를 수신하여 웹페이지를 동적으로 갱신하는 프로그래밍 방식&lt;/i&gt;을 말한다. Ajax는 브라우저에서 제공하는 Web API이며 비동기 통신인 XMLHttpRequest 객체를 기반으로 동작한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;변경할 부분을 갱신하는 데 필요한 데이터만 서버로부터 전송받으므로 불필요한 데이터 통신 발생 X&lt;/li&gt;
&lt;li&gt;변경할 필요가 없는 부분은 다시 렌더링 X, 따라서 화면 깜빡임이 X&lt;/li&gt;
&lt;li&gt;클라이언트와 서버가 비동기 통신하므로 서버에게 요청을 보낸 후 블로킹(작업 중단)이 되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;43.2 JSON&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON(JavaScript Object Notation)은 클라이언트와 서버 간의 HTTP 통신을 위한 텍스트 데이터 포맷이다. 자바스크립트에 종속되지 않는 언더 독립형 데이터 포맷으로 대부분의 프로그래밍 언어에서 사용할 수 있다.(심지어 sql 데이터 타입도)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.2.1 JSON 표기 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON은 자바스크립트의 객체 리터럴과 유사하게 키와 값으로 구성된 순수한 텍스트다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.2.2 JSON.stringify&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 서버로 객체를 전송하려면 객체를 문자열화해야 하느데 이를 직렬화(Serializing)라 한다. 이 메서드는 객체뿐만 아니라 배열도 JSON 포맷의 문자열로 변환한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.2.3 JSON.parse&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버로부터 클라이언트에게 전송된 JSON 객체 데이터는 문자열이다. 이 문자열을 객체로서 사용하려면 JSON 포맷의 문자열을 객체화해야 하는데 이를 역직렬화(Deserializing)라 한다. 배열이 JSON 포맷의 문자열로 변환되어 있는 경우 배열 객체로 변환한다. &amp;nbsp;배열의 요소가 객체인 경우 배열의 요소까지 객체로 변환한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;43.3 XMLHttpRequest&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 주소창이나 HTML의 form 태그 또는 a 태그를 통해 HTTP 요청 전송 기능을 제공하고, 자바스크립트는 WEB API인 XMLHttpRequest 객체를 사용하여 HTTP 요청을 전송한다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.3.2 XMLHttpRequest 객체의 프로퍼티와 메서드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XMLHttpRequest 객체의 프로토타입 프로퍼티&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;&lt;b&gt;프로토타입 프로퍼티&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;readyState&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;HTTP 요청의 현재 상태를 나타내는 정수. 다음과 같은 XMLHttpRequest의 정적 프로퍼티를 값으로 갖는다.&lt;br /&gt;- UNSENT: 0&lt;br /&gt;- OPENED: 1&lt;br /&gt;- HEADERS_RECEIVED: 2&lt;br /&gt;- LOADING: 3&lt;br /&gt;- DONE: 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;status&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;HTTP 요청에 대한 응답 상태(HTTP 상태 코드)를 나타내는 정수(200,404,....)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;statusText&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;HTTP 요청에 대한 응답 메세지를 나타내는 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;responseType&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;HTTP 응답 타입(document, json, text, blob, arraybuffer)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;response&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;HTTP 요청에 대한 response body, responseType에 다라 다르다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;responseText&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 18px;&quot;&gt;서버가 전송한 HTTP 요청에 대한 응답 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XMLHttpRequest 객체의 이벤트 핸들러 프로퍼티&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;이벤트 핸들러 프로퍼티&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onreadystatechange&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;readystate 프로퍼티 값이 변경된 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onloadstart&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;HTTP 요청에 대한 응답을 받기 싲가한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onprogress&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청에 대한 응답을 받는 도중 주기적으로 발생&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onabort&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;abort 메서드에 의해 HTTP 요청이 중단된 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onerror&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청에 에러가 발생한 경우&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onload&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청이 성공적으로 완료한 경우&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;ontimeout&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청 시간이 초과한 경우&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;onloaded&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청이 완료한 경우, &lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;HTTP 요청이 성공 또는 실패하면 발생&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.3.3 HTTP 요청 전송&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;XMLHttpRequest.prototype.open 메서드로 HTTP 요청을 초기화한다.&lt;/li&gt;
&lt;li&gt;필요에 따라 XMLHttpRequest.prototype.setRequestHeader 메서드로 특정 HTTP 요청의 헤더 값을 설정한다.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest.prototype.send 메서드로 HTTP 요청을 전송한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;send 메서드에는 request body에 담아 전송할 데이터(페이로드)를 인수로 전달할 수 있다. 페이로드가 객체인 경우 반드시 JSON.stringify 메서드를 사용하여 직렬화한 다음 전달해야 한다.&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;[예제 43-01]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679835208484&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// XMLHttpRequest 객체 생성
const xhr = new XMLHttpRequest();

// HTTP 요청 초기화
xhr.open('GET', '/users');

// HTTP 요청 헤더 설정
// 클라이언트가 서버로 전송할 데이터의 MIME 타입 지정: json
xhr.setRequestHeader('content-type', 'application/json');

// 서버가 응답할 데이터의 MIME 타입 지정: json, default: */*
xhr.setRequestHeader('accept', 'application/json');

// HTTP 요청 전송
xhr.send();

xhr.onreadystatechagne = () =&amp;gt; {
 if (xhr.readystate !== XMLHttpRequest.DONE) return;
 
 
 // (1)번 방법
  // status 프로퍼티는 응답 상태 코드를 나타낸다.
 if (xhr.status === 200) {
  console.log(JSON.parse(xhr.response));
 } else {
  console.error('Error', xhr.status, xhr.statusText);
 }
 
}

  // (2)번 방법
xhr.onload = () = &amp;gt; {
  if (xhr.status === 200) {
    console.log(JSON.parse(xhr.response));
  } else {
   console.error('Error', xhr.status, xhr.statusText);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;43.3.4 HTTP 응답 처리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버의 응답을 처리하려면 XMLHttpRequest 객체가 발생시키는 이벤트(&lt;span&gt;readyState 프로퍼티 값이 변경된 경우 발생하는 readystatechange&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;를 캐치해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(위의 코드 참고)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;onreadystate 이벤트 &amp;nbsp;핸들러 프로퍼티에 할당한 이벤트 핸들러는 HTTP 요청의 현재 상태를 나타내는 xhr.readyState가 XML.HttpRequest.DONE인지 확인하여 서버의 응답이 완료되었는지 확인한다.&lt;/li&gt;
&lt;li&gt;readystatechange 이벤트 대신 load 이벤트를 캐치해도 좋다. load 이벤트는 HTTP 요청이 성공적으로 완료된 경우 발생한다. 따라서 load 이벤트를 캐치하는 경우 xhr.readyState나 XMLHttpRequest.Done인지 확인 불필요&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/97</guid>
      <comments>https://daniel-park.tistory.com/97#entry97comment</comments>
      <pubDate>Sun, 26 Mar 2023 22:10:32 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 42 비동기 프로그래밍</title>
      <link>https://daniel-park.tistory.com/96</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drCTf5/btr5Touy3iq/zLTz3itDesEeGGCP2jdu6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drCTf5/btr5Touy3iq/zLTz3itDesEeGGCP2jdu6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drCTf5/btr5Touy3iq/zLTz3itDesEeGGCP2jdu6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrCTf5%2Fbtr5Touy3iq%2FzLTz3itDesEeGGCP2jdu6k%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;42.1 동기 처리와 비동기 처리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 42-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679824235402&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const foo = () =&amp;gt; {};
const bar = () =&amp;gt; {};

foo();
bar();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 42-01]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uqcKv/btr5Rhiuzqn/YbaMKe9Mtm9lcmP5ORxBok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uqcKv/btr5Rhiuzqn/YbaMKe9Mtm9lcmP5ORxBok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uqcKv/btr5Rhiuzqn/YbaMKe9Mtm9lcmP5ORxBok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuqcKv%2Fbtr5Rhiuzqn%2FYbaMKe9Mtm9lcmP5ORxBok%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;142&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;함수가 실행되려면 &quot;함수 코드 평가 과정&quot;에서 생성된 함수 실행 컨텍스트가 실행 컨텍스트에 푸시되어야 한다. 즉, 실행 컨택스트 스택에 함수 실행 컨택스트가 푸시되는 것은 바로 함수 실행의 시작을 의미한다. 함수가 호출된 순서대로 순차적으로 실행되는 이유는 호출된 순서대로 함수 실행 컨텍스트가 실행 컨텍스트 스택에 푸시되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;JS 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다.&lt;/b&gt;&amp;nbsp;&quot;실행 중인 실행 컨텍스트&quot;를 제외한 모든 실행 컨텍스트는 모두 실행 대기 중인 테스큳링다. 대기 중인 테스크들은 현재 실행 중인 실행 컨텍스트가 팝되어 실행 컨택스트에서 제거되면, 비로소 실행되기 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;JS 엔진은 하나의 태스크만 실행할 수 있는 &lt;b&gt;싱글 스레드 방식&lt;/b&gt;이기 때문에 시간이 걸리는 태스크를 실행하는 경우, 블로킹(blocking -작업 중단)이 발생한다. 예를 들어 sleep(func, 10 * 1000)을 사용하게 되면 약 10초 후에 func 함수를 호출한다. 이때 sleep 이후 코드 라인의 함수들은 10초동안 호출되지 못하고 블로킹(작업 중단)된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 한 태스크가 종료될 때까지 다음 실행될 태스크가 대기하는 방식을 동기처리(synchronous)라 한다. 동기 처리 방식은 태스크를 순서대로 하나씩 처리하므로 실행 순서가 보장되는 장점이 있지만 블로킹되는 단점이 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;42.2 이벤트 루프와 태스크 큐&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;JS 엔진은 &quot;싱글 스레드&quot;이기 때문에 하나씩 태스크를 처리해야 하는데, 우리가 사용하는 브라우저는 그렇지 않은듯 하다. 자바스크립트의 동시성(concurrecny)를 지원하기 위해 사용되는 것이 &lt;b&gt;이벤트 루프(event loop)&lt;/b&gt;이다. 이 개념 또한 FE 개발자라면 꼭 알아야 할 개념 중 하나이며, 테크 인터뷰에서 등장하는 단골 토픽 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 42-02]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVQoEt/btr5PbJXYQH/kOdYKxqQQrK0lAJcevOUe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVQoEt/btr5PbJXYQH/kOdYKxqQQrK0lAJcevOUe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVQoEt/btr5PbJXYQH/kOdYKxqQQrK0lAJcevOUe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVQoEt%2Fbtr5PbJXYQH%2FkOdYKxqQQrK0lAJcevOUe0%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;500&quot; height=&quot;423&quot; data-origin-width=&quot;634&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글의 V8 JS 엔진을 비롯한 대부분의 엔진은 크게 2개의 영역으로 구분할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;콜 스택(call stack)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;힙(heap)&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 처리에서 소스코드 평가와 실행을 제외한 모든 처리는 JS엔진을 구동하는 환경인 브라우저 또는 Node.js가 담당한다&lt;/b&gt;. 예를 들어, 비동기 방식으로 동작하는 setTimeout의 콜백 함수의 평가와 실행은 JS엔진이 담당하지만 호출 스케줄링을 위한 타이머 설정과 콜백 함수의 등록은 브라우저 또는 Node.js가 담당한다.&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;b&gt;태스크 큐(task queue/event queue/callback queue)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;setTimout이나 setInterval와 같은 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역. 태스크 큐와는 별도로 프로미스의 후속 처리 메서드의 콜백 함수가 일시적으로 보관되는 Microstack queue도 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이벤트 루프(event loop)&lt;/b&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;If(콜 스택이 빔 &amp;amp;&amp;amp; 대기 중인 함수 존재) -&amp;gt; 이벤트 루프는 순차적으로(FIFO) 태스크 큐에 대기 중인 함수를 콜 스택으로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 42-02]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679825478741&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function foo() {
  console.log('foo')
}

function bar() {
  console.log('bar')
}

setTimeout(foo, 0); // 0초(실제는 4ms) 후에 foo 함수 호출
bar();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 실행 순서&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;전역 코드가 평가되어 전역 실행 컨텍스트가 생성되고 콜 스택에 push&lt;/li&gt;
&lt;li&gt;전역 코드가 실행되기 시작하여 setTimeout 함수 호출
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;setTimout 함수의 함수 실행 컨텍스트가 생성되고 콜 스택에 푸시되어 현재 실행 중인 실핸 컨텍스트가 됨. 브라우저의 WEB API인 타이머 함수도 함수이므로 함수 실행 컨텍스트 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;setTimemout 함수라 실행되면 콜백 함수를 호출 스케줄링하고 종료되어 콜 스택에서 pop. 타이머 설정과 타이머가 만료되면 콜백 함수를 task queue에 푸시하는 것은 브라우저의 몫&lt;/li&gt;
&lt;li&gt;브라우저가 수행하는 4-1과 js엔진이 수행하는 4-2는 병행 처리 됨.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;브라우저는 타이머를 설정하고 타이머의 만료를 기다림. 이후 타이머가 만료되면 콜백 함수 foo가 태스크 큐에 push. 위 예제의 경우 지연시간(delay)이 0이지만 지연 시간이 4ms 이하인 경우 최소 지연 시간 4ms가 지정 됨. 따라서 4ms 호에 콜백 함수 foo가 task queue에 push되어 대기하게 됨. &amp;nbsp;이 예시처럼 setTimeout 함수로 호출 스케줄링한 콜백 함수는 정확히 지연 시간 이후에 콜백 함수가 호출된다는 보장이 없음. 지연 시간 이후에 콜백 함수가 task queue에 push되어 대기하게 되지만 콜 스텍이 비어야 호출되므로 실제로는 약간의 시간차가 발생&lt;/li&gt;
&lt;li&gt;bar 함수가 호출되어 bar 함수의 함수 실행 컨텍스트가 생성되고 콜 스택에 push되어 현재 실행 중인 실행 컨텍스트가 된다. 이후 bar 함수가 종료되어 콜 스택에서 pop 되고, 타이머를 설정한 후 약 4ms가 결과했다면 foo 함수는 아직 태스크 큐에서 대기 중&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;전역 코드 실행이 종료되고 전역 실행 컨텍스트가 콜 스택에서 pop 된다. 이로서 콜 스텍에는 아무런 실행 컨텍스트도 존재X&lt;/li&gt;
&lt;li&gt;이벤트 루프에 의해 콜 스텍이 비어 있음이 감지되고 테스크 큐에서 대기 중인 콜백 함수 foo가 이벤트 루프에 의해 콜 스택에 push 된다. 즉, 콜백 함수 foo의 함수 실행 컨텍스트가 생성되고 콜 스택에 push되어 현재 실행 중인 실행 컨켁스트가 됨.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;비동기 함수인 setTimeout의 콜백 함수는 태스크 큐에 푸시되어 대기하다가 콜 스택이 비게 되면, 전역 코드 및 명시적으로 호출된 함수가 모두 종료하면 콜 스택에 푸시되어 실행 됨.&lt;/li&gt;
&lt;li&gt;JS 엔진은 싱글 스레드 방식 동작&lt;/li&gt;
&lt;li&gt;브라우저는 멀티 스레드 방식 동작&lt;/li&gt;
&lt;/ul&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;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/96</guid>
      <comments>https://daniel-park.tistory.com/96#entry96comment</comments>
      <pubDate>Sun, 26 Mar 2023 19:22:26 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 41 타이머</title>
      <link>https://daniel-park.tistory.com/95</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sNvLu/btr53FvDA9h/YHpFRARP8pnazT9w2sUeHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sNvLu/btr53FvDA9h/YHpFRARP8pnazT9w2sUeHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sNvLu/btr53FvDA9h/YHpFRARP8pnazT9w2sUeHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsNvLu%2Fbtr53FvDA9h%2FYHpFRARP8pnazT9w2sUeHk%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;41.1 호출 스케줄링&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;함수를 명시적으로 호출하지 않고 &lt;i&gt;일정 시간이 경과된 이후&lt;/i&gt;에 호출되도록 함수 호출을 예약하는데 이를 &lt;b&gt;호출 스케줄링&lt;/b&gt;이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타이머는 빌트인 함수가 아닌 호스트 객체이며 생성하기 위한 setTimeout, setInterval, 제거를 위한 clearTimeout, clearInterval을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;JS 엔진은 단 하나의 실행 컨텍스트(싱글 스레드)를 갖기 때문에 두 가지 이상의 태스크를 동시에 실행할 수 없다. 따라서 setTimeout, setInterval은 비동기 처리 방식으로 동작한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;41.2 타이머 함수&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;41.2.1 setTimeout/clearTimeout&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세번째 매개변수에 전달해야 할 인수가 있는 경우 param을 전달할 수 있다. 또한 setTimeout은 고유 타이머 id을 반환한다. 따라서 변수에 저장하여 clearTimeout의 input으로 사용되고 타이머를 취소한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 72px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 48.83720930232558%; height: 18px;&quot;&gt;매개변수&lt;/td&gt;
&lt;td style=&quot;width: 51.16279069767442%; height: 18px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 48.83720930232558%; height: 18px;&quot;&gt;func&lt;/td&gt;
&lt;td style=&quot;width: 51.16279069767442%; height: 18px;&quot;&gt;타이머가 만료된 뒤 호출될 콜백 함수&lt;br /&gt;* 콜백 함수 대신 코드를 문자열로 전달 가능하지만 권장 x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 48.83720930232558%; height: 18px;&quot;&gt;delay&lt;/td&gt;
&lt;td style=&quot;width: 51.16279069767442%; height: 18px;&quot;&gt;타이머 만료 시간(밀리초ms 단위). setTimeout 함수는 delay 시간으로 단 한 번 동작하는 타이머를 생성한다. 인수 전달을 생략한 경우 기본값 0이 지정된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 48.83720930232558%; height: 18px;&quot;&gt;param&lt;/td&gt;
&lt;td style=&quot;width: 51.16279069767442%; height: 18px;&quot;&gt;호출 스케줄링된 콜백 함수에 전달해야 할 인수가 존재하는 경우 세 번째 이후의 인수로 전달 가능.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;41.2.2 setInterval/clear&lt;b&gt;Interval&lt;/b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interval 함수는 인수로 전달 받은 시간마다 반복 동작하는 타이머이다. setInterval 전달 인수는 setTimeout과 동일하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;41.3 Debounce &amp;amp; Throttle&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 이 챕터에서 가장 중요한 개념 중 하나로 보인다. Debounce와 Throttle은 면접에서도 단골 질문이며, 현생의 프로젝트에서도 꼭 사용되는 기법 중 하나이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마우스 scroll || mousemove, 브라우저 resize, input 이벤트 등 같은 이벤트들은 짧은 시간 간격으로 연속해서 발생한다. 이러한 연속적인 이벤트들에 바인딩한 이벤트 핸들러(함수)는 과도하게 호출되어 성능 문제를 발생시킬 확률이 아주아주아주 높다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;예를 들어 구글 검색 input tag에 찾고 싶은 문장의 검색어(20~30자)를 타이핑 한다고 가정해보자. input 메서드에 이벤트 핸들러가 바인딩 되어 있다면, 모든 단어를 타이핑하고 때로는 백스페이스로 지울때마다 자동 검색을 위한 api를 호출하게 된다. 자 이렇게 되면 FE 성능은 두 번째 치고, BE engineer에게 쿠사리를 먹지 않을 자신이 있을까....?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이런 불상사를 피하고 아름다운 세상(?)을 만들기 위해 사용되는 기법이 Debounce와 Throttle이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 41-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679822901556&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;body&amp;gt;
 &amp;lt;button&amp;gt;click me&amp;lt;/button&amp;gt;
 &amp;lt;pre&amp;gt;일반 클릭 이벤트 카운터 &amp;lt;span class=&quot;normal-msg&quot;&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;/pre&amp;gt;
 &amp;lt;pre&amp;gt;디바운스 클릭 이벤트 카운터 &amp;lt;span class=&quot;debounce-msg&quot;&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;/pre&amp;gt;
 &amp;lt;pre&amp;gt;스로틀 클릭 이벤트 카운터 &amp;lt;span class=&quot;throttle-msg&quot;&amp;gt;0&amp;lt;/span&amp;gt;&amp;lt;/pre&amp;gt;
 &amp;lt;script&amp;gt;
  const $button = document.querySelector('button');
  const $normalMsg = document.querySelector('.normal-msg');
  const $debuonceMsg = document.querySelector('.debounce-msg');
  const $throttleMsg = document.querySelector('.throttle-msg');
  
  const debounce = (callback, delay) =&amp;gt; {
   let timerId;
   return event =&amp;gt; {
    if (timerId) clearTimeout(timerId);
    timerId = setTimeout(callback, delay, event)
   }
  }
  
  const throttle = (callback, delay) =&amp;gt; {
   let timerId;
   return event =&amp;gt; {
    if (timerId) return;
    timerId = setTimeout(() =&amp;gt; {
     callback(event)
     timerId = null;
    }, delay, event);
   }
   
  $button.addEvnetListener('click', () =&amp;gt; {
  	$normalMsg.textContent = +$normalMsg.textContent + 1;
  )}
  $button.addEvnetListener('click', decounce() =&amp;gt; {
  	$debuonceMsg.textContent = +$debuonceMsg.textContent + 1;
  )}
  $button.addEvnetListener('click', throttle() =&amp;gt; {
  	$throttleMsg.textContent = +$throttleMsg.textContent + 1;
  )}
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&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;b&gt;41.3.1 디바운스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디바운스(debounce)는 짧은 시간 간격으로 이벤트가 연속해서 발생하면 &lt;b&gt;이벤트 핸들러를 호출하지 않다가 일정 시간이 경과한 이후&lt;/b&gt;에 이벤트 핸들러가 &lt;b&gt;한 번만 호출&lt;/b&gt;되도록 한다. 즉, 디바운스는 짧은 시간 간격으로 ㅂ라생하는 이벤트를 그룹화해서 마지막에 한 번만 이벤트 핸들러가 호출되도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위의 코드에서 보이는 것처럼 &amp;nbsp;decounce가 반환한 함수는 debounce 함수에 두번째 인수로 전달한 시간(delay)보다 짧은 간격으로 이벤트가 발생하면 이전 타이머를 취소하고 새로운 타이머를 재설정한다. 따라서 delay보다 짧은 간격으로 이벤트가 연속해서 발생하면 debounce 함수의 첫 번째 인수로 전달한 콜백 함수는 호출되지 않다가 delay동안 이벤트가 더 이상 발생하지 않으면 한번만 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위의 예시인 구글 검색 창의 input tag 이벤트에 적합하다고 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적합한 적용 예시: input event&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxYFTD/btr53D5Kink/WFuaT67OU1av6rLn7tKxKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxYFTD/btr53D5Kink/WFuaT67OU1av6rLn7tKxKK/img.png&quot; data-alt=&quot;ref&amp;amp;nbsp;https://llu.is/throttle-and-debounce-visualized/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxYFTD/btr53D5Kink/WFuaT67OU1av6rLn7tKxKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxYFTD%2Fbtr53D5Kink%2FWFuaT67OU1av6rLn7tKxKK%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;778&quot; height=&quot;418&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ref&amp;nbsp;https://llu.is/throttle-and-debounce-visualized/&lt;/figcaption&gt;
&lt;/figure&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;b&gt;41.3.2 쓰로틀&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰로틀(throttle)은 짧은 시간 간격으로 이벤트가 연속해서 발생하더라도 일정 시간 간격으로 이벤트 핸들러가 최대 한 번만 호출되도록 한다. 즉, 스로틀은 짧은 시간 간격으로 연속해서 발생하는 이벤트를 그룹화해서 일정 시간 단위로 이벤트 핸들러가 호출되도록 호출 주기를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적합한 적용 예시: scroll event&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 41-02]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JQ651/btr5Rgjws6M/MzUnKnyPeHSwPxRu1Rkvj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JQ651/btr5Rgjws6M/MzUnKnyPeHSwPxRu1Rkvj0/img.png&quot; data-alt=&quot;ref&amp;amp;nbsp;https://llu.is/throttle-and-debounce-visualized/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JQ651/btr5Rgjws6M/MzUnKnyPeHSwPxRu1Rkvj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJQ651%2Fbtr5Rgjws6M%2FMzUnKnyPeHSwPxRu1Rkvj0%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;778&quot; height=&quot;418&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ref&amp;nbsp;https://llu.is/throttle-and-debounce-visualized/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/95</guid>
      <comments>https://daniel-park.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 26 Mar 2023 18:44:12 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 40 이벤트</title>
      <link>https://daniel-park.tistory.com/94</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceB5Tv/btr18DuZmNn/Y0GIPbUm8vaVGI3jZbNbrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceB5Tv/btr18DuZmNn/Y0GIPbUm8vaVGI3jZbNbrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceB5Tv/btr18DuZmNn/Y0GIPbUm8vaVGI3jZbNbrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceB5Tv%2Fbtr18DuZmNn%2FY0GIPbUm8vaVGI3jZbNbrk%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.1 이벤트 드리븐 프로그래밍&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 처리해야 할 특정 사건(클릭, 키보드 입력, 마우스 이동, 포커스...)이 발생하면 이를 감지하여 이벤트를 발생시킨다. 우리가 만드는 애플리케이션은 특정 이벤트 타입에 대해 반응하여 어떤 일(function, logic,...)을 하길 원하면 그 타입의 이벤트가 발생했을 때 호출될 함수를 &lt;b&gt;브라우저에게 알려 호출을 위임&lt;/b&gt;한다. &lt;i&gt;호출될 함수&lt;/i&gt;를 &lt;b&gt;이벤트 핸들러&lt;/b&gt; 라 하고, 브라우저에게 &lt;i&gt;이벤트 핸들러의 호출을 위임&lt;/i&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.3 이벤트 핸들러 등록&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.3.1 이벤트 핸들러 어트리뷰트 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML element의 attribute 중에는 이벤트에 대응하는 이벤트 핸들러 attribute가 있다. onclick과 같이 &lt;i&gt;on + 이벤트 종류&amp;nbsp;&lt;/i&gt;처럼 이루어져 있는데 함수 참조가 아닌 함수 호출문을 할당하여 호출문의 평가 결과가 이벤트 핸들러로 등록된다. 만약 이벤트 핸들러 attribute 값으로 함수 참조를 할당해야 한다면 이벤트 핸들러에 paramteter을 전달하기 곤란하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678013288432&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;예시
&amp;lt;button onclick=&quot;sayHi('Park')&quot;&amp;gt; &amp;lt;/button&amp;gt;

변환되는 이벤트 핸들러
function onclick(event) { sayHi('Park') }&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.3.2 이벤트 핸들러 프로퍼티 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;window 객체와 Document, HTMLElement 타입의 DOM 노드 객체는 이벤트에 대응하는 이벤트 핸들러 프로퍼티를 가지고 있다. 이벤트 핸들러 프로퍼티의 키는 이벤트 핸들러 attribute와 마찬가지로 &lt;i&gt;on + 이벤트 종류&lt;/i&gt;로 이루어져 있다. &quot;이벤트 핸들러 프토퍼티 방식&quot;은 &quot;이벤트 핸들러 어트리뷰트 방식&quot;의 HTML과 자바스크립트가 해결할 수 있다. CBD(Component Based Development)에선 어쩔 수 없기도 하지만... 하지만, 이벤트 핸들러 프로퍼티 에 하나의 이벤트 핸들러만 바인딩 가능하다는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-02]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678013934789&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
const $button = document.querySelector('button');

$button.onclick = function () { console.log('button clicked') }
...&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.3.3 addEventListener 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이벤트 핸들러 프로퍼티&quot; 방식과는 다르게 하나 이상의 이벤트 핸들러를 등록할 수 있다. 이때 이벤트 핸들러는 &lt;b&gt;등록된 순서&lt;/b&gt;대로 호출된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uSkDj/btr1QwLi1Wt/vCAZOXONJrkWkoXJHn9Ms0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uSkDj/btr1QwLi1Wt/vCAZOXONJrkWkoXJHn9Ms0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uSkDj/btr1QwLi1Wt/vCAZOXONJrkWkoXJHn9Ms0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuSkDj%2Fbtr1QwLi1Wt%2FvCAZOXONJrkWkoXJHn9Ms0%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;700&quot; height=&quot;158&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-03]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678014247562&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
$button.addEventListner('click', function() { console.log('button clicked') })
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.4 이벤트 핸들러 제거&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. addEventListener 메서드에 전달한 인수와 removeEventListener 메서드에 전달한 인수가 일치하지 않으면 제거되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 기명 이벤트 핸들러 내부에서 removeEventListener 메서드를 호출하여 이벤트 핸들러를 제거하는 것도 가능하다. 이때 이벤트 핸들러는 단 한 번만 호출된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 함수 자신을 가리키는 arguments.callee를 사용할 수도 있지만 strict mode에서 사용이 금지된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 이벤트 핸들러 프로퍼티 방식으로 등록한 이벤트 핸들러는 removeEventListener 메서드로 제거할 수 없기 때문에 null을 할당한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.5 이벤트 객체&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트가 발생하면 이벤트에 관련한 다양한 정보를 담고 있는 이벤트 객체가 동적으로 생성된다. 생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-04]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678015098034&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...

// 클릭 이벤트에 의해 생성된 이벤트 객체는 이벤트 핸들러의 첫 번째 인수로 전달된다.
function showCoords(e) {
 $msg.textContent = `clientX: ${e.clientX}, clientY: ${e.clientY}`
}


document.onclick = showCoords;

...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-05]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678015166350&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
&amp;lt;!-- 이벤트 핸들러 어트리뷰트 방식의 경우 event가 아닌 다른 이름으로는 이벤트 객체를 전달받지 못한다. --&amp;gt;
&amp;lt;body onclick=&quot;showCoords(event)&quot;&amp;gt;
&amp;lt;/body&amp;gt;
...&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.5.1 이벤트 객체의 상속 구조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트가 발생하면 이벤트 타입에 따라 다양한 타입의 이벤트 객체가 생성되고 아래처럼 상속 구조를 갖는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diSDNC/btr1Y7QVyFx/RrGWrFeocihbsnZCCrI2L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diSDNC/btr1Y7QVyFx/RrGWrFeocihbsnZCCrI2L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diSDNC/btr1Y7QVyFx/RrGWrFeocihbsnZCCrI2L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiSDNC%2Fbtr1Y7QVyFx%2FRrGWrFeocihbsnZCCrI2L0%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;700&quot; height=&quot;353&quot; data-origin-width=&quot;1072&quot; data-origin-height=&quot;540&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.5.2 이벤트 객체의 공통 프로퍼티&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Event 인터페이스, 즉 Event, prototype에 정의되어 있는 이벤트 관련 프로퍼티는 UIEvent, CustomEvent, MouseEvent 등 모든 파생 이벤트 객체에 상속된다. 즉, Event 인터페이스의 이벤트 관련 프로퍼티는 모든 이벤트 객체가 상속받는 공통 프로퍼티다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 210px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;공통 프로퍼티&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;type&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트 타입&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;target&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트를 발생시킨 DOM 요소&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;DOM 요소 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;currentTarget&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트를 핸들러가 바인딩된 DOM 요소&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;DOM 요소 노드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;eventPhase&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트 전파 단계&lt;br /&gt;0: 이벤트 없음&lt;br /&gt;1: 캡처링&lt;br /&gt;2: 타깃&lt;br /&gt;3: 버블링&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;bubbles&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트 버블링 전파 여부&lt;br /&gt;다음 이벤트는 bubbles: false로 버블링하지 않는다.&lt;br /&gt;- 포커스: focus/blur&lt;br /&gt;- 리소스: load/unload/abor/error&lt;br /&gt;- 마우스: mouseenter/mouseleave&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;cancelable&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;preventDefault 메서드를 호출하여 이벤트의 기본 동작을 취소할 수 있는지 여부.&lt;br /&gt;다음 이벤트는 cancelable: false로 취소할 수 없다.&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;- 포커스: focus/blur&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;- 리소스: load/unload/abor/error&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;- 마우스: dbclick/mouseenter/mouseleave&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;defaultPrevented&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;preventDefault 메서드를 호출하여 이벤트를 취소했는지 여부&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;isTrusted&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;사용자의 행위에 의해 발생된 이벤트인지 여부. 예를 들어 click 메서드 또는 dispatchEvent 메서드를 통해 인위적으로 발생시킨 이벤트인 경우 false&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;timeStmap&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;이벤트가 발생한 시각(1970/01/01/00:00:0부터 경과한 밀리초)&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;number&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.5.3 마우스 정보 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;click, dbclick, mousedown, mouseup, mousemove, mouseenter, mouseleave 이벤트가 발생하면 ㅅㅐㅇ성되는 MouseEvent 타입의 이벤트 객체는 다음과 같은 고유의 프로퍼티를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 마우스 포인터의 좌표 정보를 나타내는 프로퍼티&lt;/b&gt;: screenX/screenY, clientX/clientY, pageX/pageY, offestX/offestY&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- 버튼 정보를 나타내는 프로퍼티:&lt;/b&gt; altKey, ctrlKey, shiftKey, button&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XeYBR/btr1YJpgLor/DqS8QWlOEiP3jmFBr2GwSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XeYBR/btr1YJpgLor/DqS8QWlOEiP3jmFBr2GwSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XeYBR/btr1YJpgLor/DqS8QWlOEiP3jmFBr2GwSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXeYBR%2Fbtr1YJpgLor%2FDqS8QWlOEiP3jmFBr2GwSk%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;700&quot; height=&quot;473&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;756&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.5.4 키보드 정보 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keydown, keyup, keypress 이벤트가 발생하면 생성되는 KeyboardEvent 타입의 이벤트 객체는 altKEy, ctrlKey, shiftKey, metaKey, key, keyCode 같은 고유의 프로퍼티를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.6 이벤트 전파&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 트리 상에 존재하는 DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파된다. 이를 이벤트 전파(event propogation)라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-06]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678016854423&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
 &amp;lt;ul id=&quot;fruits&quot;&amp;gt;
   &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ul 요소의 두 번째 자식 요소인 li 요소를 클릭하면 클릭 이벤트가 발생한다. 이때 &lt;b&gt;생성된 이벤트 객체는 이벤트를 발생시킨 DOM 요소인 이벤트 타겟을 중심으로 DOM 트리를 통해 전파된다&lt;/b&gt;. 이벤트 전파는 이벤트 객체가 전파되는 방향에 따라 3단계로 구분된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EvMl2/btr1UT0fZzw/vCJgfzibFvrBVeKFktfDu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EvMl2/btr1UT0fZzw/vCJgfzibFvrBVeKFktfDu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EvMl2/btr1UT0fZzw/vCJgfzibFvrBVeKFktfDu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEvMl2%2Fbtr1UT0fZzw%2FvCJgfzibFvrBVeKFktfDu1%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;700&quot; height=&quot;510&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-07]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678017258510&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
 &amp;lt;ul id=&quot;fruits&quot;&amp;gt;
   &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;script&amp;gt;
   const $fruit = document.getElementById('fruits');
   
   //#fruits 요소의 하위 요소인 li 요소를 클릭한 경우
   $fruits.addEventListner('click' e =&amp;gt; {
    console.log(`이벤트 단계: ${e.eventPhase}`) //3: 버블링 단계
    console.log(`이벤트 타깃: ${e.target}`) //[object HTMLLIlement]
    console.log(`커런트 타깃: ${e.currentTarget}`) //[object HTMLULListElement]
   })
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;li 요소를 클릭하면 클릭 이벤트가 발생하여 클릭 이벤트 객체가 생성되고 클릭된 li 요소가 이벤트 타깃이 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;캡처링 단계:&lt;/b&gt;&amp;nbsp;이벤트 객체는 window에서 시작해서 이벤트 타깃 방향으로 전파된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타깃 단계:&lt;/b&gt;&amp;nbsp;이벤트 객체는 이벤트를 발생시킨 이벤트 타깃에 도달한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버블링 단계:&lt;/b&gt;&amp;nbsp;이벤트 객체는 이벤트 타깃에서 시작해서 window 방향으로 전파된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 핸들러 어트리뷰트/프로퍼티 방식으로 등록한 이벤트 핸들러는 타깃, 버블링 단계의 이벤트만 캐치 가능하다. 하지만 addEventListner 메서드 방식으로 등록한 이벤트 핸들러는 타깃/버블링/캡처링 단계 모두 캐치 가능하다.&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;&lt;b&gt;[예제 40-08]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678017846329&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
 &amp;lt;ul id=&quot;fruits&quot;&amp;gt;
   &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
   &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;script&amp;gt;
   const $fruit = document.getElementById('fruits');
   const $banana = document.getElementById('banana');
  
  
   //캡처링 단계
   $fruits.addEventListner('click', e =&amp;gt; {
    console.log(`이벤트 단계: ${e.eventPhase}`) //1: 캡처링 단계
    console.log(`이벤트 타깃: ${e.target}`) //[object HTMLLIlement]
    console.log(`커런트 타깃: ${e.currentTarget}`) //[object HTMLULListElement]
   }, true)
   
   //버블링 단계
   $fruits.addEventListner('click', e =&amp;gt; {
    console.log(`이벤트 단계: ${e.eventPhase}`) //2: 타깃 단계
    console.log(`이벤트 타깃: ${e.target}`) //[object HTMLLIlement]
    console.log(`커런트 타깃: ${e.currentTarget}`) //[object HTMLULListElement]
   })

   //버블링 단계
   $fruits.addEventListner('click', e =&amp;gt; {
    console.log(`이벤트 단계: ${e.eventPhase}`) //3: 버블링 단계
    console.log(`이벤트 타깃: ${e.target}`) //[object HTMLLIlement]
    console.log(`커런트 타깃: ${e.currentTarget}`) //[object HTMLULListElement]
   })
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.7 이벤트 위임&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 위임(event delegation)&lt;/b&gt;은 &lt;i&gt;여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 DOM 요소에 이벤트 핸들러를 등록하는 방법&lt;/i&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 li에 eventListener을 등록하면 퍼포먼스 이슈가 생기기 때문에 이벤트 위임을 적용하는 것이 낫다. 하지만, DOM 요소가 아닌 상위 요소에 이벤트 핸들러를 등록하기 때문에 이벤트 타깃이 아닐 가능성도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-09]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678018993356&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;nav&amp;gt;
    &amp;lt;ul id=&quot;fruits&quot;&amp;gt;
     &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
     &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
     &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/nav&amp;gt;
  &amp;lt;div&amp;gt;선택된 네비게이션 아에팀: &amp;lt;em class=&quot;msg&quot;&amp;gt;apple&amp;lt;/em&amp;gt;&amp;lt;/div&amp;gt;
  
  &amp;lt;script&amp;gt;
   const $fruit = document.getElementById('fruits');
   const $msg = document.getElementById('.msg');
  
  
   // 사용자 클릭에 의해 선택된 네비게이션 아이템(li 요소)에 active 클래스를 추가하고
   // 그 외의 모든 내비게이션 아이템의 active 클래스를 제거한다.
   function activate({ target }) {
    if (!target.matches('#fruits &amp;gt; li')) return;
    
    [...$fruits.children].forEach($fruit =&amp;gt; {
     $fruit.classList.toggle('active', $fruite === target)
     $msg.textContent = target.id;
    })
   }
   
   $fruits.onclick = activate
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.8 DOM 요소의 기본 동작 조작&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.8.1 DOM 요소의 기본 동작 중단&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 객체의 preventDefault 메서드는 DOM 요소의 기본 동작을 중단시킨다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.8.2 이벤트 전파 동지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 객체의 stopDefault 메서드는이벤트 전파를 중단시킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.9 이벤트 핸들러 내부의 this&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.9.1 이벤트 핸들러 어트리뷰트 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 함수로서 호출되는 함수 내부의 this는 전역 객체를 가리킨다. 따라서 handleClick 함수 내부의 this는 전역 객체 window를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 이벤트 핸들러로 호출할 때 인수로 전달한 this는 &lt;b&gt;이벤트를 바인딩한 DOM 요소&lt;/b&gt;를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-10]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678019919067&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;button onclick=&quot;handleClick(this)&quot;&amp;gt;CLick me&amp;lt;/button&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;script&amp;gt;
function handleClick(button) {
 console.log(button) // 이벤트를 바인딩한 button 요소
 console.log(this) // window
 
}
&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.9.2 이벤트 핸들러 프로퍼티 방식과 addEvenetListener 메서드 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식 모두 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다. 즉, 이벤트 핸들러 내부의 this는 이벤트 객체의 currentTarget 프로퍼티와 같다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킨다. 화사표 함수는 함수 자체의 this를 갖지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 클래스에서 이벤트 핸들러를 바인딩하는 경우 this에 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-11]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678020535186&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;button class=&quot;btn&quot;&amp;gt;0&amp;lt;/button&amp;gt;

  &amp;lt;script&amp;gt;
    class App {
      this.$button = document.querySelector('.btn&quot;)
      this.count = 0;
      
      // increase 메서드를 이벤트 핸들러로 등록
      // 아래처럼할 경우 increase내부에서 this.$button.$button이 됨.
      // this.$button.onclick = this.increase
      
      // increase 메서드 내부의 this가 인스턴스를 가리키도록 한다.
      this.$button.onclick =  this.increase.bind(this)
      
    }
    
    // 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리키기 때문에 
    // increase 메서드 내부의 this는 this.$button을 가리킨다. 
    increase() {
      this.$button.textContent = ++this.count;
    }
    
    new App()
  &amp;lt;/script&amp;gt;


&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 필드에 할당한 화살표 함수를 이벤트 핸들러로 등록하여 이벤트 핸들러 내부의 this가 인스턴스를 가리키도록 할 수도 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 40-12]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678020619223&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;

&amp;lt;body&amp;gt;
  &amp;lt;button class=&quot;btn&quot;&amp;gt;0&amp;lt;/button&amp;gt;

  &amp;lt;script&amp;gt;
    class App {
      this.$button = document.querySelector('.btn&quot;)
      this.count = 0;
      
      // increase 메서드를 이벤트 핸들러로 등록
      // 아래처럼할 경우 increase내부에서 this.$button.$button이 됨.
      // this.$button.onclick = this.increase
      
      // increase 메서드 내부의 this가 인스턴스를 가리키도록 한다.
      this.$button.onclick =  this.increase.bind(this)
      
    }
    
    // 클래스 필드 정의
    // increase는 인스턴스 메서드이며 this는 인스턴스를 가리킨다.
    increase() = () =&amp;gt;  this.$button.textContent = ++this.count;


    new App()
  &amp;lt;/script&amp;gt;


&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.10 이벤트 핸들러에 인수 전달&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식의 경우 이벤트 핸들러를 브라우저가 호출하기 때문에 함수 호출문이 아닌 함수 자체를 등록해야 하기 때문에 인수를 전달할 수 없다. 그러나 이벤트 핸들러 내부에서 함수를 호출하면서 인수를 전달할 수 있다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 40-13]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678020874379&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;label&amp;gt;User name &amp;lt;input type='text'&amp;gt;&amp;lt;/label&amp;gt;
  &amp;lt;em class=&quot;message&quot;&amp;gt;&amp;lt;/em&amp;gt;
  &amp;lt;script&amp;gt;
   const MIN_USER_NAME_LENGTH = 5;
   const $input = document.querySelector('input[type=text]');
   const $msg = document.querySelector('.message');
   
   const checkUserNameLength = min =&amp;gt; e =&amp;gt; {
    $msg.textContent 
     = $input.value.length &amp;lt; min ? `이름음 ${min}자 이상 입력해 주세요` : '';
   }
   
   $input.onblur = checkUserNameLength(MIN_USER_NAME_LENGTH)
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;40.11 커스텀 이벤트&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;40.11.1 커스텀 이벤트 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Event, UIEvent, MouseEvent 같은 이벤트 생성자 함수를 호출하여 명시적으로 생성한 이벤트 객체는 임의의 이벤트 객체를 커스텀 이벤트로 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 40-14]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678021349638&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const keyboradEvent = new KeyboardEvent('keyup')
console.log(keyboardEvent.type) //keyup

const customEvent = new CustomEvent('foo')
console.log(customEvent.type) //foo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 커스텀 이벤트 객체는 버블링되지 않으며 preventDefault메서드로 취소할 수 없다. 즉 bubbles, cancelable 프로퍼티의 값이 false로 기본 설정된다. 설정이 필요할 경우 두 번째 인수로 bubbles, 또는 cancelable 프로퍼티를 갖는 객체를 전달하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 40-15]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678021609730&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const customEvent = new MouseEvent('click', {
 bubbles: true,
 cancelable: true,
 // 이벤트 고유의 프로퍼티 값도 지정 가능
 // clientX: 50,
 // clientY: 100
})&lt;/code&gt;&lt;/pre&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;b&gt;40.11.1 커스텀 이벤트 디스패치&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 커스텀 이벤트는 dispatchEvent 메서드로 디스패치(dispatch)할 수 있다. &amp;nbsp;dispatchEvent 메서드에 이벤트 객체를 인수로 전달하면서 호출하면 인수로 전달한 이벤트 타입의 이벤트가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트 핸들러는 비동기 처리 방식으로 동작하지만 dispatchEvent 메서드는 이벤트 핸들러를 동기적으로 호출한다. 따라서 dispatchEvent 메서드를 이벤트로 디스패치하기 이전에 커스텀 이벤트를 처리할 이벤트 핸들러를 등록해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 40-16]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678021887048&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;button class=&quot;btn&quot;&amp;gt;Click me&amp;lt;/button&amp;gt;
  &amp;lt;script&amp;gt;
    const $button = document.querySelector('.btn');
    
    // 버튼 요소에 click 커스텀 이벤트 핸들러를 등록
    //커스텀 이벤트를 티스패치하기 전에 이벤트 핸들러를 등록해야 한다.
    $button.addEventListner('click', e =&amp;gt; {
     console.log(e) // MouseEvent {isTrusted: false, screenX: 0, ...}
     alert(`${e} Clicked`);
    })
    
    const customEvent = new MouseEvent('click');
    
    $button.dispatchEvent(customEvent)
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 이벤트 타입이 아닌 임의의 이벤트 타입을 지정하여 커스텀 이벤트 객체를 생성한 경우 반드시 addEventListener 메서드 방식으로 이벤트 핸들러를 등록해야 한다. element node에 on + 이벤트 핸들러 어트리뷰트/프로퍼티가 존재하지 않기 때문.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 40-17]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678022035223&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;button class=&quot;btn&quot;&amp;gt;Click me&amp;lt;/button&amp;gt;
  &amp;lt;script&amp;gt;
    const $button = document.querySelector('.btn');
    
    // 버튼 요소에 foo 커스텀 이벤트 핸들러를 등록
    // 커스텀 이벤트를 티스패치하기 전에 이벤트 핸들러를 등록해야 한다.
    $button.addEventListner('foo', e =&amp;gt; {
     alert(e.detail.message);
    })
    
    const customEvent = new CustomEvent('foo', {
      detail: { message: 'Hello' }
    });
    
    $button.dispatchEvent(customEvent)
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&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;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/94</guid>
      <comments>https://daniel-park.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 5 Mar 2023 22:16:46 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 39 DOM</title>
      <link>https://daniel-park.tistory.com/93</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be1xRT/btrZNu86Vgk/ywYA7Htu0DlG2am5xexDXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be1xRT/btrZNu86Vgk/ywYA7Htu0DlG2am5xexDXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be1xRT/btrZNu86Vgk/ywYA7Htu0DlG2am5xexDXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe1xRT%2FbtrZNu86Vgk%2FywYA7Htu0DlG2am5xexDXk%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.0 Preface&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM, Browser Rendering, ... 등 어쩌면 FE 개발자의 정석이라고 해도 과언이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM(Document Object Model)은 HTML 문서의 계층적 구조와 정보를 표현하며 이를 제어할 수 있는 API, 즉 프로퍼티와 메서드를 제공하는 트리 자료구조다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.1 노드&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.1.1 HTML 요소와 노드 객체&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML element는 HTML 문서를 구성하는 개별적인 요소이며 렌더링 엔진에 의해 파싱되어 DOM을 구성하는 element Node 객체로 변환된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-01]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1FbA7/btrZUBffsZD/EtvixRYq45pNaUS3bOBLu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1FbA7/btrZUBffsZD/EtvixRYq45pNaUS3bOBLu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1FbA7/btrZUBffsZD/EtvixRYq45pNaUS3bOBLu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1FbA7%2FbtrZUBffsZD%2FEtvixRYq45pNaUS3bOBLu1%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;265&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 문서는 HTML element들의 집합으로 이뤄지며, element와 중첩 관계에 의해 계층적인 parent-child 관계가 형성된다. HTML element 간의 관계를 바녕ㅇ하여 HTML 요소를 개체화한 모든 노드 객체들을 트리 자료 구조로 구성한다. &lt;b&gt;노드 객체들로 구성된 트리 자료구조&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;DOM 또는 DOM Tree&lt;/b&gt;&lt;/u&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;b&gt;39.1.2 노드 객체의 타입&lt;/b&gt;&lt;/h4&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;[그림 39-02]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HVNcX/btrZK3c127J/3fKE1Aizk2W2UKmI5iSPq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HVNcX/btrZK3c127J/3fKE1Aizk2W2UKmI5iSPq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HVNcX/btrZK3c127J/3fKE1Aizk2W2UKmI5iSPq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHVNcX%2FbtrZK3c127J%2F3fKE1Aizk2W2UKmI5iSPq0%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;1220&quot; height=&quot;582&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;582&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;[그림 39-03]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uhXVo/btrZ4bUqAPP/AoFvG3uyGuHwkSUn8LcK4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uhXVo/btrZ4bUqAPP/AoFvG3uyGuHwkSUn8LcK4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uhXVo/btrZ4bUqAPP/AoFvG3uyGuHwkSUn8LcK4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuhXVo%2FbtrZ4bUqAPP%2FAoFvG3uyGuHwkSUn8LcK4K%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;1256&quot; height=&quot;564&quot; data-origin-width=&quot;1256&quot; data-origin-height=&quot;564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 39-02의 HTML 문서를 렌더링 엔진이 파싱하면 그림 39-03처럼 파싱하여 DOM을 생성한다.&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;DOM의 중요한 노드 타입 4가지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Document Node&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;DOM 트리의 최상위에 존재하는 루트 노드로 document 객체 자체, 브라우저가 렌더링한 HTML 문서 자체를 가리키는 객체이며 전역 객체 window의 document 프로퍼티에 바인딩되어 있다. (window.document or document)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;브라우저 환경의 모든 JS 코드는 script 태그에 분리되어 있어도 하나의 전역 객체 window를 공유한다. 따라서 모든 JS 코드는 전역 객체 window의 document 프로퍼티에 바인딩 되어 있는 하나의 document 객체를 바라본다. 즉, document 객체는 HTML에 하나만 존재하며 DOM 트리의 노드들에 접근하기 위한 entry point 역할을 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Element Node&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML element를 가리키는 객체, 이 element 간의 중첩에 의해 부자 관계를 가지며, 이 부자 관계를 통해 정보를 구조화한다. 따라서 문서의 구조를 표현한다고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Attribute Node&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말 그대로, HTML element의 attribute를 가리키는 객체. 당연한 이야기지만, 부모 element node에 연결이 되지 않고, 관련된 element node에 직접 연결되어 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- Text Node&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML element의 텍스트를 가리키는 객체. child node를 가질 수 없는 leaf node이므로 dom 트리의 최종단.&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;b&gt;39.1.3 노드 객체의 상속 구조&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM을 구성하는 노드 객체는 자신의 구조와 정보를 제어할 수 있는 DOM API를 사용할 수 있다. 이를 통해 자신의 부모, 형제, 자식을 탐색할 수 있으며 attribute와 텍스트를 조작할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-04] 우측 방향으로의 상하 관계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d1kYvF/btrZ2zgR30o/XCxJObt9ijQMoetTVpzGK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d1kYvF/btrZ2zgR30o/XCxJObt9ijQMoetTVpzGK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d1kYvF/btrZ2zgR30o/XCxJObt9ijQMoetTVpzGK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd1kYvF%2FbtrZ2zgR30o%2FXCxJObt9ijQMoetTVpzGK0%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;1218&quot; height=&quot;728&quot; data-origin-width=&quot;1218&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-05]&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by34Tw/btrZNuBfK3s/LBLHIm46KSdgVlHe20l4b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by34Tw/btrZNuBfK3s/LBLHIm46KSdgVlHe20l4b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by34Tw/btrZNuBfK3s/LBLHIm46KSdgVlHe20l4b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby34Tw%2FbtrZNuBfK3s%2FLBLHIm46KSdgVlHe20l4b1%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;480&quot; height=&quot;476&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;예를 들어, Input 요소 노드 객체는 프로토타입 체인에 있는 모든 프로토타입의 프로퍼티나 메서드를 상속받아 사용할 수 있다. 노드 객체의 상속 구조는 아래처럼 개발자 도구의 Elements 패널 오축의 Properties 패널에서 확인할 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-06]&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0Wauo/btrZUBzAhWd/YdCzcnKvbFhAStmHtew0k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0Wauo/btrZUBzAhWd/YdCzcnKvbFhAStmHtew0k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0Wauo/btrZUBzAhWd/YdCzcnKvbFhAStmHtew0k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0Wauo%2FbtrZUBzAhWd%2FYdCzcnKvbFhAStmHtew0k1%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;680&quot; height=&quot;455&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;670&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;노드 객체에는 노드 객체의 종류(타입)에 상관없이 공통으로 갖는 기능도 있고, 노드 타입에 따라 고유한 기능도 있다. EventTarget interface(EventTarget.addEventListener, EventTarget.removeEventListener ... 등), Node interface(Node.nodeType, node.nodeName, Node.parentNode, Node.childNodes, ...등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;정리하자면&lt;b&gt; DOM은 HTML 문서의 계층적 구조와 정보를 표현하는 것은 물론 노드 객체의 종류, 즉 노드 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공한다. 이 DOM API를 통해 HTML의 구조나 내용 또는 스타일 등을 동적으로 조작할 수 있다&lt;/b&gt;.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.2 Element Node 취득&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML의 구조나 내용 또는 스타일 등을 동적으로 조작하려면 먼저 Element Node를 취득해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.2.1 id를 이용한 Element Node 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Document.prototype.getElementByID 메서드는 인수로 전달한 id attribute 값을 갖는 하나의 element node를 탐색해 반환한다. document.getEelementById('${id}')를 통해서 얻을 수 있다. HTML 요소에 id attribute를 부여하면 id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고 해당 노드 객체가 할당되는 부수 효과가 있다.&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;b&gt;39.2.2 Tag 이름을 이용한 Element Node 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Document.prototype/Element.prototype.getElementsByTagName 메서드는 인수로 전달한 태그 이름을 갖는 모든 요소 노드들을 탐색하여 유사 배열 객체이면서 이터러블인 HTML Collecion 객체로 반환한다.&amp;nbsp;&lt;/span&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.2.3 Class를 이용한 Element Node 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Document.prototype/Element.prototype.getElementsByClassName 메서드는 인수로 전달한 class attribute 값을 갖는 모든 요소 노드들을 탐색하여 반환한다. 인수로 전달할 class 값은 공백으로 구분하여 여러 개의 class를 지정할 수 있다.&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;b&gt;39.2.4 CSS selector을 이용한 Element Node 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS Selector는 스타일을 적용하고자 하는 HTML element를 특정할 때 사용하는 문법이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-07]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;1354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvOuZm/btrZLVFIvWU/ZP7rCgM7iZkDOdKnknvenk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvOuZm/btrZLVFIvWU/ZP7rCgM7iZkDOdKnknvenk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvOuZm/btrZLVFIvWU/ZP7rCgM7iZkDOdKnknvenk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvOuZm%2FbtrZLVFIvWU%2FZP7rCgM7iZkDOdKnknvenk%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;680&quot; height=&quot;910&quot; data-origin-width=&quot;1012&quot; data-origin-height=&quot;1354&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Document.prototype/Element.prototype.querySelectorAll 메서드는 인수로 전달한 CSS 선택자를 만족시키는 모든 요소 노드를 탐색하여 반환한다. e.g(document.querySelectorAll('ul &amp;gt; li')&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;b&gt;39.2.5 특정 element 노드를 취득할 수 있는지 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Element.prototype.matches 메서드는 인수로 전달한 CSS 선택자를 통해 특정 요소 노드를 취득 할 수 있는지 확인하여 Boolean 값으로 반환한다.&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;b&gt;39.2.6 HTMLCollection과 NodeList&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML Collection은 언제나 live 객체로 동작하여 노드 객체의 상태 변화를 실시간으로 반영하지만, NodeList는 대부분 과거의 정적 상태를 유지하는 None-live 객체로 동작한다.&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;HTMLCollection&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTMLCollection 객체는 실시간으로 노드 객체의 상태 변경을 반영하여 요소를 제거할 수 있기 때문에 HTML Collection 객체를 for 문으로 순회하면서 노드 객체의 상태를 변경해야 할 때 주의해야 한다.&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;[예제 39-18]&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1676827182561&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...(생략)
&amp;lt;body&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li class=&quot;red&quot;&amp;gt;A&amp;lt;/li&amp;gt;
    &amp;lt;li class=&quot;red&quot;&amp;gt;B&amp;lt;/li&amp;gt;
    &amp;lt;li class=&quot;red&quot;&amp;gt;C&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;script&amp;gt;
   const $elems = document.getElementByClassName('red')
   console.log($elems) //HTMLCollection(3) [li.red, li.red, li.red]
   
   // not intended
   for (let i = 0; i &amp;lt; $elems.lenght; i++) $elems[i].className = 'blue'
   
   console.log($elems) //HTMLCollection(1) [li.red]
   
   
   // solution1 역방향 순회
   for (let i = $elems.length - 1; i &amp;gt;= 0; i--) $elems[i].className = 'blue'
   
   // solution2 while을 이용해 노드 객체 length
   let i = 0;
   while($elems.length &amp;gt; i)  $elems[i].className = 'blue'
  &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
...(생략)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NodeList&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTMLCollection 객체의 부작용을 해결하기 위해 NodeList를 반환하는 querySelectorAll 메서드를 사용할 수 있다. &lt;b&gt;하지만 childNodes 프로퍼티가 반환하는 NodeList 객체는 HTMLCollection 객체와 같이 실시간으로 노드 객체의 상태 변경을 반영하는 Live 객체로 동작하므로 주의가 필요하다.&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;이처럼 상태 변경과 상관없이 안전하게 DOM 컬렉션을 사용하려면 Spread 문법이나 Array.from 메서드를 사용하여 배열로 변환하여 사용하는 것이 낫다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.3 Element 탐색&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM은 트리 상의 노드를 탐색 할 수 있도록 Node, Element 인터페이스는 트리 탐색 프로퍼티를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node 탐색 프로퍼티는 모두 접근자 프로퍼티로 getter만 존재하는 읽기 전용 접근자 프로퍼티다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-08]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJymqa/btr0gl4FAnT/89ETEafu1oTvcD3mgKDic1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJymqa/btr0gl4FAnT/89ETEafu1oTvcD3mgKDic1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJymqa/btr0gl4FAnT/89ETEafu1oTvcD3mgKDic1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJymqa%2Fbtr0gl4FAnT%2F89ETEafu1oTvcD3mgKDic1%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;700&quot; height=&quot;531&quot; data-origin-width=&quot;1008&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.3.1 공백 텍스트 노드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML element 사이의 스페이스, 탭, 줄바꿈(개행) 등의 공백 문자는 공백 텍스트 노드를 생성한다.&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;b&gt;39.3.2 자식 노드 탐색&lt;/b&gt;&lt;/h4&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;[그림 39-09]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ml9O2/btr0fUF7Pli/WEKjzF4XkhHPDsj6JT9zj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ml9O2/btr0fUF7Pli/WEKjzF4XkhHPDsj6JT9zj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ml9O2/btr0fUF7Pli/WEKjzF4XkhHPDsj6JT9zj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fml9O2%2Fbtr0fUF7Pli%2FWEKjzF4XkhHPDsj6JT9zj1%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;196&quot; data-origin-width=&quot;1202&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y0rcG/btr0dpNUzAp/nHwK1jwTyJpCyGYK3TlmG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y0rcG/btr0dpNUzAp/nHwK1jwTyJpCyGYK3TlmG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y0rcG/btr0dpNUzAp/nHwK1jwTyJpCyGYK3TlmG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy0rcG%2Fbtr0dpNUzAp%2FnHwK1jwTyJpCyGYK3TlmG1%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;243&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.3.3 자식 노드 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 노드가 존해하는지 확인하려면 Node.prototype.hasChildNodes 메서드를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.4 노드 정보 취득&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드 객체에 대한 정보를 취득하기 위해선 다음과 같은 노드 정보 프로퍼티를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-10]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/urP6M/btr0eKYEYWU/eROqey01zGNzlnHsQNviMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/urP6M/btr0eKYEYWU/eROqey01zGNzlnHsQNviMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/urP6M/btr0eKYEYWU/eROqey01zGNzlnHsQNviMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FurP6M%2Fbtr0eKYEYWU%2FeROqey01zGNzlnHsQNviMK%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;275&quot; data-origin-width=&quot;1146&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.5 Element 노드의 텍스트 조작&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.5.1 nodeValue&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.prototype.nodeValue 프로퍼티는 setter와 getter 모두 존재하는 접근자 프로퍼티다 따라서 nodeValue 프로퍼티는 참조와 할당 모두 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 39-20]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677032017658&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...(생략)
&amp;lt;body&amp;gt;
 &amp;lt;div id=&quot;foo&quot;&amp;gt;Hello&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
 const $foo = docuemnt.getEelementById('foo')
 console.log($foo.nodeValue)//null
 
 const $textNode = $foo.firstChild
 console.log($textNode.nodeValue)
 
 
 $textNode.nodeValue = 'World'
 
...(생략)&lt;/code&gt;&lt;/pre&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;b&gt;39.5.2 textContent&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;textContent를 참조하면 Element Node의 HTML 마크업은 무시하고 콘텐츠 영역의 텍스트를 모두 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.6 DOM 조작&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 조작은 새로운 노드를 생성하여 DOM에 추가하거나 기존 노드를 삭제 || 교체하는 것이기 떄문에 reflow &amp;amp;&amp;amp; repaint가 발생한다. 따라서 성능에 영향을 주게 되어 성능 최적화를 위해 주의해 다루어야 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.1 innerHTML&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;element node의 innerHTML 프로퍼티를 참조하면 컨텐츠 영역 내에 포함한 모든 HTML 마크업을 문자열로 반환한다.(getter/setter)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자로부터 입력받은 데이터를 그대로 innerHTML에 할당하는것은 XSS에 취약하므로 위험하지만 HTML5는 innerHTML 프로퍼티로 삽인된 script 요소 내의 자바스크립트 코드를 실행하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;innerHTML 프로퍼티를 조작하는 경우 모든 자식 노드를 제거하고 할당한 HTML 마크업 문자열을 파싱하여 DOM을 변경하는 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.2 insertAdjacentHTML&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;innerHTML&lt;/b&gt;과 달리 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 XSS에 취약한 것은 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[그림 39-11]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LwAc0/btr0fJdEHQC/ZfzG6IKblKpS0RSELKxbpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LwAc0/btr0fJdEHQC/ZfzG6IKblKpS0RSELKxbpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LwAc0/btr0fJdEHQC/ZfzG6IKblKpS0RSELKxbpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLwAc0%2Fbtr0fJdEHQC%2FZfzG6IKblKpS0RSELKxbpk%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;192&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 39-21]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677033666208&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(생략)
&amp;lt;!-- beforebegin --&amp;gt;
&amp;lt;div id=&quot;foo&quot;&amp;gt;
  &amp;lt;!-- afterbegin --&amp;gt;
  text
  &amp;lt;!-- beforeend --&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!-- afterend --&amp;gt;


&amp;lt;script&amp;gt;
 const $foo = document.getElementById('foo')
 $foo.insertAdjacentHTML('beforebegin', &amp;lt;p&amp;gt;beforebegin&amp;lt;/p&amp;gt;')
 $foo.insertAdjacentHTML('afterbegin', &amp;lt;p&amp;gt;afterbegin&amp;lt;/p&amp;gt;')
 $foo.insertAdjacentHTML('beforeend', &amp;lt;p&amp;gt;beforeend&amp;lt;/p&amp;gt;')
 $foo.insertAdjacentHTML('afterend', &amp;lt;p&amp;gt;afterend&amp;lt;/p&amp;gt;')
&amp;lt;/script&amp;gt;
(생략)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.3 노드 생성과 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 39-22]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677033867444&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(생략)
&amp;lt;ul id=&quot;fruits&quot;&amp;gt;
 &amp;lt;li&amp;gt;Apple&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;


&amp;lt;script&amp;gt;
 const $fruits = document.getElementById('fruits')

 // 1. 요소 노드 생성
 const $li = document.createEelement('li');
 
 // 2. 텍스트 노드 생성
 const textNode = document.createTextNode('Banana');
 
 // 3.텍스트 노드를 $li 요소 노드의 자식 노드로 추가
 $li.appendChild(textNode);
 
 // 4. $li 요소 노드를 #fruits 요소 노드의 마지막 자식 노드로 추가
 $fruits.appendChild($li)
&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.4 복수의 노드 생성과 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forEach로 복수의 노드를 생성해 붙이는 경우는 dom의 N번 변경으로 비효율적이며 div를 만들어 붙이는 것은 불필요한 노드를 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 DocumentFragment 노드를 사용할 수 있는데, 기존 DOM과는 별도로 존재한다. DocumentFragment 노드에 자식 노드를 &amp;nbsp;추가해도 DOM에는 어떤 변경도 발생하지 않고 자신만 제거되고 자식의 노드만 DOM에 추가된다. 아래 예제와 같이 하면 reflow, repaint 모두 한 번만 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 39-23]&amp;nbsp;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677034317249&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(생략)
&amp;lt;body&amp;gt;
 &amp;lt;ul id=&quot;fruits&quot;&amp;gt;&amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;scripts&amp;gt;
 const $fruits = document.getElementById('fruits');
 
 //DocumentFragment
 const $fragment = document.createDocumentFragment()
 ['A, 'B', 'C'].foreEach(text =&amp;gt; {
  // 1. 요소 노드 생성
  const $li = document.createElement('li')
  
  // 2.텍스트 노드 생성
  const textNode = document.createTextNode(text)
  
  // 3 텍스트 노드를 $li 요소 노드의 자식 노드로 추가
  $li.appendChild(textNode)
  
  // 4 $li요소 노드를 DocumentFragment 노드의 마지막 자식 노드로 추가
   $fragment.appendChild($li)

 })
  //5 DocumentFragment 노드를 #fruits 요소 노드의 마지막 자식 노드로 추가
  $fruits.appendChild($fragment)
(생략)&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;[그림 39-12]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbKlYD/btr0mecoa9e/ZLskKx1pG75kQ9GZHPiOxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbKlYD/btr0mecoa9e/ZLskKx1pG75kQ9GZHPiOxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbKlYD/btr0mecoa9e/ZLskKx1pG75kQ9GZHPiOxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbKlYD%2Fbtr0mecoa9e%2FZLskKx1pG75kQ9GZHPiOxk%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;1254&quot; height=&quot;458&quot; data-origin-width=&quot;1254&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.6 노드 이동&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM에 이미 존재하는 노드를 appendChild 또는 insertBefore 메서드를 사용하여 DOM에 다시 추가하면 현재 위치에서 노드를 제거하고 새로운 위치에 노드를 추가하므로 노드가 이동한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.7 노드 복사&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Node.prototype.clondNode([deep: true | false])&lt;/b&gt; 메서드는 노드의 사본을 생성하여 반환한다. 얀튼 복사로 생성된 요소 노드는 자손 노드를 복하자이 않으므로 텍스트 노드도 없다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.7 노드 교체&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Node.prototype.replaceChild(newChild, oldChild) &lt;/b&gt;메서드는 자신을 호출한 노드의 자식 노드를 다른 노드로 교체한다&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.6.7 노드 삭제&lt;/b&gt;&lt;/h4&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;Node.prototype.removeChild(newChild, oldChild)&lt;/b&gt;&lt;/b&gt;&lt;span&gt;메서드는 child 매개변수에 인수로 전달한 노드를 DOM에 삭제한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.7 Attribute&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.7.3 HTML attribute vs DOM property&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;element 노드 객체에는 HTML attribute에 대응하는 프로퍼티가 존재한다. 이 DOM 프로퍼티들은 HTML attribute 값을 초기값으로 갖고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML attribute는 다음과 같이 DOM에서 중복 관리되고 있는 것처럼 보인다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;element 노드의 attribute property에서 관리하는 attribute 노드&lt;/li&gt;
&lt;li&gt;html attriute에 대응하는 element node의 property&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML attribute의 역할은 HTML 요소의 초기 상태를 지정하는 것이다. 즉, HTML attribute 값은 HTML element의 초기 상태를 의미하며 이는 변하지 않는다.&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;첫 렌더링 이후 사용자가 input element에 무언가를 입력하기 시작하면 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;element node는 사용자가 입력 필드에 입력한 값을 state로 가지고 있다. HTML attriute로 지정한 초기 상태 &quot;ilgwon&quot;도 관리해야하는데, 웹페이지를 처음 표시하거나 새로고침할 경우 필요하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉 element node는 2개의 상태, 즉 초기 상태와 최신 상태를 관리해야 한다. element node의 초기 상태는 attribute node가 관리하고 최신 상태는 DOM property가 관리한다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.7.4 data attribute와 dataset property&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data attribute와 dataset property를 사용하면 HTML element에 정의한 사용자 정의 attribute와 js간에 데이터를 교환할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data attribute는 data-user-id, data-role과 같이 data-접두사 다음에 임의의 이름을 붙인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;data attribute값은 HTML.dataset property로 취득 가능하다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;39.8 Style&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;39.8.1 인라인 스타일 조작&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HTMLElement.property.style property&lt;/b&gt;는 setter, getter 모두 존재하는 접근자 property로 element node의 inline style을 취득하거나 추가, 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 39-24]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677037419324&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const $style = document.querySelector('div')

console.log($div.style) //CSSStyleDeclaration { 0: &quot;color&quot;, ...}

$div.style.color = 'blue'

$div.style.width = '100px'
$div.style.height = '100px'
$div.style.backgroundColor = 'yellow'&lt;/code&gt;&lt;/pre&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;b&gt;39.8.2 클래스 조작&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 39-25]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677037544939&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const $box = document.querySelector('.box')
console.log($box.className)

$box.className = $box.className.replace('red' , 'blue')&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;b&gt;[예제 39-26]&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;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Element.prototype.classList&amp;nbsp;&lt;/b&gt;property&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;는 class attribute 정보를 담은 DOMTokenList 객체를 반환한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677037655762&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const $box = document.querySelector('.box')
console.log($box.classList)
// DOMTokenList(2) [length: 2, value: &quot;box blue&quot;, 0: &quot;box&quot;, 1: &quot;blue&quot;]

$box.classList.replace('red' , 'blue')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOMTokenList 객체는 class attribute 정보를 나타내는 collection 객체로 유사 배열 객체이면서 이터러블이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;add(...className)&lt;/li&gt;
&lt;li&gt;replace(...clasName)&lt;/li&gt;
&lt;li&gt;item(index)&lt;/li&gt;
&lt;li&gt;contains(className)&lt;/li&gt;
&lt;li&gt;replace(oldClassName, newClassName)&lt;/li&gt;
&lt;li&gt;toggle(className[, force])
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;class attribute에 인수로 전달한 문자열과 일치하는 클래스가 존재하면 제거, 존재하지 않으면 추가&lt;/li&gt;
&lt;li&gt;두 번째 인수로 boolean 값으로 평가되는 조건식 전달 가능. true이면 class attribute에 강제로 첫 번째 인수로 전달받은 문자열을 추가하고 false면 강제로 제거.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&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;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/93</guid>
      <comments>https://daniel-park.tistory.com/93#entry93comment</comments>
      <pubDate>Mon, 20 Feb 2023 02:25:23 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 37 Map</title>
      <link>https://daniel-park.tistory.com/92</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pg5uM/btrXGT4PO8I/FHt9iqDoch0JrfieGlQbp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pg5uM/btrXGT4PO8I/FHt9iqDoch0JrfieGlQbp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pg5uM/btrXGT4PO8I/FHt9iqDoch0JrfieGlQbp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpg5uM%2FbtrXGT4PO8I%2FFHt9iqDoch0JrfieGlQbp0%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;37.2 Map&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map 객체는키와 값의 쌍으로 이루어진 컬렉션이다. 객체와 유사하지만 다음과 같은 차이가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 84px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Map 객체&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;키로 사용할 수 있는 값&lt;/td&gt;
&lt;td&gt;문자열 또는 심벌 값&lt;/td&gt;
&lt;td&gt;객체를 포함한 모든 값&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이터러블&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;요소 개수 확인&lt;/td&gt;
&lt;td&gt;Object.keys(obj).length&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;map.size&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.2.1 Map 객체 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map 생성자 함수는 이터러블을 인수로 전달받아 Map 객체를 생성한다. 이때 인수로 전달되는 이터럽ㄹ은 키와 값의 쌍으로 이루어진 요소로 구성되어야 한다.&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;b&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt; 37-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675171777936&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map(['k1', 'v1'], ['k2', 'v2'])

const ma2 = new Map(['k1', 'v1'], ['k1', 'v1']) // Map(1) {&quot;k1&quot; =&amp;gt; &quot;v1&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.2.2 요소 개수 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt; 37-02]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675171867514&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map(['k1', 'v1'], ['k2', 'v2'])

map.size&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.2.3 요소 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-02]&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1675171926755&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map()

const daniel = {name: 'daniel'}

//chaining도 가능, 중복 추가 불가
map
.set('k1', 'v1')
.set('k2', 'v2')

// 키로 저장도 가능
.set(daniel, 'developer')&lt;/code&gt;&lt;/pre&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;b&gt;37.2.4 요소 취득&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-03]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675172101764&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map([[&quot;k1&quot;, &quot;v1&quot;]])
map.get(&quot;k1&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;b&gt;37.2.6 요소 삭제&lt;/b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-04]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675172315473&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map([[&quot;k1&quot;, &quot;v1&quot;]])

map.has(&quot;k1&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.2.6 요소 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-05]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675172159909&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map([[&quot;k1&quot;, &quot;v1&quot;]])
map.delete(&quot;k1&quot;)

// 없는 키이므로 무시
map.delete(&quot;k2&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.2.7 요소 일괄 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-06]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675172356592&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const map = new Map([[&quot;k1&quot;, &quot;v1&quot;]])
map.clear()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/92</guid>
      <comments>https://daniel-park.tistory.com/92#entry92comment</comments>
      <pubDate>Tue, 31 Jan 2023 22:39:31 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 37 Set</title>
      <link>https://daniel-park.tistory.com/91</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKqCVV/btrXGnLAUfo/PEAtZEWZ6UFQhrL5oru7n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKqCVV/btrXGnLAUfo/PEAtZEWZ6UFQhrL5oru7n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKqCVV/btrXGnLAUfo/PEAtZEWZ6UFQhrL5oru7n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKqCVV%2FbtrXGnLAUfo%2FPEAtZEWZ6UFQhrL5oru7n0%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;37.1 Set&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set은 수학적 집합을 구현하기 위한 자료구조로 &lt;span&gt;중복되지 않는 유일한 값들의 집합이다.&lt;span&gt;&amp;nbsp;따라서 교집합, 합집합, 차집합, 여집합 등을 구현할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set 객체는 배열과 유사하지만 다음과 같은 차이가 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 84px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 37.751937984496124%; height: 21px;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 28.914728682170544%; height: 21px;&quot;&gt;&lt;b&gt;배열&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;&lt;b&gt;Set&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 37.751937984496124%; height: 21px;&quot;&gt;동일한 값을 중복하여 포함 가능&lt;/td&gt;
&lt;td style=&quot;width: 28.914728682170544%; height: 21px;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 37.751937984496124%; height: 21px;&quot;&gt;요소 순서에 의미가 있음&lt;/td&gt;
&lt;td style=&quot;width: 28.914728682170544%; height: 21px;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 37.751937984496124%; height: 21px;&quot;&gt;인덱스로 요소에 접근 가능&lt;/td&gt;
&lt;td style=&quot;width: 28.914728682170544%; height: 21px;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%; height: 21px;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.1 Set 객체 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set 생성자 함수는 이터러블을 인수로 전달받아 Set 객체를 생성한다. 당연한 말이지만, 이터러블의 중복된 값은 Set 객체에 저장되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 37-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675167448732&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set1 = new Set([1,2,3,3]) // Set(3) {1,2,3}

const set2 = new Set('hello') // set(4) {&quot;h&quot;, &quot;e&quot;, &quot;l&quot;, &quot;o&quot;}

// 배열의 중복 요소 제거
const uniq = array =&amp;gt; array.filter((v, i, self) =&amp;gt; self.indexOf(v) === i)

// Set을 사용한 배열의 중복 요소 제거
const uniq = array =&amp;gt; [...new Set(array)]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.2 요소 개수 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 37-02]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675167536380&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const {size} = new Set([1,2,3,3])

const set = new Set([1,2,3,3])

console.log(set.size) //3&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.3 요소 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 37-03]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675167683703&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set = new Set()
set.add(1)
set.add(2).add(3)
// 모든 값 저장 가능
set.add(NaN).add(null).add(true).add('a').add({}).add([]).add(() =&amp;gt; {})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.4 요소 존재 여부 확인&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;[예제 37-04]&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675167748875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set = new Set([1,2,3])

console.log(set.has(2))
console.log(set.has(4))&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.5 요소 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-05]&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1675167800040&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set = new Set([1,2,3])

set.delete(2)

// 에러 없이 무시
set.delete(4)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.6 요소 일괄 삭제(비우기)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&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;[예제 37-06]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675167873132&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set = new Set([1,2,3])
set.clear()&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.7 요소 순회&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Set 객체의 요소를 순회하려면 Set.prototype.forEach 메서드를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인수&lt;/b&gt;&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;현재 순회중인 요소 값&amp;nbsp;&lt;/li&gt;
&lt;li&gt;현재 순회 중인 Set 객체 자체&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;[예제 37-07]&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675168008798&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const set = new Set([1,2,3])

ser.forEach((v, v2, set) =&amp;gt; console.log(v,v2,set));

/*
1 1 Set(3) {1,2,3}
2 2 Set(3) {1,2,3}
3 3 Set(3) {1,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;Set 또한 이터러블이므로 for ... of 문으로 순회 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Set 또한 이터러블이므로&lt;span&gt;&amp;nbsp;디스트럭처링 할당의 대상이 될 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;37.1.8 집합 연산&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 37-08] 교집합&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675168602247&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set.prototype.intersection = function(set) {
 return new Set([...this].filter(v =&amp;gt; set.has(v)));
}

const setA = new Set([1,2,3,4,])
const setB = new Set([2,4,])

setA.intersection(setA.intersection(setB))&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;[예제 37-09]&lt;span&gt;&amp;nbsp;합집합&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675168738793&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set.prototype.union = function(set) {
 return new Set([...this], ...set);
}

const setA = new Set([1,2,3,4])
const setB = new Set([2,4])

console.log(setA.union(setB))&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;[예제 37-10]&lt;span&gt;&amp;nbsp;차집합&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675168870859&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set.prototype.difference = function (set) {
 return new Set([...this].filter(v =&amp;gt; !set.has(v)))
}

const setA = new Set([1,2,3,4])
const setB =  new Set([2,4])

console.log(setA.difference(setB))&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;[예제 37-11]&lt;span&gt;&amp;nbsp;상위 집합 &amp;amp; 부분집합&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1675168995219&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set.prototype.isSuperset = function (subset) {
 for (const value of subset) {
  if (!this.has(value)) return false
 }
 
 return true
}

const setA = new Set([1,2,3,4])
const setB = new Set([2,4])

console.log(setA.isSuperSet(setB))&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;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;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/91</guid>
      <comments>https://daniel-park.tistory.com/91#entry91comment</comments>
      <pubDate>Tue, 31 Jan 2023 21:56:12 +0900</pubDate>
    </item>
    <item>
      <title>[Group Study, 모던 자바스크립트 Deep Dive] - 36 디스트럭처링 할당</title>
      <link>https://daniel-park.tistory.com/90</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5E2fi/btrWteh5R10/N0oVcTXBLmLek98CwL4L61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5E2fi/btrWteh5R10/N0oVcTXBLmLek98CwL4L61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5E2fi/btrWteh5R10/N0oVcTXBLmLek98CwL4L61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5E2fi%2FbtrWteh5R10%2FN0oVcTXBLmLek98CwL4L61%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;183&quot; height=&quot;480&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Group study background&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나만 그런건지는 모르겠지만, 실무를 하다보면 잊어버리는 개념들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가끔 FE 뉴비인분들에게 질문을 받는데, 아리송 할때만큼 쪽팔릴때가 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인간은 망각의 동물이라고 교수님께서 말씀하셨지만 반복 학습의 힘을 믿는다. React 오픈카톡방에서 모집한 스터디원분들과 함께&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&quot;모던 자바스크립트 Deep Dive&quot;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1권 톺아보기를 시작한다!&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;36.0 디스트럭처링 할당(destructuring assignment)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디스트럭처링 할당(destructuriing assignment-구조 분해 할당은 구조화된 배열과 같은 이터러블 또는 객체를 destructuring(비구조화, 구조 파괴)하여 1개 이상의 변수에 개별적으로 할당하는 것을 말한다. 배열과 같은 이터러블 또는 객체 리터럴에 필요한 값만 추출하여 변수에 할당할 때 유용하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;36.1 배열 디스트럭처링 할당&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES5에서 구조화된 배열을 디스트럭처링하여 1개 이상의 변수에 할당하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES6의 배열 디스트럭처링 할당은 배열의 각 요소를 배열로부터 추출하여 1개 이상의 변수에 할당한다. 배열 디스트럭처링 할당의 대상은 이터러블이어야 하고, 할당 기준은 배열의 인덱스다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[예제 36-01]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673949105998&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//ES5

var arr = [1, 2, 3]

var one = arr[0]
var two = arr[1]
var three = arr[2]




//ES6

const [one, two, three] = arr

// 기본값
const [a, b, c = 3] = [1, 2]
console.log(a,b,c) //1 2 3

// 기본값보다 할당된 값이 우선
const [e, f=10, g=3] = [1, 2]
consoel.log(e,f,g) // 1,2,3&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;36.2 객체 디스트럭처링 할당&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ES5에서&lt;span&gt;&amp;nbsp;객체의 각 프로퍼티를 객체로부터 디스트럭처링하여 변수에 할당하기 위해서는 프로퍼티 키를 사용해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;[예제 36-02]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673949650956&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//ES5
var user = { firstName: 'ilgwon', lastName: 'Park' }

var firstName = user.firstName
var lastName = user.lastName


//ES6
const {lastName, firstName } = user

// 프로퍼티 키를 기준으로 디스트럭처링 할당이 이루어진다.
// 프로퍼티 키가 lastName인 프로퍼티 값을 ln에 할당,
// 프로퍼티 키가 firstName인 프로퍼티 값을 fn에 할당.
const {lastName: ln, firstName: fn} = user
consle.log(ln, fn)

// 기본값 설정
const { firstName = 'ilgwon', lastName } = {lastName: 'Park'}

const { firstName: fn = 'ilgwon', lastName: ln} =  {lastName: 'Park'}
console.log(fn, ln)&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;[예제 36-03]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673950024115&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello'

const {length} = str
console.log(length) //5


const todo = { id: 1, content: 'HTML', completed: true ,} 
const { id } = todo



function printTodo({ content, completed }) {
 console.log(`할일 ${content}은 ${complted ? '완료' : '비완료'} 상태입니다.`)
}

printTodo({id: 1, content: 'HTML', complted: true})



// 배열의 요소각 객체인 경우 배열 디스트럭처링 할당과 객체 디스트럭처링 할당 혼용 가능

const todos = [
 { id: 1, content: 'HTML', completed: true },
 { id: 2, content: 'CSS', completed: false },
 { id: 3, content: 'JS', completed: false },
]

const[, {id}] = todos


//중첩 객체인 경우

const user = {
 name: 'ilgwon',
 address: {
  zipCode: '12345',
  city: 'Seoul',
 },
}

const { address: { city } } = user
console.log(city)


//Rest
const {x, ...rest} = {x:1, y:2, z:3}
console.log(x, rest) // 1 {y:2, z:3}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ㅇ&lt;/p&gt;</description>
      <category>Front-end/Javascript</category>
      <author>Daniel(빡일)</author>
      <guid isPermaLink="true">https://daniel-park.tistory.com/90</guid>
      <comments>https://daniel-park.tistory.com/90#entry90comment</comments>
      <pubDate>Tue, 17 Jan 2023 19:07:06 +0900</pubDate>
    </item>
  </channel>
</rss>