<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>아 오늘 금요일인 줄</title>
    <link>https://developing-move.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 31 May 2026 17:44:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>금요일인줄</managingEditor>
    <item>
      <title>[Javascript] map()과 filter()의 차이 이해하기</title>
      <link>https://developing-move.tistory.com/343</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQcRUk/btsO7qnOGhF/1yhC0KFt2Z8bj5ZhWsdcP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQcRUk/btsO7qnOGhF/1yhC0KFt2Z8bj5ZhWsdcP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQcRUk/btsO7qnOGhF/1yhC0KFt2Z8bj5ZhWsdcP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQcRUk%2FbtsO7qnOGhF%2F1yhC0KFt2Z8bj5ZhWsdcP1%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;map()과 filter(). 둘은 매우 비슷하게 생겼다. 콜백 함수의 인자도 거의 똑같고 생김새까지도. 다만 각 함수는 return하는 기능이 다르다고 할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;map()&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;callback 함수를 각각의 요소에 대해 한 번씩 순서대로 불러 그 함수의 반환 값으로 새로운 배열을 생성.&lt;/p&gt;
&lt;pre id=&quot;code_1751816605253&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr.map(callback(currentValue[, index[, array]])[, thisArg])&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;callback은 새로운 배열 요소를 생성하는 함수로 다음 세 가지 인수를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;currentValue: 처리할 현재 요소&lt;/li&gt;
&lt;li&gt;index(Optional): 처리할 현재 요소의 인덱스&lt;/li&gt;
&lt;li&gt;array(Optional): map()을 호출한 배열&lt;/li&gt;
&lt;li&gt;thisArg(Optional): callback을 실행할 때 this로 사용할 값&lt;/li&gt;
&lt;/ul&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;filter()&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환.&lt;/p&gt;
&lt;pre id=&quot;code_1751816744943&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;arr.filter(callback(element[, index[, array]])[, thisArg])&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;callback은 각 요소를 시험할 함수로 true를 반환하면 요소를 유지하고 false를 반환하면 버리며 다음의 세 가지 인수를 갖는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;element: 처리할 현재 요소&lt;/li&gt;
&lt;li&gt;index(Optional): 처리할 현재 요소의 인덱스&lt;/li&gt;
&lt;li&gt;array(Optional): filter()를 호출한 배열&lt;/li&gt;
&lt;li&gt;thisArg(Optional): callback을 실행할 때 this로 사용할 값&lt;/li&gt;
&lt;/ul&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;map() vs filter()&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래의 퀴즈를 통해 이 둘의 차이를 알아 보자.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 배열 [0, 1, 2, 3, 4, 5]이 있고 이 중에서 2보다 작은 값으로만 구성된 배열을 얻어라.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751817002937&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var testArray = [0,1,2,3,4,5];

testArray.filter(function(c){ return c &amp;lt;= 2; }); // [0, 1, 2]

testArray.map(function(c){ return c &amp;lt;= 2 }); // [true, true, true, false, false, false]

testArray.map(function(c){
    if (c &amp;lt;= 2)
        return c;
}) // [0, 1, 2, undefined, undefined, undefined] 빈값을 제거하기 위해선 아이러니하게도 filter을 써야 함&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;왜 같은 코드임에도 filter와 map은 결과 값에 차이가 나는 걸까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;콜백 함수의 역할이 다르기 때문&lt;/b&gt;&lt;/u&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;map()&lt;/b&gt;의 콜백 함수는 산술된 인자를 받아 배열을 만드는 역할을 한다. 따라서 c &amp;lt;= 2를 받으면 그 산술 결과인 boolean 값을 반환해 배열을 만드는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;filter()&lt;/b&gt;의 콜백 함수는 리턴 값의 boolean이 true인 값만 가지고 배열을 만드는 역할을 한다. 따라서 c &amp;lt;= 2에서 c 값에 따라 저 조건식이 true면 c를 그대로 저장하는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 반대의 경우를 보자. 논리 연산이 아닌 산술 연산을 리턴 값으로 한다면 어떻게 될까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Q. 배열 [0, 1, 2, 3, 4, 5]이 있고 각 인자 값의 2배로 이루어진 배열을 얻어라.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751818505828&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var testArray = [0,1,2,3,4,5];

testArray.filter(function(c){ return c * 2; }); // [1, 2, 3, 4, 5]

testArray.map(function(c){ return c * 2 }); // [0, 2, 4, 6, 8, 10]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;map은 산술된 값을 반환, 즉 c * 2를 산술하여 배열에 넣으므로 원하는 답을 얻을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 filter()의 경우 c * 2를 산술이 아닌 논리로 본다. c * 2는 뭘 해도 참이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;딱 한 가지만 제외하고 말이다. c의 값으로 0이 들어가면 0이 되니까 0은 false. 이는 위 filter()의 결과 배열에 '0' 원소가 빠져 있는 이유이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1024&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HFdyk/btsO5DoKPBq/RFihakjTCDzfVkp2ygK481/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HFdyk/btsO5DoKPBq/RFihakjTCDzfVkp2ygK481/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HFdyk/btsO5DoKPBq/RFihakjTCDzfVkp2ygK481/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHFdyk%2FbtsO5DoKPBq%2FRFihakjTCDzfVkp2ygK481%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;719&quot; height=&quot;511&quot; data-origin-width=&quot;1024&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;&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;
&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>Javascript/Javascript</category>
      <category>filter</category>
      <category>javascript</category>
      <category>map</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/343</guid>
      <comments>https://developing-move.tistory.com/343#entry343comment</comments>
      <pubDate>Thu, 10 Jul 2025 09:00:44 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Number 메서드</title>
      <link>https://developing-move.tistory.com/342</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biKlSn/btsO531DMUx/whKtxEkQwM9bcsUefD7hV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biKlSn/btsO531DMUx/whKtxEkQwM9bcsUefD7hV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biKlSn/btsO531DMUx/whKtxEkQwM9bcsUefD7hV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiKlSn%2FbtsO531DMUx%2FwhKtxEkQwM9bcsUefD7hV1%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Number Contructor&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Number 객체는 Number() 생성자 함수를 통해 생성할 수 있다. 만일 인자가 숫자로 변한될 수 없다면 NaN을 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751814129502&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = new Number(123);
var y = new Number('123');
var z = new Number('str');

console.log(x); // 123
console.log(y); // 123
console.log(z); // NaN&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 일반적으로 숫자를 사용할 때에는 원시 타입 숫자를 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751814153271&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 123;
var y = new Number(123);

console.log(x == y);  // true
console.log(x === y); // false

console.log(typeof x); // number
console.log(typeof y); // object&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;new 연산자를 사용하여 객체를 생성할 때에는 매우 많은 추가 연산을 해야만 한다. 따라서 가능한 한 숫자 리터럴을 사용하여 수를 표현하고 Number 객체는 래퍼 객체로만 활용하는 것이 좋다.&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Number.EPSILON&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Number.EPSILON은 자바스크립트에서 표현할 수 있는 가장 작은 수로, 이는 임의의 수와 그 수보다 큰 수 중 가장 작은 수와의 차이와 같다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 부동 소수점 산술 연산 비교는 정확한 값을 기대하기 어려운데 정수는 2진법으로 오차 없이 저장이 가능하지만 부동소수점을 표현하는 데 가장 널리 쓰이는 표준인 IEEE754는 2진법으로 변환 시 무한 소수가 되어 미세한 오차가 발생할 수밖에 없는 구조적 한계를 갖기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 부동 소수점의 비교는 Number.EPSILON을 사용하여 비교 기능을 갖는 함수를 작성해야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751814571824&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(0.1 + 0.2);        // 0.30000000000000004
console.log(0.1 + 0.2 == 0.3); // false

function isEqual(a, b){
  // Math.abs는 절댓값을 반환한다.
  // 즉 a와 b의 차이가 JavaScript에서 표현할 수 있는 가장 작은 수인 Number.EPSILON보다 작으면 같은 수로 인정할 수 있다.
  return Math.abs(a - b) &amp;lt; Number.EPSILON;
}

console.log(isEqual(0.1 + 0.2, 0.3)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Number.MAX_VALUE&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 사용 가능한 가장 큰 숫자를 반환한다. MAX_VALUE보다 큰 숫자는 Infinity이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Number.MIN_VALUE&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 사용 가능한 가장 작은 숫자를 반환한다. MIN_VALUE는 0에 가장 가까운 양수 값으로 MIN_VALUE보다 작은 숫자는 0으로 변환된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;Number.POSITIVE_INFINITY&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;양의 무한대 Infinity를 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Number.NAGATIVE_INFINITY&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;음의 무한대 -Inifinity를 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;br /&gt;Number.NaN&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;숫자가 아님(Nat a Number)을 나타내는 숫자값이다. Number.NaN 프로퍼티는 window.NaN 프로퍼티와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1751814803474&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(Number('xyz')); // NaN
console.log(1 * 'string');  // NaN
console.log(typeof NaN);    // number&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;null, undefined, NaN, Infinity에 대한 비교&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 약간 비슷한 것 같으면서도 전혀 다른 4가지 값을 제공하고 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;null은 object 타입이며 아직 값이 정해지지 않은 것을 의미하는 값이다.&lt;/li&gt;
&lt;li&gt;undefined는 null과 달리 하나의 타입으로, 타입이 정해지지 않은 것을 의미하는 값이기도 하다.&lt;/li&gt;
&lt;li&gt;NaN은 number 타입으로 '숫자가 아님'을 의미하는 숫자이다.&lt;/li&gt;
&lt;li&gt;Infinity는 number 타입으로 '무한대'를 의미하는 숫자이다.&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;자바스크립트는 타입 검사가 매우 유연한 언어이다. 따라서 위의 값들 또한 문맥에 따라 다음과 같이 자동으로 타입 변환이 이루어진다.&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: 25%;&quot;&gt;값&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;Boolean 문맥&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;Number 문맥&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;String 문맥&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;null&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&quot;null&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;undefined&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;NaN&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&quot;undefined&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;NaN&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;false&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;NaN&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&quot;NaN&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;Infinity&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;true&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;Infinity&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&quot;Infinity&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Number Method&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.isFinite(number): boolean&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수에 전달된 값이 정상적인 유한수인지 검사하여 그 결과를 Boolean으로 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Number.isFinite()는 전역 함수 isFinite()와 차이가 있다. 전역 함수 isFinite()는 인수를 숫자로 변환하여 검사를 수행하지만 Number.isFinite()는 인수를 변환하지 않는다. 따라서 숫자가 아닌 인수가 주어졌을 때 반환값은 언제나 false가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1751815181961&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Number.isFinite(Infinity)  // false
Number.isFinite(NaN)       // false
Number.isFinite('Hello')   // false

Number.isFinite(0)         // true
Number.isFinite(2e64)      // true
Number.isFinite(null)      // false. isFinite(null) =&amp;gt; true&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.isInteger(number): boolean&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수에 전달된 값이 &lt;b&gt;정수(Integer)인지 검사&lt;/b&gt;하여 그 결과를 Boolean으로 반환한다. 검사 전에 인수를 숫자로 변환하지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1751815233208&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Number.isInteger(123)   //true
Number.isInteger(-123)  //true
Number.isInteger(5-2)   //true
Number.isInteger(0)     //true
Number.isInteger(0.5)   //false
Number.isInteger('123') //false
Number.isInteger(false) //false
Number.isInteger(Infinity)  //false
Number.isInteger(-Infinity) //false
Number.isInteger(0 / 0) //false&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.isNaN(number): boolean&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수에 전달된 값이 &lt;b&gt;NaN인지 검사&lt;/b&gt;하여 그 결과를 Boolean으로 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Number.isNaN()은 전역 함수 isNaN()과 차이가 있다. 전역 함수 isNaN()은 인수를 숫자로 변환하여 검사를 수행하지만 Number.isNaN은 인수를 변환하지 않는다. 따라서 숫자가 아닌 인수가 주어졌을 때 반환값은 언제나 false가 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751815329357&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Number.isNaN(NaN)       // true
Number.isNaN(undefined) // false. undefined &amp;rarr; NaN. isNaN(undefined) &amp;rarr; true.
Number.isNaN({})        // false. {} &amp;rarr; NaN.        isNaN({}) &amp;rarr; true.
Number.isNaN('blabla')  // false. 'blabla' &amp;rarr; NaN.  isNaN('blabla') &amp;rarr; true.

Number.isNaN(true)      // false
Number.isNaN(null)      // false
Number.isNaN(37)        // false
Number.isNaN('37');     // false
Number.isNaN('37.37');  // false
Number.isNaN('');       // false
Number.isNaN(' ');      // false
Number.isNaN(new Date())             // false
Number.isNaN(new Date().toString())  // false. String &amp;rarr; NaN. isNaN(String) &amp;rarr; true.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.isSafeInteger(number): boolean&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수에 전달된 값이 안전한(safe) 정수인지 검사하여 그 결과를 Boolean으로 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;안전한 정수 값은 -(2^53 - 1)과 2^53 - 1 사이의 정수 값이다. 검사 전에 인수를 숫자로 변환하지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1751815447250&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Number.isSafeInteger(123)   //true
Number.isSafeInteger(-123)  //true
Number.isSafeInteger(5-2)   //true
Number.isSafeInteger(0)     //true
Number.isSafeInteger(1000000000000000)  // true
Number.isSafeInteger(10000000000000001) // false
Number.isSafeInteger(0.5)   //false
Number.isSafeInteger('123') //false
Number.isSafeInteger(Infinity)  //false
Number.isSafeInteger(-Infinity) //false
Number.isSafeInteger(0 / 0) //false&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.prototype.toFixed(number): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수로 지정된 소숫점자리를 반올림하여 문자열로 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751815712927&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var numObj = 12345.6789;

// 소숫점 이하 반올림
numObj.toFixed();   // '12346'
// 소숫점 이하 1자리수 유효, 나머지 반올림
numObj.toFixed(1);  // '12345.7'
// 소숫점 이하 2자리수 유효, 나머지 반올림
numObj.toFixed(2);  // '12345.68'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.prototype.toPrecision(number): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수로 지정된 전체 자리수까지 유효하도록 나머지 자리수를 반올림하여 문자열로 반환한다. 지정된 전체 자리수로 표현할 수 없는 경우 지수 표기법으로 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751815795549&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var n = 123.112

n.toPrecision(3)  // &quot;123&quot;
n.toPrecision(4) // &quot;123.1&quot;
n.toPrecision(5) // &quot;123.11&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Number.prototype.toString(number): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751815824135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var count = 10;
count.toString();   // '10'
(17).toString();    // '17'
17 .toString();     // '17'
(17.2).toString();  // '17.2'

var x = 16;
x.toString(2);       // '10000'
x.toString(8);       // '20'
x.toString(16);      // '10'

(254).toString(16);  // 'fe'
(-10).toString(2);   // '-1010'
(-0xff).toString(2); // '-11111111'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;진법 표현&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 기본적으로 10진법을 사용하여 수를 표현한다. 따라서 아래의 예시처럼 산술 연산 시 모든 수가 10진수로 자동 변한되어 계산된다.&lt;/p&gt;
&lt;pre id=&quot;code_1751815958683&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 0xAB; // 16진법으로 표현된 10진수 171
var y = 29; // 10진법으로 표현된 10진수 29

x + y; // 두 수 모두 10진법으로 자동으로 변환되어 계산됨. -&amp;gt; 200&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;또한 숫자에 toString() 메서드를 사용하여 해당 숫자를 여러 진법의 형태로 변환할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1751816069279&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var num = 256;

num.toString(2); // 2진법으로 변환 : 100000000
num.toString(8); // 8진법으로 변환 : 400
num.toString(10); // 10진법으로 변환 : 256
num.toString(16); // 16진법으로 변환 : 100

// 2진수로 변환한 결괏값을 문자열로 반환함.
num.toString(2); // 100000000
// 문자열을 숫자로 나눴기 때문에 자동으로 10진수로 변환되어 산술 연산된 결괏값
(num.toString(2) / 2); // 50000000&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Number.prototype.valueOf(): number&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Number 객체의 &lt;b&gt;원시 타입 값을 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751816122988&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var numObj = new Number(10);
typeof numObj; // object

var num = numObj.valueOf();
num;           // 10
typeof num;    // number&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 225px;&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: 21px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 21px; text-align: center;&quot;&gt;&lt;b&gt;Method&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 21px; text-align: center;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.parseFloat()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;문자열을&amp;nbsp;파싱하여,&amp;nbsp;문자열에&amp;nbsp;포함된&amp;nbsp;숫자&amp;nbsp;부분을&amp;nbsp;실수&amp;nbsp;형태로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.parseInt()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;문자열을&amp;nbsp;파싱하여,&amp;nbsp;문자열에&amp;nbsp;포함된&amp;nbsp;숫자&amp;nbsp;부분을&amp;nbsp;정수&amp;nbsp;형태로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.isNaN()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;전달된&amp;nbsp;값이&amp;nbsp;NaN인지&amp;nbsp;아닌지를&amp;nbsp;검사함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.isFinite()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;전달된&amp;nbsp;값이&amp;nbsp;유한한&amp;nbsp;수인지&amp;nbsp;아닌지를&amp;nbsp;검사함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.isInteger()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;전달된&amp;nbsp;값이&amp;nbsp;정수인지&amp;nbsp;아닌지를&amp;nbsp;검사함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;Number.isSafeInteger()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;전달된&amp;nbsp;값이&amp;nbsp;안전한&amp;nbsp;정수(safe&amp;nbsp;integer)인지&amp;nbsp;아닌지를&amp;nbsp;검사함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;toExponential()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;Number&amp;nbsp;인스턴스를&amp;nbsp;지수&amp;nbsp;표기법으로&amp;nbsp;변환한&amp;nbsp;후,&amp;nbsp;그&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;toFixed()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;Number&amp;nbsp;인스턴스의&amp;nbsp;소수&amp;nbsp;부분&amp;nbsp;자릿수를&amp;nbsp;전달받은&amp;nbsp;값으로&amp;nbsp;고정한&amp;nbsp;후,&amp;nbsp;그&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;toPrecision()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;Number&amp;nbsp;인스턴스의&amp;nbsp;가수와&amp;nbsp;소수&amp;nbsp;부분의&amp;nbsp;합친&amp;nbsp;자릿수를&amp;nbsp;전달받은&amp;nbsp;값으로&amp;nbsp;고정한&amp;nbsp;후,&amp;nbsp;그&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;toString()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;Number&amp;nbsp;인스턴스의&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 24.6512%; height: 17px;&quot;&gt;&lt;b&gt;valueOf()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 75.3488%; height: 17px;&quot;&gt;Number&amp;nbsp;인스턴스가&amp;nbsp;가지고&amp;nbsp;있는&amp;nbsp;값을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>javascript</category>
      <category>js Number</category>
      <category>number 메서드</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/342</guid>
      <comments>https://developing-move.tistory.com/342#entry342comment</comments>
      <pubDate>Wed, 9 Jul 2025 09:00:41 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] String 메서드</title>
      <link>https://developing-move.tistory.com/341</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nD4gu/btsO6ZK0HRE/7YloO3FRLnnKDTtq9Kp4aK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nD4gu/btsO6ZK0HRE/7YloO3FRLnnKDTtq9Kp4aK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nD4gu/btsO6ZK0HRE/7YloO3FRLnnKDTtq9Kp4aK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnD4gu%2FbtsO6ZK0HRE%2F7YloO3FRLnnKDTtq9Kp4aK%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;String 객체는 원시 타입인 문자열을 다룰 때 유용한 프로퍼티와 메서드를 제공하는 wrapper 객체이다. 변수 또는 객체 프로퍼티가 문자열을 값으로 가지고 있다면 String 객체를 별도 생성하지 않고도 String 객체의 프로퍼티와 메서드를 사용할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;원시 타입인 String이 객체의 메서드를 사용할 수 있는 이유는 원시 타입으로 프로퍼티나 메서드를 호출할 때 원시 타입과 연관된 wrapper 객체로 일시적으로 변환되어 프로토타입 객체를 공유하게 되기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751813933959&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var str = &quot;문자열&quot;; // 리터럴 문자열 생성
