<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>도서의 코딩노트</title>
    <link>https://leedoseo.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 21 Jul 2026 08:15:27 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>이도서</managingEditor>
    <item>
      <title>[TypeScript] void와 never</title>
      <link>https://leedoseo.tistory.com/300</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;void 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;void&amp;nbsp;타입은 아무런 값도 없음을 의미하는 타입임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;보통은 다음과 같이 아무런 값도 반환하지 않는 함수의 반환값 타입을 정의할 때 사용함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function func1(): void {
	console.log(&quot;hello&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;물론 다음과 같이 변수의 타입으로도&amp;nbsp;void타입을 지정할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그러나&amp;nbsp;void타입의 변수에는&amp;nbsp;undefined&amp;nbsp;이외의 다른 타입의 값은 담을 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let a: void;
a = undefined;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그런데&amp;nbsp;tsconfig.json에 엄격한 null 검사 (strictNullChecks)옵션을 해제(false)로 설정하면&amp;nbsp;void타입의 변수에&amp;nbsp;null값도 담을 수 있게됨.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// strictNullChecks: false 일 경우
let a: void;
a = undefined;
a = null;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;never 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;never&amp;nbsp;타입은 불가능을 의미하는 타입임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;보통 함수가 어떠한 값도 반환할 수 없는 상태일 때 해당 함수의 반환값 타입을 정의할 때 사용됨&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function func3(): never {
	while (true) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;func3는 무한 루프를 돌기 때문에 아무런 값도 반환할 수 없음. &amp;rArr; 영원히 종료될 수 없기 때문에 반환하는 것 자체가 불가능&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇게 불가능한 값의 타입을 정의할 때&amp;nbsp;never타입을 사용함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;무한 루프 외에도 다음과 같이 의도적으로 오류를 발생시키는 함수도&amp;nbsp;never&amp;nbsp;타입으로 반환값 타입을 정의할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;function func4(): never {
	throw new Error();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;추가로, 변수의 타입을&amp;nbsp;never로 정의하면&amp;nbsp;any를 포함해 그 어떠한 값도 이 변수에 담을 수 없게 됨.&lt;/span&gt;&lt;/p&gt;</description>
      <category>React/TypeScript</category>
      <category>Never</category>
      <category>Typescript</category>
      <category>void</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/300</guid>
      <comments>https://leedoseo.tistory.com/300#entry300comment</comments>
      <pubDate>Mon, 9 Mar 2026 18:58:56 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] any와 unknown</title>
      <link>https://leedoseo.tistory.com/299</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  any와 unknown&lt;/span&gt;&lt;/h1&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;any 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;any 타입은 타입스크립으에서만 제공되는 특별한 타입으로 타입 검사를 받지않는 특수한 치트키 타입임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;예를 들어 아주 범용적으로 사용되어야 하는 변수가 있다고 가정을 해보겠음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let anyVar = 10;
anyVar = &quot;hello&quot;; // 오류 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;변수&amp;nbsp;anyVar는&amp;nbsp;number타입의 값 10으로 초기화 했지만 이후에&amp;nbsp;string타입의 값을 넣는다고 가정을 했음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;타입스크립트에서는 변수의 타입이 변수를 초기화할 때 초기화 하는 값을 기준으로 추론하기 때문에&amp;nbsp;number&amp;nbsp;&amp;rarr;&amp;nbsp;string이 될 수가 없음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이럴 때&amp;nbsp;any를 사용함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let anyVar: any = 10;
anyVar = &quot;hello&quot;;

anyVar = true;
anyVar = {};

anyVar.toUpperCase();
anyVar.toFixed();
anyVar.a;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇듯&amp;nbsp;any타입은 어떠한 타입 검사도 받지 않기 때문에 아무 타입의 값이나 범용적으로 담아 사용할 수 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다양한 타입의 메서드도 마음대로 호출해서 사용해도 문제가 되지 않음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;또한, 어떤 타입으로 정의된 변수던 문제 없이 다 할당할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let anyVar: any = 10;
anyVar = &quot;hello&quot;;

let num: number = 10;
num = anyVar;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;하지만 any는 최대한 사용하면 안됨&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;우리가 아까 작성한 다음과 같은 코드를 컴파일 하거나 ts-node로 실행해보면 런타임 오류가 발생함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let anyVar: any = 10;
anyVar = &quot;hello&quot;;

anyVar = true;
anyVar = {};

anyVar.toUpperCase();
anyVar.toFixed();
anyVar.a;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇듯&amp;nbsp;any&amp;nbsp;타입은 타입 검사를 받지 않는 타입이므로 모든 타입스크립트의 문법과 규칙으로부터 자유롭지만 그만큼 위험한 타입임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;따라서&amp;nbsp;any&amp;nbsp;타입을 많이 사용하면 많은 부분에서 타입 검사가 제대로 이루어지지 않기에 위험한 코드가 생산됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;정말 어쩔 수 없는 경우를 제외하고는&amp;nbsp;any타입을 사용하지 않는 것을 권장함.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;Unknown 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;unknown&amp;nbsp;타입은&amp;nbsp;any&amp;nbsp;타입과 비슷하지만 보다 안전한 타입임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;unknown&amp;nbsp;타입의 변수는 다음과 같이 어떤 타입의 값이든 다 저장할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let unknown: unknown;

unknownVar = &quot;&quot;;
unknownVar = 1;
unknownVar = () =&amp;gt; {};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그러나 반대로는 안됨.&amp;nbsp;unknown&amp;nbsp;타입의 값은 어떤 타입의 변수에도 저장할 수 없음.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let num: number = 10;

let unknownVar: unknown;
unknownVar = &quot;&quot;;
unknownVar = 1;
unknownVar = () = &amp;gt; {};

num = unknownVar; // 오류 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;또한,&amp;nbsp;unknown&amp;nbsp;타입의 값은 어떠한 연산에도 참여할 수 없으며, 어떠한 메서드도 사용할 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let unknownVar: unknown;

unknownVar * 2 // 오류 발생&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;정리하자면&amp;nbsp;unknown&amp;nbsp;타입은 변수의 타입으로 정의되면 모든 값을 할당받을 수 있게 되지만, 어떠한 타입의 변수에도 할당할 수 없고, 모든 연산에 참가할 수 없게됨. &amp;rArr; 값을 저장하는 행위밖에 할 수 없게됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;만약, 위 코드와 같이&amp;nbsp;unknown&amp;nbsp;타입의 값을&amp;nbsp;number&amp;nbsp;타입의 값처럼 취급하여 곱셈 연산을 수행하게 하고 싶다면&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;조건문을 이용해 이 값이&amp;nbsp;number&amp;nbsp;타입의 값임을 보장해줘야 함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;if (typeof unknownVar === &quot;number&quot;) {
	// 이 조건이 참이 된다면 unknownVar는 number 타입으로 볼 수 있음
	unknownVar * 2;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>React/TypeScript</category>
      <category>Any</category>
      <category>Typescript</category>
      <category>UNKNOWN</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/299</guid>
      <comments>https://leedoseo.tistory.com/299#entry299comment</comments>
      <pubDate>Mon, 9 Mar 2026 18:44:26 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 열거형 타입(enum)</title>
      <link>https://leedoseo.tistory.com/298</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  열거형 타입(enum)&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;열거형 타입은 자바스크립트에는 존재하지 않고 타입스크립트에서만 사용할 수 있는 특별한 타입임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;열거형은 다음과 같이 여러 개의 값을 나열하는 용도로 사용함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;enum Role {
	ADMIN,
	USER,
	GUEST,
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;3개의 등급&amp;nbsp;ADMIN,&amp;nbsp;USER,&amp;nbsp;GUEST를 나열한 열거형 타입을 하나 만들었음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;enum의 각 멤버에는 다음과 같이 숫자를 할당할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;enum Role {
	ADMIN = 0,
	USER = 1,
	GUEST = 2,
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;또 다음과 같이&amp;nbsp;enum의 멤버들의 값으로도 활용할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// enum 타입
// 여러 가지 값들에 각각 이름을 부여해 열거해두고 사용하는 타입

enum Role {
	ADMIN = 0,
	USER = 1,
	GUEST = 2,
}

const user1 = {
	name: &quot;이도서&quot;,
	role: Role.ADMIN, // 관리자
};

const user2 = {
	name: &quot;도서&quot;,
	role: Role.USER, // 회원
};

const user3 = {
	name: &quot;홍길동&quot;,
	role: Role.GUEST, // 게스트
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;user1.role에는 0이,&amp;nbsp;user2.role에는 1이&amp;nbsp;user3.role에는 2가 할당됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇듯 유저의 권한과 같은 여러 개의 멤버를 갖는 값을 숫자로 표기할 때&amp;nbsp;enum을 사용하게되면 보다 안전하고 직관적으로 관리할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;참고로&amp;nbsp;enum멤버에 숫자 값을 직접 할당하지 않아도 0부터 1씩 늘어나는 값으로 자동으로 할당됨.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;enum Role {
	ADMIN, // 0할당 (자동)
	USER, // 1할당 (자동)
	GUEST, // 2할당 (자동)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;rArr; 자동으로 할당되는 값은 기본적으로 0부터 시작함. 만약 이 값을 변경하고 싶다면 시작하는 위치에 직접 값을 할당하면 그 뒤에 오는 아래에 멤버들은 1씩 증가된 값으로 할당됨.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;문자열 열거형&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;enum의 멤버에는 숫자 말고도 문자열 값도 할당할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;국가별 언어를 열거하는&amp;nbsp;enum이 필요하다면 각 멤버에 문자열 값을 할당하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;enum Language {
	korean = &quot;ko&quot;,
	english = &quot;en&quot;,
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;모든 멤버의 값이 문자열인 값인&amp;nbsp;enum을 문자열 enum이라고 부름.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;숫자형 enum과 동일하게 프로퍼티의 값으로 사용할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;enum Role {
  ADMIN,
  USER,
  GUEST,
}

enum Language {
  korean = &quot;ko&quot;,
  english = &quot;en&quot;,
}

const user1 = {
  name: &quot;이도서&quot;,
  role: Role.ADMIN, // 0
  language: Language.korean,// &quot;ko&quot;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;문자열 enum을 사용하면&amp;nbsp;user1.language같은 프로퍼티에 실수로&amp;nbsp;&quot;ko&quot;로 적었어야 할 것을 오타가 났을 경우를 방지해줌&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;enum은 컴파일 결과로 객체가 됨&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;enum은 컴파일될 때 다른 타입들 처럼 사라지지 않고 자바스크립트 객체로 변환됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;따라서 우리가 위에서 했던 것 처럼 값으로 사용할 수 있는 것임.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;var Role;
(function (Role) {
    Role[Role[&quot;ADMIN&quot;] = 0] = &quot;ADMIN&quot;;
    Role[Role[&quot;USER&quot;] = 1] = &quot;USER&quot;;
    Role[Role[&quot;GUEST&quot;] = 2] = &quot;GUEST&quot;;
})(Role || (Role = {}));
var Language;
(function (Language) {
    Language[&quot;korean&quot;] = &quot;ko&quot;;
    Language[&quot;english&quot;] = &quot;en&quot;;
    Language[&quot;japanese&quot;] = &quot;jp&quot;;
})(Language || (Language = {}));
const user1 = {&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>React/TypeScript</category>
      <category>Enum</category>
      <category>Typescript</category>
      <category>열거형 타입</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/298</guid>
      <comments>https://leedoseo.tistory.com/298#entry298comment</comments>
      <pubDate>Mon, 9 Mar 2026 18:26:22 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 별칭과 인덱스 시그니처</title>
      <link>https://leedoseo.tistory.com/297</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  타입 별칭과 인덱스 시그니처&lt;/span&gt;&lt;/h1&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;타입 별칭(Type Alias)&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;타입 별칭을 이용하면 다음과 같이 변수를 선언하듯 타입을 별도로 정의할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// 타입 별칭
type User = {
	id: number;
	name: string;
	nickname: string;
	brith: string;
	bio: string;
	location: string;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;type 타입이름 = 타입형태로 타입을 정의함. 위 코드 타입 이름으로는&amp;nbsp;User&amp;nbsp;그리고 타입으로는 여러 개의 프로퍼티가 있는 객체 타입을 정의했음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇게 만든 타입 별칭은 다음과 같이 변수의 타입을 정의할 때 타입 주석과 함께 사용할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type User = {
  id: number;
  name: string;
  nickname: string;
  birth: string;
  bio: string;
  location: string;
};

let user: User = {
  id: 1,
  name: &quot;이도서&quot;,
  nickname: &quot;leedoseo&quot;,
  birth: &quot;1998.02.07&quot;,
  bio: &quot;안녕하세요&quot;,
  location: &quot;화성시&quot;,
};

let user2: User = {
  id: 2,
  name: &quot;도서&quot;,
  nickname: &quot;doseo&quot;,
  birth: &quot;1998.02.08&quot;,
  bio: &quot;안녕하세요&quot;,
  location: &quot;서울시&quot;,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;참고로 동일한 스코프에 동일한 이름의 타입 별칭을 선언하는 것은 불가능함. &amp;rArr; 변수 선언과 유사함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type User = {
  id: number;
  name: string;
  nickname: string;
  birth: string;
  bio: string;
  location: string;
};

type User = {}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;단, 스코프가 다르다면 다음과 같이 중복된 이름으로 여러 개의 별칭을 선언하는 것이 가능&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type User = {
  id: number;
  name: string;
  nickname: string;
  birth: string;
  bio: string;
  location: string;
};

function test() {
  type User = string;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;인덱스 시그니처&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;인덱스 시그니처는 객체 타입을 유연하게 정의할 수 있도록 돕는 특수한 문법임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다양한 국가들의 영어 코드를 저장하는 객체가 있다고 가정해보겠음.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryCodes = {
  Korea: string;
  UnitedState: string;
  UnitedKingdom: string;
};

let countryCodes: CountryCodes = {
  Korea: &quot;ko&quot;,
  UnitedState: &quot;us&quot;,
  UnitedKingdom: &quot;uk&quot;,
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;만약, 이때&amp;nbsp;countryCodes에 100개의 프로퍼티(국가 코드)가 추가가 되어야한다면 타입 정의에도 각 프로퍼티를 모두 하나하나 정의해주어야 하기 때문에 매우 코드가 길어지고 불편함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryCodes = {
  Korea: string;
  UnitedState: string;
  UnitedKingdom: string;
  // (... 약 100개의 국가)
  Brazil : string
};

let countryCodes: CountryCodes = {
  Korea: &quot;ko&quot;,
  UnitedState: &quot;us&quot;,
  UnitedKingdom: &quot;uk&quot;,
  // (... 약 100개의 국가)
  Brazil : 'bz'
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이럴 때 인덱스 시그니처를 사용하면 간단하게 타입을 정의할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryCodes = {
  [key: string]: string;
};

let countryCodes: CountryCodes = {
  Korea: &quot;ko&quot;,
  UnitedState: &quot;us&quot;,
  UnitedKingdom: &quot;uk&quot;,
  // (... 약 100개의 국가)
  Brazil : 'bz'
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;[key : string] : string&amp;nbsp;은 인덱스 시그니쳐 문법으로 이 객체 타입에는&amp;nbsp;key가&amp;nbsp;string&amp;nbsp;타입이고&amp;nbsp;value가&amp;nbsp;string&amp;nbsp;타입인 모든 프로퍼티를 포함된다 라는 의미임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;따라서&amp;nbsp;Korea : &amp;ldquo;ko&amp;rdquo;나&amp;nbsp;Brazil : &amp;ldquo;bz&amp;rdquo;&amp;nbsp;처럼&amp;nbsp;key와&amp;nbsp;value가 모두&amp;nbsp;string&amp;nbsp;타입인 이런 프로퍼티들 이 타입에 자동으로 모두 포함되므로 굳이 일일이 이런 타입들을 직접 명시할 필요가 없어짐.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;만약 국가 코드를 숫자로 보관하는 객체가 하나 더 필요하다고 하면 그때의 타입은 다음과 같이 정의하면 됨.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryNumberCodes = {
	[key: string]: number;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;추가로 이 때 반드시 포함해야 하는 프로퍼티가 있다면 다음과 같이 직접 명시하는 것도 가능&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryNumberCodes = {
  [key: string]: number;
  Korea: number;
};&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;한 가지 주의할 점은 인덱스 시그니처를 사용하면서 동시에 추가적인 프로퍼티를 또 정의할 때에는 인덱스 시그니처의&amp;nbsp;value타입과 직접 추가한 프로퍼티의&amp;nbsp;value&amp;nbsp;타입이 호환되거나 일치해야함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;type CountryNumberCodes = {
  [key: string]: number;
  Korea: string; // 오류!
};&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;rArr;&amp;nbsp;string타입은&amp;nbsp;number타입과 호환되지 않기 때문임.&lt;/span&gt;&lt;/p&gt;</description>
      <category>React/TypeScript</category>
      <category>Index signature</category>
      <category>type alias</category>
      <category>Typescript</category>
      <category>인덱스 시그니처</category>
      <category>타입별칭</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/297</guid>
      <comments>https://leedoseo.tistory.com/297#entry297comment</comments>
      <pubDate>Mon, 9 Mar 2026 18:12:38 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 객체</title>
      <link>https://leedoseo.tistory.com/296</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  객체&lt;/span&gt;&lt;/h1&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;object로 정의하기&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user = {
	id: 1,
	name: &quot;이도서&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;user의 타입을 객체를 의미하는&amp;nbsp;object로 정의해보겠음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: object = {
	id: 1,
	name: &quot;이도서&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇게 하면 타입은 잘 정의가 됐음. 근데 문제가 생김&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: object = {
  id: 1,
  name: &quot;이도서&quot;,
};

user.id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;위 코드의&amp;nbsp;user.id&amp;nbsp;처럼 점 표기법으로 객체의 특정 프로퍼티에 접근하려고 하면 오류가 발생함&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;rArr; 오류 메시지를 확인해보면 다음과 같이&amp;nbsp;object&amp;nbsp;타입에&amp;nbsp;id프로퍼티가 없다라고 뜸&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그럼 어떻게 해야할까?&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;객체 리터럴 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;객체 리터럴 타입을 이용하면 해결됨&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: {
  id: number;
  name: string;
} = {
  id: 1,
  name: &quot;이도서&quot;,
};

user.id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;변수&amp;nbsp;user의 타입을&amp;nbsp;number타입의&amp;nbsp;id&amp;nbsp;그리고&amp;nbsp;string타입의&amp;nbsp;name프로퍼티를 갖는 객체 타입으로 정의했음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;변수의 타입을 객체 리터럴 타입으로 정의하면 이제 타입내에 정의되어 있는 프로퍼티에 이상 없이 접근할 수 있게됨.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;특수한 프로퍼티 정의&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;객체 타입을 정의할 때 특정 프로퍼티를 선택적이거나 읽기 전용으로 만드는 타입스크립트의 독특한 문법이 있음.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;선택적 프로퍼티&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;자바스크립트에서 객체를 다루다보면 자주 특정 프로퍼티는 있어도 되고 없어도 되는 그런 상황이 존재함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;예를 들어 다음과 같이 이름은 있지만 아직 id가 없는 유저가 존재할 수도 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: {
  id: number;
  name: string;
} = {
  id: 1,
  name: &quot;이도서&quot;,
};

user = {
  name: &quot;도서&quot;, // 오류 발생!
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그러나 이렇게 코드를 작성하면 타입스크립트에서는 오류가 발생함.&amp;nbsp;user의 타입은&amp;nbsp;id와&amp;nbsp;name&amp;nbsp;프로퍼티가 있는 객체인데 마지막 라인에서&amp;nbsp;name만 존재하는 객체를 할당했기 때문임. 이렇게 특정 프로퍼티를 상황에 따라 생략하도록 만들고 싶다면 해당 프로퍼티를 선택적 프로퍼티로 만들어줘야 함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;선택적 프로퍼티를 설정하는 방법은 다음과 같이 프로퍼티의 이름 뒤에&amp;nbsp;?&amp;nbsp;를 붙여주면 됨.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: {
  id?: number; // 선택적 프로퍼티가 된 id
  name: string;
} = {
  id: 1,
  name: &quot;이도서&quot;,
};

user = {
  name: &quot;도서&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;id&amp;nbsp;프로퍼티 뒤에 붙은 물음표의 의미는 이 프로퍼티는 이제 생략 가능한 선택적(Optional) 프로퍼티라는 의미임. 한 가지 주의할 점이 있는데 선택적 프로퍼티가 존재한다면 그때의&amp;nbsp;value&amp;nbsp;타입은 반드시&amp;nbsp;number&amp;nbsp;타입이어야 한다는 점임. 따라서 다음과 같이&amp;nbsp;id&amp;nbsp;프로퍼티를 추가하고&amp;nbsp;value를&amp;nbsp;string타입의 값으로 설정하면 오류가 발생함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xquery&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let user: {
  id?: number;
  name: string;
} = {
  id: 1,
  name: &quot;이도서&quot;,
};

user = {
  id: &quot;id&quot;, // 오류 발생!
  name: &quot;도서&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;읽기 전용 프로퍼티 (Readonly Property)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다음으로는 읽기 전용 프로퍼티임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;특정 프로퍼티를 읽기 전용으로 만들고 싶다면 다음과 같이 프로퍼티의 이름 앞에&amp;nbsp;readonly&amp;nbsp;키워드를 붙이면 됨.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;// name은 이제 Readonly 프로퍼티가 되었음}={  id:1,  name:&quot;이도서&quot;,};
let user:{  id?:number;readonly name:string;
user.name=&quot;dskfd&quot;;// 오류 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;name&amp;nbsp;프로퍼티는 이제 읽기 전용 프로퍼티가 되었기 때문에 마지막 라인처럼 프로퍼티의 값을 수정하려고 하면&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;오류가 발생하게 됨. 이를 통해 의도치 않은 프로퍼티의 수정을 방지할 수 있음.&lt;/span&gt;&lt;/p&gt;</description>
      <category>React/TypeScript</category>
      <category>Typescript</category>
      <category>객체</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/296</guid>
      <comments>https://leedoseo.tistory.com/296#entry296comment</comments>
      <pubDate>Fri, 6 Mar 2026 19:50:34 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 배열과 튜플</title>
      <link>https://leedoseo.tistory.com/295</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  배열과 튜플&lt;/span&gt;&lt;/h1&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;배열&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;타입스크립트에서는 다음과 같이 배열 타입을 정의함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let numArr: number[] = [1, 2, 3];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;배열을 저장하는 변수의 이름 뒤에 타입 주석의 시작을 의미하는&amp;nbsp;:을 작성한다음&amp;nbsp;배열요소타입[]형식으로 배열 타입을 정의함.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let strArr: string[] = [&quot;hello&quot;, &quot;im&quot;, &quot;doseo&quot;];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;배열 요소의 타입이&amp;nbsp;string이므로 이번에는&amp;nbsp;string[]으로 문자열 배열 타입을 정의 해봤음&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let boolArr: Arr&amp;lt;boolean&amp;gt; = [true, false];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;Array&amp;lt;배열요소타입&amp;gt;형태로도 배열의 타입을 정의할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇게&amp;nbsp;&amp;lt;&amp;gt;와 함께 타입을 작성하는 문법을 타입스크립트에서는 &amp;ldquo;제네릭&amp;rdquo;이라고 부름&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다양한 타입 요소를 갖는 배열 타입 정의하기&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;만약 다음과 같이 다양한 배열 요소를 갖는 배열 타입을 정의해야 할 때는 어떻게 해야할까?&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let multiArr = [1, &quot;hello&quot;];

let multiArr: (number | string)[] = [1, &quot;hello&quot;];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이때&amp;nbsp;(...)[]형식에서 소괄호는 앞서 배열의 요소의 타입을 의미하고 소괄호 내부의&amp;nbsp;number | string은 배열 요소의 타입이&amp;nbsp;string이거나&amp;nbsp;number일 것을 의미함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇듯&amp;nbsp;|를 이용해 여러 타입 중 하나를 만족하는 타입을 정의하는 문법을 &amp;ldquo;유니온 타입&amp;rdquo;이라고 부름&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다차원 배열 타입 정의하기&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다음과 같이&amp;nbsp;[]을 연달아 작성해 다차원 배열 타입도 정의할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let doubleArr: number[][] = [
	[1, 2, 3],
	[4, 5],
];

let doubleArr2: (number | string)[][] = [
	[1, 2, 3],
	[&quot;hi&quot;, 4],
];&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;튜플&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;튜플은 자바스크립트에는 없는 타입스크립트의 특수한 타입으로 &amp;ldquo;길이&amp;rdquo;와 &amp;ldquo;타입&amp;rdquo;이 고정된 배열을 의미함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;길이가 2로 고정된 2개의&amp;nbsp;number타입 요소를 갖는 튜플 타입은 다음과 같이 정의함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let tup1: [number, number] = [1, 2];

let tup2: [number, string, boolean] = [1, &quot;hi&quot;, true];&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;튜플은 결국 배열임.&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;튜플은 결국 배열이므로 배열 매서드인&amp;nbsp;push나&amp;nbsp;pop을 이용해 고정된 길이를 무시하고 요소를 추가하거나 삭제할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;let tup1: [number, number] = [1, 2];

tup1.push(1);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;따라서 튜플을 사용할 떄에는 최대한 배열 메서드를 이용해 요소를 추가하거나 삭제하는 등의 연산을 할 때에는 주의해야함.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;튜플은 왜 씀?&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;다음과 같이 회원 정보를 2차원 배열로 저장하는 상황을 가정해보겠음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;const users: [string, number][] = [
  [&quot;도서&quot;, 1],
  [&quot;이도서&quot;, 2],
  [&quot;김도서&quot;, 3],
  [&quot;박도서&quot;, 4],
  // [5, &quot;최도서&quot;] -&amp;gt; string과 number의 위치가 틀림 -&amp;gt; 오류 발생
  // 순서를 지키는게 중요할 때 튜플을 사용해서 값을 잘못 넣는 것을 방지!
];&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;각 배열의 0번 인덱스에는 회원의 이름, 1번 인덱스에는 회원의 아이디를 저장해 두었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;동료 중 한명이 다음과 같이 순서를 잘 못 배치해 요소를 추가할 경우 문제가 될 수 있음.&lt;/span&gt;&lt;/p&gt;</description>
      <category>React/TypeScript</category>
      <category>Typescript</category>
      <category>배열</category>
      <category>튜플</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/295</guid>
      <comments>https://leedoseo.tistory.com/295#entry295comment</comments>
      <pubDate>Fri, 6 Mar 2026 19:16:32 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 원시타입과 리터럴 타입</title>
      <link>https://leedoseo.tistory.com/294</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;  원시타입과 리터럴 타입&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;원시 타입(Primitive Type)은 동시에 한개의 값만 저장할 수 있는 타입들을 말함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;예를 들어 원시 타입이 아닌 배열이나 객체 같은 비 원시 타입들은 동시에 여러개의 값들을 저장할 수 있는 반면,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;number,&amp;nbsp;string,&amp;nbsp;boolean&amp;nbsp;등의 원시 타입은 숫자면 숫자, 문자열이면 문자열 딱 하나의 값만 저장할 수 있음 원시 타입은 여러 타입들중 가장 기본이 되는 타입임&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;number 타입&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;// number
let num1: number = 123;
let num2: number = -123;
let num3: number = 0.123;
let num4: number = -0.123;
let num5: number = Infinity;
let num6: number = -Infinity;
let num7: number = NaN;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;number타입은 자바스크립트에서 숫자를 의미하는 모든 값을 포함하는 타입임.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;단순 정수 뿐 아니라 소수, 음수,&amp;nbsp;Infinity,&amp;nbsp;NaN&amp;nbsp;등의 특수한 숫자들도 포함됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;참고로 변수의 이름 뒤에&amp;nbsp;:과 함께 변수의 타입을 정의하는 문법을 &amp;ldquo;타입 주석&amp;rdquo; 혹은 &amp;ldquo;타입 어노테이션&amp;rdquo; 이라고 함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;gcode&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;num1 = 'hello'; // X

num1.toUpperCase(); // X
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이때&amp;nbsp;number타입으로 정의한 변수에는&amp;nbsp;number&amp;nbsp;타입을 제외한 값을 할당할 수 없음.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;rArr; 그에 맞지않는 메서드도 사용 불가!&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;String 타입&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;qml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;// string
let str1: string = &quot;hello&quot;;
let str2: string = 'hello';
let str3: string = `hello`;
let str4: string = `hello ${str1}`;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;string&amp;nbsp;타입은 문자열을 의미하는 타입임&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&quot;&quot;,&amp;nbsp;'', 백틱, 템플릿 리터럴로 만든 모든 문자열을 포함함&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;boolean 타입&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;// boolean
let bool1: boolean = true;
let bool2: boolean = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;boolean&amp;nbsp;타입은 참과 거짓만을 저장하는 타입.&amp;nbsp;true&amp;nbsp;,&amp;nbsp;false만 이 타입에 해당됨&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;null 타입&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;// null
let null1: null = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;null&amp;nbsp;타입은 오직&amp;nbsp;null값만 포함하는 타입.&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;undefined 타입&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;// undefined 타입
let unde1: undefined = undefined;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;undefined&amp;nbsp;타입 역시&amp;nbsp;null타입과 마찬가지로 오직 하나의 값&amp;nbsp;undefined만 포함하는 타입&lt;/span&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;null 값을 다른 타입 변수에 할당하기&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;자바스크립트에서는 다음과 같이 아직 값이 정해지지 않은 상태에서는 변수에&amp;nbsp;null을 임시로 넣어두곤 했었음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;nix&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let numA = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;하지만 타입스크립트에서는 이&amp;nbsp;numA가 만약&amp;nbsp;number타입의 변수일 경우 오류가 발생함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let numA: number = null; // X
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;null은&amp;nbsp;number타입에 포함되는 값이 아니기 때문임!&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그런데,&amp;nbsp;null값을 변수의 임시값으로 활용할 때가 분명히 존재함.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;그럴 때는&amp;nbsp;tsconfig.json의&amp;nbsp;strictNullChecks(엄격한 null 검사)&amp;nbsp;옵션을 false로 설정하면 됨&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;clojure&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    ...
    &quot;strictNullChecks&quot;: false,
		...
  },
  &quot;ts-node&quot;: {
    &quot;esm&quot;: true
  },
  &quot;include&quot;: [&quot;src&quot;]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;리터럴 타입&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;타입스크립트에는&amp;nbsp;string,&amp;nbsp;number&amp;nbsp;처럼 범용적으로 많은 값을 포함하는 타입 뿐만 아니라 딱 하나의 값만 포함하는 타입도 존재함. 따라서 다음과 같이 변수의 타입을 숫자 10으로 설정하는 것 또한 가능함&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let numA: 10 = 10;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;변수&amp;nbsp;numA의 타입을 숫자 10으로 설정했음. 이렇게 설정하면&amp;nbsp;numA에는 10이외의 값을 저장할 수 없게 됨.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;이렇듯 하나의 값만 포함되도록 값 자체로 만들어진 타입을 타입스크립트에서는 &amp;ldquo;리터럴 타입&amp;rdquo;이라고 부름&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;숫자 값 뿐 아니라&amp;nbsp;string이나&amp;nbsp;boolean타입의 값도 모두 리터럴로 만들 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;let strA: &quot;hello&quot; = &quot;hello&quot;;
let boolA: true = true;
let boolB: false = false;
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>React/TypeScript</category>
      <category>Typescript</category>
      <category>리터럴타입</category>
      <category>원시타입</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/294</guid>
      <comments>https://leedoseo.tistory.com/294#entry294comment</comments>
      <pubDate>Fri, 6 Mar 2026 19:01:09 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript 심화] 이벤트 핸들링</title>
      <link>https://leedoseo.tistory.com/293</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 이벤트 핸들링 (Event Handling)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개념&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 웹페이지에서 발생하는 &lt;b&gt;사용자의 행동이나 브라우저의 동작임&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클릭, 키보드 입력, 스크롤, 폼 제출 등이 모두 이벤트임. 이벤트 핸들링은 이런 이벤트가 발생했을 때 실행할 코드(함수)를 연결하는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 이벤트 리스너 등록 방법&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const button = document.getElementById('myBtn');

// 방법 1: addEventListener (권장!)
button.addEventListener('click', function() {
    console.log('버튼이 클릭되었습니다!');
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`addEventListener`(이벤트타입, 콜백함수)&lt;/li&gt;
&lt;li&gt;첫 번째 인자: 이벤트 종류 (문자열) - 'click', 'keydown', 'submit' 등&lt;/li&gt;
&lt;li&gt;두 번째 인자: 이벤트 발생 시 실행할 함수 (이벤트 핸들러)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 화살표 함수로 더 간결하게
button.addEventListener('click', () =&amp;gt; {
    console.log('클릭!');
});

// 별도 함수로 분리 (재사용, 테스트 용이)
function handleClick() {
    console.log('클릭!');
}
button.addEventListener('click', handleClick);

// 주의: 함수를 &quot;호출&quot;하면 안 됨!
button.addEventListener('click', handleClick());  // 잘못됨
button.addEventListener('click', handleClick);    // 올바름&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`handleClick()`: 함수를 즉시 실행하고 그 반환값을 전달 (의도한 게 아님)&lt;/li&gt;
&lt;li&gt;`handleClick`: 함수 자체를 전달 (이벤트 발생 시 호출됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 리스너 제거&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 이벤트 리스너 제거
function handleClick() {
    console.log('클릭!');
}

button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick); // 동일한 함수 참조여야 제거됨

// 이건 제거 안 됨! (다른 함수 객체이므로)
button.addEventListener('click', function() { console.log('클릭!'); });
button.removeEventListener('click', function() { console.log('클릭!'); }); //&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 이벤트 리스너 등록&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 같은 요소에 여러 이벤트 리스너 등록 가능
button.addEventListener('click', () =&amp;gt; console.log('핸들러 1'));
button.addEventListener('click', () =&amp;gt; console.log('핸들러 2'));
// 클릭 시 둘 다 실행됨

// 다른 이벤트 타입도 등록 가능
button.addEventListener('mouseenter', () =&amp;gt; console.log('마우스 진입'));
button.addEventListener('mouseleave', () =&amp;gt; console.log('마우스 이탈'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3-2) 주요 이벤트 종류&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;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const box = document.getElementById('box');

// 클릭 이벤트
box.addEventListener('click', () =&amp;gt; {
    console.log('클릭됨');
});

// 더블클릭
box.addEventListener('dblclick', () =&amp;gt; {
    console.log('더블클릭됨');
});

// 마우스 진입/이탈 (자식 요소 무시)
box.addEventListener('mouseenter', () =&amp;gt; {
    console.log('마우스가 들어왔습니다');
    box.style.backgroundColor = 'yellow';
});

box.addEventListener('mouseleave', () =&amp;gt; {
    console.log('마우스가 나갔습니다');
    box.style.backgroundColor = '';
});

// 마우스 이동
box.addEventListener('mousemove', (e) =&amp;gt; {
    console.log(`마우스 위치: ${e.clientX}, ${e.clientY}`);
});

// 마우스 버튼 누름/뗌
box.addEventListener('mousedown', () =&amp;gt; console.log('마우스 버튼 누름'));
box.addEventListener('mouseup', () =&amp;gt; console.log('마우스 버튼 뗌'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키보드 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const input = document.getElementById('myInput');

// 키를 누를 때 (키가 눌려있는 동안 반복 발생 가능)
input.addEventListener('keydown', (e) =&amp;gt; {
    console.log('keydown:', e.key);
});

// 키를 뗄 때
input.addEventListener('keyup', (e) =&amp;gt; {
    console.log('keyup:', e.key);
});

// 실용 예시: Enter 키 감지
input.addEventListener('keydown', (e) =&amp;gt; {
    if (e.key === 'Enter') {
        console.log('엔터가 눌렸습니다!');
        console.log('입력값:', input.value);
    }
});

// Escape 키로 입력 취소
input.addEventListener('keydown', (e) =&amp;gt; {
    if (e.key === 'Escape') {
        input.value = '';
        input.blur(); // 포커스 해제
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;폼 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const form = document.getElementById('myForm');
const input = document.getElementById('myInput');
const select = document.getElementById('mySelect');

// 폼 제출
form.addEventListener('submit', (e) =&amp;gt; {
    e.preventDefault(); // 페이지 새로고침 방지 (매우 중요!)
    console.log('폼이 제출되었습니다');
    // 여기서 데이터 처리...
});

// input 이벤트: 값이 변경될 때마다 실시간으로 발생
input.addEventListener('input', (e) =&amp;gt; {
    console.log('현재 입력값:', e.target.value);
});

// change 이벤트: 값이 변경되고 포커스를 잃을 때 발생
input.addEventListener('change', (e) =&amp;gt; {
    console.log('최종 값:', e.target.value);
});

// select, checkbox, radio는 change 이벤트가 더 적합
select.addEventListener('change', (e) =&amp;gt; {
    console.log('선택된 값:', e.target.value);
});

// 포커스 이벤트
input.addEventListener('focus', () =&amp;gt; {
    console.log('입력 필드에 포커스됨');
    input.style.borderColor = 'blue';
});

input.addEventListener('blur', () =&amp;gt; {
    console.log('입력 필드에서 포커스 해제됨');
    input.style.borderColor = '';
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;input vs change 차이&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;`input`: 타이핑할 때마다 실시간 발생 (검색 자동완성 등에 사용)&lt;/li&gt;
&lt;li&gt;`change`: 입력을 완료하고 포커스를 잃을 때 한 번 발생 (폼 저장 등에 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;윈도우/문서 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 페이지 로드 완료 (이미지 등 모든 리소스 포함)
window.addEventListener('load', () =&amp;gt; {
    console.log('페이지 완전히 로드됨');
});

// DOM만 로드 완료 (더 빠름, 보통 이걸 사용)
document.addEventListener('DOMContentLoaded', () =&amp;gt; {
    console.log('DOM 로드 완료');
    // 여기서 DOM 조작 시작
});

// 스크롤
window.addEventListener('scroll', () =&amp;gt; {
    console.log('스크롤 위치:', window.scrollY);
});

// 창 크기 변경
window.addEventListener('resize', () =&amp;gt; {
    console.log('창 크기:', window.innerWidth, window.innerHeight);
});&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3-3) 이벤트 객체 (Event Object)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트가 발생하면 브라우저가 자동으로 이벤트에 대한 정보를 담은 객체를 핸들러에 전달&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;button.addEventListener('click', function(event) {
    // event (또는 e로 줄여서 씀)에 이벤트 정보가 담겨 있음
    console.log(event);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;div&gt;
&lt;div&gt;
&lt;pre class=&quot;scilab&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;element.addEventListener('click', function(e) {
    // 이벤트 종류
    console.log(e.type);          // 'click'

    // 이벤트가 발생한 요소 (실제로 클릭된 요소)
    console.log(e.target);        // 클릭된 요소

    // 이벤트 리스너가 등록된 요소
    console.log(e.currentTarget); // 핸들러가 붙은 요소

    // 마우스 좌표
    console.log(e.clientX);       // 뷰포트 기준 X 좌표
    console.log(e.clientY);       // 뷰포트 기준 Y 좌표
    console.log(e.pageX);         // 문서 기준 X 좌표 (스크롤 포함)
    console.log(e.pageY);         // 문서 기준 Y 좌표

    // 이벤트 발생 시간
    console.log(e.timeStamp);     // 밀리초 단위 타임스탬프
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;target vs currentTarget&lt;/b&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;html xml&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;outer&quot;&amp;gt;
    &amp;lt;button id=&quot;inner&quot;&amp;gt;클릭&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;document.getElementById('outer').addEventListener('click', function(e) {
    console.log('target:', e.target.id);         // 'inner' (실제 클릭된 요소)
    console.log('currentTarget:', e.currentTarget.id); // 'outer' (핸들러가 붙은 요소)
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;버튼을 클릭하면 버블링으로 인해 div의 핸들러도 실행됨&lt;/li&gt;
&lt;li&gt;`target`: 실제로 클릭한 요소 (button)&lt;/li&gt;
&lt;li&gt;`currentTarget`: 이 핸들러가 등록된 요소 (div)&lt;/li&gt;
&lt;li&gt;이벤트 위임 패턴에서 이 차이가 중요함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;키보드 이벤트 객체&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lua&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;input.addEventListener('keydown', function(e) {
    console.log(e.key);      // 눌린 키: 'a', 'Enter', 'Escape', 'ArrowUp' 등
    console.log(e.code);     // 물리적 키 코드: 'KeyA', 'Enter', 'Escape' 등
    console.log(e.shiftKey); // Shift 키 눌림 여부 (true/false)
    console.log(e.ctrlKey);  // Ctrl 키 눌림 여부
    console.log(e.altKey);   // Alt 키 눌림 여부
    console.log(e.metaKey);  // Meta 키 (Mac의 Cmd) 눌림 여부

    // 단축키 구현 예시: Ctrl + S
    if (e.ctrlKey &amp;amp;&amp;amp; e.key === 's') {
        e.preventDefault(); // 브라우저 기본 저장 대화상자 방지
        console.log('저장 단축키!');
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;key vs code 차이&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;`key`: 입력된 문자 ('a', 'A', 'ㄱ' 등 - 언어/Shift 영향 받음)&lt;/li&gt;
&lt;li&gt;`code`: 물리적 키 위치 ('KeyA' - 어떤 키보드든 동일)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 기본 동작 방지 &amp;amp; 이벤트 전파 중단&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;preventDefault() - 기본 동작 방지&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 1. 폼 제출 시 페이지 새로고침 방지
const form = document.querySelector('form');
form.addEventListener('submit', function(e) {
    e.preventDefault(); // 폼의 기본 동작(페이지 이동) 막기
    
    console.log('폼 데이터를 JavaScript로 처리합니다');
    // fetch로 서버에 데이터 전송 등...
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`&amp;lt;form&amp;gt;`의 기본 동작: 제출 시 지정된 URL로 이동 또는 새로고침&lt;/li&gt;
&lt;li&gt;SPA(Single Page Application)에서는 이걸 막고 JavaScript로 처리&lt;/li&gt;
&lt;li&gt;React에서 폼 다룰 때도 항상 `e.preventDefault()` 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 2. 링크 클릭 시 페이지 이동 방지
const link = document.querySelector('a');
link.addEventListener('click', function(e) {
    e.preventDefault(); // 링크 이동 막기
    
    console.log('링크 클릭됨, 하지만 이동 안 함');
    // 대신 모달을 띄우거나 다른 작업 수행
});

// 3. 우클릭 메뉴 막기
document.addEventListener('contextmenu', function(e) {
    e.preventDefault();
    console.log('커스텀 메뉴를 띄울 수 있음');
});

// 4. 특정 키 입력 막기 (숫자만 입력 가능하게)
input.addEventListener('keydown', function(e) {
    // 숫자가 아니면 입력 막기
    if (!/[0-9]/.test(e.key) &amp;amp;&amp;amp; e.key !== 'Backspace') {
        e.preventDefault();
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;stopPropagation() - 이벤트 버블링 중단&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;html xml&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;outer&quot;&amp;gt;
    &amp;lt;div id=&quot;inner&quot;&amp;gt;
        &amp;lt;button id=&quot;btn&quot;&amp;gt;클릭&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;coffeescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;document.getElementById('outer').addEventListener('click', () =&amp;gt; {
    console.log('outer 클릭!');
});

document.getElementById('inner').addEventListener('click', () =&amp;gt; {
    console.log('inner 클릭!');
});

document.getElementById('btn').addEventListener('click', (e) =&amp;gt; {
    e.stopPropagation(); // 버블링 중단!
    console.log('button 클릭!');
});

// 버튼 클릭 시 출력:
// &quot;button 클릭!&quot; 만 출력됨
// inner, outer로는 이벤트가 전파되지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`stopPropagation()`을 호출하면 이벤트가 부모로 전파되지 않음&lt;/li&gt;
&lt;li&gt;특정 요소에서만 이벤트를 처리하고 싶을 때 사용&lt;/li&gt;
&lt;li&gt;남용하면 디버깅이 어려워지므로 꼭 필요할 때만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) 이벤트 버블링 &amp;amp; 캡처링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 버블링 (Bubbling)&lt;/b&gt;: 이벤트가 발생하면 해당 요소에서 시작해서 &lt;b&gt;부모 요소들로 전파됨&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;html xml&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;grandparent&quot;&amp;gt;
    &amp;lt;div id=&quot;parent&quot;&amp;gt;
        &amp;lt;button id=&quot;child&quot;&amp;gt;클릭&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;document.getElementById('grandparent').addEventListener('click', () =&amp;gt; {
    console.log('grandparent');
});
document.getElementById('parent').addEventListener('click', () =&amp;gt; {
    console.log('parent');
});
document.getElementById('child').addEventListener('click', () =&amp;gt; {
    console.log('child');
});

// 버튼 클릭 시 출력 순서:
// child
// parent
// grandparent&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;버튼을 클릭하면 버튼 &amp;rarr; 부모 div &amp;rarr; 조부모 div 순서로 이벤트 전파&lt;/li&gt;
&lt;li&gt;마치 거품이 올라가는 것처럼 아래에서 위로 전파 (그래서 &quot;버블링&quot;)&lt;/li&gt;
&lt;li&gt;이게 기본 동작이고, 이벤트 위임 패턴의 핵심 원리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 캡처링 (Capturing)&lt;/b&gt;: 버블링과 반대로 &lt;b&gt;위에서 아래로&lt;/b&gt; 전파되는 단계&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;typescript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 세 번째 인자를 true로 설정하면 캡처링 단계에서 실행
document.getElementById('grandparent').addEventListener('click', () =&amp;gt; {
    console.log('grandparent (캡처링)');
}, true); // true = 캡처링 단계에서 실행

document.getElementById('parent').addEventListener('click', () =&amp;gt; {
    console.log('parent (캡처링)');
}, true);

document.getElementById('child').addEventListener('click', () =&amp;gt; {
    console.log('child');
}); // 기본값 false = 버블링 단계에서 실행

// 버튼 클릭 시 출력 순서:
// grandparent (캡처링)  - 캡처링: 위에서 아래로
// parent (캡처링)
// child                 - 타겟 단계
// (버블링 핸들러가 있다면 여기서 아래&amp;rarr;위로)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이벤트 전파 3단계&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;캡처링 단계&lt;/b&gt;: window &amp;rarr; document &amp;rarr; ... &amp;rarr; 타겟의 부모 (위&amp;rarr;아래)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타겟 단계&lt;/b&gt;: 실제 이벤트가 발생한 요소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버블링 단계&lt;/b&gt;: 타겟의 부모 &amp;rarr; ... &amp;rarr; document &amp;rarr; window (아래&amp;rarr;위)&lt;/li&gt;
&lt;/ol&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-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3-6) 이벤트 위임 (Event Delegation)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개념&lt;/b&gt;: 이벤트 버블링을 활용해서 &lt;b&gt;부모 요소 하나에만 이벤트 리스너를 등록&lt;/b&gt;하고, 자식 요소들의 이벤트를 처리하는 패턴.&lt;/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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;: 리스너 개수를 줄여 메모리 절약&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 요소&lt;/b&gt;: 나중에 추가되는 요소도 자동으로 처리됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드 간결&lt;/b&gt;: 하나의 핸들러로 여러 요소 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;html xml&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;ul id=&quot;todoList&quot;&amp;gt;
    &amp;lt;li&amp;gt;할 일 1 &amp;lt;button class=&quot;delete&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;할 일 2 &amp;lt;button class=&quot;delete&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;할 일 3 &amp;lt;button class=&quot;delete&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;안 좋은 방법 (각 버튼에 개별 리스너)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const deleteButtons = document.querySelectorAll('.delete');

deleteButtons.forEach(btn =&amp;gt; {
    btn.addEventListener('click', function() {
        this.parentElement.remove();
    });
});

// 문제점:
// 1. 버튼 100개면 리스너도 100개 (메모리 낭비)
// 2. 나중에 동적으로 추가된 li에는 이벤트가 안 붙음!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;좋은 방법 (이벤트 위임)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const todoList = document.getElementById('todoList');

todoList.addEventListener('click', function(e) {
    // 클릭된 요소가 delete 버튼인지 확인
    if (e.target.classList.contains('delete')) {
        // 버튼의 부모(li)를 삭제
        e.target.parentElement.remove();
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;삭제 버튼을 클릭함&lt;/li&gt;
&lt;li&gt;이벤트가 버블링되어 ul까지 올라감&lt;/li&gt;
&lt;li&gt;ul에 등록된 핸들러가 실행됨&lt;/li&gt;
&lt;li&gt;`e.target`으로 실제 클릭된 요소(버튼)를 확인&lt;/li&gt;
&lt;li&gt;버튼이 맞으면 해당 작업 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;p 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;리스너가 1개뿐 (버튼이 몇 개든 상관없음)&lt;/li&gt;
&lt;li&gt;나중에 li가 추가되어도 자동으로 동작함!&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 나중에 추가된 요소도 잘 동작함
const newLi = document.createElement('li');
newLi.innerHTML = '새 할 일 &amp;lt;button class=&quot;delete&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;';
todoList.appendChild(newLi);
// 새 삭제 버튼도 클릭하면 잘 삭제됨!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;더 복잡한 이벤트 위임 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;&amp;lt;ul id=&quot;todoList&quot;&amp;gt;
    &amp;lt;li data-id=&quot;1&quot;&amp;gt;
        &amp;lt;span class=&quot;todo-text&quot;&amp;gt;할 일 1&amp;lt;/span&amp;gt;
        &amp;lt;button class=&quot;edit&quot;&amp;gt;수정&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;delete&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;
        &amp;lt;button class=&quot;complete&quot;&amp;gt;완료&amp;lt;/button&amp;gt;
    &amp;lt;/li&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const todoList = document.getElementById('todoList');

todoList.addEventListener('click', function(e) {
    const target = e.target;
    const li = target.closest('li'); // 가장 가까운 li 조상 찾기
    
    if (!li) return; // li 안의 요소가 아니면 무시
    
    const todoId = li.dataset.id; // data-id 값 가져오기

    if (target.classList.contains('delete')) {
        console.log(`${todoId}번 삭제`);
        li.remove();
    }
    
    if (target.classList.contains('edit')) {
        console.log(`${todoId}번 수정`);
        // 수정 로직...
    }
    
    if (target.classList.contains('complete')) {
        console.log(`${todoId}번 완료`);
        li.querySelector('.todo-text').classList.toggle('completed');
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;closest() 메서드&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;`e.target.closest('li')`: target에서 시작해서 위로 올라가며 'li'를 찾음&lt;/li&gt;
&lt;li&gt;버튼 안에 아이콘이 있어도 안전하게 li를 찾을 수 있음&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>javascript</category>
      <category>이벤트 핸들링</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/293</guid>
      <comments>https://leedoseo.tistory.com/293#entry293comment</comments>
      <pubDate>Wed, 3 Dec 2025 17:22:19 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript 심화] DOM</title>
      <link>https://leedoseo.tistory.com/292</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DOM 이란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DOM은 &lt;b&gt;HTML 문서를 JavaScript가 이해할 수 있는 객체 트리 구조로 표현한 것&lt;/b&gt;입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;브라우저가 HTML을 파싱하면 DOM 트리가 만들어지고, JavaScript로 이 트리를 조작해서 웹페이지를 동적으로 변경할 수 있음. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, HTML은 단순한 텍스트 파일인데, 브라우저가 이걸 읽어서 JavaScript가 조작할 수 있는 &quot;객체들의 집합&quot;으로 바꿔놓은 것임&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764748078030&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTML 문서가 이렇게 되어 있으면
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;제목&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&quot;container&quot;&amp;gt;
      &amp;lt;h1&amp;gt;안녕&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;내용&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1764748097149&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DOM 트리는 이런 구조가 됨
document
  └── html
       ├── head
       │    └── title
       │         └── &quot;제목&quot; (텍스트 노드)
       └── body
            └── div#container
                 ├── h1
                 │    └── &quot;안녕&quot;
                 └── p
                      └── &quot;내용&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) DOM 요소 선택하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM을 조작하려면 먼저 원하는 요소를 선택해야 함&lt;/p&gt;
&lt;pre id=&quot;code_1764748152894&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 예시 HTML --&amp;gt;
&amp;lt;div id=&quot;header&quot;&amp;gt;헤더&amp;lt;/div&amp;gt;
&amp;lt;p class=&quot;item&quot;&amp;gt;아이템 1&amp;lt;/p&amp;gt;
&amp;lt;p class=&quot;item&quot;&amp;gt;아이템 2&amp;lt;/p&amp;gt;
&amp;lt;p class=&quot;item&quot;&amp;gt;아이템 3&amp;lt;/p&amp;gt;
&amp;lt;button&amp;gt;버튼 1&amp;lt;/button&amp;gt;
&amp;lt;button&amp;gt;버튼 2&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1764748170769&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. getElementById - ID로 선택 (단일 요소)
const header = document.getElementById('header');
console.log(header); // &amp;lt;div id=&quot;header&quot;&amp;gt;헤더&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML에서 `id`는 문서 내에서 유일해야 함&lt;/li&gt;
&lt;li&gt;따라서 항상 &lt;b&gt;하나의 요소&lt;/b&gt;만 반환&lt;/li&gt;
&lt;li&gt;해당 ID가 없으면 `null` 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764748294801&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 2. getElementsByClassName - 클래스로 선택 (여러 요소)
const items = document.getElementsByClassName('item');
console.log(items);        // HTMLCollection(3) [p.item, p.item, p.item]
console.log(items.length); // 3
console.log(items[0]);     // &amp;lt;p class=&quot;item&quot;&amp;gt;아이템 1&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 클래스를 가진 요소가 여러 개일 수 있으므로 &lt;b&gt;HTMLCollection&lt;/b&gt; 반환&lt;/li&gt;
&lt;li&gt;HTMLCollection은 배열처럼 생겼지만 진짜 배열은 아님 (유사 배열)&lt;/li&gt;
&lt;li&gt;인덱스로 접근 가능 (`items[0]`, `items[1]` 등)&lt;/li&gt;
&lt;li&gt;`map`, `filter` 같은 배열 메서드 직접 사용 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;dart&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 3. querySelector - CSS 선택자로 첫 번째 요소 선택 (가장 많이 씀!)
const firstItem = document.querySelector('.item');      // 클래스 선택
const header2 = document.querySelector('#header');      // ID 선택
const firstButton = document.querySelector('button');   // 태그 선택
const complex = document.querySelector('div.container &amp;gt; p'); // 복잡한 선택자&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;CSS에서 쓰는 선택자를 그대로 사용할 수 있음&lt;/li&gt;
&lt;li&gt;`.클래스`, `#아이디`, `태그`, `부모 &amp;gt; 자식` 등 모든 CSS 선택자 사용 가능&lt;/li&gt;
&lt;li&gt;여러 요소가 매칭되어도 &lt;b&gt;첫 번째 것만&lt;/b&gt; 반환&lt;/li&gt;
&lt;li&gt;실무에서 가장 많이 사용하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 4. querySelectorAll - CSS 선택자로 모든 요소 선택
const allItems = document.querySelectorAll('.item');
console.log(allItems); // NodeList(3) [p.item, p.item, p.item]

// NodeList는 forEach 사용 가능!
allItems.forEach(item =&amp;gt; {
    console.log(item.textContent);
});
// 아이템 1
// 아이템 2
// 아이템 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;b&gt;NodeList&lt;/b&gt;로 반환&lt;/li&gt;
&lt;li&gt;NodeList는 `forEach` 사용 가능 (HTMLCollection과의 차이점)&lt;/li&gt;
&lt;li&gt;`map`, `filter` 등은 바로 사용 불가, 배열로 변환 필요: `Array.from(allItems)`&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;querySelector vs getElementById&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;`getElementById`가 약간 더 빠름&lt;/li&gt;
&lt;li&gt;하지만 `querySelector`가 더 유연하고 일관성 있음&lt;/li&gt;
&lt;li&gt;실무에서는 대부분 `querySelector` / `querySelectorAll` 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) DOM 요소 조작하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소를 선택했으면 이제 내용, 스타일, 속성 등을 변경할 수 있음.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;&amp;lt;!-- 예시 HTML --&amp;gt;
&amp;lt;div id=&quot;container&quot;&amp;gt;
    &amp;lt;h1 id=&quot;title&quot;&amp;gt;안녕하세요&amp;lt;/h1&amp;gt;
    &amp;lt;p id=&quot;description&quot;&amp;gt;설명 텍스트입니다.&amp;lt;/p&amp;gt;
    &amp;lt;button id=&quot;myBtn&quot;&amp;gt;클릭&amp;lt;/button&amp;gt;
    &amp;lt;img id=&quot;myImg&quot; src=&quot;photo.jpg&quot; alt=&quot;사진&quot;&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;텍스트 내용 변경&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xl&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const title = document.getElementById('title');

// textContent: 순수 텍스트만 (HTML 태그는 그대로 텍스트로 표시됨)
title.textContent = '반갑습니다';
console.log(title); // &amp;lt;h1 id=&quot;title&quot;&amp;gt;반갑습니다&amp;lt;/h1&amp;gt;

title.textContent = '&amp;lt;span&amp;gt;테스트&amp;lt;/span&amp;gt;';
// 화면에 &quot;&amp;lt;span&amp;gt;테스트&amp;lt;/span&amp;gt;&quot; 라는 텍스트가 그대로 보임

// innerHTML: HTML을 파싱해서 적용
title.innerHTML = '&amp;lt;span style=&quot;color: red&quot;&amp;gt;빨간 텍스트&amp;lt;/span&amp;gt;';
// 화면에 빨간색으로 &quot;빨간 텍스트&quot;가 보임&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`textContent`: 안전함, XSS 공격 방지 (사용자 입력 표시할 때 권장)&lt;/li&gt;
&lt;li&gt;`innerHTML`: HTML 태그 해석됨, 동적 HTML 삽입 시 사용&lt;/li&gt;
&lt;li&gt;보안상 사용자가 입력한 값은 `textContent`로 표시하는 게 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스타일 변경&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;maxima&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const title = document.getElementById('title');

// style 속성으로 인라인 스타일 적용
title.style.color = 'red';
title.style.fontSize = '24px';           // CSS: font-size &amp;rarr; JS: fontSize (카멜케이스)
title.style.backgroundColor = '#f0f0f0'; // CSS: background-color &amp;rarr; JS: backgroundColor
title.style.padding = '10px';
title.style.border = '1px solid black';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;CSS 속성명에서 `-`를 빼고 카멜케이스로 변환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`font-size` &amp;rarr; `fontSize`&lt;/li&gt;
&lt;li&gt;`background-color` &amp;rarr; `backgroundColor`&lt;/li&gt;
&lt;li&gt;`border-radius` &amp;rarr; `borderRadius`&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;값은 문자열로 전달 (단위 포함)&lt;/li&gt;
&lt;li&gt;인라인 스타일이므로 우선순위가 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클래스 조작&lt;/b&gt; (스타일 변경의 권장 방법)&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xl&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const title = document.getElementById('title');

// 클래스 추가
title.classList.add('active');
title.classList.add('highlight', 'bold'); // 여러 개 동시에 추가 가능

// 클래스 제거
title.classList.remove('active');

// 클래스 토글 (있으면 제거, 없으면 추가)
title.classList.toggle('active'); // 없으면 추가됨
title.classList.toggle('active'); // 있으면 제거됨

// 클래스 존재 여부 확인
if (title.classList.contains('active')) {
    console.log('active 클래스가 있습니다');
}

// 클래스 교체
title.classList.replace('old-class', 'new-class');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;직접 style을 변경하는 것보다 클래스를 추가/제거하는 게 더 좋은 방법&lt;/li&gt;
&lt;li&gt;CSS 파일에 스타일을 정의해두고, JS에서는 클래스만 조작&lt;/li&gt;
&lt;li&gt;유지보수와 관심사 분리 측면에서 권장되는 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;/* CSS 파일 */
.active {
    color: red;
    font-weight: bold;
}
.hidden {
    display: none;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// JS에서는 클래스만 조작
element.classList.add('active');    // 빨간색 + 굵게
element.classList.add('hidden');    // 숨기기
element.classList.remove('hidden'); // 다시 보이기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;속성(Attribute) 조작&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const img = document.getElementById('myImg');
const btn = document.getElementById('myBtn');

// 속성 값 가져오기
console.log(img.getAttribute('src')); // 'photo.jpg'
console.log(img.getAttribute('alt')); // '사진'

// 속성 값 설정하기
img.setAttribute('src', 'new-photo.jpg');
img.setAttribute('alt', '새로운 사진');

// 속성 제거하기
btn.setAttribute('disabled', 'true'); // 버튼 비활성화
btn.removeAttribute('disabled');       // 버튼 다시 활성화

// 속성 존재 여부 확인
if (img.hasAttribute('alt')) {
    console.log('alt 속성이 있습니다');
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;HTML 요소의 속성(src, href, alt, disabled 등)을 읽고 쓸 수 있음&lt;/li&gt;
&lt;li&gt;`data-*` 커스텀 속성도 조작 가능&lt;/li&gt;
&lt;li&gt;`disabled`, `checked`, `selected` 같은 불리언 속성도 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// data-* 속성 활용 (커스텀 데이터 저장)
// HTML: &amp;lt;div id=&quot;user&quot; data-user-id=&quot;123&quot; data-role=&quot;admin&quot;&amp;gt;

const user = document.getElementById('user');

// dataset으로 접근 (data- 접두사 제외, 카멜케이스로)
console.log(user.dataset.userId); // '123'
console.log(user.dataset.role);   // 'admin'

user.dataset.status = 'active';   // data-status=&quot;active&quot; 추가됨&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) DOM 요소 생성 및 추가/삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 새 요소를 만들어서 페이지에 추가하거나, 기존 요소를 삭제할 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요소 생성 및 추가&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;haxe&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 1. 새 요소 생성
const newDiv = document.createElement('div');

// 2. 내용 및 속성 설정
newDiv.textContent = '새로 만든 div입니다';
newDiv.classList.add('new-item');
newDiv.id = 'newElement';
newDiv.style.backgroundColor = 'yellow';

// 3. DOM에 추가
const container = document.getElementById('container');

container.appendChild(newDiv);        // container의 맨 뒤에 추가
// 또는
container.prepend(newDiv);            // container의 맨 앞에 추가
// 또는
container.insertBefore(newDiv, 기준요소); // 특정 요소 앞에 추가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`createElement`로 요소를 만들면 아직 DOM에 연결되지 않은 상태&lt;/li&gt;
&lt;li&gt;메모리에만 존재하는 &quot;떠 있는&quot; 요소&lt;/li&gt;
&lt;li&gt;`appendChild` 등으로 DOM에 연결해야 화면에 나타남&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 실용 예시: 리스트 아이템 동적 추가
const ul = document.querySelector('ul');

function addItem(text) {
    const li = document.createElement('li');
    li.textContent = text;
    ul.appendChild(li);
}

addItem('첫 번째 아이템');
addItem('두 번째 아이템');
addItem('세 번째 아이템');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 요소 효율적으로 추가 (DocumentFragment)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const ul = document.querySelector('ul');
const items = ['사과', '바나나', '오렌지', '포도', '수박'];

// 비효율적인 방법: 매번 DOM에 접근
items.forEach(item =&amp;gt; {
    const li = document.createElement('li');
    li.textContent = item;
    ul.appendChild(li); // 매번 DOM이 다시 그려짐 (5번)
});

// 효율적인 방법: DocumentFragment 사용
const fragment = document.createDocumentFragment();

items.forEach(item =&amp;gt; {
    const li = document.createElement('li');
    li.textContent = item;
    fragment.appendChild(li); // fragment에 모음 (DOM 변경 없음)
});

ul.appendChild(fragment); // 한 번에 DOM에 추가 (1번만 다시 그림)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`DocumentFragment`는 가상의 컨테이너&lt;/li&gt;
&lt;li&gt;여기에 요소들을 모았다가 한 번에 DOM에 추가하면 성능이 좋음&lt;/li&gt;
&lt;li&gt;DOM 조작은 비용이 크기 때문에 최소화하는 게 좋음&lt;/li&gt;
&lt;li&gt;React가 이런 최적화를 자동으로 해줌 (Virtual DOM)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요소 삭제&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const title = document.getElementById('title');
const container = document.getElementById('container');

// 방법 1: 자기 자신 삭제 (모던 방식)
title.remove();

// 방법 2: 부모에서 자식 삭제 (구 방식, IE 지원 필요시)
container.removeChild(title);

// 모든 자식 요소 삭제
container.innerHTML = ''; // 간단하지만 이벤트 리스너도 같이 제거됨

// 또는 하나씩 제거
while (container.firstChild) {
    container.removeChild(container.firstChild);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요소 교체&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const oldElement = document.getElementById('old');
const newElement = document.createElement('div');
newElement.textContent = '새로운 요소';

// 교체
oldElement.replaceWith(newElement); // 모던 방식
// 또는
oldElement.parentNode.replaceChild(newElement, oldElement); // 구 방식&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-4) DOM 탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 요소를 기준으로 부모, 자식, 형제 요소를 찾을 수 있음&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;parent&quot;&amp;gt;
    &amp;lt;p id=&quot;first&quot;&amp;gt;첫째&amp;lt;/p&amp;gt;
    &amp;lt;p id=&quot;second&quot;&amp;gt;둘째&amp;lt;/p&amp;gt;
    &amp;lt;p id=&quot;third&quot;&amp;gt;셋째&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;qml&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const second = document.getElementById('second');

// 부모 요소
console.log(second.parentElement);         // &amp;lt;div id=&quot;parent&quot;&amp;gt;...&amp;lt;/div&amp;gt;

// 형제 요소
console.log(second.previousElementSibling); // &amp;lt;p id=&quot;first&quot;&amp;gt;첫째&amp;lt;/p&amp;gt;
console.log(second.nextElementSibling);     // &amp;lt;p id=&quot;third&quot;&amp;gt;셋째&amp;lt;/p&amp;gt;

// 부모의 모든 자식 요소
const parent = document.getElementById('parent');
console.log(parent.children);              // HTMLCollection(3) [p, p, p]
console.log(parent.firstElementChild);     // &amp;lt;p id=&quot;first&quot;&amp;gt;첫째&amp;lt;/p&amp;gt;
console.log(parent.lastElementChild);      // &amp;lt;p id=&quot;third&quot;&amp;gt;셋째&amp;lt;/p&amp;gt;
console.log(parent.childElementCount);     // 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;`parentElement`: 바로 위 부모&lt;/li&gt;
&lt;li&gt;`children`: 모든 직계 자식 (HTMLCollection)&lt;/li&gt;
&lt;li&gt;`firstElementChild` / `lastElementChild`: 첫 번째/마지막 자식&lt;/li&gt;
&lt;li&gt;`previousElementSibling` / `nextElementSibling`: 이전/다음 형제&lt;/li&gt;
&lt;li&gt;이런 탐색 메서드를 사용하면 DOM 구조를 따라 이동할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 실용 예시: 클릭한 버튼의 부모 li 삭제
document.querySelector('ul').addEventListener('click', function(e) {
    if (e.target.tagName === 'BUTTON') {
        const li = e.target.parentElement; // 버튼의 부모인 li
        li.remove();
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;</description>
      <category>DOM</category>
      <category>javascript</category>
      <category>돔</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/292</guid>
      <comments>https://leedoseo.tistory.com/292#entry292comment</comments>
      <pubDate>Wed, 3 Dec 2025 17:02:55 +0900</pubDate>
    </item>
    <item>
      <title>[JavaScript 심화] 고차함수 총정리(복습)</title>
      <link>https://leedoseo.tistory.com/291</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 고차함수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개념&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고차함수는 &lt;b&gt;함수를 인자로 받거나, 함수를 반환하는 함수&lt;/b&gt;임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaSCript에서 함수는 &quot;일급 객체&quot;이기 때문에 변수에 담거나, 다른 함수에 전달하거나 반환할 수 있음&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;통 함수는 숫자나 문자열 같은 &quot;값&quot;을&lt;/b&gt; 받지만, &lt;b&gt;고차함수는 &quot;함수 자체&quot;를 값처럼 주고 받는 함수&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;size18&quot;&gt;&lt;b&gt;대표적인 고차함수들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) forEach - 배열 순회&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764744577566&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fruits = ['사과', '바나나', '오렌지'];

fruits.forEach(function(fruit, index) {
    console.log(`${index}: ${fruit}`);
});

// 화살표 함수로 더 간단하게
fruits.forEach((fruit, index) =&amp;gt; {
    console.log(`${index}: ${fruit}`);
});

// 출력:
// 0: 사과
// 1: 바나나
// 2: 오렌지&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`forEach`는 배열의 요소를 처음부터 끝까지 하나씩 순회함&lt;/li&gt;
&lt;li&gt;콜백 함수에 전달되는 인자: 첫 번째는 현재 요(`fruit`), 두 번째는 인덱스(`index`)&lt;/li&gt;
&lt;li&gt;1회차: `fruit = 사과`, `index = 0` -&amp;gt; &quot;0:사과&quot; 출력&lt;/li&gt;
&lt;li&gt;2회차: `fruit = 바나나`, `index = 1` -&amp;gt; &quot;1:바나나&quot; 출력&lt;/li&gt;
&lt;li&gt;3회차: `fruit = 오렌지`, `index = 2` -&amp;gt; &quot;2:오렌지&quot; 출력&amp;nbsp;&lt;/li&gt;
&lt;li&gt;반환값이 없음 (undefined) - 단순히 실행만 하고 끝&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 화살표 함수를 더 자주 쓰기 때문에 화살표 함수로 줄여쓰는 습관을 들여보자&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) map - 배열 변환 (새 배열 반환)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1764745074881&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(num =&amp;gt; num * 2);

console.log(doubled);   // [2, 4, 6, 8, 10]
console.log(numbers);   // [1, 2, 3, 4, 5] - 원본은 그대로!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`map`은 배열의 각 요소에 함수를 적용하고, 그 결과들을 모아 새 배열을 반환함&lt;/li&gt;
&lt;li&gt;콜백 함수가 `return`하는 값이 새 배열의 요소가 됨&lt;/li&gt;
&lt;li&gt;1회차: `num = 1` -&amp;gt; `1 * 2 = 2` 반환&lt;/li&gt;
&lt;li&gt;2회차: `num = 2` -&amp;gt; `2 * 2 = 4` 반환&lt;/li&gt;
&lt;li&gt;... 5회차 : `num = 5` -&amp;gt; `5 * 2 = 10` 반환&lt;/li&gt;
&lt;li&gt;최종적으로 `[2, 4, 6, 8, 10]` 이라는 새 배열이 만들어짐&lt;/li&gt;
&lt;li&gt;원본 배열 `numbers`는 변하지 않음!!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;forEach와 map 차이&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;`forEach`: 반환값 없음, 단순히 각 요소에 대해 작업 수행&lt;/li&gt;
&lt;li&gt;`map` : 새 배열 반환, 변환된 결과를 담은 배열이 필요할 때 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1764745297935&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실제로 많이 쓰는 패턴: 객체 배열에서 특정 속성만 추출
const users = [
    { id: 1, name: '김철수', age: 25 },
    { id: 2, name: '이영희', age: 30 },
    { id: 3, name: '박민수', age: 28 }
];

const userNames = users.map(user =&amp;gt; user.name);
console.log(userNames); // ['김철수', '이영희', '박민수']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 `user`객체에서 `name` 속성만 꺼내서 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764745410491&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 객체를 다른 형태의 객체로 변환
const userCards = users.map(user =&amp;gt; {
    return {
        displayName: `${user.name} (${user.age}세)`,
        isAdult: user.age &amp;gt;= 18
    };
});

console.log(userCards);
// [
//   { displayName: '김철수 (25세)', isAdult: true },
//   { displayName: '이영희 (30세)', isAdult: true },
//   { displayName: '박민수 (28세)', isAdult: true }
// ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;:&lt;/p&gt;
&lt;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;각 `user`에서 필요한 정보를 조합해서 새로운 형태로 가공&lt;/li&gt;
&lt;li&gt;React에서 API 응답 데이터를 화면에 맞게 변환할 때 자주 사용하는 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) filter - 조건에 맞는 요소만 추출&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적: 배열에서 특정 조건을 만족하는 요소들만 골라서 새 배열을 만들고 싶을 때 사용&lt;/p&gt;
&lt;pre id=&quot;code_1764745761051&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const evenNumbers = numbers.filter(num =&amp;gt; num % 2 === 0);

console.log(evenNumbers); // [2, 4, 6, 8, 10]
console.log(numbers);     // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - 원본 그대로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`filter`는 콜백 함수가 `true`를 반환하는 요소만 모아서 새 배열을 만듭니다&lt;/li&gt;
&lt;li&gt;`num % 2 === 0`: 2로 나눈 나머지가 0이면 짝수&lt;/li&gt;
&lt;li&gt;1회차: `num = 1` -&amp;gt; `1 % 2 = 1` -&amp;gt; `false` -&amp;gt; 제외&lt;/li&gt;
&lt;li&gt;2회차: `num = 2` -&amp;gt; `2 % 2 = 0 `-&amp;gt; `true` -&amp;gt; &lt;b&gt;포함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;3회차: `num = 3` -&amp;gt; `3 % 2 = 0 `-&amp;gt; `false` -&amp;gt; 제외&amp;nbsp;&lt;/li&gt;
&lt;li&gt;4회차: `num = 4` -&amp;gt; `4 % 2 = 0 `-&amp;gt; `true` -&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;포함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;... (이하 동일한 방식으로 진행)&lt;/li&gt;
&lt;li&gt;결과: `true`를 반환한 `[2, 4, 6, 8, 10]`만 남음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764746329455&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실용 예시: 특정 조건으로 데이터 필터링
const people = [
    { name: '김철수', age: 25 },
    { name: '이영희', age: 17 },
    { name: '박민수', age: 30 },
    { name: '최지원', age: 15 }
];

// 성인만 필터링 (18세 이상)
const adults = people.filter(person =&amp;gt; person.age &amp;gt;= 18);

console.log(adults);
// [
//   { name: '김철수', age: 25 },
//   { name: '박민수', age: 30 }
// ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 `person` 객체의 `age`가 18 이상인지 검사&lt;/li&gt;
&lt;li&gt;1회차: 김철수(25세) -&amp;gt; `25 &amp;gt;= 18` -&amp;gt; `true` -&amp;gt; &lt;b&gt;포함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;2회차: &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;김철수(17세) -&amp;gt; `17 &amp;gt;= 18` -&amp;gt; `false` -&amp;gt;&lt;span&gt;&amp;nbsp;제외&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;3회차: &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;김철수(30세) -&amp;gt; `30 &amp;gt;= 18` -&amp;gt; `true` -&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;포함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;4회차: &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;김철수(15세) -&amp;gt; `15 &amp;gt;= 18` -&amp;gt; `false` -&amp;gt;&lt;span&gt;&amp;nbsp;제외&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;결과: 성인인 김철수, 박민수만 남은 배열&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764746429500&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 검색 기능 구현 예시
const products = ['아이폰', '아이패드', '맥북', '애플워치', '삼성 갤럭시'];

const searchKeyword = '아이';
const searchResults = products.filter(product =&amp;gt; product.includes(searchKeyword));

console.log(searchResults); // ['아이폰', '아이패드']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;`includes()`: 문자열에 특정 문자가 포함되어 있는지 확인 (있으면 true)&lt;/li&gt;
&lt;li&gt;'아이폰'.includes('아이') &amp;rarr; `true` &amp;rarr; 포함&lt;/li&gt;
&lt;li&gt;'아이패드'.includes('아이') -&amp;gt; `true` -&amp;gt; 포함&lt;/li&gt;
&lt;li&gt;'맥북'.includes('아이') -&amp;gt; `false` -&amp;gt; 제외&lt;/li&gt;
&lt;li&gt;실제 검색 기능 구현할 때 이런 패턴을 많이 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) reduce - 배열을 하나의 값으로 축소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목적: 배열의 모든 요소를 순회하면서 하나의 결과값으로 합치고 싶을 때 사용&lt;/p&gt;
&lt;pre id=&quot;code_1764746849135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

const sum = numbers.reduce((accumulator, current) =&amp;gt; {
    return accumulator + current;
}, 0);

console.log(sum); // 15
```

**동작 설명**:
- `reduce`는 두 개의 인자를 받습니다: 콜백 함수, 초기값(여기서는 0)
- `accumulator`: 누적값 (이전 단계의 결과)
- `current`: 현재 순회 중인 요소
- 초기값 0에서 시작해서 각 요소를 더해나감

**단계별 진행**:
```
1단계: accumulator = 0 (초기값), current = 1
       &amp;rarr; return 0 + 1 = 1

2단계: accumulator = 1 (이전 결과), current = 2
       &amp;rarr; return 1 + 2 = 3

3단계: accumulator = 3, current = 3
       &amp;rarr; return 3 + 3 = 6

4단계: accumulator = 6, current = 4
       &amp;rarr; return 6 + 4 = 10

5단계: accumulator = 10, current = 5
       &amp;rarr; return 10 + 5 = 15

최종 결과: 15&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764747000287&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 실용 예시: 장바구니 총액 계산
const cart = [
    { name: '사과', price: 3000, quantity: 2 },
    { name: '바나나', price: 2000, quantity: 3 },
    { name: '오렌지', price: 2500, quantity: 1 }
];

const totalPrice = cart.reduce((total, item) =&amp;gt; {
    return total + (item.price * item.quantity);
}, 0);

console.log(totalPrice); // 14500&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 상품의 (가격 &amp;times; 수량)을 누적해서 더함&lt;/li&gt;
&lt;li&gt;1단계: `total = 0`, 사과 &amp;rarr; `0 + (3000 &amp;times; 2) = 6000`&lt;/li&gt;
&lt;li&gt;2단계: `total = 6000`, 바나나 &amp;rarr; `6000 + (2000 &amp;times; 3) = 12000`&lt;/li&gt;
&lt;li&gt;3단계: `total = 12000`, 오렌지 &amp;rarr; `12000 + (2500 &amp;times; 1) = 14500`&lt;/li&gt;
&lt;li&gt;최종: 14500원&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;pre id=&quot;code_1764747365830&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 배열을 객체로 변환하는 예시
const fruits = ['사과', '바나나', '사과', '오렌지', '바나나', '사과'];

const fruitCount = fruits.reduce((count, fruit) =&amp;gt; {
    count[fruit] = (count[fruit] || 0) + 1;
    return count;
}, {});

console.log(fruitCount); // { 사과: 3, 바나나: 2, 오렌지: 1 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명&lt;/b&gt;:&lt;/p&gt;
&lt;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;`count[fruit] || 0`: count 객체에 해당 과일이 없으면 0, 있으면 기존 값&lt;/li&gt;
&lt;li&gt;각 과일을 만날 때마다 해당 과일의 카운트를 1씩 증가&lt;/li&gt;
&lt;li&gt;1단계: `count = {}`, '사과' &amp;rarr; `{ 사과: 1 }`&lt;/li&gt;
&lt;li&gt;2단계: `count = { 사과: 1 }`, '바나나' &amp;rarr; `{ 사과: 1, 바나나: 1 }`&lt;/li&gt;
&lt;li&gt;3단계: '사과' &amp;rarr; `{ 사과: 2, 바나나: 1 }`&lt;/li&gt;
&lt;li&gt;... 반복&lt;/li&gt;
&lt;li&gt;이런 패턴은 데이터 집계할 때 유용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-5) find / findIndex - 조건에 맞는 첫 번째 요소 찾기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목적&lt;/b&gt;: 배열에서 조건을 만족하는 &lt;b&gt;첫 번째 요소&lt;/b&gt;를 찾고 싶을 때 사용&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;qml&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;const users = [
    { id: 1, name: '김철수' },
    { id: 2, name: '이영희' },
    { id: 3, name: '박민수' }
];

// find: 조건에 맞는 첫 번째 &quot;요소&quot; 반환
const user = users.find(u =&amp;gt; u.id === 2);
console.log(user); // { id: 2, name: '이영희' }

// findIndex: 조건에 맞는 첫 번째 &quot;인덱스&quot; 반환
const index = users.findIndex(u =&amp;gt; u.id === 2);
console.log(index); // 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명 (find)&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;b&gt;즉시 반환하고 종료&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;1회차: `u = { id: 1, name: '김철수' }` &amp;rarr; `1 === 2` &amp;rarr; `false` &amp;rarr; 다음으로&lt;/li&gt;
&lt;li&gt;2회차: `u = { id: 2, name: '이영희' }` &amp;rarr; `2 === 2` &amp;rarr; `true` &amp;rarr; &lt;b&gt;이 요소 반환, 종료&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;3회차는 실행되지 않음 (이미 찾았으므로)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;filter와의 차이&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;`filter`: 조건 맞는 &lt;b&gt;모든&lt;/b&gt; 요소를 배열로 반환&lt;/li&gt;
&lt;li&gt;`find`: 조건 맞는 &lt;b&gt;첫 번째&lt;/b&gt; 요소 하나만 반환&lt;/li&gt;
&lt;li&gt;하나만 찾으면 되는 경우 `find`가 더 효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot;&gt;&lt;code&gt;// 못 찾은 경우
const notFound = users.find(u =&amp;gt; u.id === 999);
console.log(notFound); // undefined

const notFoundIndex = users.findIndex(u =&amp;gt; u.id === 999);
console.log(notFoundIndex); // -1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;조건에 맞는 요소가 없으면 `find`는 `undefined` 반환&lt;/li&gt;
&lt;li&gt;`findIndex`는 `-1` 반환&lt;/li&gt;
&lt;li&gt;실제 코드에서는 이 경우를 처리해줘야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-6) some / every - 조건 만족 여부 확인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목적&lt;/b&gt;: 배열의 요소들이 조건을 만족하는지 &lt;b&gt;불리언(true/false)으로&lt;/b&gt; 확인하고 싶을 때&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4, 5];

// some: 하나라도 조건을 만족하면 true
const hasEven = numbers.some(num =&amp;gt; num % 2 === 0);
console.log(hasEven); // true (2, 4가 짝수이므로)

// every: 모든 요소가 조건을 만족해야 true
const allPositive = numbers.every(num =&amp;gt; num &amp;gt; 0);
console.log(allPositive); // true (모두 양수)

const allEven = numbers.every(num =&amp;gt; num % 2 === 0);
console.log(allEven); // false (홀수도 있으므로)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명 (some)&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;하나라도 `true`를 반환하면 즉시 `true` 반환하고 종료&lt;/li&gt;
&lt;li&gt;1회차: `1 % 2 === 0` &amp;rarr; `false` &amp;rarr; 계속&lt;/li&gt;
&lt;li&gt;2회차: `2 % 2 === 0` &amp;rarr; `true` &amp;rarr; &lt;b&gt;즉시 true 반환, 종료&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;나머지는 확인하지 않음 (효율적)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 설명 (every)&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;하나라도 `false`를 반환하면 즉시 `false` 반환하고 종료&lt;/li&gt;
&lt;li&gt;모두 `true`여야 최종 `true`&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 실용 예시: 유효성 검사
const formFields = [
    { name: 'email', value: 'test@test.com', valid: true },
    { name: 'password', value: '1234', valid: false },
    { name: 'name', value: '홍길동', valid: true }
];

const isFormValid = formFields.every(field =&amp;gt; field.valid);
console.log(isFormValid); // false (password가 invalid)

const hasError = formFields.some(field =&amp;gt; !field.valid);
console.log(hasError); // true (password에 에러 있음)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-7) 메서드 체이닝 - 여러 고차함수 연결&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;목적&lt;/b&gt;: 여러 고차함수를 연결해서 복잡한 데이터 처리를 깔끔하게 표현&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const products = [
    { name: '노트북', price: 1500000, inStock: true },
    { name: '마우스', price: 50000, inStock: true },
    { name: '키보드', price: 100000, inStock: false },
    { name: '모니터', price: 300000, inStock: true }
];

// 재고 있는 상품 중 가격이 10만원 이상인 것의 이름만 추출
const result = products
    .filter(product =&amp;gt; product.inStock)         // 1단계: 재고 있는 것만
    .filter(product =&amp;gt; product.price &amp;gt;= 100000) // 2단계: 10만원 이상만
    .map(product =&amp;gt; product.name);              // 3단계: 이름만 추출

console.log(result); // ['노트북', '모니터']
```

**단계별 동작 설명**:
```
원본 데이터:
[노트북(150만,재고O), 마우스(5만,재고O), 키보드(10만,재고X), 모니터(30만,재고O)]

1단계 filter (inStock === true):
&amp;rarr; [노트북(150만), 마우스(5만), 모니터(30만)]
  (키보드는 재고 없어서 제외됨)

2단계 filter (price &amp;gt;= 100000):
&amp;rarr; [노트북(150만), 모니터(30만)]
  (마우스는 5만원이라 제외됨)

3단계 map (name만 추출):
&amp;rarr; ['노트북', '모니터']&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p 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;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;javascript&quot; style=&quot;color: #383a42; text-align: left;&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 체이닝 없이 같은 작업을 하면...
const inStockProducts = products.filter(p =&amp;gt; p.inStock);
const expensiveProducts = inStockProducts.filter(p =&amp;gt; p.price &amp;gt;= 100000);
const productNames = expensiveProducts.map(p =&amp;gt; p.name);
// 변수가 많아지고 번거로움
```

---&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React/JavaScript 심화</category>
      <category>javascript</category>
      <category>고차함수</category>
      <author>이도서</author>
      <guid isPermaLink="true">https://leedoseo.tistory.com/291</guid>
      <comments>https://leedoseo.tistory.com/291#entry291comment</comments>
      <pubDate>Wed, 3 Dec 2025 16:16:54 +0900</pubDate>
    </item>
  </channel>
</rss>