var len = str.length; // 문자열 프로퍼티인 length 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 예시에서 생성한 문자열 리터럴 str은 객체가 아님에도 불구하고 length 프로퍼티를 사용할 수 있다. 프로그램이 문자열 리터럴 str의 프로퍼티를 참조하려고 하면 자바스크립트는 new String(str)을 호출한 것처럼 문자열 리터럴을 객체로 자동 변환해 주기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 임시 객체는 String 객체의 메서드를 상속 받아 프로퍼티를 참조하는 데 사용된다. 이후 프로퍼티의 참조가 끝나면 임시 객체는 자동으로 삭제된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 숫자, 문자열, bolean 등 &lt;b&gt;원시 타입의 프로퍼티에 접근하려고 할 때 생성되는 임시 객체를 wrapper 객체&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 글에서는 사용 빈도가 높은 String 객체의 프로퍼티와 메서드에 대해 살펴보도록 하자.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;String Property&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.length&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문자열 내의 문자 갯수를 반환&lt;/b&gt;한다. String 객체는 length 프로퍼티를 소유하고 있으므로 유사 배열 객체이다.&lt;/p&gt;
&lt;pre id=&quot;code_1751809789836&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str1 = 'Hello';
console.log(str1.length); // 5&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;String Method&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;String 객체의 모든 메서드는 &lt;u&gt;언제나 새로운 문자열을 반환&lt;/u&gt;한다.&lt;/b&gt; 문자열은 변경 불가능한(immutable) 원시 값이기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.charAt(number): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;인수로 전달한 index를 사용하여 index에 해당하는 위치의 문자를 반환한다. index의 범위는 0 ~ (문자열 길이 - 1) 사이의 정수이다. 지정한 index가 문자열의 범위를 벗어난 경우 빈 문자열을 반환한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eiVNJo/btsO60b4kOu/cdplefRUB9kTva3QaO4JE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eiVNJo/btsO60b4kOu/cdplefRUB9kTva3QaO4JE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eiVNJo/btsO60b4kOu/cdplefRUB9kTva3QaO4JE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeiVNJo%2FbtsO60b4kOu%2FcdplefRUB9kTva3QaO4JE0%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;379&quot; height=&quot;140&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1751810065622&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello';

console.log(str.charAt(0)); // H
console.log(str.charAt(1)); // e
console.log(str.charAt(2)); // l
console.log(str.charAt(3)); // l
console.log(str.charAt(4)); // o

// 지정한 index가 범위(0 ~ str.length-1)를 벗어난 경우 빈문자열을 반환.
console.log(str.charAt(5)); // ''

// 문자열 순회. 문자열은 length 프로퍼티를 가짐.
for (let i = 0; i &amp;lt; str.length; i++) {
  console.log(str.charAt(i));
}

// String 객체는 유사 배열 객체이므로 배열과 유사하게 접근할 수 있음.
for (let i = 0; i &amp;lt; str.length; i++) {
  console.log(str[i]); // str['0']
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.indexOf(searchstring, fromIndex): number&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인수로 전달한 문자 또는 문자열을 대상 문자열에서 검색하여 처음 발견된 곳의 index를 반환&lt;/b&gt;한다. &lt;b&gt;발견하지 못한 경우 -1을 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751810310168&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello World';

console.log(str.indexOf('l'));  // 2
console.log(str.indexOf('or')); // 7
console.log(str.indexOf('or' , 8)); // -1

if (str.indexOf('Hello') !== -1) {
  // 문자열 str에 'hello'가 포함되어 있는 경우에 처리할 내용
}

// ES6: String.prototype.includes
if (str.includes('Hello')) {
  // 문자열 str에 'hello'가 포함되어 있는 경우에 처리할 내용
}&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-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.lastIndexOf(searchstring, fromIndex): number&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;마지막으로 발견된 곳의 index를 반환&lt;/b&gt;한다. 발견하지 못할 경우 &lt;b&gt;-1&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;두 번째 인수(fromIndex)가 전달되면 검색 시작 위치를 fromIndex으로 이동하여 역방향으로 검색을 시작한다. 이때 검색 범위는 0 ~ fromIndex이며 반환 값은 indexOf 메서드와 동일하게 발견된 곳의 index이다.&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;1289&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOmfh6/btsO5Bq7qh2/9jLAfhN1xMKk7kqkILKg30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOmfh6/btsO5Bq7qh2/9jLAfhN1xMKk7kqkILKg30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOmfh6/btsO5Bq7qh2/9jLAfhN1xMKk7kqkILKg30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOmfh6%2FbtsO5Bq7qh2%2F9jLAfhN1xMKk7kqkILKg30%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;587&quot; height=&quot;170&quot; data-origin-width=&quot;1289&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1751810461817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello World';

console.log(str.lastIndexOf('World')); // 6
console.log(str.lastIndexOf('l'));     // 9
console.log(str.lastIndexOf('o', 5));  // 4
console.log(str.lastIndexOf('o', 8));  // 7
console.log(str.lastIndexOf('l', 10)); // 9

console.log(str.lastIndexOf('H', 0));  // 0
console.log(str.lastIndexOf('W', 5));  // -1
console.log(str.lastIndexOf('x', 8));  // -1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.replace(searchValue, replaceValue): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫 번째 인수로 전달한 문자열 또는 정규 표현식을 대상 문자열에서 검색하여 두 번째 인수로 전달한 문자열로 대체하여 결과가 반영된 새로운 문자열을 반환&lt;/b&gt;한다. 이때 원본 문자열은 변경되지 않는다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;검색 문자열(searchValue)이 여럿 존재할 경우 &lt;b&gt;첫 번째로 검색된 문자열만 대체&lt;/b&gt;된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;searchValue: 문자 또는 정규 표현식&lt;/li&gt;
&lt;li&gt;replaceValue: 문자 또는 콜백함수(searchValue를 인자로 받아 리턴 값으로 대체)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1751810806490&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello world';

// 첫번째로 검색된 문자열만 대체하여 새로운 문자열을 반환한다.
str.replace('world', 'Lee'); // Hello Lee

// 특수한 교체 패턴을 사용할 수 있다. ($&amp;amp; =&amp;gt; 검색된 문자열)
str.replace('world', '&amp;lt;strong&amp;gt;$&amp;amp;&amp;lt;/strong&amp;gt;'); // Hello &amp;lt;strong&amp;gt;world&amp;lt;/strong&amp;gt;

/* 정규표현식
g(Global): 문자열 내의 모든 패턴을 검색한다.
i(Ignore case): 대소문자를 구별하지 않고 검색한다.
*/
str.replace(/hello/gi, 'Lee'); // Lee world&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751811778424&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const camelCase = 'helloWorld';

// 두 번째 인수로 치환 함수를 전달할 수 있다.
// 특정 문자를 검색해 모두 대문자로 치환 하는 코드
// 문자를 찾아 인수로 match에 대입해 함수 실행
camelCase.replace(&quot;World&quot;, match =&amp;gt; match.toUpperCase()); // &quot;helloWORLD&quot;


// /.[A-Z]/g =&amp;gt; 1문자와 대문자의 조합을 문자열 전체에서 검색한다.
camelCase.replace(/.[A-Z]/g, function (match) {
  // match : oW =&amp;gt; match[0] : o, match[1] : W
  return match[0] + '_' + match[1].toLowerCase();
}); // hello_world


// /(.)([A-Z])/g =&amp;gt; 1문자와 대문자의 조합
// $1 =&amp;gt; (.)
// $2 =&amp;gt; ([A-Z])
camelCase.replace(/(.)([A-Z])/g, '$1_$2').toLowerCase(); // hello_world&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751811921471&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const snakeCase = 'hello_world';

// /_./g =&amp;gt; _와 1문자의 조합을 문자열 전체에서 검색한다.
snakeCase.replace(/_./g, function (match) {
  // match : _w =&amp;gt; match[1] : w
  return match[1].toUpperCase();
}); // helloWorld&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-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.split(seperator, limit): string[]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;첫 번째 인수로 전달한 문자열 또는 정규 표현식을 대상 문자열에서 검색하여 문자열을 구분한 뒤 분리된 각 문제열로 이루어진 배열을 반환&lt;/b&gt;한다. 이때 원본 문자열은 변경되지 않는다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;인수가 없는 경우 대상 문자열 전체를 단일 요소로 하는 배열을 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751812113541&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'How are you doing?';

// 공백으로 구분(단어로 구분)하여 배열로 반환.
console.log(str.split(' ')); // [ 'How', 'are', 'you', 'doing?' ]

// 각 문자를 모두 분리.
console.log(str.split('')); // [ 'H','o','w',' ','a','r','e',' ','y','o','u',' ','d','o','i','n','g','?' ]

// 정규 표현식
console.log(str.split(/\s/)); // [ 'How', 'are', 'you', 'doing?' ]

// 인수가 없는 경우, 대상 문자열 전체를 단일 요소로 하는 배열을 반환.
console.log(str.split()); // [ 'How are you doing?' ]

// 공백으로 구분하여 배열로 반환. 단 요소수는 3개까지만 허용.
console.log(str.split(' ', 3)); // [ 'How', 'are', 'you' ]

// 'o'으로 구분하여 배열로 반환.
console.log(str.split('o')); // [ 'H', 'w are y', 'u d', 'ing?' ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.substring(start, end): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 인수로 전달한 start 인덱스에 해당하는 문자부터 두 번째 인자에 전달된 end 인덱스에 해당하는 문자의 &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;1290&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z3ugu/btsO5LtrLm6/TuWgUPiNXyChkSEhKUWf7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z3ugu/btsO5LtrLm6/TuWgUPiNXyChkSEhKUWf7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z3ugu/btsO5LtrLm6/TuWgUPiNXyChkSEhKUWf7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz3ugu%2FbtsO5LtrLm6%2FTuWgUPiNXyChkSEhKUWf7k%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;556&quot; height=&quot;161&quot; data-origin-width=&quot;1290&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751812312277&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'Hello World'; // str.length == 11

str.substring(1, 4); // ell

// 첫 번째 인수 &amp;gt; 두번째 인수 : 순서 맞추기 위해 자동 교환된다.
str.substring(4, 1); // ell

// 두 번째 인수가 생략된 경우 : 해당 문자열의 끝까지 반환한다.
str.substring(4); // o World
str.substring(4,); // o World

// 인수 &amp;lt; 0 또는 NaN인 경우 : 0으로 취급된다.
str.substring(-2); // Hello World

// 인수 &amp;gt; 문자열의 길이(str.length) : 인수는 문자열의 길이(str.length)으로 취급된다.
str.substring(1, 12); // ello World
str.substring(11); // '' str[10] == 'd'
str.substring(20); // ''
str.substring(0, str.indexOf(' ')); // 'Hello'
str.substring(str.indexOf(' ') + 1, str.length); // 'World'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.slice(start, end): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;substring()과 동일하다. 단, slice()는 음수의 인수를 전달할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1751812359356&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'hello world';

// 인수 &amp;lt; 0 또는 NaN인 경우 : 0으로 취급된다.
str.substring(-5); // 'hello world'
// 뒤에서 5자리를 잘라내어 반환한다.
str.slice(-5); // 'world'

// 2번째부터 마지막 문자까지 잘라내어 반환
tr.substring(2); // llo world
str.slice(2); // llo world

// 0번째부터 5번째 이전 문자까지 잘라내어 반환
str.substring(0, 5); // hello
str.slice(0, 5); // hello&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-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.toLowerCase(): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;대상 문자열의 모든 문자를 &lt;b&gt;소문자로 변경&lt;/b&gt;한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.toUpperCase(): string&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;대문자로 변경&lt;/b&gt;한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.trim(): string&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;대상 문자열의 &lt;b&gt;양쪽 끝에 있는 공백 문자를 제거한 문자열을 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre id=&quot;code_1751812517127&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = '   foo  ';

console.log(str.trim()); // 'foo'

// String.prototype.replace
console.log(str.replace(/\s/g, ''));   // 'foo'
console.log(str.replace(/^\s+/g, '')); // 'foo  '
console.log(str.replace(/\s+$/g, '')); // '   foo'

// String.prototype.{trimStart,trimEnd} : Proposal stage 3
console.log(str.trimStart()); // 'foo  '
console.log(str.trimEnd());   // '   foo'&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-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.repeat(count): string&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;인수로 전달한 숫자만큼 반복해 연결한 새로운 문자열을 반환&lt;/b&gt;한다. count가 0이면 빈 문자열을 반환하고 음수면 RangeError를 발생시킨다.&lt;/p&gt;
&lt;pre id=&quot;code_1751812589679&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'abc'.repeat(0);   // ''
'abc'.repeat(1);   // 'abc'
'abc'.repeat(2);   // 'abcabc'
'abc'.repeat(2.5); // 'abcabc' (2.5 &amp;rarr; 2)
'abc'.repeat(-1);  // RangeError: Invalid count value&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.includes(searchString[, position]): boolean&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인수로 전달한 문자열이 포함되어 있는지를 검사하고 결과를 boolean 값으로 반환&lt;/b&gt;한다. 이때 두 번째 인수는 옵션으로 검색할 위치를 나타내는 정수이다(생략 시 기본 값으로 0이 사용된다).&lt;/p&gt;
&lt;pre id=&quot;code_1751812675883&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const str = 'hello world';

str.includes('hello'); // true
str.includes('hello', 0); // true
str.includes('hello', 2); // false

// String.prototype.indexOf 메소드로 대체할 수 있다.
str.indexOf('hello'); // 0&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;String.prototype.padStart(targetLength[, padString]) / padEnd(targetLength[, padString])&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;번째 인수로 전체 문자열 길이를 지정하고 현재 문자열의 길이가 인수보다 짧다면 나머지를 두 번째 인수 값으로 채운다&lt;/b&gt;. padStrart()의 경우 채워넣기는 대상 문자열의 시작(왼쪽)부터 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1751812987440&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'abc'.padStart(10);         // &quot;       abc&quot;
'abc'.padStart(10, &quot;foo&quot;);  // &quot;foofoofabc&quot;
'abc'.padStart(6,&quot;123465&quot;); // &quot;123abc&quot;
'abc'.padStart(8, &quot;0&quot;);     // &quot;00000abc&quot;
'abc'.padStart(1);          // &quot;abc&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;padEnd()는 우측부터 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1751813096706&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'abc'.padEnd(10);          // &quot;abc       &quot;
'abc'.padEnd(10, &quot;foo&quot;);   // &quot;abcfoofoof&quot;
'abc'.padEnd(6, &quot;123456&quot;); // &quot;abc123&quot;
'abc'.padEnd(1);           // &quot;abc&quot;&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-style=&quot;style3&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 471px;&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: 21px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt;Method&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; text-align: center; height: 21px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 21px;&quot;&gt;&lt;b&gt;String.fromCharCode()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 21px;&quot;&gt;쉼표로&amp;nbsp;구분되는&amp;nbsp;일련의&amp;nbsp;유니코드에&amp;nbsp;해당하는&amp;nbsp;문자들로&amp;nbsp;구성된&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 21px;&quot;&gt;&lt;b&gt;String.fromCodePoint()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 21px;&quot;&gt;쉼표로&amp;nbsp;구분되는&amp;nbsp;일련의&amp;nbsp;코드&amp;nbsp;포인트(code&amp;nbsp;point)에&amp;nbsp;해당하는&amp;nbsp;문자들로&amp;nbsp;구성된&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;String.raw()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;템플릿&amp;nbsp;문자열(template&amp;nbsp;string)의&amp;nbsp;원형을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;indexOf()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;특정&amp;nbsp;문자나&amp;nbsp;문자열이&amp;nbsp;처음으로&amp;nbsp;등장하는&amp;nbsp;위치의&amp;nbsp;인덱스를&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;lastIndexOf()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;특정&amp;nbsp;문자나&amp;nbsp;문자열이&amp;nbsp;마지막으로&amp;nbsp;등장하는&amp;nbsp;위치의&amp;nbsp;인덱스를&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;charAt()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;인덱스에&amp;nbsp;위치한&amp;nbsp;문자를&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;charCodeAt()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;인덱스에&amp;nbsp;위치한&amp;nbsp;문자의&amp;nbsp;UTF-16&amp;nbsp;코드를&amp;nbsp;반환함.&amp;nbsp;(0&amp;nbsp;~&amp;nbsp;65535)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;charPointAt()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;인덱스에&amp;nbsp;위치한&amp;nbsp;문자의&amp;nbsp;유니코드&amp;nbsp;코드&amp;nbsp;포인트(unicode&amp;nbsp;code&amp;nbsp;point)를&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;slice()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;시작&amp;nbsp;인덱스부터&amp;nbsp;종료&amp;nbsp;인덱스&amp;nbsp;바로&amp;nbsp;앞까지의&amp;nbsp;문자열을&amp;nbsp;추출한&amp;nbsp;새&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;substring()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;시작&amp;nbsp;인덱스부터&amp;nbsp;종료&amp;nbsp;인덱스&amp;nbsp;바로&amp;nbsp;앞까지의&amp;nbsp;문자열을&amp;nbsp;추출한&amp;nbsp;새&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;substr()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;전달받은&amp;nbsp;시작&amp;nbsp;인덱스부터&amp;nbsp;길이만큼의&amp;nbsp;문자열을&amp;nbsp;추출한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;split()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에서&amp;nbsp;구분자(separator)를&amp;nbsp;기준으로&amp;nbsp;나눈&amp;nbsp;후,&amp;nbsp;나뉜&amp;nbsp;문자열을&amp;nbsp;하나의&amp;nbsp;배열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;concat()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스에&amp;nbsp;전달받은&amp;nbsp;문자열을&amp;nbsp;결합한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;toUpperCase()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스의&amp;nbsp;모든&amp;nbsp;문자를&amp;nbsp;대문자로&amp;nbsp;변환한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;toLowerCase()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스의&amp;nbsp;모든&amp;nbsp;문자를&amp;nbsp;소문자로&amp;nbsp;변환한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;trim()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스의&amp;nbsp;양&amp;nbsp;끝에&amp;nbsp;존재하는&amp;nbsp;공백과&amp;nbsp;모든&amp;nbsp;줄&amp;nbsp;바꿈&amp;nbsp;문자(LF,&amp;nbsp;CR&amp;nbsp;등)를&amp;nbsp;제거한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;search()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;정규&amp;nbsp;표현식에&amp;nbsp;맞는&amp;nbsp;문자나&amp;nbsp;문자열이&amp;nbsp;처음으로&amp;nbsp;등장하는&amp;nbsp;위치의&amp;nbsp;인덱스를&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;replace()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;패턴에&amp;nbsp;맞는&amp;nbsp;문자열을&amp;nbsp;대체&amp;nbsp;문자열로&amp;nbsp;변환한&amp;nbsp;새&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;match()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;정규&amp;nbsp;표현식에&amp;nbsp;맞는&amp;nbsp;문자열을&amp;nbsp;찾아서&amp;nbsp;하나의&amp;nbsp;배열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;includes()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;문자나&amp;nbsp;문자열이&amp;nbsp;포함되어&amp;nbsp;있는지를&amp;nbsp;검사한&amp;nbsp;후&amp;nbsp;그&amp;nbsp;결과를&amp;nbsp;불리언&amp;nbsp;값으로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;startsWith()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;문자나&amp;nbsp;문자열로&amp;nbsp;시작되는지를&amp;nbsp;검사한&amp;nbsp;후&amp;nbsp;그&amp;nbsp;결과를&amp;nbsp;불리언&amp;nbsp;값으로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;endsWith()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;문자나&amp;nbsp;문자열로&amp;nbsp;끝나는지를&amp;nbsp;검사한&amp;nbsp;후&amp;nbsp;그&amp;nbsp;결과를&amp;nbsp;불리언&amp;nbsp;값으로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;toLocaleUpperCase()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;영문자뿐만&amp;nbsp;아니라&amp;nbsp;모든&amp;nbsp;언어의&amp;nbsp;문자를&amp;nbsp;대문자로&amp;nbsp;변환한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;toLocaleLowerCase()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;영문자뿐만&amp;nbsp;아니라&amp;nbsp;모든&amp;nbsp;언어의&amp;nbsp;문자를&amp;nbsp;소문자로&amp;nbsp;변환한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;localeCompare()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;인수로&amp;nbsp;전달받은&amp;nbsp;문자열과&amp;nbsp;정렬&amp;nbsp;순서로&amp;nbsp;비교하여&amp;nbsp;그&amp;nbsp;결과를&amp;nbsp;정수&amp;nbsp;값으로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;normalize()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;해당&amp;nbsp;문자열의&amp;nbsp;유니코드&amp;nbsp;표준화&amp;nbsp;양식(Unicode&amp;nbsp;Normalization&amp;nbsp;Form)을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;repeat()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%;&quot;&gt;해당&amp;nbsp;문자열을&amp;nbsp;인수로&amp;nbsp;전달받은&amp;nbsp;횟수만큼&amp;nbsp;반복하여&amp;nbsp;결합한&amp;nbsp;새로운&amp;nbsp;문자열을&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;toString()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스의&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 22.2093%; height: 17px;&quot;&gt;&lt;b&gt;valueOf()&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 77.7907%; height: 17px;&quot;&gt;String&amp;nbsp;인스턴스의&amp;nbsp;값을&amp;nbsp;문자열로&amp;nbsp;반환함.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>javascript</category>
      <category>js string</category>
      <category>string</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/341</guid>
      <comments>https://developing-move.tistory.com/341#entry341comment</comments>
      <pubDate>Mon, 7 Jul 2025 09:00:14 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 비동기 처리 - (3) async/await</title>
      <link>https://developing-move.tistory.com/340</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFIODh/btsOLzzNQMd/40PXNvkgGyKHkiE6CMVFr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFIODh/btsOLzzNQMd/40PXNvkgGyKHkiE6CMVFr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFIODh/btsOLzzNQMd/40PXNvkgGyKHkiE6CMVFr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFIODh%2FbtsOLzzNQMd%2F40PXNvkgGyKHkiE6CMVFr1%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;async/await에 대해 알아보기 전에 먼저 자바스크립트에서 Promise를 이용해 비동기 처리를 어떻게 해왔는지 간단히 살펴 보자.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 특정 게시물의 작성자 이름을 가져오는 함수는 다음과 같이 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750609695212&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function fetchAuthorName(postId) {
  return fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`)
    .then((response) =&amp;gt; response.json())
    .then((post) =&amp;gt; post.userId)
    .then((userId) =&amp;gt; {
      return fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
        .then((response) =&amp;gt; response.json())
        .then((user) =&amp;gt; user.name);
    });
}

fetchAuthorName(1).then((name) =&amp;gt; console.log(&quot;name:&quot;, name));

// 출력 결과
// name: Leanne Graham&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 함수는 fetch()를 이용해 게시물을 불러오고 그 안에서 userId를 추출한 다음 다시 해당 사용자의 정보를 요청해서 name을 반환하는 구조이다. 중간중간 필요한 데이터를 .then() 체이닝을 ㅌ통해 단계별로 받아 처리하고 있고 최종적으로 작성자의 이름을 얻을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 프로미스는 마치 리눅스의 파이프(|)처럼 이전 단계의 출력값을 다음 단계의 입력값으로 전달하면서 비동기 흐름을 구성한다. 결과적으로 fetchAuthorName() 함수는 작성자 이름을 비동기적으로 리턴하는 Promise 객체이므로 호출할 때도 .then()을 사용해 결과를 받아야 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise 방식의 한계&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 .then()을 계속 이어붙이는 방식은 복잡한 로직을 작성할수록 몇 가지 문제를 낳는다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;디버깅이 불편하다&lt;br /&gt;예를 들오 .then(user =&amp;gt; user1.name)처럼 오타가 나면 에러 메시지에 어떤 .then()에서 문제가 발생했는지 명확하게 드러나지 않아 추적이 어려울 수 있다. 특히 화살표 함수로 한 줄짜리 콜백을 작성한 경우 브레이크 포인트를 걸어도 디버거가 멈추지 않아 디버깅이 번거롭다.&lt;/li&gt;
&lt;li&gt;예외처리 흐름이 직관적이지 않다.&lt;br /&gt;Promise에서는 try/catch 대신 .catch()로 예외처리를 해야 한다. 이 자체는 문제가 되지 않지만 동기 코드와 비동기 코드가 섞여 있는 경우에는 예외처리가 끊기거나 누락되기 쉬워진다.&lt;/li&gt;
&lt;li&gt;가독성이 떨어진다&lt;br /&gt;단순한 작업일 때는 체이닝 구조가 괜찮지만 실제 프로젝트에서는 조건문, 반복문, 중첩 호출, 병렬 처리 등 다양한 로직이 섞이기 마련이다. 그러다 보면 .then()안에 또 .then()이 들어가는 식으로 들여쓰기가 깊어지고 결국 코드의 가독성이 급격히 나빠진다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이유들로 인해 자바스크립트에서는 더 읽기 쉬운 비동기 코드의 작성을 목적으로 async/await 문법이 도입되었다.&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;style3&quot; /&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; async/await 키워드를 이용한 비동기 처리 &lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 살펴본 것처럼 Promise를 활용하면 비동기 처리를 체계적으로 할 수 있지만 .then() 체이닝 방식은 디버깅이 불편하고 가독성이 떨어지며 예외 처리도 다소 번거로울 수 있다.&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;이러한 단점을 개선하기 위해 ES2017(ES8)에서는 async/await 키워드가 도입되었다. 이 문법을 사용하면 비동기 코드를 마치 동기 코드처럼 자연스럽게 작성할 수 있다.&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;위 예시를 async/await으로 바꿔 보면 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1750610108483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function fetchAuthorName(postId) {
  const postResponse = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );
  const post = await postResponse.json();
  const userId = post.userId;

  const userResponse = await fetch(
    `https://jsonplaceholder.typicode.com/users/${userId}`
  );
  const user = await userResponse.json();

  return user.name;
}

fetchAuthorName(1).then((name) =&amp;gt; console.log(&quot;name:&quot;, name));&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 앞에 async 키워드가 붙었다.&lt;/li&gt;
&lt;li&gt;모든 비동기 작업(fetch, json 파싱 등) 앞에 await 키워드가 붙었다.&lt;/li&gt;
&lt;li&gt;중첩된 .then() 없이 일반적인 동기 코드처럼 순서대로 코드를 작성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;await는 Promise가 완료될 때까지 기다린 뒤 그 결과를 변수에 담아 다음 라인으로 넘어간다. 덕분에 코드 흐름이 훨씬 직관적이고 읽기도 훨씬 편해졌다.&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;async 키워드가 붙은 함수는 자동으로 Promise 객체를 반환한다. 따라서 fetchAuthorName() 함수는 명시적으로 new Promise()를 사용하지는 않았지만 결과적으로는 프로미스를 반환하므로 호출 시 .then()을 통해 결과를 처리할 수도 있다. 그리고 만약 호출부토 async 함수라면 .then() 대신 await을 사용해서 바로 값을 받을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750610254035&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function printAuthorName(postId) {
  const name = await fetchAuthorName(postId);
  console.log(&quot;name:&quot;, name);
}

printAuthorName(1);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;async/await의 또 하나의 장점은 예외 처리를 try/catch 블록으로 동기 코드와 동일한 방식으로 할 수 있다는 점이다. .catch()로 따로 이어붙이지 않아도 되고 동기/비동기 코드가 섞여 있어도 일관된 방식으로 처리할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750610323811&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function fetchAuthorName(postId) {
  const postResponse = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );
  const post = await postResponse.json();
  const userId = post.userId;

  try {
    const userResponse = await fetch(
      `https://jsonplaceholder.typicode.com/users/${userId}`
    );
    const user = await userResponse.json();
    return user.name;
  } catch (err) {
    console.log(&quot;Failed to fetch user:&quot;, err);
    return &quot;Unknown&quot;;
  }
}

fetchAuthorName(1).then((name) =&amp;gt; console.log(&quot;name:&quot;, name));&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드에서는 사용자 정보를 가져오는 과정에서 문제가 생길 경우 &quot;Unknown&quot;이라는 기본 값을 반환하도록 처리했다. 이처럼 에러 발생 가능성이 있는 부분만 try/catch로 감싸면 되므로 코드 구조 또한 훨씬 깔끔해진다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;async/await은 자바스크립트에서 비동기 코드를 더 깔끔하고 직관적으로 만들 수 있는 강력한 도구이다. 특히 Promise 체이닝 방식의 한계로 인해 코드가 난잡해질 때 async/await을 도입하면 읽기 쉬우면서 일관된 예외처리, 편리한 디버깅이라는 세 마리 토끼를 한꺼번에 잡을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>async</category>
      <category>async await</category>
      <category>javascript</category>
      <category>js async</category>
      <category>js await</category>
      <category>js 비동기</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/340</guid>
      <comments>https://developing-move.tistory.com/340#entry340comment</comments>
      <pubDate>Thu, 3 Jul 2025 09:00:06 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 비동기 처리 - (2) Promise</title>
      <link>https://developing-move.tistory.com/339</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AiT4K/btsOLpqt91O/6MEjvSC0KyAUdesIcrApo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AiT4K/btsOLpqt91O/6MEjvSC0KyAUdesIcrApo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AiT4K/btsOLpqt91O/6MEjvSC0KyAUdesIcrApo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAiT4K%2FbtsOLpqt91O%2F6MEjvSC0KyAUdesIcrApo0%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;지난 포스팅에서 언급했던 비동기 처리의 콜백 함수는 엄연히 말하자면 비동기를 순차적으로 처리하기 위한 일종의 편법 같은 것이지 정식으로 지원하는 비동기 전용 함수가 아니다. 따라서 Promise 객체는 이러한 한계점을 극복하기 위해 비동기 처리를 위한 전용 객체로 탄생하게 되었다. Promise는 비동기 작업의 성공 또는 실패와 그 결과 값을 나타내는 객체로 비동기 작업을 쉽고 깔끔하게 연결할 수 있도록 해준다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;콜백 함수를 통한 비동기 처리의 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;ES6에 Promise가 도입되어 지금처럼 널리 사용되기 이전에는 아래와 같이 주로 콜백 함수를 다른 함수의 인자로 넘겨 비동기 처리해왔다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1750605164511&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;findUserAndCallBack(1, function (user) {
  console.log(&quot;user:&quot;, user);
});

function findUserAndCallBack(id, cb) {
  setTimeout(function () {
    console.log(&quot;waited 0.1 sec.&quot;);
    const user = {
      id: id,
      name: &quot;User&quot; + id,
      email: id + &quot;@test.com&quot;,
    };
    cb(user);
  }, 100);
}

// 결과
// waited 0.1 sec.
// user: {id: 1, name: &quot;User1&quot;, email: &quot;1@test.com&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;단순한 코드를 작성할 때에는 위와 같이 전통적인 방식으로 콜백 함수를 통해 비동기 처리를 해도 문제가 발생하지 않는다. 하지만 콜백 함수를 중첩하여 연쇄적으로 호출해야 하는 복잡한 코드의 경우 계속되는 들여쓰기 때문에 코드 가독성이 현저히 떨어지게 된다. 자바스크립트 개발자들 사이에서 소위 &lt;b&gt;콜백 지옥&lt;/b&gt;이라고 불리는 이 문제를 해결하기 위해 여러 방법들이 논의되었고 그 중 하나가 바로 &lt;b&gt;Promise&lt;/b&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise의 개념&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: justify;&quot;&gt;자바스크립트의 Promise는 처음 접하면 다소 낯설 수 있는 개념이다.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;많은 개발자들이 자바스크립트를 공부하는 과정에서 Promise 때문에 포기하게 된다. 그러니 우리는 조금 쉽게 이해해 보자. 우리의 일상 속에서 흔히 일어나는 '약속'이라는 개념으로 접근해 보면 이해하기 훨씬 쉬워진다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;여러분이 어린 아이라고 가정해 보자. 그리고 어느 날 아이스크림이 먹고 싶어졌다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&quot;엄마, 나 아이스크림 사줘!&quot;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 엄마는 바로 사주는 것이 아니라 이렇게 답한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&quot;조금만 이따가 사줄게.&quot;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;즉 지금 당장은 아무 일도 일어나지 않지만 &lt;u&gt;&lt;b&gt;나중에 어떤 결과가 생길 수 있다는 '약속'&lt;/b&gt;&lt;/u&gt;이 생긴 것이다. 자바스크립트에서 &lt;b&gt;Promise&lt;/b&gt;를 생성하는 상황 또한 이와 유사하다.&lt;/p&gt;
&lt;pre id=&quot;code_1750606448410&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const 아이스크림약속 = new Promise((resolve, reject) =&amp;gt; {
  // 엄마가 아이스크림을 사주면 resolve,
  // 못 사주면 reject
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;얼마 후 엄마가 진짜로 아이스크림을 사줬다면 이 약속은 이행된 것이다. Promise에서는 resolve()가 호출되는 상황이다. .then()은 약속이 지켜졌을 때 실행할 코드를 등록하는 메서드다. 즉 아이가 아이스크림을 받았을 때의 반응이라고 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750606563531&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const 아이스크림약속 = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; {
    resolve(&quot;아이스크림 맛있다!&quot;);
  }, 3000); // 3초 후에 결과 전달
});

아이스크림약속.then((결과) =&amp;gt; {
  console.log(결과); // &quot;아이스크림 맛있다!&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;반대로 엄마가 갑자기 바빠져서 아이스크림을 사주지 못했을 수도 있다. 이 경우는 약속이 지켜지지 않은 상황이며 Promise에서는 reject()가 호출된다. 실패한 경우에는 아래와 같이 .catch()를 사용해서 에러를 처리할 수 있다. 현실적으로는 아이가 실망하는 상황에 해당한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750606689715&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let 아이스크림약속 = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; {
    reject(&quot;미안해. 바빠서 못 샀어..&quot;);
  }, 3000);
});

아이스크림약속
  .then((결과) =&amp;gt; {
    console.log(결과);
  })
  .catch((에러) =&amp;gt; {
    console.log(에러); // &quot;미안해. 바빠서 못 샀어..&quot;
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;프로미스(Promise)는 지금 당장은 원하는 결과를 얻을 수 없지만 가까운 미래에 그 결과를 제공해 주겠다는 약속인 것&lt;/b&gt;이다. 그렇다면 왜 자바스크립트는 이러한 약속(Promise)라는 개념이 필요할까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트는 기본적으로 Non-blocking 코드를 지향하는 언어이다. 이는 어떤 작업을 실행할 때 그 결과가 나올 때까지 코드 실행을 기다리지 않고 다음 작업을 계속 진행한다는 뜻이다. 예를 들어 어떤 데이터를 서버에서 받아와야 하는 상황을 가정해 보자. 이 경우 네트워크를 통해 요청하고 서버가 응답을 줄 때까지 기다려야 한다. 파일을 읽거나 데이터베이스에 접근하는 경우도 마찬가지다. 이들 모두 시간이 걸리는 작업인데 그 시간은 사람에게는 잠깐일지 몰라도 컴퓨터, 특히 CPU에서 실행되는 코드 입장에서는 엄청나게 긴 지연 시간(delay)으로 느껴진다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약 이런 작업이 끝날 때까지 자바스크립트가 모든 동작을 멈추고 기다린다면 어떤 문제가 발생할까? 사용자는 웹 페이지가 멈춘 것처럼 느낄 수 있고 다른 작업은 아무것도 진행되지 않으며 전체 앱의 반응성이 떨어지게 된다. 그래서 자바스크립트는 이러한 작업들을 비동기 방식으로 처리한다. 즉 데이터를 요청해 놓고 기다리는 동안 다른 코드를 ㅁ너저 실행하고 나중에 결과가 준비되면 그때 다시 처리하는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 나중에 결과가 생기는 작업을 처리하려면 뭔가 체계적인 방법이 필요하다. 처음에는 콜백 함수를 사용해서 처리했지만 위에서 언급한 것과 같이 코드가 복잡해지고 가독성이 떨어지는 문제가 생긴 것이다. 이를 해결하기 위해 등장한 것이 바로 Promise이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위에서 봤던 예시는 Promise를 이용해 아래와 같이 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750607651024&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;findUser(1).then(function (user) {
  console.log(&quot;user:&quot;, user);
});

function findUser(id) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      console.log(&quot;waited 0.1 sec.&quot;);
      const user = {
        id: id,
        name: &quot;User&quot; + id,
        email: id + &quot;@test.com&quot;,
      };
      resolve(user);
    }, 100);
  });
}

// 결과
// waited 0.1 sec.
// user: {id: 1, name: &quot;User1&quot;, email: &quot;1@test.com&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드는 콜백 함수를 인자로 넘기는 대신 Promise 객체를 생성하여 반환하였고 호출부에서는 리턴 받은 Promise 객체에 then()을 호출하여 결과 값을 가지고 실행할 로직을 넘겨주고 있다. 콜백 함수를 통해 비동기를 처리하던 기존 코드와의 가장 큰 차이점은 함수를 호출하면 Promise 타입의 결과 값이 리턴되고 이 결과 값을 가지고 다음에 수행할 작업을 진행한다는 것이다. 따라서 기존 방식보다 비동기 처리 코드임에도 불구하고 마치 동기 방식의 처리 코드처럼 읽히기 때문에 가독성 면에서 직관적으로 느껴질 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise 생성 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 자바스크립트에서 직접 Promise 객체를 만드는 방법에 대해 알아보자.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Promise는 new 키워드를 사용해 객체처럼 만들 수 있다. 이때 생성자에는 함수 하나를 인자로 전달해야 하고, 이 함수는 두 개의 파라미터 resolve와 reject를 갖는다.&lt;/p&gt;
&lt;pre id=&quot;code_1750607857463&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(function(resolve, reject) {
  // 작업 수행 후 성공하면 resolve(), 실패하면 reject()
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 구조는 사실상 어떠한 비동기 작업을 시도하고 성공하거나 실패하면 알려주겠다는 약속을 만드는 것이다. 실제로는 위처럼 변수에 담아서 쓰기보다는 함수의 반환 값으로 Promise를 만들어 return하는 방식이 더 일반적이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;화살표 함수를 사용하면 아래와 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750607941521&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function returnPromise() {
  return new Promise((resolve, reject) =&amp;gt; {
    // 어떤 비동기 작업...
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 함수 안에서는 상황에 따라 resolve() 또는 reject()를 호출해야 한다. 보통 resolve()에는 나중에 얻게 될 성공 결과 값을 넘기고, reject()에는 실패했을 때 넘길 에러 정보를 담는다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Promise를 직접 만들어 보기 위해 간단한 나눗셈 함수를 예시로 들어보자(실제로 나눗셈을 비동기로 작업할 필요는 없지만 이해하기 쉽도록).&lt;/p&gt;
&lt;pre id=&quot;code_1750608040691&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function devide(numA, numB) {
  return new Promise((resolve, reject) =&amp;gt; {
    if (numB === 0) {
      reject(new Error(&quot;0으로는 나눌 수 없습니다.&quot;));
    } else {
      resolve(numA / numB);
    }
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 함수는 두 숫자를 받아 나눗셈을 시도하고 정상적인 경우 결과 값을 resolve()로 넘기고 나눗셈이 불가능한 경우(0으로 나누는 경우)는 reject()로 에러를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750608129390&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 정상적인 인자일 때
devide(8, 2)
  .then((result) =&amp;gt; console.log(&quot;성공:&quot;, result))
  .catch((error) =&amp;gt; console.log(&quot;실패:&quot;, error));

// 결과
// 성공: 4


// 비정상적인 인자일 때
devide(8, 0)
  .then((result) =&amp;gt; console.log(&quot;성공:&quot;, result))
  .catch((error) =&amp;gt; console.log(&quot;실패:&quot;, error));
  
// 결과
// 실패: Error: 0으로는 나눌 수 없습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 결과를 보면 나눗셈이 성공했을 땐 .then()이 실행되고 실패했을 땐 .catch()가 실행된다는 걸 확인할 수 있다. 즉 Promise는 비동기 작업이 끝난 뒤 어떤 일이 일어났는지에 따라 적절한 처리를 할 수 있도록 .then과 .catch() 메서드를 제공한다는 것을 알 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise 사용 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;실제 개발을 하다 보면 우리가 직접 new Promise()를 사용해 Promise 객체를 생성하는 경우는 그리 많지 않다. 대부분의 경우는 이미 Promise를 반환하도록 만들어진 라이브러리 함수나 브라우저 내장 함수를 활용하게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 예로 브라우저 환경에서 API 호출을 할 때 사용하는 fetch() 함수가 있다. 이 함수는 URL을 인자로 받아 네트워크 요청을 보내고 미래 시점에 얻게 될 그 결과를 Promise 객체로 리턴해 준다. 즉 지금은 결과가 없지만 나중에 응답이 도착하면 알려주겠다는 약속을 만들어 주는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1750608466533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;)
  .then((response) =&amp;gt; console.log(&quot;response:&quot;, response))
  .catch((error) =&amp;gt; console.log(&quot;error:&quot;, error));
  
// 결과
// response: Response {type: &quot;cors&quot;, url: &quot;https://jsonplaceholder.typicode.com/posts/1&quot;, redirected: false, status: 200, ok: true, &amp;hellip;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위의 경우 fetch 함수가 리턴한 Promise는 정상적으로 응답을 받아오면서 resolve() 상태가 되고 .then()에 넘겨준 콜백 함수가 호출된다. 실제로 콘솔에는 HTTP 응답 객체가 출력될 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 만약 fetch 함수에 잘못된 인자를 넘기면 어떻게 될까? 예를 들어 인자를 아예 넘기지 않는다면?&lt;/p&gt;
&lt;pre id=&quot;code_1750608570782&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch()
  .then((response) =&amp;gt; console.log(&quot;response:&quot;, response))
  .catch((error) =&amp;gt; console.log(&quot;error:&quot;, error));
  
// 결과
// error: TypeError: Failed to execute 'fetch' on 'Window': 1 argument required, but only 0 present.
//     at main-sha512-G7qgGx8Wefk5JskAfRw2DfBPNPQTxDC23DcZ+KQTmNoSr2S6pZ3IJgYs1ThvLvvH7uI_KhycDx_FIDNlu5KhOw==.bundle.js:9070
//     at &amp;lt;anonymous&amp;gt;:1:1&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이 경우에는 fetch()가 실행되자마자 내부적으로 오류가 발생하고 Promise는 reject() 상태가 되며 .catch()에 넘긴 콜백 함수가 실행된다. 콘솔에는 argument required와 같은 에러 메시지가 출력된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 프로미스를 사용하는 구조에서 .then()에는 작업이 성공했을 때 실행할 코드를, .catch()에는 실패하거나 예외가 발생했을 때 실행할 코드를 각각 등록할 수 있다. 결과적으로 then-catch 구조는 동기 처리에서 사용하던 try-catch 블록과 유사한 형태로 비동기 상황에서도 정상 흐름과 에러 처리를 분리해서 깔끔하게 코드 구조를 유지할 수 있도록 도와준다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise의 메서드 체이닝(Method Chaining)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 소개했던 .then()이나 .catch() 메서드는 단순히 결과를 처리하는 것에서 끝나지 않는다. 이 메서드들은 새로운 Promise 객체를 리턴하기 때문에 사슬처럼 이어 붙이면서 연쇄적으로 호출할 수 있다. 이러한 방식을 흔히 메서드 체이닝(Method Chaining)이라고 부른다. 즉 하나의 작업이 끝나고 그 결과를 바탕으로 또 다른 작업을 이어나가는 흐름을 콜백 중첩 없이 자연스럽게 구성할 수 있는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;기존에 사용했던 fetch() 예제를 다시 가져와 보자. 기본적으로 fetch() 함수는 네트워크 응답 전체(Response 객체)를 반환하는데 우리가 자주 사용하는 본문 내용(JSON)을 얻기 위해서는 response.json()을 호출해 줘야 한다. 이 또한 비동기 작업이기 때문에 또 다시 .then()으로 이어받아야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750608992459&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;)
  .then((response) =&amp;gt; response.json())
  .then((post) =&amp;gt; console.log(&quot;post:&quot;, post))
  .catch((error) =&amp;gt; console.log(&quot;error:&quot;, error));

// 결과
// post: {userId: 1, id: 1, title: &quot;sunt aut facere repellat provident occaecati excepturi optio reprehenderit&quot;, body: &quot;quia et suscipit&amp;crarr;suscipit recusandae consequuntur &amp;hellip;strum rerum est autem sunt rem eveniet architecto&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 .then()은 응답을 JSON으로 파싱하는 작업을 하고 두 번째 .then()은 그 파싱된 데이터를 받아소 콘솔에 출력한다. 어떤 단계에서든 문제가 발생하면 .catch()가 실행되어 에러 처리를 담당한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 이번에는 좀 더 복잡한 작업을 연결해 보자. 앞선 예시에서 사용자의 ID를 가져와 해당 사용자의 상세 정보를 추가로 요청하는 흐름이다.&lt;/p&gt;
&lt;pre id=&quot;code_1750609157535&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;)
  .then((response) =&amp;gt; response.json()) // 게시글 데이터를 JSON으로 변환
  .then((post) =&amp;gt; post.userId)         // userId만 추출
  .then((userId) =&amp;gt; &quot;https://jsonplaceholder.typicode.com/users/&quot; + userId) // 사용자 API URL 생성
  .then((url) =&amp;gt; fetch(url))           // 해당 URL로 다시 fetch 요청
  .then((response) =&amp;gt; response.json()) // 응답을 다시 JSON으로 파싱
  .then((user) =&amp;gt; console.log(&quot;user:&quot;, user)) // 사용자 정보 출력
  .catch((error) =&amp;gt; console.log(&quot;error:&quot;, error));

// 결과
// user: {id: 1, name: &quot;Leanne Graham&quot;, username: &quot;Bret&quot;, email: &quot;Sincere@april.biz&quot;, address: {&amp;hellip;}, &amp;hellip;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 여러 개의 .then()을 이어붙이면 복잡한 비동기 로직도 동기 코드처럼 읽기 쉬운 구조로 만들 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 여기에 한 가지 중요한 포인트가 있다. .then()이나 .catch()에 넘긴 콜백 함수 안에서 Promise 객체를 리턴하든 일반 값을 리턴하든 다음 .then()에서는 항상 그 값을 받을 수 있는 Promise 객체가 자동으로 생성된다는 점이다. 그러므로 아래 두 예시는 모두 유효하다.&lt;/p&gt;
&lt;pre id=&quot;code_1750609282191&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.then(() =&amp;gt; {
  return 42; // 일반 값
})


.then(() =&amp;gt; {
  return fetch(url); // Promise 객체
})&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 자바스크립트의 Promise 체이닝은 내부적으로 굉장히 유연하게 동작하기 때문에 단계별로 값을 가공하거나 새로운 비동기 작업을 이어붙이는 작업을 자연스럽게 처리할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;정리하면 .then()이나 .catch()는 단순히 결과를 처리하는 메서드가 아니라 비동기 작업을 단계적으로 이어서 구성할 수 있도록 도와주는 핵심 기능이라고 할 수 있다. 이러한 체이닝 구조를 이해하고 활용하면 복잡한 비동기 로직도 훨씬 깔끔하게 작성할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Promise를 사용하면서 자연스럽게 발생하는 이러한 코딩 스타일은 정말 흔히 볼 수 있으며 자바스크립트 개발자들 사이에서도 호불호가 갈리기도 한다. 따라서 최근에는 이러한 Promise를 이용해 메서드 체이닝하는 코딩 스타일은 async/await 키워드를 사용하는 방식으로 대체되는 추세이다. 다음 포스팅에서는 async/await을 사용해 어떻게 자바스크립트 비동기 처리 코드를 개선할 수 있는지 알아보려 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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>Javascript/Javascript</category>
      <category>catch</category>
      <category>javascript</category>
      <category>js async</category>
      <category>js promise</category>
      <category>js 비동기</category>
      <category>promise</category>
      <category>Then</category>
      <category>프로미스</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/339</guid>
      <comments>https://developing-move.tistory.com/339#entry339comment</comments>
      <pubDate>Wed, 2 Jul 2025 09:00:02 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 비동기 처리 - (1) 콜백 함수</title>
      <link>https://developing-move.tistory.com/338</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuTuro/btsONyTI4GC/YVdlQfjVCV2Dfzi9yEIlKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuTuro/btsONyTI4GC/YVdlQfjVCV2Dfzi9yEIlKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuTuro/btsONyTI4GC/YVdlQfjVCV2Dfzi9yEIlKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuTuro%2FbtsONyTI4GC%2FYVdlQfjVCV2Dfzi9yEIlKK%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 콜백 함수&lt;/b&gt;는 흔히 비동기를 다룰 때 자주 엮여 등장하는 개념이다. 콜백 함수는 자바스크립트의 일급 객체 특성을 이용해 함수의 매개변수에 함수 자체를 넘겨 함수 내에서 매개변수 함수를 실행하는 기법을 말한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자세한 내용은 아래 포스팅 참조&lt;/p&gt;
&lt;figure id=&quot;og_1750603946647&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Javascript] 콜백 함수&quot; data-og-description=&quot;콜백(Callback) 함수. 간단히 말하면 파라미터로 함수 객체를 전달해서 호출 함수 내에서 파라미터로 전달된 함수를 실행하는 것을 말한다.예를 들어 아래 코드와 같이 sayHello() 함수를 호출할때 파&quot; data-og-host=&quot;developing-move.tistory.com&quot; data-og-source-url=&quot;https://developing-move.tistory.com/270&quot; data-og-url=&quot;https://developing-move.tistory.com/270&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cmBT1i/hyY76t8Lu8/OORqok1zVrlgmqbxdZfaZ1/img.png?width=266&amp;amp;height=330&amp;amp;face=0_0_266_330,https://scrap.kakaocdn.net/dn/bIvEP2/hyZbvy2ZI3/01Qt7HsD8aVGDOZmZudd40/img.png?width=266&amp;amp;height=330&amp;amp;face=0_0_266_330,https://scrap.kakaocdn.net/dn/rgv8g/hyY8VF3DWa/KSWpIPQM9tSItuvu6xgn7K/img.jpg?width=1170&amp;amp;height=749&amp;amp;face=0_0_1170_749&quot;&gt;&lt;a href=&quot;https://developing-move.tistory.com/270&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developing-move.tistory.com/270&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cmBT1i/hyY76t8Lu8/OORqok1zVrlgmqbxdZfaZ1/img.png?width=266&amp;amp;height=330&amp;amp;face=0_0_266_330,https://scrap.kakaocdn.net/dn/bIvEP2/hyZbvy2ZI3/01Qt7HsD8aVGDOZmZudd40/img.png?width=266&amp;amp;height=330&amp;amp;face=0_0_266_330,https://scrap.kakaocdn.net/dn/rgv8g/hyY8VF3DWa/KSWpIPQM9tSItuvu6xgn7K/img.jpg?width=1170&amp;amp;height=749&amp;amp;face=0_0_1170_749');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Javascript] 콜백 함수&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;콜백(Callback) 함수. 간단히 말하면 파라미터로 함수 객체를 전달해서 호출 함수 내에서 파라미터로 전달된 함수를 실행하는 것을 말한다.예를 들어 아래 코드와 같이 sayHello() 함수를 호출할때 파&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developing-move.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;콜백 함수&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 사용자 ID를 파라미터로 받아 DB나 API 연동 없이 임의의 사용자 객체를 반환하는 함수를 만들어 보는 것으로 시작하려 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750602331302&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findUser(id) {
  const user = {
    id: id,
    name: &quot;User&quot; + id,
    email: id + &quot;@test.com&quot;,
  };
  return user;
}

const user = findUser(1);
console.log(&quot;user:&quot;, user); // user: {id: 1, name: &quot;User1&quot;, email: &quot;1@test.com&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 우리가 흔히 생각하는 일반적인 함수란 입력(파라미터)이 있고 출력(리턴 값)이 있다. 하지만 자바스크립트에서는 출력값이 없고 그 대신 콜백 함수를 입력 받는 함수들이 있다. 콜백 함수는 다른 함수에 인자로 넘겨 실행될 로직을 담게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들면 위 코드는 아래와 같이 다른 방식으로 동일한 결과를 출력하도록 재작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1750602406353&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findUserAndCallBack(id, cb) {
  const user = {
    id: id,
    name: &quot;User&quot; + id,
    email: id + &quot;@test.com&quot;,
  };
  cb(user);
}

findUserAndCallBack(1, function (user) {
  console.log(&quot;user:&quot;, user); // user: {id: 1, name: &quot;User1&quot;, email: &quot;1@test.com&quot;}
});&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUserAndCallBack()&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b2e46; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수의 호출부를 보면 두 번째 인자로 콜백 함수를 선언하여 넘긴 것을 볼 수 있다. 따라서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUserAndCallBack()&lt;/span&gt; 함수가 실행될 때 매개변수 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;cb&lt;/span&gt;는 콜백 함수를 할당 받으며 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;cb(user)&lt;/span&gt;가 실행될 때 이 콜백함수가 실행되는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b2e46; text-align: start;&quot;&gt;위 두 코드의 차이점은 첫 번째 예시의&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUser()&lt;/span&gt;는 결과 값을 리턴하고 함수 외부에서 그 값을 이용해 작업을 수행하는 반면, 두 번째 예시의 &lt;span style=&quot;background-color: #ffffff; color: #1b2e46; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUserAndCallBack()&lt;/span&gt;는 결과 값을 이용해서 해야 할 작업까지 함수 내부에서 수행해 주기 때문에 결과 값을 굳이 리턴할 필요가 없다는 것이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b2e46;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;콜백 함수를 이용한 비동기 처리&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 함수&lt;/b&gt;란 쉽게 말해서 &lt;u&gt;&lt;b&gt;호출부에서 실행 결과를 기다리지 않아도 되는 함수&lt;/b&gt;&lt;/u&gt;이다. 비동기 함수의 이러한 Non-blocking 이점 덕분에 &lt;b&gt;싱글 스레드 환경에서 실행되는 언어에서 광범위하게 사용&lt;/b&gt;된다. 예를 들어 브라우저에서 어떠한 로직이 비동기 함수만으로 실행될 경우 기다리는 시간이 길어진다면 사용자 경험에 부정적인 영향을 미치게 될 것이다. 또한 비동기 방식을 사용하면 로직을 순차적으로 처리할 필요가 없기 때문에 동시 처리에서도 동기 방식 대비 유리한 것으로 알려져 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 개발자 입장에서 비동기 방식은 동기 방식에 비해 덜 직관적으로 느껴질 수 있다. 동기 방식과 같이 순차적 처리가 보장되지 않기 때문에 아래에 위치한 코드가 위에 있는 코드보다 먼저 실행될 수 있기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에는 &lt;b&gt;setTimeout()&lt;/b&gt;이라는 내장 비동기 함수가 있다. setTimeout()은 두 개의 매개변수를 받는데 첫 번째는 실행할 작업 내용을 담은 콜백 함수이고 두 번째는 이 콜백 함수를 수행하기 전에 기다리는 밀리세컨드 단위의 시간이다. 즉 setTimeOut()은 두 번째 파라미터로 들어온 시간만큼 기다린 후에 첫 번째 파라미터로 들어온 콜백 함수를 실행하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1750603109794&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(&quot;2초 후에 실행됨&quot;), 2000);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;실제 프로젝트에서 DB나 API를 통해서 유저 데이터를 얻어오는 경우 필연적으로 이러한 지연이 발생하게 된다. 이러한 상황을 시뮬레이션하기 위해 setTimeout을 이용해 위에서 예로 들었던 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUser()&lt;/span&gt; 함수를 수정한 결과이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1750603243119&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findUser(id) {
  let user;
  setTimeout(function () {
    console.log(&quot;waited 0.1 sec.&quot;);
    user = {
      id: id,
      name: &quot;User&quot; + id,
      email: id + &quot;@test.com&quot;,
    };
  }, 100);
  return user;
}

const user = findUser(1);
console.log(&quot;user:&quot;, user); 

// 실행 결과
// user: undefined
// waited 0.1 sec.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드를 실행해 보면 예상치 못한 순서로 코드가 실행되는 것을 알 수 있다. 세 번째 라인의 setTimeout()은 비동기 함수의 호출이기 때문에 실행이 완료될 때까지 기다리지 않고 다음 라인인 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;return user&lt;/span&gt;로 넘어가버린다. 따라서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUser(1)&lt;/span&gt;은 undefined를 리턴하게 되고 user 변수에는 그대로 undefined가 할당되는 것이다.&amp;nbsp; 그리고 0.1초 후 setTimeout()의 콜백함수가 실행되면서 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;waited 0.1 sec&lt;/span&gt;가 출력되고 user에는 원하는 객체가 할당되었지만 이미 때는 늦어버리게 되었다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이와 같이 비동기 함수를 호출하게 되면 함수의 실행이 완료도 되기 전에 다음 라인이 실행되어버리기 때문에 각별한 주의가 필요하다. 그러나&amp;nbsp;코드 실행 순서가 뒤섞일 수 있는 난처한 상황에서는 콜백 함수를 이용해 해결할 수 있다. 함수로부터 결과 값을 리턴 받기를 포기하고 결과 값을 이용해 처리할 로직을 콜백 함수에 담아 인자로 던지면 되는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1750603552849&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findUserAndCallBack(id, cb) {
  setTimeout(function () {
    console.log(&quot;waited 0.1 sec.&quot;);
    const user = {
      id: id,
      name: &quot;User&quot; + id,
      email: id + &quot;@test.com&quot;,
    };
    cb(user);
  }, 100);
}

findUserAndCallBack(1, function (user) {
  console.log(&quot;user:&quot;, user);
});

// 결과
// waited 0.1 sec.
// user: {id: 1, name: &quot;User1&quot;, email: &quot;1@test.com&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;findUserAndCallBack()&lt;/span&gt;의 두 번째 인자로 결과 값을 이용해 실행될 로직을 넘겼고 setTimeout()은 0.1초 후에 이 함수를 호출하였다. 이처럼 비동기 함수를 호출할 때에는 결과 값을 통해 처리할 로직을 콜백 함수로 넘겨야 예상된 결과를 얻을 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 자바스크립트 프로젝트가 점점 더 복잡해지면서 최근에는 콜백 함수를 인자로 넘겨서 비동기 처리를 하는 스타일을 피하는 추세이다. 콜백 함수를 중첨해서 사용하게 되면 계속해서 코드를 들여쓰기해야 하고 그럴수록 코드 가족성이 현저히 떨어지게 되기 때문이다. 결국 많은 개발자들이 콜백 지옥이라 불리는 끔찍한 상황을 겪게 되었고 Promise나 async/await을 이용하는 방법들로 대체되고 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>async</category>
      <category>Callback</category>
      <category>setTimeout</category>
      <category>비동기 콜백</category>
      <category>자바스크립트</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/338</guid>
      <comments>https://developing-move.tistory.com/338#entry338comment</comments>
      <pubDate>Tue, 1 Jul 2025 09:00:29 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 비동기의 특징</title>
      <link>https://developing-move.tistory.com/336</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GF1ps/btsOChSLOf6/T7LBAqZHmy4TXDowfL6vzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GF1ps/btsOChSLOf6/T7LBAqZHmy4TXDowfL6vzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GF1ps/btsOChSLOf6/T7LBAqZHmy4TXDowfL6vzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGF1ps%2FbtsOChSLOf6%2FT7LBAqZHmy4TXDowfL6vzk%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자바스크립트의 동기와 비동기&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트는 싱글 스레드 언어이기 땜누에 한 번에 하나의 작업만 수행할 수 있다. 즉 이전 작업이 완료되어야 다음 작업을 수행할 수 있게 된다는 얘기다. 우리가 프로그래밍을 하면서 일반적으로 각 함수와 코드들이 위에서 아래로 차례대로 동작하는 방식이라고 할 수 있다. 이러한 &lt;u&gt;&lt;b&gt;코드의 순차 실행&lt;/b&gt;&lt;/u&gt;을 &lt;b&gt;동기(Synchronous)&lt;/b&gt;라고 부른다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;714&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7bc4q/btsOCl11XEe/FgYLfHL1mQ7UKNMhg4pqck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7bc4q/btsOCl11XEe/FgYLfHL1mQ7UKNMhg4pqck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7bc4q/btsOCl11XEe/FgYLfHL1mQ7UKNMhg4pqck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7bc4q%2FbtsOCl11XEe%2FFgYLfHL1mQ7UKNMhg4pqck%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;474&quot; height=&quot;382&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 자바스크립트는 여러 작업을 동시에 처리하기 위해 &lt;b&gt;비동기(Asynchronous)&lt;/b&gt;라는 개념을 도입하여, 특정 작업의 완료를 기다리지 않고 다른 작업을 동시에 수행할 수 있도록 하였다. 자바스크립트를 공부하다 보면 setTimeout()이나 fetch() 함수를 접해봤을 것이고, 이들이 비동기로 동작한다는 말을 한 번쯤은 들어봤을 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;비동기는 메인 스레드가 작업을 다른 곳에 인가하여 처리하게 되고, 그 작업이 완료되면 콜백 함수를 받아 실행하는 방식으로 쉽게 말해 백그라운드에 요청하여 처리되도록 하여 &lt;u&gt;&lt;b&gt;멀티로 동시에 작업을 처리하는 것&lt;/b&gt;&lt;/u&gt;으로 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGCKMd/btsOAIxr9BD/hDKiXdBMV9GDUIGJ2xcVmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGCKMd/btsOAIxr9BD/hDKiXdBMV9GDUIGJ2xcVmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGCKMd/btsOAIxr9BD/hDKiXdBMV9GDUIGJ2xcVmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGCKMd%2FbtsOAIxr9BD%2FhDKiXdBMV9GDUIGJ2xcVmK%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;363&quot; height=&quot;481&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;서버에 데이터를 요청하고 응답을 받아야 하는 작업이 있다면 응답이 오는 것과 관계 없이 다른 작업을 계속 이어나가 병렬로 동시에 처리하는 것이 가능해져 프로그램의 흐름이 멈추거나 지연되지 않게 된다. 따라서 task들이 병렬적으로 동시에 처리되고 총 코드의 실행 시간은 획기적으로 줄어들게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자바스크립트 비동기의 특징&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비동기 처리의 유용성&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 웹 애플리케이션에서 데이터베이스 쿼리를 수행하는 작업이 있다고 가정해 보자. 이 작업을 만일 동기적으로 수행하면 데이터베이스에서 응답이 올 때까지 기다려야 한다. 그러면 이때 애플리케이션은 다른 요청을 처리하지 못하므로 대규모 트래픽이 발생할 경우 성능이 저하될 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 비동기 방식으로 데이터베이스 쿼리를 수행하면 DB에서 응답이 올 때까지 기다리는 동안에도 다른 요청을 처리할 수 있게 된다. 결과가 주어지는 데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 것이다. 이렇게 비동기 방식을 사용하면 대규모 트래픽에서도 안정적으로 동작할 수 있는 애플리케이션을 만들 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로 웹에서 비동기 처리를 가능하게 하는 것으로 Ajax가 있다. 다른 서버에 데이터를 요청할 때 XMLHttpRequest 객체 또는 fetch 메서드로 요청을 하는데, 서버로부터 응답을 기다리는 동안에도 사용자와의 상호작용을 유지할 수 있으므로 사용자 경험을 향상시킬 수 있게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1749994537846&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// fetch 함수에 URL 전달
fetch(&quot;https://test.com/todos/1&quot;)
  .then(function(response) {
    return response.json(); // 응답을 JSON 형식으로 변환
  })
  .then(function(data) {
    console.log(data); // JSON 데이터를 출력
  })
  .catch(function(error) {
    console.error(error); // 에러를 출력
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;비동기 병렬 처리의 원리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 개발자라면 필수로 익히는 지식 중 하나가 호출 스택과 이벤트 루프일 것이다. 그리고 어쩌면 아래와 같은 그림을 본 적이 있을 수도 있다. 비동기 함수의 콜백 함수가 이벤트 루프에 의해서 Callback Queue에 담기고 다시 싱글 스레드인 Call Stack에 담겨서 콜백 함수가 실행되는 동작 원리 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crEFkY/btsOCzr73BA/4WTnqLV4k1KOgoQHUgMmn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crEFkY/btsOCzr73BA/4WTnqLV4k1KOgoQHUgMmn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crEFkY/btsOCzr73BA/4WTnqLV4k1KOgoQHUgMmn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrEFkY%2FbtsOCzr73BA%2F4WTnqLV4k1KOgoQHUgMmn1%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;565&quot; height=&quot;410&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 자바스크립트는 싱글 스레드 언어라고 했는데 어떻게 작업(task)들을 동시에 처리할 수 있는 걸까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트를 실행하는 콜 스택(Call Stack)은 싱글 스레드지만 서버에 리소스를 요청하거나 파일 입출력 혹은 타이머 대기 작업을 실행하는 Web APIs들은 멀티 스레드이기 때문에 동시 작업 처리가 가능하기 때문이다(멀티 스레드를 잘 모른다면 백그라운드에서 동시에 처리된다고 이해하면 된다).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwMwho/btsOBgmPSqO/sA44FqrecSH5pRoUe80VX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwMwho/btsOBgmPSqO/sA44FqrecSH5pRoUe80VX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwMwho/btsOBgmPSqO/sA44FqrecSH5pRoUe80VX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwMwho%2FbtsOBgmPSqO%2FsA44FqrecSH5pRoUe80VX0%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;354&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Web API는 타이머, 네트워크 요청, 파일 입출력, 이벤트 처리 등 브라우저에서 제공하는 다양한 API를 포괄하는 API의 총칭이다. 브라우저마다 다를 수 있지만 크롬 브라우저일 경우 Web API는 멀티 스레드로 구현되어 있다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;즉 브라우저라는 소프트웨어가 멀티 스레드이기 때문에 메인 자바스크립트의 스레드를 차단하지 않고 다른 스레드를 사용하여 Web API의 작업을 처리하여 동시 처리가 가능한 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;만약 아래와 같이 3초를 대기하는 setTimeout 비동기 함수와 그 외 작업들이 있다고 한다면 이 setTimeout 코드가 Web APIs들 중 타이머 처리를 담당하는 Timer API에 넘어가서 3000ms 밀리초를 병렬로 처리되면서 동시에 메인 콜 스택의 Task1, Task2 ...를 처리하는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1749995147281&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('3초 대기')
}, 3000);

Task1();
Task2();
Task3();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;820&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG1Jw8/btsOB8BSNl6/ik45a88tuByHRFcke1MOq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG1Jw8/btsOB8BSNl6/ik45a88tuByHRFcke1MOq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG1Jw8/btsOB8BSNl6/ik45a88tuByHRFcke1MOq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG1Jw8%2FbtsOB8BSNl6%2Fik45a88tuByHRFcke1MOq1%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;625&quot; height=&quot;387&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;정리하자면 브라우저는 멀티 스레드로 이루어져 있고 이러한 동시적 처리 작업 원리 덕분에 우리는 비동기 함수를 통해 성능 향상을 누릴 수 있었던 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;완벽하지 못한 멀티 스레딩&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;setTimeout을 이용해 비동기의 멀티 작업 처리를 설명했지만 사실 자바스크립트의 비동기는 완벽한 멀티 스레딩이 아니다. 위 예시에서 타이머 3000ms만 병렬적으로 처리되고그 안의 콜백 함수 실행 코드는 추후에 이벤트 루프에 의해 콜 스택(Call Stack)에 들어가 싱글 스레드로 처리되기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1749995550913&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setTimeout(() =&amp;gt; { // 그러나 콜백 함수 자체는 나중에 Call Stack에서 싱글 스레드로 처리
	console.log('3초 대기 완료')
}, 3000); // 타이머 3초는 멀티 스레드로 처리

Task1();
Task2();
Task3();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;setTimeout뿐만 아니라 fetch 함수도 마찬가지다. 서버에 요청하여 리소스를 다운로드하는 것은 멀티 스레드로 병렬적으로 처리되지만 요청이 완료되고 나서의 then 핸들러의 콜백 함수는 콜 스택에 별도로 처리된다.&lt;/p&gt;
&lt;pre id=&quot;code_1749995681330&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fetch(&quot;https://test.com/todos/1&quot;) // 서버에서 리소스 다운로드는 멀티 스레드로 처리
  .then(function(response) {
    return response.json(); // 콜백 함수 부분은 나중에 콜 스택 싱글 스레드로 처리
  })
  .then(function(data) {
    console.log(data);
  })
  .catch(function(error) {
    console.error(error);
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 병렬로 동시 처리를 할 거라면 전체를 완전히 처리할 것이지 왜 이런 식으로 번거롭게 나눈 것일까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아마 자바의 멀티 스레드 프로그래밍을 해 본 개발자라면 이에 대한 이유를 알고 있을지 모른다. 완전한 병렬 처리는 성능만큼은 이득을 얻을 수 있을지도 모르겠지만 항상 동시성 문제가 따라와 synchronized 처리가 수반된다는 것을 말이다. 자바스크립트의 비동기만 고려한다면 잘 와닿지 않을 수 있지만, 이러한 synchronized 처리를 잘못하면 오히려 성능 감소가 일어나기 때문에 고난이도의 지식과 실력을 요구한다. 따라서 자바스크립트에서는 동시성 문제에 대해 심플하게 처리하기 위해 비동기 콜백 함수 방식을 채택하였다고 볼 수 있다. 이밖에도 자바스크립트라는 언어를 설계하던 당시에는 멀티 프로세스 컴퓨터가 보편적이지 않았을 뿐더러 자바스크립트가 처리할 코드의 양 또한 적었기 때문이라는 이유도 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자바스크립트에서도 멀티 스레딩을 사용하고 싶다면?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 자바스크립트에서는 영원히 멀티 스레딩을 구현하지 못하는 것일까? 그래서 나온 것이 바로 웹 워커(web workers)이다. 웹 워커를 사용하면 자바스크립트도 자바의 스레드와 같이 멀티 스레드 프로그래밍을 할 수가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1749996096726&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 웹 워커 스크립트 파일(worker.js)
self.addEventListener('message', function(e) {
  // 메인 스크립트로부터 메시지를 받으면 실행할 함수
  var result = &quot;Hello &quot; + e.data;
  self.postMessage(result); // 결과를 메인 스크립트로 전송
}, false);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1749996105908&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 메인 스크립트에서 웹 워커 사용 예시
var worker = new Worker('./worker.js'); // 웹 워커 객체 생성

worker.addEventListener('message', function(e) {
  // 웹 워커로부터 메시지를 받으면 실행할 함수
  console.log(e.data); // 결과 출력
}, false);

worker.postMessage('World'); // 웹 워커에게 메시지 전송&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;582&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PCHzc/btsOB1WXonI/2PJBE4frHXNIk9qCgq8KsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PCHzc/btsOB1WXonI/2PJBE4frHXNIk9qCgq8KsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PCHzc/btsOB1WXonI/2PJBE4frHXNIk9qCgq8KsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPCHzc%2FbtsOB1WXonI%2F2PJBE4frHXNIk9qCgq8KsK%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;471&quot; height=&quot;380&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;브라우저의 비동기 처리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 비동기 원리는 꼭 자바스크립트뿐만 아니라 브라우저의 HTML 마크업 언어에서도 동일하게 적용된다. HTML의 파싱 동작 방식을 예로 들 수 있는데 아래와 같이 &amp;lt;script&amp;gt; 태그를 HTML 파일의 &amp;lt;head&amp;gt; 안에 넣으면 자바스크립트 파일이 다운로드되고 실행될 때까지 HTML의 파싱이 중단된다. 이는 사용자가 웹 페이지의 내용을 보는 데 오래 기다려야 하게 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1749996405046&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;script src=&quot;script1.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;script2.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&quot;script3.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;웹 페이지 제목&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;웹 페이지 내용&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1157&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRnhQ6/btsOBfBIcSF/98h5bxBMlIsCw4yHQNlJb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRnhQ6/btsOBfBIcSF/98h5bxBMlIsCw4yHQNlJb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRnhQ6/btsOBfBIcSF/98h5bxBMlIsCw4yHQNlJb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRnhQ6%2FbtsOBfBIcSF%2F98h5bxBMlIsCw4yHQNlJb0%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;682&quot; height=&quot;146&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에 비동기 함수가 있다면 HTML에도 비동기를 이용할 수 있는 기술이 있다. 바로 &amp;lt;script&amp;gt; 태그에 붙이는 async와 defer 키워드이다. async와 defer 속성은 자바스크립트 파일을 비동기적으로 다운로드하고 실행할 수 있게 해 준다. 이렇게 하면 HTML 파싱과 자바스크립트의 다운로드가 동시에 진행되어 페이지 로딩 속도를 향상시킬 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1749996511947&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;script async src=&quot;script1.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script async src=&quot;script2.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script async src=&quot;script3.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;웹 페이지 제목&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;웹 페이지 내용&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1157&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LXdHq/btsOCBXRzvG/fDrkqDzuVMqs7RWdS0ssh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LXdHq/btsOCBXRzvG/fDrkqDzuVMqs7RWdS0ssh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LXdHq/btsOCBXRzvG/fDrkqDzuVMqs7RWdS0ssh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLXdHq%2FbtsOCBXRzvG%2FfDrkqDzuVMqs7RWdS0ssh0%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;689&quot; height=&quot;161&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;두 그림을 비교하면 똑같은 작업을 처리하는 데 있어 Asynchronous에 총 걸린 시간이 더 적은 것을 볼 수 있다. 이 역시 위에서 배운 자바스크립트와 Web API 원리와 같이 파일 다운로드 동작 자체를 비동기로 브라우저 내부의 멀티 스레드에 양도하고 계속 HTML 파싱을 이어나가면서 동시에 파일을 다운 받는 원리이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;HTML의 비동기는 자바스크립트의 콜 스택과 이벤트 루프 동작과는 별개로 브라우저 내부 구현에 의존하는 것이다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션을 이용하는 빠른 서비스를 원하지 불러오는 속도가 느리고 반응이 없는 것을 원하지 않기 때문에 비동기적으로 페이지를 구성하는 것은 필수 스킬이라 할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비동기 처리의 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;성능 향상을 위해 비동기 처리를 이용할 때 주의해야 할 점이 있다. 앞서 Asynchronous는 요청한 작업의 완료 여부를 기다리지 않고 자신의 그 다음 작업을 계속 수행해 나간다고 했다. 그런데 만약 &lt;b&gt;그 다음에 실행할 작업이 이전에 요청한 작업의 결과를 반드시 필요로 하는 경우&lt;/b&gt; 문제가 생긴다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;쉽게 예를 들어 보면 아래 HTML의 스크립트 코드는 에러를 일으키게 된다. 왜냐하면 $('body').append() 코드는 제이쿼리 전용 코드로서 제이쿼리 라이브러리 파일이 다운을 모두 받은 상태여야만 사용할 수 있기 때문이다. 하지만 제이쿼리 파일의 호출을 비동기적으로 진행해 다운로드되기도 전에 제이쿼리 코드를 사용했으니 에러가 일어나는 게 당연한 것이다(만약 파일의 다운로드가 엄청 빨리 진행된다면 오류가 발생하지 않을 수도 있다).&lt;/p&gt;
&lt;pre id=&quot;code_1749997240957&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script async src='https://code.jquery.com/jquery-3.6.0.min.js'&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
	// 제이쿼리 파일을 비동기적으로 호출하고 바로 제이쿼리 전용 코드를 실행 시켰기 때문에 에러가 발생하다
    $('body').append('&amp;lt;h1&amp;gt;Hello World&amp;lt;/h1&amp;gt;'); // ! ERROR
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 코드는 서버의 데이터베이스를 조회하여 데이터를 가져오는 로직을 간단하게 표현한 예제이다. getDB() 함수를 통해 데이터베이스를 조회하는데 이때 조회 시간이 3초 걸린다고 가정해 보자. 그리고 DB로부터 응답을 받게 되면 data 변수에 저장하고 값을 * 2 연산 후 출력하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749997328054&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function getDB() {
    let data;
    // 데이터베이스에서 값을 가져오는 3초 걸린다고 가정 (비동기 처리)
    setTimeout(() =&amp;gt; {
        data = 100;
    }, 3000);

    return data;
}

function main() {
    let value = getDB();
    value *= 2;
    console.log('value의 값 : ', value); // value의 값 :  NaN
}
main(); // 메인 스레드 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 결과를 확인해 보니 data 변수에 NaN이라는 값이 들어가 있다. 왜 이런 결과가 나왔을까? 그 이유는 비동기 함수인 setTimeout 함수가 3초를 대기하는 동안 완료될 때까지 기다리지 않고 그 다음 코드인 console.log(data)를 실행하였기 때문이다. 이때 data 변수에는 아직 데이터가 저장되지 않았으므로 여기에 연산을 하니 이상한 값이 출력되는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 위와 같이 작업 순서를 맞추는 것이 필수 불가결일 경우 어쩔 수 없이 비동기를 포기하고 동기로 처리해야 하나 싶겠지만 이를 해결하는 몇 가지 방법이 있다. &lt;b&gt;콜백함수&lt;/b&gt;, &lt;b&gt;Promise&lt;/b&gt;, &lt;b&gt;async / await&lt;/b&gt;이 바로 그것이다.&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/336</guid>
      <comments>https://developing-move.tistory.com/336#entry336comment</comments>
      <pubDate>Mon, 30 Jun 2025 09:00:24 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] 이벤트 루프</title>
      <link>https://developing-move.tistory.com/337</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baTTLW/btsODjh9wOA/x6aaWZtMgcoefbR4kUlCm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baTTLW/btsODjh9wOA/x6aaWZtMgcoefbR4kUlCm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baTTLW/btsODjh9wOA/x6aaWZtMgcoefbR4kUlCm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaTTLW%2FbtsODjh9wOA%2Fx6aaWZtMgcoefbR4kUlCm0%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자바스크립트는 싱글 스레드 언어라는 말을 들어본 적이 있는가? 싱글 스레드는 스레드가 하나뿐이라는 것으로 한 번에 하나의 작업만 처리할 수 있다는 것을 의미한다. 반면 Java나 Python는 멀티 스레드를 지원하여 원하는 코드 로직을 동시에 수행시키는 멀티 작업이 가능하다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 웹 애플리케이션에서는 네트워크 요청이나 이벤트 처리, 타이머와 같은 작업을 멀티로 처리해야 하는 경우가 많다. 만약 싱글 스레드로 브라우저 동작이 한 번에 하나씩 수행하게 되면 우리가 파일을 다운로드 받을 동안 브라우저는 파일을 다 받을 때까지 아무것도 못하고 멈춰서 대기해야 할 것이다. 따라서 파일 다운로드, 네트워크 요청, 타이머, 애니메이션 같은 오래 걸리고 반복적인 작업들은 자바스크립트 엔진이 아닌 브라우저 내부의 멀티 스레드인 Web APIs에서 비동기 + Non-Blocking으로 처리된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;비동기 + Non-Blocking은 메인 스레드가 작업을 다른 곳에 요청하여 대신 실행하고 그 작업이 완료되고 나면 이벤트나 콜백 함수를 받아 결과를 실행하는 방식을 말한다. 쉽게 말해 파일 다운로드 요청 작업을 백그라운드 작업으로 전이하여 동시에 처리가 가능하도록 한 것으로 이해할 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉 비동기로 동작하는 핵심 요소는 자바스크립트 언어가 아니라 브라우저라는 소프트웨어가 가지고 있다고 볼 수 있다. Node.js에서는 libuv 내장 라이브러리가 처리한다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이벤트 루프&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;싱글 스레드인 자바스크립트의 작업을 멀티 스레드로 돌려 작업을 동시에 처리하도록 하든 또는 여러 작업 중 어떤 작업을 우선적으로 동작시킬 것인지 결정하는 세심한 컨트롤을 하기 위해 존재하는 것이 바로 이벤트 루프(Event Loop)이다. 이벤트 루프는 브라우저 내부의 Call Stack, Callback Queue, Web APIs 등의 요소들을 모니터링하면서 비동기적으로 실행되는 작업들을 관리하고 이를 순서대로 처리하여 프로그램의 실행 흐름을 제어하는 녀석이다. 간단히 표현하자면 브라우저의 동작 타이밍을 제어하는 관리자라고 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이벤트 루프의 동작 과정을 간단히 살펴 보자면, 자바스크립트의 setTimeout이나 fetch와 같은 비동기 자바스크립트 코드를 브라우저 Web APIs에 맡기고 백그라운드 작업이 끝난 결과를 콜백 함수 형태로 큐(Callback Queue)에 넣고 처리 준비가 되면 호출 스택(Call Stack)에 넣어 마무리 작업을 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/20BCY/btsOAHFm0ei/dmjGFIBIcybyPArM73N3S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/20BCY/btsOAHFm0ei/dmjGFIBIcybyPArM73N3S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/20BCY/btsOAHFm0ei/dmjGFIBIcybyPArM73N3S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F20BCY%2FbtsOAHFm0ei%2FdmjGFIBIcybyPArM73N3S0%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;615&quot; height=&quot;346&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 이벤트 루프를 이용한 프로그램 방식을 이벤트 기반(Event Driven) 프로그래밍이라고 한다. 이벤트 기반 프로그래밍은 프로그램의 흐름이 이벤트에 의해 결정되는 방식이다. 예를 들어 사용자의 클릭이나 키보드 입력과 같은 이벤트가 발생하면 그에 맞는 콜백 함수가 실행된다. 대표적으로 자바스크립트의 addEventListener()가 있겠다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이벤트 기반 프로그래밍을 통해 비동기 작업을 쉽게 처리할 수 있고 멀티 스레드 언어에 비해 단순하고 직관적인 코드 작성이 가능해지며 브라우저와 같은 환경에서도 안정적인 실행을 가능하게 하여 사용자와의 상호작용을 높일 수 있다. 따라서 이를 이해하고 적절한 방식으로 비동기 작업을 처리하는 것은 자바스크립트를 이용한 웹 애플리케이션 개발에 있어 매우 중요하다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;자바스크립트는 왜 싱글 스레드인가?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;자바스크립트는 1995년 넷스케이프에서 웹 브라우저에 동적인 웹 페이지를 만들기 위해 개발된 스크립트 언어이다. 당시에는 멀티 코어 프로세서가 보편화되지 않았고, 자바스크립트는 웹 브라우저에서 간단한 스크립트 동작을 수행하는 데 주로 사용되었기 때문에 복잡한 병렬 처리를 필요로 하지 않아 메모리 사용량이 적고 동기화 문제를 피할 수 있는 싱글 스레드로 구현하였다.&lt;br /&gt;그러나 싱글 스레드는 오래 걸리는 작업이 실행되면 다른 작업들이 대기해야 하므로 응답성이 떨어진다. 또한 CPU 코어를 여러 개 사용할 수 없으므로 성능이 제한된다. 이러한 문제를 해결하기 위해 언어 자체의 설계를 바꾸는 것보다는 브라우저의 멀티 스레드를 이용하는 자바스크립트의 비동기 프로그래밍을 지원하는 것이다. 그리고 이 비동기 프로그래밍의 핵심이 바로 이벤트 루프인이다(다만 Web worker라는 최신 기술을 통해 자바스크립트도 멀티 스레드의 구현이 가능해졌다).&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자바스크립트 엔진의 구동 환경&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트를 실행하는 소프트웨어로는 우리가 잘 알고 있는 웹 브라우저와 런타임인 Node.js가 있다. 이벤트 루프의 동작 원리를 보기에 앞서 싱글 스레드인 자바스크립트 엔진이 어느 곳을 거쳐 비동기 작업을 수행하는지 이들의 내부 구성도를 눈에 익혀 볼 필요가 있다. 본 포스팅에서는 둘 중 브라우저의 내부 구성도만 살펴볼 예정이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;cf) 본 포스팅에서 예시로 사용하는 브라우저는 Chrome으로 다른 부라우저에서는 자바스크립트 엔진이나 내부 구성이 약간씩 다를 수 있다.&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;브라우저의 내부 구성도&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;브라우저는 웹 사이트를 화면에 보여주기 위해 여러 가지 역할을 하는 부품들로 이루어져 있다. 그중 우리가 알아볼 것은 자바스크립트 비동기 코드의 동작 과정이니 이에 관련된 요소로는 Web APIs, Event Table, Callback Queue, Event Loop 등이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJV0VX/btsOBd42jpp/PDAkPnJ0kl91kex2YPEgt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJV0VX/btsOBd42jpp/PDAkPnJ0kl91kex2YPEgt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJV0VX/btsOBd42jpp/PDAkPnJ0kl91kex2YPEgt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJV0VX%2FbtsOBd42jpp%2FPDAkPnJ0kl91kex2YPEgt1%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;593&quot; height=&quot;430&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Call Stack: 자바스크립트 엔진이 코드 실행을 위해 사용하는 메모리 구조.&lt;/li&gt;
&lt;li&gt;Heap: 동적으로 생성된 자바스크립트 객체가 저장되는 공간&lt;/li&gt;
&lt;li&gt;Web APIs: 브라우저에 제공하는 API의 모음으로 비동기적으로 실행되는 작업들을 전담하여 처리&lt;br /&gt;(ajax 호출, 타이머 함수, DOM 조작 등)&lt;/li&gt;
&lt;li&gt;Callback Queue: 비동기적 작업이 완료되면 실행되는 함수들이 대기하는 공간&lt;/li&gt;
&lt;li&gt;Event Loop: 비동기 함수들을 적절한 시점에 실행시키는 관리자&lt;/li&gt;
&lt;li&gt;Event Table: 특정 이벤트(timeout, click, mouse 등)가 발생했을 때 어떤 callback 함수가 호출되어야 하는지 알고 있는 자료 구조(위 그림에는 없음).&lt;/li&gt;
&lt;/ul&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Web APIs의 종류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Web APIs는 타이머, 네트워크 요청, 파일 입출력, 이벤트 처리 등 브라우저에서 제공하는 다양한 API를 포괄하는 총칭이다. Web API는 브라우저(Chrome)에서 멀티 스레드로 구현되어 있다. 그래서 브라우저는 비동기 작업에 대해 메인 스레드를 차단하지 않고 다른 스레드를 사용하여 동시에 처리할 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yfAac/btsOA5MERqu/K7hnxv0G9aLutnNdcGfInK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yfAac/btsOA5MERqu/K7hnxv0G9aLutnNdcGfInK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yfAac/btsOA5MERqu/K7hnxv0G9aLutnNdcGfInK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyfAac%2FbtsOA5MERqu%2FK7hnxv0G9aLutnNdcGfInK%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;591&quot; height=&quot;308&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 setTimeout이라는 비동기 작업은 Web APIs의 한 종류인 Timer API에서 타이머 스레드를 사용하여 타이머를 수행한다. 마찬가지로 XMLHttpRequest, fetch와 같은 네트워크 관련 API는 네트워크 스레드를 사용하여 네트워크 요청과 응답을 처리한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1280&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDhJ93/btsOCnyQbMH/Gu7cHJgK5UQWHc90nTkrek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDhJ93/btsOCnyQbMH/Gu7cHJgK5UQWHc90nTkrek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDhJ93/btsOCnyQbMH/Gu7cHJgK5UQWHc90nTkrek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDhJ93%2FbtsOCnyQbMH%2FGu7cHJgK5UQWHc90nTkrek%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;641&quot; height=&quot;220&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Web APIs의 대표적인 종류는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM: HTML 문서의 구조와 내용을 표현하고 조작할 수 있는 객체.&lt;/li&gt;
&lt;li&gt;XMLHttpRequest: 서버와 비동기적으로 데이터를 교환할 수 있는 객체. ajax 기술의 핵심.&lt;/li&gt;
&lt;li&gt;Timer API: 일정한 시간 간격으로 함수를 실행하거나 지연시키는 메서드를 제공.&lt;/li&gt;
&lt;li&gt;Console API: 개발자 도구에서 콘솔 기능을 제공.&lt;/li&gt;
&lt;li&gt;Canvas API: &amp;lt;canvas&amp;gt; 요소를 통해 그래픽을 그리거나 애니메이션을 만들 수 있는 메서드를 제공.&lt;/li&gt;
&lt;li&gt;Geolocation API: 웹 브라우저에서 사요앚의 현재 위치 정보를 얻을 수 있는 메서드들을 제공.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;오해하지 말아야 할 것은 모든 Web API들이 비동기로 동작되는 것은 아니라는 것이다. Web API에는 동기적으로 처리되는 것과 비동기적으로 처리되는 것이 모두 있다. 예를 들어 DOM API나 Console API는 동기적으로 처리되고 XMLHttpRequest나 Timer API는 비동기적으로 처리된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Callback Queue의 종류&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Web APIs가 여러 API들을 묶어 말하듯이 Callback Queue도 여러 종류의 Queue를 묶어 총칭하는 개념이다. Callback Queue에는 (macro) tasck queue와 microtask queue 두 종류가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PS6qp/btsOCRMSo7j/1GoBlJ9kYQQZenQXx0KcLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PS6qp/btsOCRMSo7j/1GoBlJ9kYQQZenQXx0KcLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PS6qp/btsOCRMSo7j/1GoBlJ9kYQQZenQXx0KcLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPS6qp%2FbtsOCRMSo7j%2F1GoBlJ9kYQQZenQXx0KcLK%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;705&quot; height=&quot;386&quot; data-origin-width=&quot;987&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Task Queue: setTimeout, setInterval, fetch, addEventListener와 같이 비동기로 처리되는 함수들의 콜백 함수가 들어가는 큐(macrotask queue는 보통 task queue라고 부른다)&lt;/li&gt;
&lt;li&gt;Microtask Queue: Promise.then, process.nextTick, MutationObserver와 같이 우선적으로 비동기로 처리되는 함수들의 콜백 함수가 들어가는 큐(처리 우선순위가 높음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Callback Queue의 종류에 따라 이벤트 루프가 콜 스택으로 옮기는 순서가 달라진다. 일반적으로 microtask queue가 가장 우선순위가 높아 microtask queue를 처리하여 먼저 비우고 그 다음 task queue의 콜백을 처리한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;또한 같은 queue 안에 적재되는 콜백이라도 어떠한 비동기 작업이냐에 따라 우선순위가 다른 task들이 있을 수 있다. 예를 들어 Microtask Queue에 적재되는 Promise와 Mutation Observer 콜백 중 Mutation Observer이 먼저 처리되는 식이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;자바스크립트 이벤트 루프의 동작 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;앞의 내용을 복습하자면 싱글 스레드인 자바스크립트에서도 작업의 동시 처리를 지원할 수 있는 비결에는 이벤트 루프가 자바스크립트 엔진과 브라우저의 웹 API를 연결하여 비동기적인 일 처리를 가능케 하기 때문이다. 다만 모든 자바스크립트 코드를 비동기로 처리할 수 있는 것은 아니다. 자바스크립트에는 비동기로 동작하는 비동기 전용 함수가 있는데 대표적으로 setTimeout이나 fetch, addEventListener가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWJQG/btsOBYeTG7Y/8ykMTHzazSIIMbWXHngap0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWJQG/btsOBYeTG7Y/8ykMTHzazSIIMbWXHngap0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWJQG/btsOBYeTG7Y/8ykMTHzazSIIMbWXHngap0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWJQG%2FbtsOBYeTG7Y%2F8ykMTHzazSIIMbWXHngap0%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;510&quot; height=&quot;470&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;브라우저의 Web APIs는 위 그림과 같이 각각 전용 작업을 처리하는 API 스레드들로 구성된 집합을 말한다. 따라서 setTimeout이 호출되면 Timer API라는 별도의 스레드에서 타이머 동작이 별도로 실행되는 것이며 fetch가 호출되면 Ajax API 스레드에서 네트워크 통신이 이루어지는 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이벤트 루프(Event Loop)는 이 비동기 함수 작업을 Web API에 옮기는 역할을 하고 작업이 완료되면 콜백을 큐(Queue)에 적재했다가 다시 자바스크립트 엔진에 적재해 수행시키는 일종의 '작업을 옮기는 역할'만 한다. 작업을 처리하는 주체는 자바스크립트 엔진과 Web API이다. 그래서 이벤트 루프는 Call Stack에 현재 실행 중인 작업이 있는지 그리고 Task Queue에 대기 중인 작업이 있는지 반복적으로 확인하는 일종의 무한 루프만 돌고 대기 작업이 있다면 작업을 옮겨 주는 형태로 동작한다고 보면 된다(그래서 이벤트 루프인 것).&lt;/p&gt;
&lt;pre id=&quot;code_1750002739032&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이벤트 루프의 동작을 나타내는 가상의 코드
while(queue.waitForMessage()){ // 큐에 메시지가 있을 때까지 대기
  queue.processNextMessage(); // 가장 오래된 메시지를 큐에서 꺼내서 호출 스택으로 옮김
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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>Javascript/Javascript</category>
      <category>call stack</category>
      <category>queue</category>
      <category>Task Queue</category>
      <category>Web API</category>
      <category>이벤트 루프</category>
      <category>자바스크립트</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/337</guid>
      <comments>https://developing-move.tistory.com/337#entry337comment</comments>
      <pubDate>Fri, 27 Jun 2025 09:00:14 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Sync와 Asyc</title>
      <link>https://developing-move.tistory.com/335</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tg4HU/btsOBtfkxPR/LAT7kugC8NNBdLGrGfPKX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tg4HU/btsOBtfkxPR/LAT7kugC8NNBdLGrGfPKX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tg4HU/btsOBtfkxPR/LAT7kugC8NNBdLGrGfPKX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftg4HU%2FbtsOBtfkxPR%2FLAT7kugC8NNBdLGrGfPKX0%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;266&quot; height=&quot;330&quot; data-filename=&quot;JS.png&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;409&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOubqz/btsOAxQn1q5/uMhaRvEgfkFCYHuxrqKiG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOubqz/btsOAxQn1q5/uMhaRvEgfkFCYHuxrqKiG1/img.png&quot; data-alt=&quot;동기식 처리 모델과 비동기식 처리 모델의 예&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOubqz/btsOAxQn1q5/uMhaRvEgfkFCYHuxrqKiG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOubqz%2FbtsOAxQn1q5%2FuMhaRvEgfkFCYHuxrqKiG1%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;409&quot; height=&quot;370&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;동기식 처리 모델과 비동기식 처리 모델의 예&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;동기식 처리 모델(Synchronous processing model)은 직렬적으로 태스크(task)를 수행한다. 즉 로직이 순차적으로 실행되며 어떤 작업이 수행 중이면 다음 작업은 대기하게 된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 서버에서 데이터를 가져와 화면에 표시하는 작업을 수행할 때 서버에 데이터를 요청하고 데이터가 응답될 때까지 이후 태스크들은 블로킹(blocking, 작업 중단)된다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1157&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cU0KWU/btsOAUq1DJA/genGmKbNvQfa5XMkYBRTV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cU0KWU/btsOAUq1DJA/genGmKbNvQfa5XMkYBRTV1/img.png&quot; data-alt=&quot;동기식 처리 모델(Synchronous processing model)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cU0KWU/btsOAUq1DJA/genGmKbNvQfa5XMkYBRTV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcU0KWU%2FbtsOAUq1DJA%2FgenGmKbNvQfa5XMkYBRTV1%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;640&quot; height=&quot;137&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;동기식 처리 모델(Synchronous processing model)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 동기식으로 동작하는 코드의 예시. 순차적으로 실행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1749981075793&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function func1() {
  console.log('func1');
  func2();
}

function func2() {
  console.log('func2');
  func3();
}

function func3() {
  console.log('func3');
}

func1();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;반면 비동기식 &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;처리 모델(Asynchronous processing model)은 병렬적으로 작업을 수행한다. 즉 앞선 작업이 종료되지 않은 상태라 하더라도 대기하지 않고 다음 작업을 실행한다. 예를 들어 서버에서 데이터를 가져와 화면에 표시할 때, 서버에 데이터를 요청한 이후 응답이 올 때까지 대기하지 않고(Non-Blocking) 즉시 다음 작업을 수행하는 것. 이후 서버로부터 데이터가 응답되면 이벤트가 발생하고 이벤트 핸들러가 데이터를 가지고 수행할 작업을 계속해 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;자바스크립트의 대부분의 DOM 이벤트 핸들러와 타이머 함수(setTimeout, setInterval), Ajax 요청은 비동기식 처리 모델로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1157&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI1Wy8/btsOAZskl1Q/5iURLCmeQjIH7GTKTWvoj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI1Wy8/btsOAZskl1Q/5iURLCmeQjIH7GTKTWvoj1/img.png&quot; data-alt=&quot;비동기식 처리 모델(Asynchronous processing model)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI1Wy8/btsOAZskl1Q/5iURLCmeQjIH7GTKTWvoj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI1Wy8%2FbtsOAZskl1Q%2F5iURLCmeQjIH7GTKTWvoj1%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;693&quot; height=&quot;162&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;비동기식 처리 모델(Asynchronous processing model)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 비동기식으로 동작하는 코드의 예시. 순차적으로 실행되지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1749981410776&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function func1() {
  console.log('func1');
  func2();
}

function func2() {
  setTimeout(function() {
    console.log('func2');
  }, 0);

  func3();
}

function func3() {
  console.log('func3');
}

func1();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 예시를 실행하면 setTimeout 메서드에 두 번째 인수 인터벌을 0초로 설정해도 콘솔창에 'func1, func2, func3'의 순서로 로그가 출력되지 않는다. setTimeout 메서드가 비동기 함수이기 때문.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;1158&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brU0D6/btsOBSTupOM/OCz9CGx9i5OMPESGgAQTP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brU0D6/btsOBSTupOM/OCz9CGx9i5OMPESGgAQTP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brU0D6/btsOBSTupOM/OCz9CGx9i5OMPESGgAQTP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrU0D6%2FbtsOBSTupOM%2FOCz9CGx9i5OMPESGgAQTP0%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;637&quot; height=&quot;143&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;함수 func1이 호출되면 func1은 Call Stack에 쌓인다. 그리고 func1은 다시 func2를 호출하므로 func2가 Call Stack에 쌓이고 setTimeout이 호출된다. setTimeout의 콜백 함수는 즉시 실행되지 않고 지정 대기 시간만큼 기다리다가 'tick' 이벤트가 발생하면 task queue로 이동한 다음 Call Stack 비워졌을 때 Call Stack으로 이동되어 실행된다(이벤트 루프에 대한 자세한 내용은 별도 포스팅 예정).&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; 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;976&quot; data-origin-height=&quot;876&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cc1xm/btsOBbeRy14/2KrcjklJRMIqmCjtHqkQgK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cc1xm/btsOBbeRy14/2KrcjklJRMIqmCjtHqkQgK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cc1xm/btsOBbeRy14/2KrcjklJRMIqmCjtHqkQgK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Cc1xm/btsOBbeRy14/2KrcjklJRMIqmCjtHqkQgK/img.gif&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;521&quot; height=&quot;468&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;876&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹에서의 비동기와 동기&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Sync와 Async. 이 두 용어는 주로 웹에서 데이터를 주고받는 방식을 설명하는 데 사용되는데, 동기(Sync)는 요청과 응답이 동시에 일어난다는 뜻이고 비동기(Async)는 요청과 응답이 동시에 일어나지 않고 나중에 응답하는 것을 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHZMk2/btsONyGbrJf/hRaw7y9I81o7I9H1XYe0uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHZMk2/btsONyGbrJf/hRaw7y9I81o7I9H1XYe0uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHZMk2/btsONyGbrJf/hRaw7y9I81o7I9H1XYe0uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHZMk2%2FbtsONyGbrJf%2FhRaw7y9I81o7I9H1XYe0uK%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;620&quot; height=&quot;382&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 왜 웹에서는 비동기와 동기라는 방식을 사용하는 걸까?&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Sync(동기)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;동기 통신은 웹 페이지를 새로고침하면서 데이터를 불러오는 방식이라고 볼 수 있다. 예를 들면 보낸 메일함에서 받은 메일함으로 페이지를 이동했을 때 메일 리스트 전체가 다시 로딩되는 것.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;동기(Sync) 통신의 가장 대표적인 예시가 Form 제출이다. 폼은 웹 페이지에서 사용자의 입력을 받아 서버에 전송하는 역할을 하는데 클라이언트에서 폼을 서버에 제출하면 서버로부터 새로운 웹 페이지를 받아 화면에 표시하게 된다. 이처럼 웹 페이지의 전체를 갱신할 수 있게 해 주는 기술이 바로 동기(Sync) 통신이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동기 통신의 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 통신보다 코드를 작성하고 이해하기 쉽다.&lt;/li&gt;
&lt;li&gt;요청과 응답이 순차적으로 이루어지기 때문에 코드의 간결성과 직관성을 유지할 수 있다.&lt;/li&gt;
&lt;li&gt;요청을 보낸 후에 응답을 받아야 다음 작업을 수행하기 때문에 요청과 응답의 순서가 보장된다. 예를 들어 A와 B라는 두 요청을 순서대로 보냈으면 반드시 A의 응답이 먼저 도착하고 B의 응답이 나중에 도착하낟.&lt;/li&gt;
&lt;li&gt;동기 통신의 요청과 응답은 연결되어 있기 때문에 오류 발생 시 오류에 대한 처리가 쉬울 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;361&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csegFc/btsONAxeONq/g4y3E34WlNOkJBysDNgruK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csegFc/btsONAxeONq/g4y3E34WlNOkJBysDNgruK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csegFc/btsONAxeONq/g4y3E34WlNOkJBysDNgruK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsegFc%2FbtsONAxeONq%2Fg4y3E34WlNOkJBysDNgruK%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;330&quot; height=&quot;361&quot; data-origin-width=&quot;330&quot; data-origin-height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동기 통신의 단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 페이지를 다시 로딩하기 때문에 서버와의 통신량이 많아지고 자원과 시간이 낭비될 수 있어 웹 페이지의 속도와 성능이 저하될 수 있다.&lt;/li&gt;
&lt;li&gt;화면이 깜빡거리거나 멈추는 현상이 발생하기 때문(전체 페이지를 다시 로딩하니까)에 사용자 경험이 떨어질 수 있다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Async(비동기)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;비동기 통신은 웹 페이지를 새로고침하지 않고도 데이터를 불러오는 방식이다. 예를 들어 블로그나 카페에서 댓글을 작성하고 등록 버튼을 누르면 페이지 전체가 리로드되지 않고 댓글 영역 부분만 업데이트되어 댓글이 적용되는 것. 이처럼 웹 페이지의 일부분만 업데이트할 수 있게 해주는 기술이 바로 비동기 통신인 것이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 통신의 장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 페이지를 다시 로딩하지 않고 필요한 부분만 업데이트하기 때문에 웹 페이지의 속도와 성능을 향상시킬 수 있다.&lt;/li&gt;
&lt;li&gt;서버와의 통신량이 줄어들고 자원과 시간을 절약할 수 있다. 화면이 깜빡거리거나 멈추지 않고 부드럽게 동작하기 때문에 사용자 경험을 개선시킬 수 있다.&lt;/li&gt;
&lt;li&gt;요청과 응답이 동시에 일어나지 않아도 되기 때문에 요청을 보낸 후에 다른 작업을 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vRaaA/btsOLf9xQj8/Iphy6QuQ0pUEKid5Zi5hMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vRaaA/btsOLf9xQj8/Iphy6QuQ0pUEKid5Zi5hMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vRaaA/btsOLf9xQj8/Iphy6QuQ0pUEKid5Zi5hMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvRaaA%2FbtsOLf9xQj8%2FIphy6QuQ0pUEKid5Zi5hMk%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;678&quot; height=&quot;354&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비동기 통신의 단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 통신은 동기 통신보다 코드를 작성하고 이해하는 것이 어려워 코드의 복잡도가 증가할 수 있다.&lt;/li&gt;
&lt;li&gt;비동기 통신은 요청을 보낸 후에 응답을 기다리지 않고 다음 작업을 수행하기 때문에 요청의 처리 속도에 따라 응답이 뒤죽박죽될 수 있어 요청과 응답의 순서를 보장할 수 없다. 예를 들어 A와 B라는 두 요청을 보냈는데 B의 처리 속도가 더 빠르다면 B의 응답이 먼저 도착하는 경우가 생길 수 있다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이처럼 Sync와 Asnc는 장단점이 명확한 만큼 처리 순서와 결과에 맞게 처리하여 서비스의 질을 높일 수 있는 Synchronous 방식과 처리 결과에 의존하지 않고 성능적으로 빠른 처리가 가능한 Asynchronous 방식을 잘 알고 적용하는 것이 중요하다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&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;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Async(비동기)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;Sync(동기)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;요청과 응답이 동시에 일어나지 않는다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;요청과 응답이 동시에 일어난다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;웹 페이지의 일부분만 업데이트된다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;웹 페이지의 전체를 업데이트한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;코드의 복잡도가 증가할 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;코드의 간결성과 직관성을 유지할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;요청과 응답의 순서를 보장할 수 없다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;요청과 응답의 순서를 보장할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;에러 처리가 어려울 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;에러 처리가 쉬울 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;웹 페이지의 속도와 성능을 향상시킬 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;웹 페이지의 속도와 성능이 저하될 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;사용자 경험을 개선시킬 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;사용자 경험이 떨어질 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;병렬적으로 여러 작업을 수행할 수 있다.&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;병렬적으로 여러 작업을 수행할 수 없다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>js asynchronous</category>
      <category>js synchronous</category>
      <category>동기</category>
      <category>비동기</category>
      <category>자바스크립트</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/335</guid>
      <comments>https://developing-move.tistory.com/335#entry335comment</comments>
      <pubDate>Thu, 26 Jun 2025 09:00:31 +0900</pubDate>
    </item>
    <item>
      <title>[Javascript] Symbol</title>
      <link>https://developing-move.tistory.com/334</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doBrNJ/btsOskpqTVN/HyDVOHwKPUtujyuRYVo4k0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doBrNJ/btsOskpqTVN/HyDVOHwKPUtujyuRYVo4k0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doBrNJ/btsOskpqTVN/HyDVOHwKPUtujyuRYVo4k0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoBrNJ%2FbtsOskpqTVN%2FHyDVOHwKPUtujyuRYVo4k0%2Fimg.jpg&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;266&quot; height=&quot;330&quot; data-origin-width=&quot;266&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol이란?&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;1997년 자바스크립트가 ECMAScript로 처음 표준화된 이래로 자바스크립트는 6개의 타입을 가지고 있었다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[원시 타입(primitive data type)]&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Boolean&lt;/li&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;undefined&lt;/li&gt;
&lt;li&gt;Number&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[객체 타입(Object type)]&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;심볼(symbol)&lt;/b&gt;은 ES6에서 새롭게 추가된 7번째 타입으로 &lt;u&gt;&lt;b&gt;변경 불가능한 원시 타입의 값&lt;/b&gt;&lt;/u&gt;이다. 주로 &lt;u&gt;&lt;b&gt;이름의 충돌 위험이 없는 유일한 객체의 프로퍼티 키(property key)를 만들기 위해 사용&lt;/b&gt;&lt;/u&gt;한다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol의 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;심볼은 아래의 3가지 방법으로 생성할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symbol()&lt;/li&gt;
&lt;li&gt;Symbol.for()&lt;/li&gt;
&lt;li&gt;Symbor.iterator&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Symbol()&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Symbol은&lt;b&gt; Symbol() 함수&lt;/b&gt;로 생성할 수 있다. 이때 &lt;b&gt;생성된 심볼은 객체가 아니라 변경 불가능한 원시 타입의 값&lt;/b&gt;이다. Symbol()은 String, Number, Boolean 등 wrapper 객체를 생성하는 생성자 함수와는 달리 new 연산자를 사용하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;let mySymbol = Symbol();

let mySymbol2 = Symbol(&quot;something&quot;);
// Symbol()에 문자열을 줄수 있는데 별다른 뜻은 없고 일종의 주석 같은 개념이다. 
// 디버깅할 때 이 심볼이 어느 심볼인지 구분하기 편하게 하기 위한 장치

console.log(mySymbol);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Symbol()
console.log(typeof mySymbol); // symbol&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;심볼은 유일성이 보장되는 자료형이기 때문에 설명이 동일한 심볼을 여러 개 만든다 해도 각 심볼 값은 다르다. 심볼에 붙이는 설명(심볼 이름)은 어떤 것에도 영향을 주지 않는 이름표 역할만 하는 것이다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;let id1 = Symbol(&quot;id&quot;);
let id2 = Symbol(&quot;id&quot;);

alert(id1 == id2); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol.for()&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Symbol()이 고유한 심볼을 반환한다면 &lt;b&gt;Symbol.for() 는 전역으로 존재하는 global symbol table의 목록을 참조&lt;/b&gt;한다.&lt;br /&gt;&lt;br /&gt;그러므로 Symbol.for(token string)으로 정의할 때 token string으로 정의 된 심볼이 있다면 해당 심볼을 반환하게 된다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;// 전역 Symbol 레지스트리에 foo라는 키로 저장된 Symbol이 없으면 새로운 Symbol 생성
const s1 = Symbol.for('foo');

// 전역 Symbol 레지스트리에 foo라는 키로 저장된 Symbol이 있으면 해당 Symbol을 반환
const s2 = Symbol.for('foo');

console.log(s1 === s2); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol.keyFor()&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;Symbol.keyFor()&lt;/b&gt;은 &lt;u&gt;&lt;b&gt;global symbol table로부터 존재하는 Symbol의 token string을 반환&lt;/b&gt;&lt;/u&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;var token = Symbol.for(&quot;tokenString&quot;);
console.log(Symbol.keyFor(token) === &quot;tokenString&quot;); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol.description&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Symbol.keyFor()가 전역 심볼의 이름을 반환한다면 Symbol.description은 &lt;b&gt;일반 심볼 이름을 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;const shareSymbol = Symbol.for('myKey');
console.log(Symbol.keyFor(shareSymbol)); // myKey

const unsharedSymbol = Symbol('myKey');
console.log(Symbol.keyFor(unsharedSymbol)); // undefined
console.log(unsharedSymbol.description); // myKey&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Symbol()이 매번 다른 Symbol 값을 생성하는 것에 반해 Symbol.for() 메서드는 하나의 심볼을 생성하여 여러 모듈이 key를 통해 같은 심볼을 공유할 수 있다.&lt;br /&gt;Symbol.for()를 통해 생성된 심볼 값은 반드시 key를 갖는다. 이에 반해 Symbol()을 통해 생성된 심볼 값은 key가 없다.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol의 사용&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;객체 프로퍼티의 key는 빈 문자열을 포함하는 모든 문자열로 만들 수 있다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;const obj = {};
const v = &quot;name&quot;;

obj[v] = 'myProp';
obj[123] = 123; // 123은 문자열로 변환된다.
// obj.123 = 123;&amp;nbsp;&amp;nbsp;// SyntaxError: Unexpected number
obj['prop' + 123] = false;

console.log(obj); 
/* 
{ 
&amp;nbsp;&amp;nbsp;name : 'myProp', 
&amp;nbsp;&amp;nbsp;'123' : 123, 
&amp;nbsp;&amp;nbsp;prop123 : false 
}
*/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Symbol 값 또한 객체의 프로퍼티 key로 사용할 수 있다. Symbol은 유일한 값이므로 Symbol을 key로 갖는 프로퍼티는 다른 어떠한 프로퍼티와도 충돌하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;const obj = {};

const mySymbol = Symbol('mySymbol');
const mySymbol2 = Symbol('mySymbol');

obj[mySymbol] = 123;
obj[mySymbol2] = 456;

console.log(obj); // { [Symbol(mySymbol)] : 123, Symbol(mySymbol)] : 456}
console.log(obj[mySymbol]); // 123&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;심볼은 문자형으로 자동 형변환되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;자바스크립트에서는 문자형으로의 암시적 형변환이 비교적 자유롭게 일어나는 편이다. alert() 함수가 거의 모든 값을 인자로 받을 수 있는 이유가 바로 이 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 심볼의 경우 예외다. 심볼형의 값은 다른 자로형으로 암시적 형변환(자동 형변환)되지 않는다. 따라서 아래 예시에서 alert는 에러를 발생시킨다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;let id = Symbol(&quot;id&quot;); 
alert(id); // TypeError: Cannot convert a Symbol value to a string&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;문자열과 심볼은 근본이 다르기 때문에 우연이라도 서로의 타입으로 변환되어서는 안 된다. 자바스크립트에서는 '언어 차원의 보호장치(language guard)'를 마련해 심볼형이 다른 자료형으로 변환되지 않도록 막아준다. 심볼을 반드시 출력해 줘야 하는 상황이라면 아래와 같이 toString() 메서드를 명시적으로 호출해 주면 된다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let id = Symbol(&quot;id&quot;);
alert(id.toString()); // Symbol(id)가 얼럿 창에 출력됨&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;symbol.description 프로퍼티를 사용하면 설명만 보여주는 것도 가능하다.&lt;/p&gt;
&lt;pre class=&quot;Javascript&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;Javascript&quot;&gt;&lt;code&gt;let id = Symbol(&quot;id&quot;);
alert(id.description); // id&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실무에서의 Symbol&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1749978570136&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Counter {
  count = 0;

  add() {
    return this.count++;
  }
  get() {
    return this.count;
  }
}

class BetterCounter extends Counter {
  count = function() { ... }; // conflict !!!!!!!!!!!!!!!!!
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 객체의 내부 필드는 기본적으로 모두 public이다. 이는 누구든 어디에서든 내부 함수 값을 덮어쓸 수 있다는 말이기도 하다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드에서는 그냥 count라는 문자열 key 값을 사용하는데 이를 라이브러리로 외부에 배포했다고 상상해 보자. 그리고 어떤 개발자가 이 Count라는 라이브러리를 받아 상속을 통해 기능을 확장하여 사용하려다가 내부 코드를 잘 모르기 때문에 자연스럽게 변수를 하나 선언하게 되는데 이름을 count라고 지었다면 어떻게 될까.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;코드를 작성하고 실행하는 과정에서 잘 동작하지 않을 것이다. 로직상 문제가 될 것은 없는데 동작하지 않는 이유는 부모 클래스의 인스턴스 count 변수가 덮어씌워졌기 때문이다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;심볼을 선언하는 순간 이는 private라고 개발자에게 가독성을 높여줄 뿐만 아니라 인스턴스 중복을 피할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1749979257066&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const count = Symbol();

class Counter {
  [count] = 0;
  
  add(){
    this[count] += 1;
    return this;
  }
  
  get(){
    return this[count];
  }
}

const counter = new Counter();
console.log(counter.get()); // 0

counter.add().add().add();
console.log(counter.get()); // 3&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&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;style6&quot; /&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Symbol.iterator&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;어떤 객체가 Symbol.iterator를 프로퍼티 key로 사용한 메서드를 가지고 있으면 자바스크립트 엔진은 이 객체가 이터레이션 프로토콜을 따르는 것으로 간주하고 이터레이터로 동작하도록 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Symbol.iterator를 프로퍼티 key로 사용하여 메서드를 구현하고 있는 빌트인 객체(빌트인 이터러블)는 아래와 같다. 아래 객체들은 이터레이션 프로토콜을 준수하고 있으며 이터레이터를 반환한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;이터레이터를 반환한다는 뜻은 for of문으로 요소 하나씩 순회가 가능하다는 것을 뜻한다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;Array&amp;nbsp; &lt;/b&gt;Array.prototype[Symbol.iterator]&lt;br /&gt;​&lt;br /&gt;&lt;b&gt;String&amp;nbsp; &lt;/b&gt;String.prototype[Symbol.iterator]&lt;br /&gt;​&lt;br /&gt;&lt;b&gt;Map&amp;nbsp; &lt;/b&gt;Map.prototype[Symbol.iterator]&lt;br /&gt;​&lt;br /&gt;&lt;b&gt;Set&amp;nbsp; &lt;/b&gt;Set.prototype[Symbol.iterator]&lt;br /&gt;​&lt;br /&gt;&lt;b&gt;DOM data structures&amp;nbsp; &lt;/b&gt;NodeList.prototype[Symbol.iterator], HTMLCollection.prototype[Symbol.iterator]&lt;br /&gt;​&lt;br /&gt;&lt;b&gt;arguments&amp;nbsp; &lt;/b&gt;arguments[Symbol.iterator]&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749979605135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// iterable
// Symbol.iterator를 프로퍼티 key로 사용한 메서드를 구현하여야 한다.
// 배열에는 Array.prototype[Symbol.iterator] 메서드가 구현되어 있다.
const iterable = ['a', 'b', 'c'];

// iterator
// 이터러블의 Symbol.iterator를 프로퍼티 key로 사용한 메서드는 이터레이터를 반환한다.
const iterator = iterable[Symbol.iterator]();

// 이터레이터는 순회 가능한 자료 구조인 이터러블의 요소를 탐색하기 위한 포인터로,
// value, done 프로퍼티를 갖는 객체를 반환하는 next() 함수를 메서드로 갖는 객체이다. 
// 이터레이터의 next() 메서드를 통해 이터러블 객체를 순회할 수 있다.
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Symbol 유의점&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;객체의 key가 Symbol일 경우 for ... in 반복문에서는 배제된다. Object.keys를 사용해도 key가 심볼인 프로퍼티는 배제된다.&lt;br /&gt;숨김 처리 기능을 하는 자료형이기 때문.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;심볼형 프로퍼티 숨기기(hiding symbolic property) 원칙&lt;/b&gt;&lt;br /&gt;외부 스크립트나 라이브러리는 심볼형 key를 가진 프로퍼티에 접근하지 못함.&lt;/blockquote&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/Javascript</category>
      <category>javascript</category>
      <category>javascript private</category>
      <category>symbol</category>
      <category>심볼</category>
      <category>자바스크립트 심볼</category>
      <author>금요일인줄</author>
      <guid isPermaLink="true">https://developing-move.tistory.com/334</guid>
      <comments>https://developing-move.tistory.com/334#entry334comment</comments>
      <pubDate>Wed, 25 Jun 2025 09:00:08 +0900</pubDate>
    </item>
  </channel>
</rss>