<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>van_lan.log</title>
        <link>https://velog.io/</link>
        <description>프론트엔드 개발자를 꿈꾸는 이</description>
        <lastBuildDate>Mon, 02 Mar 2026 23:43:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>van_lan.log</title>
            <url>https://velog.velcdn.com/images/van_lan/profile/868eaaaf-2cf7-4ae0-a79f-a99b38778100/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. van_lan.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/van_lan" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[모딥다] 38장. 브라우저의 렌더링 과정]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-38%EC%9E%A5.-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-38%EC%9E%A5.-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EB%A0%8C%EB%8D%94%EB%A7%81-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Mon, 02 Mar 2026 23:43:29 GMT</pubDate>
            <description><![CDATA[<h1 id="38장-브라우저의-렌더링-과정">38장. 브라우저의 렌더링 과정</h1>
<blockquote>
<p><strong>파싱(Parsing)</strong>
프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 들여 실행하기 위해 텍스트 문서의 문자열 -&gt; 토큰으로 분해 -&gt; 토큰에 문법적 의미와 구조를 반영하여 트리 구조의 자료구조인 파스 트리를 생성.
일반적으로 파싱이 완료된 이후에는 파스 트리를 기반으로 중간 언어인 바이트코드를 생성하고 실행</p>
</blockquote>
<blockquote>
<p><strong>렌더링(Rendering)</strong>
HTML, CSS, JS로 작성된 문서를 파싱하여 브라우저에 시각적으로 출력하는 것을 의미</p>
</blockquote>
<h2 id="📁-브라우저-렌더링-과정">📁 브라우저 렌더링 과정</h2>
<ol>
<li>브라우저는 HTML, CSS, JS, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 서버로 부터 응답을 받음.</li>
<li>브라우저의 렌더링 엔진은 서버로 부터 응답된 HTML과 CSS를 파싱하여 <strong>DOM과 CSSOM을 생성</strong>하고 이들을 <strong>결합하여 렌더 트리를 생성</strong>.</li>
<li>브라우저의 JS엔진은 서버로 부터 응답된 JS를 파싱하여 AST를 생성하고 바이트코드로 변환하여 실행.
이때 JS는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있음.
변경된 DOM과 CSSOM은 다시 렌더 트리로 결합됨.</li>
<li>렌터 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅.</li>
</ol>
<br/>

<h2 id="📁-요청과-응답">📁 요청과 응답</h2>
<ul>
<li>브라우저의 핵심 기능은 필요한 리소스를 서버에 <strong>요청</strong>하고 서버로 부터 <strong>응답</strong> 받아 브라우저에 시각적으로 렌더링 하는 것임.</li>
<li>서버에 요청을 전송하기 위해 브라우저는 주소창을 제공.</li>
<li>브라우저 주소창에 URL 입력 -&gt; URL 호스트이름이 DNS를 통해 IP 주소로 변환 -&gt; 해당 IP 주소를 갖는 서버에 요청을 전송.</li>
</ul>
<br/>

<h2 id="📁-http11과-http20">📁 HTTP/1.1과 HTTP/2.0</h2>
<ul>
<li>HTTP/1.1은 기본적으로 커넥션당 <strong>하나의 요청과 응답만 처리</strong>.</li>
<li>여러개의 요청을 한 번에 전송할 수 없고 응답 또한 마찬가지 임.</li>
<li><code>link</code> 태크, <code>img</code> 태그, <code>script</code> 태그 등에 의한 리소스 요청이 개별적으로 전송되고 응답 또한 개별적으로 전송됨.</li>
<li>이처럼 HTTP/1.1은 리소스의 동시 전송이 불가능한 구조이므로 요청할 리소스의 개수에 비례하여 응답 시간도 증가하는 단점이 존재.</li>
<li>HTTP/2는 커넥션당 여러개의 요청과 응답, 즉 다중 요청/응답이 가능.</li>
<li>HTTP/1.1에 비해 페이지 로드 속도가 약 50% 정도 빠르다고 알려져 있음.</li>
</ul>
<br/>

<h2 id="📁-html-파싱과-dom-생성">📁 HTML 파싱과 DOM 생성</h2>
<ul>
<li>브라우저의 요청에 의해 서버가 응답한 HTML 문서는 문자열로 이루어진 순수한 텍스트임.</li>
<li>이를 시각적인 픽셀로 렌더링하려면 HTML 문서를 브라우저가 이해할 수 있는 자료구조(객체)로 변환하여 메모리에 저장해야 함.</li>
<li>브라우저의 렌더링 엔진은 HTML 문서를 파싱하여 브라우저가 이해할 수 있는 자료구조인 <strong>DOM</strong>을 생성.<h3 id="dom-생성-과정">DOM 생성 과정</h3>
</li>
</ul>
<ol>
<li>HTML 문서가 브라우저 요청에 의해 서버로 부터 응답됨.
서버는 브라우저가 요청한 HTML 파일을 읽어 들여 메모리에 저장한 다음 메모리에 저장된 바이트(2진수)를 인터넷을 경유하여 응답</li>
<li>브라우저는 HTML 문서를 바이트(2진수) 형태로 응답 받음.
이를 <code>meta</code> 태그의 <code>charset</code> 어트리뷰트에 지정된 인토딩 방식(ex: UTF-8)을 기준으로 문자열로 변환.</li>
<li>문자열로 변환된 HTML 문서를 읽어 들여 문법적 의미를 갖는 코드의 최소 단위인 <strong>토큰</strong>들로 분해.</li>
<li>각 토큰을 객체로 변환하여 <strong>노드</strong>를 생성.
토큰의 내용에 따라 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노드 등이 생성됨. ( <code>DOM</code>을 구성하는 기본 요소들이 됨 )</li>
<li>HTML 요소는 중첩 관계를 갖는데, 이를 반영하여 <strong>트리 자료구조</strong>로 구성. 이를 <strong>DOM</strong>이라 부름.</li>
</ol>
<br/>

<h2 id="📁-css-파싱과-cssom-생성">📁 CSS 파싱과 CSSOM 생성</h2>
<ul>
<li>렌더링 엔진은 HTML을 처음부터 한 줄씩 순차적으로 파싱하며 <code>DOM</code>을 생성하게 되는데, 이때에 CSS를 로드하는 <code>link</code> 태그나 <code>style</code> 태그를 만나면 파싱을 일시 중단함.</li>
<li>이어서 <code>link</code> 태그의 <code>href</code> 어트리뷰트에 지정된 CSS파이을 서버에 요청하여 응답된 CSS파일이나 <code>style</code> 태그 내의 CSS를 HTML과 동일한 파싱 과정(바이트 -&gt; 문자 -&gt; 토큰 -&gt; 노드 -&gt; CSSOM)을 거치며 해석하여 <strong>CSSOM</strong>을 생성.</li>
<li>이후 CSS 파싱을 완료하면 일시 중단지점으로 돌아가 HTML 파싱을 이어나감.</li>
</ul>
<br/>

<h2 id="📁-렌더-트리-생성">📁 렌더 트리 생성</h2>
<ul>
<li>렌더링 엔진은 응답된 HTML과 CSS를 파싱하여 각각 <code>DOM</code>과 <code>CSSOM</code>을 생성.</li>
<li>렌더링을 위해 두 트리구조를 결합하여 <strong>렌더 트리</strong>를 생성.</li>
<li>렌더 트리는 <strong>브라우저 화면에 렌더링 되는 노드만으로 구성</strong>됨.</li>
<li>이 렌더 트리는 각 HTML 요소의 레이아웃(위치와 크기)를 계산하는 데 사용되며 브라우저 화면에 픽셀을 렌더링하는 페이팅 처리에 입력됨.</li>
<li>이 브라우저 렌더링 과정은 반복되서 실행 됨.<ul>
<li>JS에 의한 노드 추가 또는 삭제 시.</li>
<li>브라우저 창의 리사징ㅇ에 의한 뷰포트 크기 변화.</li>
<li>HTML 요소의 레이아웃(위치, 크기)에 변경을 발생시키는 <code>width/height</code>, <code>margin</code>, <code>padding</code>, <code>border</code>, <code>display</code>, <code>position</code>, <code>top/right/bottom/left</code> 등의 스타일 변경.</li>
</ul>
</li>
<li>레이아웃 계산과 페인팅을 다시 실행하는 리렌더링은 비용이 많이드는 작업이므로 가급적 리렌더링이 빈번하게 발생하지 않도록 주의할 필요가 있음.</li>
</ul>
<br/>

<h2 id="📁-자바스크립트-파싱과-실행">📁 자바스크립트 파싱과 실행</h2>
<ul>
<li><code>DOM</code>은 HTML 문서의 구조와 정보뿐만 아니라 HTML 요소와 스타일 등을 변경할 수 있는 프로그래밍 인터페이스로서 DOM API를 제공.</li>
<li>이를 통해 JS코드에서 이미 생성된 <code>DOM</code>을 동적으로 조작이 가능.</li>
<li>CSS 파싱 과정과 마찬가지로 렌더링 엔진은 HTML을 순차적으로 한 줄씩 파싱하며 <code>DOM</code>을 생성해 나가다가 JS파일을 로드하는 <code>script</code> 태그나 JS 코드를 컨텐츠로 담은 <code>script</code> 태그를 만나면 <code>DOM</code> 생성을 일시 중단함.</li>
<li>JS 코드를 파싱하기 위해 JS엔진에 제어권을 넘겨준 후 이후 JS 파싱과 실행이 종료되면 렌더링 엔진으로 다시 제어권을 넘겨 HTML 파싱이 중단된 지점 부터 다시 HTML 파싱을 시작하여 DOM 생성을 재개함.</li>
</ul>
<h3 id="js엔진의-파싱과-실행-과정">JS엔진의 파싱과 실행 과정</h3>
<ul>
<li>자바스크립트 소스 코드 -&gt; 토크나이징 -&gt; 토큰 -&gt; 파싱 -&gt; AST -&gt; 바이트 코드 생성 -&gt; 바이트 코드 -&gt; 실행<h4 id="🔹토크나이징">🔹토크나이징</h4>
</li>
<li>단순히 문자열인 JS 소스코드를 어휘 분석하여 문법적 의미를 갖는 코드의 최소 단위인 토큰들로 분해.<h4 id="🔹파싱">🔹파싱</h4>
</li>
<li>토큰들의 집합을 구문 분석하여 AST(추상적 구문 트리)를 생성.</li>
<li>AST는 토큰에 문법적 의미와 구저를 반영한 트리 구조의 자료구조임.
(AST는 인터프리터나 컴파일러만 사용하는 것이 아니고, 이를 활용해 Typescript, Babel, Prettier 같은 트랜스파일러를 구현하기도 함)<h4 id="🔹바이트코드-생성과-실행">🔹바이트코드 생성과 실행</h4>
</li>
<li>생성된 AST는 인터프리터가 실행할 수 있는 중간 코드인 바이트코드로 변환되고 인터프리터에 의해 실행됨.</li>
</ul>
<br/>

<h2 id="📁-리플로우와-리페인트">📁 리플로우와 리페인트</h2>
<ul>
<li>JS코드에 DOM이나 CSSOM을 변경하는 DOM API가 사용된 경우 DOM이나 CSSOM이 변경되며 이는 다시 렌더트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 거쳐 브라우저의 화면에 다시 렌더링 됨.</li>
<li>이를 리플로우, 리페인트 라고 함.<h3 id="1-리플로우">1. 리플로우</h3>
</li>
<li>레아이아웃 계산을 다시하는 과정을 말함.</li>
<li>노드 추가/삭제, 요소의 크기/위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우에 한하여 실행됨.<h3 id="2-리페인트">2. 리페인트</h3>
</li>
<li>재결합된 렌더 트리를 기반으로 다시 페인트 하는 것을 말함.</li>
<li>레이아웃에 영향이 없는 변경은 리플로우 없이 리페인트만 실행 됨.</li>
</ul>
<br/>

<h2 id="📁-script-태그의-asyncdefer-어트리뷰트">📁 script 태그의 async/defer 어트리뷰트</h2>
<ul>
<li>JS 파싱에 의한 DOM 생성 중단이 되는 문제를 근본적으로 해결하기 위해 async와 deffer 어트리뷰트가 추가됨.</li>
<li><code>src</code> 어트리뷰트를 통해 외부 JS파일을 로드하는 경우에만 사용 가능. ( 인라인 스크립트에는 사용 X )</li>
<li>사용하게 되면 JS파일의 로드가 비동기적으로 동시에 진행됨.<h3 id="1-async-어트리뷰트">1. async 어트리뷰트</h3>
</li>
<li>HTML 파싱과 외부 JS파일의 로드가 비동기적으로 동시에 진행됨.</li>
<li>단, JS 파싱과 실행은 JS파일의 로드가 완료된 직후에 진행되며, 이때 HTML 파싱이 중단됨.</li>
<li><code>script</code> 태그의 순서와는 상관없이 JS파일의 로드가 완료된 JS부터 먼저 실행되므로 실행 순서가 보장되지 않음.</li>
<li>실행 순서 보장이 필요한 <code>script</code> 태그에는 <code>async</code> 어트리뷰트를 지정하지 않아야 함.<h3 id="2-defer-어트리뷰트">2. defer 어트리뷰트</h3>
</li>
<li>동일하게 HTML 파싱과 JS파일로드가 비동기적으로 동시에 진행됨.</li>
<li>단, JS의 파싱과 실행은 HTML 파싱이 모두 완료된 직후(DOM 생성 완료 직후)에 진행됨.</li>
<li><code>DOM</code> 생성이 완료된 이후 실행되어야 할 JS에 유용함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 37장. Set과 Map]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-37%EC%9E%A5.-Set%EA%B3%BC-Map</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-37%EC%9E%A5.-Set%EA%B3%BC-Map</guid>
            <pubDate>Mon, 02 Mar 2026 22:42:06 GMT</pubDate>
            <description><![CDATA[<h1 id="37장-set과-map">37장. Set과 Map</h1>
<h2 id="📁-set">📁 Set</h2>
<ul>
<li><p>Set 객체는 중복되지 않은 유일한 값들을 집합.</p>
</li>
<li><p><strong>배열과 차이점:</strong></p>
<ul>
<li>중복 값 X.</li>
<li>요소 순서의 의미 X.</li>
<li>인덱스로 요소에 접근 X.</li>
</ul>
</li>
<li><p>수학적 집합의 특성과 일치. ( 교집합, 차집합, 여집합 등 구현 가능 )</p>
<h3 id="1-set-객체의-생성">1. Set 객체의 생성</h3>
</li>
<li><p>Set 생성자 함수로 생성. ( 인수 전달 X -&gt; 빈 Set 객체 생성 )</p>
<pre><code class="language-js">const set = new Set();
console.log(set);  // Set(0) {}</code></pre>
</li>
<li><p>Set 생성자 함수는 이터러블을 인수로 전달받아 Set 객체를 생성. ( 이때 중복된 값은 Set 객체에 요소로 저장 X )</p>
<pre><code class="language-js">const set1 = new Set([1, 2, 3, 3]);
console.log(set1);  // Set(3) {1, 2, 3}

const set2 = new Set(&#39;string&#39;);
console.log(set2);  // Set(6) {&quot;s&quot;, &quot;t&quot;, &quot;r&quot;, &quot;i&quot;, &quot;n&quot;, &quot;g&quot;}</code></pre>
</li>
<li><p>배열의 중복 요소 제거시 사용 가능.</p>
<pre><code class="language-js">const uniq = array =&gt; [...new Set(array)];
console.log(uniq[2, 1, 2, 3, 4, 3, 4]);  // [2, 1, 3, 4]</code></pre>
<h3 id="2-요소-개수-확인">2. 요소 개수 확인</h3>
</li>
<li><p>요소 개수를 확인할 때는 <code>Set.prototype.size</code> 프로퍼티를 사용.</p>
<pre><code class="language-js">const { size } = new Set([1, 2, 3, 3]);
console.log(size);</code></pre>
</li>
<li><p><code>size</code> 프로퍼티는 <code>setter</code> 함수 없이 <code>getter</code> 함수만 존재하는 접근자 프로퍼티이므로 직접적으로 요소 개수를 변경 불가.</p>
<h3 id="3-요소-추가">3. 요소 추가</h3>
</li>
<li><p>요소 추가시에는 <code>Set.prototype.add</code> 메서드를 사용.</p>
<pre><code class="language-js">const set = new Set();
console.log(set);  // Set(0) {}

set.add(1);
console.log(set);  // Set(1) {1}</code></pre>
</li>
<li><p><code>add</code> 메서드는 새로운 요소가 추가된 Set 객체를 반환. ( 연속적 호출 가능 )</p>
<pre><code class="language-js">const set = new Set();

set.add(1).add(2);
console.log(set);  // Set(2) {1, 2}</code></pre>
</li>
<li><p>객체나 배열과 같이 JS의 모든 값을 요소로 저장 가능.</p>
<pre><code class="language-js">const set = new Set();

set
  .add(1)
  .add(&#39;a&#39;)
  .add(true)
  .add(undefined)
  .add(null)
  .add({})
  .add([])
  .add(() =&gt; {});

console.log(set);  // Set(8) {1, &quot;a&quot;, true, undefined, null, {}, [], () =&gt; {}}</code></pre>
<h3 id="4-요소-존재-여부-확인">4. 요소 존재 여부 확인</h3>
</li>
<li><p>특정 요소 존재확인은 <code>Set.prototype.has</code> 메서드를 사용. ( 요소 존재 여부를 나타내는 불리언 값을 반환 )</p>
<pre><code class="language-js">const set = new Set([1, 2, 3]);

console.log(set.has(2));  // true
console.log(set.has(4));  // false</code></pre>
<h3 id="5-요소-삭제">5. 요소 삭제</h3>
</li>
<li><p>특정 요소 삭제시 <code>Set.prototype.delete</code> 메서드를 사용. ( 삭제 성공여부를 나타내는 불리언 값 반환 )</p>
</li>
<li><p>인수로 삭제하려는 <strong>요소값</strong>을 전달.</p>
<pre><code class="language-js">const set = new Set([1, 2, 3]);

// 요소 2를 삭제
set.delete(2);
console.log(set);  // Set(2) {1, 3}

// 요소 1을 삭제
set.delete(1);
console.log(set);  // Set(1) {3}

// 존재하지 않는 요소 삭제시 에러없이 무시
set.delete(0);
console.log(set);  // Set(1) {3}</code></pre>
<h3 id="6-요소-일괄-삭제">6. 요소 일괄 삭제</h3>
</li>
<li><p>모든 요소 일괄 삭제시 <code>Set.prototype.clear</code> 메서드를 사용. ( <code>undefined</code>를 반환 )</p>
<pre><code class="language-js">const set = new Set([1, 2, 3]);

set.clear();
console.log(set);  // Set(0) {}</code></pre>
<h3 id="7-요소-순회">7. 요소 순회</h3>
</li>
<li><p><code>Set</code> 객체의 요소를 순회하려면 <code>Set.prototype.forEach</code> 메서드를 사용.</p>
</li>
<li><p>인수 설명:</p>
<ul>
<li>1: 현재 순회 중인 요소값</li>
<li>2: 현재 순회 중인 요소값</li>
<li>3: 현재 순회 중인 Set 객체 자체</li>
</ul>
</li>
<li><p>첫 번째 인수와 두번째 인수는 같은 값이며, 이는 Array.prototype.forEach 메서드와 인터페이스를 통일하기 위함일 뿐 다른 의미는 없음.</p>
</li>
<li><p><code>Set</code> 객체는 이터러블 이므로, <code>for ...of</code> 문으로 순회가 가능하며, 스프레드 문법과 배열 구조분해의 대상이 될 수 있음.</p>
</li>
<li><p><code>Set</code> 객체는 요소의 순서에 의미를 갖지 않지만, 순회시에는 요소가 추가된 순서를 따름.</p>
<h3 id="8-집합-연산">8. 집합 연산</h3>
</li>
<li><p><code>Set</code> 객체는 수학적 집합을 구현하기 위한 자료구조 임. ( 교집합, 합집합, 차집합 등을 구현 가능 )</p>
<h4 id="🔹교집합">🔹교집합</h4>
<pre><code class="language-js">Set.prototype.intersection = function (set) {
return new Set([...this].filter(v =&gt; set.has(v)));
};
</code></pre>
</li>
</ul>
<p>const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 4]);</p>
<p>console.log(setA.intersection(setB));  // Set(2) {2, 4}
console.log(setB.intersection(setA));  // Set(2) {2, 4}</p>
<pre><code>#### 🔹합집합
```js
Set.prototype.union = function (set) {
  return new Set([...this, ...set]);
};

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

// SetA와 setB의 합집합
console.log(setA.union(setB));  // Set(4) {1, 2, 3, 4}
console.log(setB.union(setA));  // Set(4) {2, 4, 1, 3}</code></pre><h4 id="🔹차집합">🔹차집합</h4>
<pre><code class="language-js">Set.prototype.difference = function (set) {
  return new Set([...this].filter(v =&gt; !set.has(v)));
}

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

// setA에 대한 setB의 차집합
console.log(setA.difference(setB));  // Set(2) {1, 3}
// setB에 대한 setA의 차집합
console.log(setB.difference(setA));  // Set(0) {}</code></pre>
<h4 id="🔹부분-집합과-상위-집합">🔹부분 집합과 상위 집합</h4>
<pre><code class="language-js">// this가 subset의 상위 집합인지 확인
Set.prototype.inSuperset = function (subset) {
  const supersetArr = [...this];
  return [...subset].every(v =&gt; supersetArr.includes(v));
};

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

// setA가 setB의 상위 집합인지 확인
console.log(setA.isSuperset);  // true
// setB가 setA의 상위 집합인지 확인
console.log(setB.isSuperset);  // false</code></pre>
<br/>

<h2 id="📁-map">📁 Map</h2>
<ul>
<li><p>키와 값의 쌍으로 이루어진 컬렉션.</p>
</li>
<li><p><strong>객체와의 차이점:</strong></p>
<ul>
<li>키로 객체를 포함한 모든 값을 사용 가능.</li>
<li>이터러블 임.</li>
<li>요소 개수 확인시 <code>Map.prototype.size</code> 사용.<h3 id="1-map-객체의-생성">1. Map 객체의 생성</h3>
</li>
</ul>
</li>
<li><p><code>Map</code> 생성자 함수로 생성. ( 인수 전달 X -&gt; 빈 <code>Map</code> 객체 생성 )</p>
<pre><code class="language-js">const map = new Map();
console.log(map);  // Map(0) {}</code></pre>
</li>
<li><p>이터러블을 인수로 전달받아 <code>Map</code> 객체를 생성. ( 이때 이터러블은 키와 값의 쌍으로 이루어진 요소로 구성되어야 함 )</p>
<pre><code class="language-js">const map1 = new Map([[&#39;key1&#39;, &#39;value1&#39;], [&#39;key2&#39;, &#39;value2&#39;]]);
console.log(map1);  // Map(2) {&quot;key1&quot; =&gt; &quot;value1&quot;, &quot;key2&quot; =&gt; &quot;value2&quot;}

const map2 = new Map([1, 2]);  // TypeError: Iterator value 1 is not an entry object</code></pre>
</li>
<li><p>전달된 이터러블에 중복된 키를 갖는 요소가 있으면, 값이 덮어써짐. ( 중복된 키를 갖는 요소 X )</p>
<pre><code class="language-js">const map = new Map([[&#39;key1&#39;, &#39;value1&#39;], [&#39;key1&#39;, &#39;value2&#39;]]);
console.log(map);  // Map(1) {&quot;key1&quot; =&gt; &quot;value2&quot;}</code></pre>
<h3 id="2-요소-개수-확인-1">2. 요소 개수 확인</h3>
</li>
<li><p>요소 개수 확인시 <code>Map.prototype.size</code> 프로퍼티를 사용.</p>
<pre><code class="language-js">const { size } = new Map([[&#39;key1&#39;, &#39;value1&#39;], [&#39;key2&#39;, &#39;value2&#39;]]);
console.log(size);  // 2</code></pre>
<h3 id="3-요소-추가-1">3. 요소 추가</h3>
</li>
<li><p>요소 추가시 <code>Map.prototype.set</code> 메서드를 사용.</p>
</li>
<li><p>마찬가지로 새로운 요소가 추가된 Map 객체를 반환함. ( 연속적으로 호출 가능 )</p>
<pre><code class="language-js">const map = new Map();
console.log(map);  // Map(0) {}

map.set(&#39;key1&#39;, &#39;value1&#39;);
console.log(map);  // Map(1) {&quot;key1&quot; =&gt; &quot;value1&quot;}

map
  .set(&#39;key2&#39;, &#39;value2&#39;)
  .set(&#39;key3&#39;, &#39;value3&#39;);

console.log(map);  // Map(3) {&quot;key1&quot; =&gt; &quot;value1&quot;, &quot;key2&quot; =&gt; &quot;value2&quot;, &quot;key3&quot; =&gt; &quot;value3&quot;}</code></pre>
</li>
<li><p>중복된 키를 갖는 요소가 존재할 수 없기 때문에 중복된 키를 갖는 요소를 추가하면 값이 덮어 써짐. ( 에러 발생 X )</p>
<pre><code class="language-js">const map = new Map();

map
  .set(&#39;key1&#39;, &#39;value1&#39;)
  .set(&#39;key2&#39;, &#39;value2&#39;);

console.log(map);  // Map(1) {&quot;key1&quot; =&gt; &quot;value2&quot;}</code></pre>
</li>
<li><p><code>Map</code> 객체는 키 타입에 제한이 없으므로 객체를 포함한 모든 값을 키로 사용할 수 있음.</p>
<pre><code class="language-js">const map = new Map();

const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };

// 객체도 키로 사용 가능
map
  .set(lee, &#39;developer&#39;)
  .set(kim, &#39;designer&#39;);

console.log(map);  // Map(2) { {name: &quot;Lee&quot;} =&gt; &quot;developer&quot;, {name: &quot;Kim&quot;} =&gt; &quot;designer&quot; }</code></pre>
<h3 id="4-요소-취득">4. 요소 취득</h3>
</li>
<li><p>특정 요소를 취득하기 위해 <code>Map.prototype.get</code> 메서드를 사용.</p>
</li>
<li><p>인수로 키를 전달하면 전달한 키가 갖는 값을 반환. ( 존재하지 않을 시 <code>undefined</code> 반환 )</p>
<pre><code class="language-js">const map = new Map();

const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };

// 객체도 키로 사용 가능
map
  .set(lee, &#39;developer&#39;)
  .set(kim, &#39;designer&#39;);

console.log(map.get(lee));  // developer
console.log(map.get(&#39;key&#39;));  // undefined</code></pre>
<h3 id="5-요소-존재-여부-확인">5. 요소 존재 여부 확인</h3>
</li>
<li><p>특정 요소가 존재하는지 확인하려면 <code>Map.prototype.has</code> 메서드를 사용. ( 특정 요소의 존재 여부를 나타낸는 불리언 값을 반환 )</p>
<pre><code class="language-js">const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };

const map = new Map([[lee, &#39;developer&#39;], [kim, &#39;designer&#39;]]);

console.log(map.has(lee));  // true
console.log(map.has(&#39;key&#39;));  // false</code></pre>
<h3 id="6-요소-삭제">6. 요소 삭제</h3>
</li>
<li><p>객체의 요소를 삭제하려면 <code>Map.prototype.delete</code> 메서드를 사용. ( 삭제 성공 여부를 나타내는 불리언 값을 반환 )</p>
</li>
<li><p>존재하지 않는 키로 <code>Map</code> 요소를 삭제하려면 에러 없이 무시됨.</p>
</li>
<li><p>불리언 값을 반환하므로 연속적으로 호출은 불가.</p>
<pre><code class="language-js">const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };

const map = new Map([[lee, &#39;developer&#39;], [kim, &#39;designer&#39;]]);

map.delete(kim);
console.log(map);  // Map(1) { { name: &quot;Lee&quot; } =&gt; &quot;developer&quot; }</code></pre>
<h3 id="7-요소-일괄-삭제">7. 요소 일괄 삭제</h3>
</li>
<li><p>요소 일괄 삭제시 <code>Map.prototype.clear</code> 메서드를 사용. ( 언제나 <code>undefined</code>를 반환 )</p>
<pre><code class="language-js">const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };

const map = new Map([[lee, &#39;developer&#39;], [kim, &#39;designer&#39;]]);

map.clear();
console.log(map);  // Map(0) {}</code></pre>
<h3 id="8-요소-순횐">8. 요소 순횐</h3>
</li>
<li><p>요소 순회시 <code>Map.prototype.forEach</code> 메서드를 사용.</p>
</li>
<li><p><strong>인수 설명:</strong></p>
<ul>
<li>1: 현재 순회 중인 요소값</li>
<li>2: 현재 순회 중인 요소키</li>
<li>3: 현재 순회 중인 Map 객체 자체</li>
</ul>
</li>
<li><p><code>Map</code> 객체는 이터러블이므로, <code>for ...of</code> 문으로 순회가 가능하며, 스프레드 문법과 배열 구조분해 할당의 대상이 될 수 있음.</p>
</li>
<li><p><code>Map</code>객체는 이터러블이면서 동시에 이터레이터인 객체를 반환하는 메서드를 제공.</p>
<ul>
<li><code>Map.prototype.keys</code>: <code>Map</code> 객체에서 요소키를 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환.</li>
<li><code>Map.prototype.values</code>: <code>Map</code> 객체에서 요소값을 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환.</li>
<li><code>Map.prototype.entries</code>: <code>Map</code> 객체에서 요소키와 요소값을 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환.<pre><code class="language-js">const lee = { name: &#39;Lee&#39; };
const kim = { name: &#39;Kim&#39; };
</code></pre>
</li>
</ul>
<p>const map = new Map([[lee, &#39;developer&#39;], [kim, &#39;designer&#39;]]);</p>
<p>// 요소키를 값으로 갖는 이터레이터를 반환
for (const key of map.keys()) {
  console.log(key);  // {name: &quot;Lee&quot;} {name: &quot;Kim&quot;}
}</p>
<p>// 요소값을 값으로 갖는 이터레이터를 반환
for (const value of map.values()) {
  console.log(value);  // developer designer
}</p>
<p>// 요소키와 요소값을 값으로 갖는 이터레이터를 반환
for (const entry of map.entries()) {
  console.log(entry);  // [{name: &quot;Lee&quot;}, &quot;developer&quot;] [{name: &quot;Kim&quot;}, &quot;designer&quot;]
}
```</p>
</li>
<li><p><code>Map</code> 객체는 요소의 순서에 의미를 갖지 않지만 순회시에는 요소가 추가된 순서를 따름.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 36장. 디스트럭처링 할당]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-36%EC%9E%A5.-%EB%94%94%EC%8A%A4%ED%8A%B8%EB%9F%AD%EC%B2%98%EB%A7%81-%ED%95%A0%EB%8B%B9</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-36%EC%9E%A5.-%EB%94%94%EC%8A%A4%ED%8A%B8%EB%9F%AD%EC%B2%98%EB%A7%81-%ED%95%A0%EB%8B%B9</guid>
            <pubDate>Wed, 25 Feb 2026 21:53:39 GMT</pubDate>
            <description><![CDATA[<h1 id="36장-디스트럭처링-할당">36장. 디스트럭처링 할당</h1>
<ul>
<li>구조화된 배열과 같은 이터러블 또는 객체를 destructuring(비구조화, 구조 파괴)하여 1개 이상의 변수에 개별적으로 할당하는 것.</li>
<li>배열과 같은 이터러블 또는 객체 리터럴에서 필요한 값만 추출하여 변수에 할당할 때 유용.</li>
</ul>
<h2 id="📁-배열-디스트럭처링-할당">📁 배열 디스트럭처링 할당</h2>
<ul>
<li><p>대상은 이터러블 이어야 하며, 할당 기준은 배열의 인덱스임.</p>
<pre><code class="language-js">const arr = [1, 2, 3];

const [one, two, three] = arr;
console.log(one, two, three);  // 1 2 3</code></pre>
</li>
<li><p>우변에 이터러블을 할당하지 않으면 에러 발생.</p>
<pre><code class="language-js">const [x, y];  // SyntaxError: Missing initializer in destructuring declaration
const [a, b] = {};  // TypeError: {} is not iterable</code></pre>
</li>
<li><p>배열 디스트럭처링 할당의 기준은 배열 인덱스이므로, 변수의 개수와 이터러블의 요소 개수가 반드시 일치할 필요 X.</p>
<pre><code class="language-js">const [a, b] = [1, 2];
console.log(a, b);  // 1 2

const [c, d] = [1];
console.log(c, d);  // 1 undefined

const [e, f] = [1, 2, 3];
console.log(e, f);  // 1 2</code></pre>
</li>
<li><p>배열 디스트럭처링 할당을 위한 변수에 기본값 설정 가능.</p>
<pre><code class="language-js">// 기본값
const [a, b, c = 3] = [1, 2];
console.log(a, b, c);  // 1 2 3

// 기본값 보다 할당된 값이 우선
const [e, f = 10, g = 3] = [1, 2];
console.log(e, f, g);  // 1 2 3</code></pre>
</li>
<li><p>Rest 요소 사용 가능.</p>
<pre><code class="language-js">// Rest 요소
const [x, ...y] = [1, 2, 3];
console.log(x, y);  // 1 [2, 3]</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-객체-디스트럭처링-할당">📁 객체 디스트럭처링 할당</h2>
<ul>
<li><p>대상은 객체이어야 하며, 할당 기준은 프로퍼티 키임.</p>
<pre><code class="language-js">const user = { firstName: &#39;HyounSeok&#39;, lastName: &#39;Kim&#39; };

const { lastName, firstName } = user;
console.log(firstName, lastName);  // HyounSeok Kim</code></pre>
</li>
<li><p>우변에 객체 또는 객체로 평가될 수 있는 표현식을 할당하지 않으면 에러 발생.</p>
<pre><code class="language-js">const { lastName, firstName };  // SyntaxError: Missing initailizer in destructuring declaration

const { lstName, firstName } = null;  // TypeError: Cannot destructure propery &#39;lastName&#39; of &#39;null&#39; as it is null.</code></pre>
</li>
<li><p>객체의 프로퍼티 키와 다른 변수 이름으로 프로퍼티 값을 할당받으려면 다음과 같이 변수를 선언.</p>
<pre><code class="language-js">const user = { firstName: &#39;HyounSeok&#39;, lastName: &#39;Kim&#39; };

const { lastName: ln, firstName: fn } = user;
console.log(fn, ln);  // HyounSeok Kim</code></pre>
</li>
<li><p>변수에 기본값 설정 가능.</p>
<pre><code class="language-js">const { lastName, firstName = &#39;HyounSeok&#39; } = { lastName: &#39;Kim&#39; };
console.log(firstName, lastName);  // HyounSeok Kim

const { lastName: ln, firstName: fn = &#39;HyounSeok&#39; } = { lastName: &#39;Kim&#39; };
console.log(fn, ln);  // HyounSeok Kim</code></pre>
</li>
<li><p>중첩 객체일 경우 사용의 예:</p>
<pre><code class="language-js">const user = {
  name: &#39;Lee&#39;,
  address: {
    zipCode: &#39;03068&#39;,
    city: &#39;Seoul&#39;
  }
};

const { address: { city } } = user;
console.log(city);  // &#39;Seoul&#39;</code></pre>
</li>
<li><p>Rest 프로퍼티 사용.</p>
<pre><code class="language-js">const { x, ...rest } = { x: 1, y: 2, z: 3 };
console.log(x, rest);  // 1 { y: 2, z: 3 }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 35장. 스프레드 문법]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-35%EC%9E%A5.-%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-35%EC%9E%A5.-%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Wed, 25 Feb 2026 21:28:42 GMT</pubDate>
            <description><![CDATA[<h1 id="35장-스프레드-문법">35장. 스프레드 문법</h1>
<ul>
<li><p><code>...</code>은 하나로 뭉쳐 있는 여러 값들의 집합을 펼쳐서(전개, 분산, spread) 개별적인 값들의 목록으로 만듬.</p>
</li>
<li><p>사용할 수 있는 대상은 이터러블에 한정됨.</p>
<pre><code class="language-js">console.log(...[1, 2, 3]);  // 1 2 3
console.log(...&#39;Hello&#39;);  // H e l l o
console.log(...new Map([&#39;a&#39;, &#39;1&#39;], [&#39;b&#39;, &#39;2&#39;]));  // [&#39;a&#39;, &#39;1&#39;] [&#39;b&#39;, &#39;2&#39;]
console.log(...new Set([1, 2, 3]));  // 1 2 3

// 이터러블이 아닌 일반 객체는 스프레드 문법의 대상이 될 수 없음
console.log(...{ a: 1, b: 2 });  // TypeError: Found non-callable @@iterator</code></pre>
</li>
<li><p>스프레드 문법의 결과물은 값으로 사용할 수 없고, 다음과 같이 쉼표로 구분한 값의 목록을 사용하는 문맥에서만 사용 가능.</p>
<ul>
<li>함수 호출문의 인수 목록</li>
<li>배열 리터럴의 요소 목록</li>
<li>객체 리터럴의 프로퍼티 목록<pre><code class="language-js">// 스프레드 문법의 결과는 값이 아님
const list = ...[1, 2, 3];  // SyntaxError: Unexpected token ...</code></pre>
</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-함수-호출문의-인수목록에서-사용">📁 함수 호출문의 인수목록에서 사용</h2>
<ul>
<li><p>배열을 펼쳐서 요소들의 목록을 함수의 인수로 전달하고 싶은경우</p>
<pre><code class="language-js">const arr = [1, 2, 3];

const max = Math.max(...arr);  // -&gt; 3</code></pre>
</li>
<li><p>Rest 파라미터와 형태가 동일하여 혼동할 수 있으나, Rest 파라미터와 스프레드 문법은 서로의 반대의 개념.</p>
<pre><code class="language-js">// Rest 파라미터는 인수들의 목록을 배열로 전달받음
function foo(...rest) {
  console.log(rest);  // 1, 2, 3 -&gt; [1, 2, 3]
}

// 스프레드 문법은 배열과 같은 이터러블을 펼쳐서 개별적인 값들의 목록을 만듬
foo(..[1, 2, 3]);  // [1, 2, 3] -&gt; 1, 2, 3</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-배열-리터럴-내부에서-사용">📁 배열 리터럴 내부에서 사용</h2>
<h3 id="1-concat">1. concat</h3>
<ul>
<li><p>ES5에선 배열을 결합하고 싶은 경우 <code>concat</code> 메서드를 사용해야 했었음.</p>
<pre><code class="language-js">// ES5
var arr = [1, 2].concat([3, 4]);
console.log(arr);  // [1, 2, 3, 4]

// ES6
const arr = [...[1, 2], ...[3, 4]];
console.log(arr);  // [1, 2, 3, 4]</code></pre>
<h3 id="2-splice">2. splice</h3>
</li>
<li><p>배열의 중간에 다른 배열의 요소를 추가하거나 제거하려면 <code>splice</code> 메서드를 사용함. 이때 <code>splice</code> 메서드의 세 번째 인수로 배열을 전달하면 배열 자체가 추가됨.</p>
<pre><code class="language-js">// ES5
const arr1 = [1, 4];
const arr2 = [2, 3];

// 세 번째 인수 arr2를 해제하여 전달해야 함.
// 그렇지 않으면 arr1에 arr2 배열 자체가 추가됨.
arr1.splice(1, 0, ...arr2);
console.log(arr1);  // [1, 2, 3, 4]</code></pre>
<h3 id="3-배열-복사">3. 배열 복사</h3>
</li>
<li><p>원본 배열의 각 요소를 얕은 복사하여 새로운 복사본 생성.</p>
<pre><code class="language-js">const origin = [1, 2];
const copy = [...origin];

console.log(copy);  // [1, 2]
console.log(copy === origin);  // false</code></pre>
<h3 id="4-이터러블을-배열로-변환">4. 이터러블을 배열로 변환</h3>
</li>
<li><p>이터러블을 배열로 변환.</p>
<pre><code class="language-js">function sum() {
  // 이터러블이면서 유사 배열 객체인 arguments를 배열로 변환
  return [...arguments].reduce((pre, cur) =&gt; pre + cur, 0);
}

console.log(sum(1, 2, 3));  // 6</code></pre>
</li>
<li><p>이터러블이 아닌 유사 배열 객체를 배열로 변경시에는 <code>Array.from</code> 메서드 사용.</p>
</li>
</ul>
<br/>

<h2 id="📁-객체-리터럴-내부에서-사용">📁 객체 리터럴 내부에서 사용</h2>
<ul>
<li><p>스프레드 문법의 대상은 이터러블이어야 하지만, 스프레드 프로퍼티 제안으로 일반 객체를 대상으로도 스프레드 문법의 사용을 허용.</p>
<pre><code class="language-js">// 스프레드 프로퍼티
// 객체 복사(얕은 복사)
const obj = { x: 1, y: 2 };
const copy = { ...obj };
console.log(copy);  // { x: 1, y: 2 }
console.log(obj === copy);  // false

// 객체 병합
const merged = { x: 1, y: 2, ...{ a: 3, b: 4 } };
console.log(merged);  // { x: 1, y: 2, a: 3, b: 4 }</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 34장. 이터러블]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-34%EC%9E%A5.-%EC%9D%B4%ED%84%B0%EB%9F%AC%EB%B8%94</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-34%EC%9E%A5.-%EC%9D%B4%ED%84%B0%EB%9F%AC%EB%B8%94</guid>
            <pubDate>Wed, 25 Feb 2026 20:53:48 GMT</pubDate>
            <description><![CDATA[<h1 id="34장-이터러블">34장. 이터러블</h1>
<h2 id="📁-이터레이션-프로토콜">📁 이터레이션 프로토콜</h2>
<ul>
<li><p>순회 가능한 데이터 컬렉션(자료구조)을 만들기 위해 ECMAScript 사양에 정의하여 미리 약속한 규칙.</p>
</li>
<li><p>순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 <code>for ...of</code> 문, 스프레드 문법, 배열 디스트럭처링 할당의 대상으로 사용할 수 있도록 <strong>일원화</strong>.</p>
<h3 id="1-이터러블">1. 이터러블</h3>
</li>
<li><p><code>Symbol.iterator</code>를 프로퍼티 키로 사용한 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은 객체.</p>
</li>
<li><p>예를 들어, 배열은 <code>Array.prototype</code>의 <code>Symbol.iterator</code> 메서드를 상속받은 이터러블. 이터러블은 <code>for ...of</code> 문으로 순회 가능하며, 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용 가능.</p>
<pre><code class="language-js">const array = [1, 2, 3];

// 배열은 Array.prototype의 Symbol.iterator 메서드를 상속받는 이터러블
console.log(Symbol.iterator in array);  // true

// 이터러블인 배열은 for ...of 문으로 순회 가능
for (const item of array) {
  console.log(item);  // 1, 2, 3
}

// 이터러블인 배열은 스프레드 문법의 대상으로 사용 가능
console.log([...array]);  // [1, 2, 3]

// 이터러블인 배열은 배열 디스트럭처링 할당의 대상으로 사용 가능
const [a, ...rest] = array;
console.log(a, rest);  // 1, [2, 3]</code></pre>
</li>
<li><p><code>Symbol.iterator</code> 메서드를 직접 구현하지 않거나 상속받지 않은 일반 객체는 이터러블이 아님. ( 일반 객체는 <code>for ...of</code> 문으로 순회 불가, 스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용 불가 )</p>
<pre><code class="language-js">const obj = { a: 1, b: 2 };

// 일반 객체는 이터러블이 아님
console.log(Symbol.iterator in obj);  // false

// 이터러블이 아닌 일반 객체는 for ...of 문으로 순회 불가
for (const item of obj) {
  console.log(item);
}

// 이터러블이 아닌 일반 객체는 배열 디스트럭처링 할당의 대상으로 사용 불가
const [a, b] = obj;  // TypeError: obj is not iterable</code></pre>
</li>
<li><p>단, 일반 객체의 스프레드 문법의 사용은 허용됨.</p>
<pre><code class="language-js">const obj = { a: 1, b: 2 };

// 객체 리터럴 내부에서 스프레드 문법의 사용을 허용
console.log({ ...obj });  // { a: 1, b: 2 }</code></pre>
<h3 id="2-이터레이터">2. 이터레이터</h3>
</li>
<li><p>이터러블의 <code>Symbol.iterator</code> 메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환.</p>
</li>
<li><p>이터러블의 <code>Symbol.iterator</code> 메서드가 반환한 이터레이터는 <code>next</code> 메서드를 갖음.</p>
<pre><code class="language-js">const array = [1, 2, 3];

// Symbol.iterator 메서드는 이터레이터를 반환
const iterator = array[Symbol.iterator]();

// Symbol.iterator 메서드가 반환한 이터레이터는 next 메서드를 갖음
console.log(&#39;next&#39; in iterator);  // true</code></pre>
</li>
<li><p>이터레이터의 <code>next</code> 메서드는 이터러블의 각 요소를 순회하기 위한 포인터의 역할. ( <code>next</code> 메서드 호출 -&gt; 이터레이터 리절트 객체 반환 )</p>
<pre><code class="language-js">const array = [1, 2, 3];

const iterator = array[Symbol.iterator]();

// next 메서드를 호출하면 이터러블을 순회하며 순회 결과를 나타내는 이터레이터 리절트 객체를 반환
// 이터레이터 리절트 객체는 value와 done 프로퍼티를 갖는 객체
console.log(iterator.next());  // { value: 1, done: false }
console.log(iterator.next());  // { value: 2, done: false }
console.log(iterator.next());  // { value: 3, done: false }
console.log(iterator.next());  // { value: undefined, done: true }</code></pre>
</li>
<li><p><code>next</code> 메서드가 반환하는 이터레이터 리절트 객체의 <code>value</code> 프로퍼티는 현재 순회 중인 이터러블의 값, <code>done</code> 프로퍼티는 이터러블의 순회 완료 여부.</p>
</li>
</ul>
<br/>

<h2 id="📁-빌트인-이터러블">📁 빌트인 이터러블</h2>
<ul>
<li>JS는 이터레이션 프로토콜을 준수한 객체인 빌트인 이터러블을 제공.</li>
<li><code>Array</code>, <code>String</code>, <code>Map</code>, <code>Set</code>, <code>TypedArray</code>, <code>arguments</code>, <code>Nodelist</code>, <code>HTMLCollection</code> 등의 표준 빌트인 객체들은 빌트인 이터러블임.</li>
</ul>
<br/>

<h2 id="📁-for-of-문">📁 for ...of 문</h2>
<ul>
<li><p>이터러블을 순회하면서 이터러블의 요소를 변수에 할당.</p>
</li>
<li><p><strong>문법:</strong></p>
<pre><code class="language-js">for ( 변수선언문 of 이터러블 ) { ... }</code></pre>
</li>
<li><p>내부적으로 이터레이터의 <code>next</code> 메서드를 호출하여 이터러블을 순회하며, <code>next</code> 메서드가 반환한 이터레이터 리절트 객체의 <code>value</code> 프로퍼티 값을 변수에 할당. 그리고 이터레이터 리절트 객체의 <code>done</code> 프로퍼티 값이 <code>false</code>이면 이터러블의 순회를 계속하고 <code>true</code>이면 순회를 중단.</p>
<pre><code class="language-js">for (const item of [1, 2, 3]) {
  console.log(item);  // 1 2 3
}</code></pre>
</li>
<li><p><strong>내부 동작:</strong></p>
<pre><code class="language-js">// 이터러블
const iterable = [1, 2, 3];

// 이터러블의 Symbol.iterator 메서드를 호출하여 이터레이터를 생성
const iterator = interable[Symbol.iterator]();

for( ;; ) {
  // 이터레이터의 next 메서드를 호출하여 이터러블을 순회
  // 이때 next 메서드는 이터레이터 리절트 객체를 반환
  const res = iterator.next();

  // next 메서드가 반환한 이터레이터 리절트 객체의 done 프로퍼티 값이 true이면 이터러블의 순회를 중단
  if(res.done) break;

  // 이터레이터 리절트 객체의 value 프로퍼티 값을 item 변수에 할당
  const item = res.value;
  console.log(item);  // 1 2 3
}</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-이터러블과-유사-배열-객체">📁 이터러블과 유사 배열 객체</h2>
<ul>
<li><p>유사 배열 객체는 인덱스로 프로퍼티 값에 접근할 수 있고, length 프로퍼티를 갖는 객체. ( for문으로 순회 가능, 인덱스를 나타내는 숫자 형식의 문자열을 프로퍼티 키로 가지므로 마치 배열처럼 인덱스로 프로퍼티 값에 접근 가능 )</p>
<pre><code class="language-js">// 유사 배열 객체
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

// 유사 배열 객체는 length 프로퍼티를 갖기 때문에 for 문으로 순회 가능
for (let i = 0; i &lt; arrayLike.length; i++) {
  //  유사 배열 객체는 마치 배열처럼 인덱스로 프로퍼티 값에 접근 가능
  console.log(arrayLike[i]);  // 1 2 3
}</code></pre>
</li>
<li><p>하지만 <code>Symbol.iterator</code> 메서드가 없기 때문에 <code>for ...of</code> 문으로 순회 불가.</p>
</li>
<li><p><code>arguments</code>, <code>NodeList</code>, <code>HTMLCollection</code>은 유사 배열 객체이지만 객체에 <code>Symbol.iterator</code> 메서드를 구현하여 이터러블임.</p>
</li>
<li><p><code>Array.from</code> 메서드를 사용하여 배열로 간단히 변환 가능. ( 유사 배열 객체 또는 이터러블을 인수로 전달받아 배열로 변환하여 반환 )</p>
<pre><code class="language-js">// 유사 배열 객체
const arrayLike = {
  0: 1,
  1: 2,
  2: 3,
  length: 3
};

// Array.from은 유사 배열 객체 또는 이터러블을 배열로 변환
const arr = Array.from(arrayLike);
console.log(arr);  // [1, 2, 3]</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-이터레이션-프로토콜의-필요성">📁 이터레이션 프로토콜의 필요성</h2>
<ul>
<li>다양한 데이터 공급자가 하나의 순회 방식을 갖도록 규정하여 데이터 소비자가 효율적으로 다양한 데이터 공급자를 사용할 수 있도록 <strong>데이터 소비자와 데이터 공급자를 연결하는 인터페이스의 역할</strong>을 함.</li>
</ul>
<br/>

<h2 id="📁-사용자-정의-이터러블">📁 사용자 정의 이터러블</h2>
<h3 id="1-사용자-정의-이터러블-구현">1. 사용자 정의 이터러블 구현</h3>
<ul>
<li><p>이터레이션 프로토콜을 준수하지 않는 일반 객체도 이터레이션 프로토콜을 준수하도록 구현하면 사용자정의 이터러블이 됨.</p>
</li>
<li><p>사용자 정의 이터러블은 <code>Symbol.iterator</code> 메서드를 구현하고 <code>Symbol.iterator</code> 메서드가 <code>next</code> 메서드를 갖는 이터레이터를 반환하도록 함. 그리고 이터레이터의 <code>next</code> 메서드는 <code>done</code>과 <code>value</code> 프로퍼티를 가지는 이터레이터 리절트 객체를 반환함.</p>
<pre><code class="language-js">// 피보나치 수열을 구현한 사용자 정의 이터러블
const fibonacci = {
  // Symbol.iterator 메서드를 구현하여 이터러블 프로토콜 준수
  [Symbol.iterator]() {
    let [pre, cur] = [0, 1];
    const max = 10;  // 수열의 최대값

    // Symbol.iterator 메서드는 next 메서드를 소유한 이터레이터를 반환
    // next 메서드는 이터레이터 리절트 객체를 반환
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        // 이터레이터 리절트 객체 반환
        return { value: cur, done: cur &gt;= max }
      }
    };
  }
};

// 이터러블인 fibonacci 객체를 순회할 때마다 next 메서드가 호출됨
for (const num of fibonacci) {
  console.log(num);  // 1 2 3 5 8
}

// 이터러블은 스프레드 문법 사용 가능
const arr = [...fibonacci];
console.log(arr);  // [1, 2, 3, 5, 8]

// 이터러블은 배열 디스트럭처링 할당 가능
const [first, second, ...rest] = fibonacci;
console.log(first, second, rest);  // 1 2 [3, 5, 8]</code></pre>
<h3 id="2-이터러블을-생성하는-함수">2. 이터러블을 생성하는 함수</h3>
</li>
<li><p>이터러블을 반환하는 함수를 만들면 됨.</p>
<pre><code class="language-js">// 피보나치 수열을 구현한 사용자 정의 이터러블을 반환하는 함수
const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];

  // Symbol.iterator 메서드를 구현한 이터러블을 반환
  return {
    [Symbol.iterator]() {
      return {
        next() {
          [pre, cur] = [cur, pre + cur];
          return { value: cur, done: cur &gt;= max };
        }
      };
    }
  };
};

// 이터러블을 반환하는 함수에 수열의 최대값을 인수로 전달하면서 호출
// fibonacciFunc(10)은 이터러블을 반환
for (const num of fibonacciFunc(10)) {
  console.log(num);  // 1 2 3 5 8
}</code></pre>
<h3 id="3-이터러블이면서-이터레이터인-객체를-생성하는-함수">3. 이터러블이면서 이터레이터인 객체를 생성하는 함수</h3>
</li>
<li><p>이터러블이면서 이터레이터인 객체를 생성하여 반환.</p>
<pre><code class="language-js">// 이터러블이면서 이터레이터인 객체를 반환하는 함수
const fibonacciFunc = function (max) {
  let [pre, cur] = [0, 1];

  // Symbol.iterator 메서드와 next 메서드를 소유한 이터러블이면서 이터레이터인 객체를 반환
  return {
    [Symbol.iterator]() { return this; },
    // next 메서드는 이터레이터 리절트 객체를 반환
    next() {
      [pre, cur] = [cur, pre + cur];
      return { value: cur, done: cur &gt;= max };
    }
  };
};

// iter는 이터러블이면서 이터레이터임
let iter = fibonacciFunc(10);

// iter는 이터러블이므로 for ...of 문으로 순회 가능
for (const num of iter) {
  console.log(num);  // 1 2 3 5 8
}

// iter는 이터레이터이므로 이터레이션 리절트 객체를 반환하는 next 메서드를 소유
console.log(iter.next());  // { value: 1, done: false }
console.log(iter.next());  // { value: 2, done: false }
console.log(iter.next());  // { value: 3, done: false }
console.log(iter.next());  // { value: 5, done: false }
console.log(iter.next());  // { value: 8, done: false }
console.log(iter.next());  // { value: 13, done: true }</code></pre>
<h3 id="4-무한-이터러블과-지연평가">4. 무한 이터러블과 지연평가</h3>
</li>
<li><p>무한 이터러블을 생성하는 함수 정의 가능</p>
<pre><code class="language-js">// 무한 이터러블을 생성하는 함수
const fibonacciFunc = function () {
  let [pre, cur] = [0, 1];

  return {
    [Symbol.iterator]() { return this; },
    next() {
      [pre, cur] = [cur, pre + cur];
      // 무한을 구현해야 하므로 done 프로퍼티를 생략
      return { value: cur };
    }
  };
};

// fibonacciFunc 함수는 무한 이터러블을 생성함
for (const num of fibonacciFunc()) {
  if (num &gt; 10000) break;
  console.log(num);  // 1 2 3 5 8 ...  4181 6765
}

// 배열 디스트럭처링 할다응ㄹ 통해 무한 이터러블에서 3개의 요소만 취득
const [f1, f2, f3] = fibonacciFunc();
console.log(f1, f2, f3);</code></pre>
</li>
<li><p>배열이나 문자열 등은 모든 데이터를 메모리에 미리 확보한 다음 데이터를 공급함. 하지만 이터러블은 <strong>지연 평가</strong>를 통해 데이터를 생성.</p>
</li>
<li><p><strong>지연 평가:</strong> 데이터가 필요한 시점 이전까지는 미리 데이터를 생성 X &lt;-&gt; 필요 시점이 되면 그때야 비로소 데이터를 생성.</p>
</li>
</ul>
<h2 id="📁-제너레이터">📁 제너레이터</h2>
<ul>
<li><p>이터러블 객체를 생성하는 특수 함수.</p>
</li>
<li><p>일반 함수와 달리 실행을 일시 중지했다가 필요한 시점에 재개할 수 있음.</p>
<pre><code class="language-js">// 제너레이터 함수 정의
const fibonacciGen = function* () {
  let [pre, cur] = [0, 1];

  while (true) {
    [pre, cur] = [cur, pre + cur];
    yield cur;  // 값을 내뱉고 여기서 멈춤 (무한 루프지만 안전)
  }
};

// 1. for ...of 문 사용
for (const num of fibonacciGen()) {
  if (num &gt; 10000) break;
  console.log(num);  // 1 2 3 5 8 ...  6765
}

// 2. 배열 디스트럭처링 할당
const [f1, f2, f3] = fibonacciGen();
console.log(f1, f2, f3);  // 1 2 3</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 33장. Symbol]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-33%EC%9E%A5.-Symbol</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-33%EC%9E%A5.-Symbol</guid>
            <pubDate>Wed, 25 Feb 2026 18:45:33 GMT</pubDate>
            <description><![CDATA[<h1 id="33장-symbol">33장. Symbol</h1>
<h2 id="📁-심벌이란">📁 심벌이란?</h2>
<ul>
<li>ES6에서 도입된 7번째 데이터 타입으로 변경 불가능한 원시 타입의 값.</li>
<li>다른 값과 중복되지 않는 유일무이한 값.
(주로 이름의 출돌 위험이 없는 유일한 프로퍼티 키를 만들기 위해 사용)</li>
</ul>
<br/>

<h2 id="📁-심벌-값의-생성">📁 심벌 값의 생성</h2>
<h3 id="1-symbol-함수">1. Symbol 함수</h3>
<ul>
<li><p><code>Symbol</code> 함수를 호출하여 생성.</p>
<pre><code class="language-js">// Symbol 함수를 호출하여 유일무이한 심벌 값을 생성
const mySymbol = Symbol();
console.log(typeof mySymbol);  // symbol

// 심벌 값은 외부로 노출되지 않아 확인할 수 없다.
console.log(mySymbol);  // Symbol()</code></pre>
</li>
<li><p>심벌은 <code>new</code> 연산자와 함께 호출하지 않음. ( 심벌 값은 변경 불가능한 원시 값 )</p>
<pre><code class="language-js">new Symbol();  // TypeError: Symbol is not a constructor</code></pre>
</li>
<li><p>문자열을 인수로 전달 가능. ( 생성된 심벌 값에 대한 설명으로 디버깅 용도로만 사용됨. )</p>
<pre><code class="language-js">// 심벌 값에 대한 설명이 같더라도 유일무이한 심벌 값을 생성
const mySymbol1 = Symbol(&#39;mySymbol&#39;);
const mySymbol2 = Symbol(&#39;mySymbol&#39;);

console.log(mySymbol1 === mySymbol2);  // false</code></pre>
</li>
<li><p>객체처럼 접근하면 암묵적으로 래퍼 객체를 생성.</p>
<pre><code class="language-js">const mySymbol = Symbol(&#39;mySymbol&#39;);

// 심벌도 래퍼 객체를 생성
console.log(mySymbol.descripttion);  // mySymbol
console.log(mySymbol.toString());  // Symbol(mySymbol)</code></pre>
</li>
<li><p>심벌 값은 암묵적으로 문자열이나 숫자 타입으로 변환되지 않음.</p>
<pre><code class="language-js">const mySymbol = Symbol();

// 심벌 값은 암묵적으로 문자열이나 숫자 타입으로 변환되지 않음.
console.log(mySymbol + &#39;&#39;);  // TypeError: Cannot convert a Symbol value to a string
console.log(+mySymbol);  // TypeError: Cannot convert a Symbol value to a string</code></pre>
</li>
<li><p>불리언 타입으로는 암묵적 타입 변환 가능. ( <code>if</code>문 등에서 존재 확인이 가능 )</p>
<pre><code class="language-js">const mySymbol = Symbol();

// 불리언 타입으로는 암묵적 타입 변환
console.log(!!mySymbol);  // true

// if문 등에서 존재 확인 가능
if (mySymbol) console.log(&#39;mySymbol is not empty.&#39;);</code></pre>
<h3 id="2symbolfor--symbolkeyfor-메서드">2.Symbol.for / Symbol.keyFor 메서드</h3>
<h4 id="2-1-symbolfor-메서드">2-1. Symbol.for 메서드</h4>
</li>
<li><p>인수로 전달받은 문자열을 키로 사용 -&gt; 전역 심벌 레지스트리에서 해당 키와 일치하는 심벌 값을 검색 -&gt; 검색 실패 시 인수로 전달받은 문자열의 키로 전역 심벌 레지스트레이 저장 -&gt; 생성된 심벌값을 반환.</p>
<pre><code class="language-js">// 전역 심벌 레지스트리에 mySymbol이라는 키로 저장된 심벌 값이 없으면 새로운 심벌 값을 생성
const s1 = Symbol.for(&#39;mySymbol&#39;);
// 전역 심벌 레지스트리에 mySymbol이라는 키로 저장된 심벌 값이 있으면 해당 시벌 값을 반환
const s2 = Symbol.for(&#39;mySymbol&#39;);

console.log(s1 === s2);  // true</code></pre>
</li>
<li><p><code>Symbol</code> 함수 호출: 유일무이한 심벌 값 생성 ( 키 지정 불가 -&gt; 전역 심벌 레지스트리에 등록/관리 X )
<code>Symbol.for</code> 메서드: 애플리케이션 전역에 중복되지 않는 유일무이한 상수인 심벌 값을 단 하나만 생성하여 전역 심벌 레지스트리를 통해 공요.</p>
<h4 id="2-2-symbolkeyfor-메서드">2-2. Symbol.keyFor 메서드</h4>
</li>
<li><p>전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출.</p>
<pre><code class="language-js">// 전역 심벌 레지스트리에 mySymbol이라는 키로 지정된 심벌 값이 없으면 새로운 심벌 값을 생성
const s1 = Symbol.for(&#39;mySymbol&#39;);
// 전역 심벌 레지스트리에 지정된 심벌 값의 키를 추출
Symbol.keyFor(s1);  // -&gt; mySymbol

// Symbol 함수를 호출하여 생성한 심벌 값은 전역 심벌 레지스트리에 등록되어 관리되지 않음
const s2 = Symbol(&#39;foo&#39;);
// 전역 심벌 레지스트리에 저장된 심벌 값의 키를 추출
Symbol.keyFor(s2);  // -&gt; undefined</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-심벌과-상수">📁 심벌과 상수</h2>
<ul>
<li><p>값에는 특별한 의미가 없고 상수 이름 자체에 의미가 있는 경우, 변경/중복될 가능 성이 있는 무의미한 상수 대신 중복될 가능성이 없는 유일무이한 심벌 값을 사용 가능.</p>
<pre><code class="language-js">// 중복될 가능성이 없는 심벌 값으로 상수 값을 생성
const Direction = {
  UP: Symbol(&#39;up&#39;),
  DOWN: Symbol(&#39;down&#39;),
  LEFT: Symbol(&#39;left&#39;),
  RIGHT: Symbol(&#39;right&#39;)
};

const myDirection = Direction.UP;

if (myDirection === Direction.UP) {
  console.log(&#39;You are going UP.&#39;);
}</code></pre>
</li>
<li><p>Enum</p>
<ul>
<li><p>명명된 상수의 집합으로 열거형이라고 부름. ( JS는 enum을 지원하지 않지만 타입스크립트에선 enum을 지원 )</p>
</li>
<li><p><code>Object.freeze</code> 메스드와 심벌 값을 사용해 enum을 흉내 내어 사용 가능.</p>
<pre><code class="language-js">// 중복될 가능성이 없는 심벌 값으로 상수 값을 생성
const Direction = Object.freeze({
  UP: Symbol(&#39;up&#39;),
  DOWN: Symbol(&#39;down&#39;),
  LEFT: Symbol(&#39;left&#39;),
  RIGHT: Symbol(&#39;right&#39;)
});

const myDirection = Direction.UP;

if (myDirection === Direction.UP) {
  console.log(&#39;You are going UP.&#39;);
}</code></pre>
</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-심벌과-프로퍼티-키">📁 심벌과 프로퍼티 키</h2>
<ul>
<li><p>객체의 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열 또는 심벌 값으로 만들 수 있으며, 동적으로 생성 가능.</p>
<pre><code class="language-js">const obj = {
  [Symbol.for(&#39;mySymbol&#39;)]: 1
};

obj[Symbol.for(&#39;mySymbol&#39;)];  // -&gt; 1</code></pre>
</li>
<li><p>심벌 값으로 프로퍼티 키를 만들면 다른 프로퍼티 키와 절대 충돌하지 않음.</p>
</li>
</ul>
<br/>

<h2 id="📁-심벌과-프로퍼티-은닉">📁 심벌과 프로퍼티 은닉</h2>
<ul>
<li><p>심벌 값을 프로퍼티 키로 사용하여 생성한 프로퍼티는 <code>for ...in</code> 문이나 <code>Object.keys</code>, <code>Object.getOwnPropertyNames</code> 메서드로 찾을 수 없음.</p>
</li>
<li><p>심벌 값을 프로퍼티 키로 사용하여 프로퍼티를 생성하면 외부에 노출할 필요가 없는 프로퍼티를 은닉 가능.</p>
<pre><code class="language-js">const obj = {
  [Symbol(&#39;mySymbol&#39;)]: 1
};

for (const key in obj) {
  console.log(key);  // 아무것도 출력되지 않음
}

console.log(Object.keys(obj));  // []
console.log(Object.getOwnPropertyNames(obj));  // []

// getOwnPropertySymbols 메서드는 인수로 전달된 객체의 심벌 프로퍼티 키를 배열로 반환
console.log(Object.getOwnPropertySymbols(obj));  // [Symbol(mySymbol)]

// getOwnPropertySymbols 메서드로 심벌 값도 찾을 수 있음
const symbolKey1 = Object.getOwnPropertySymbols(obj)[0];
console.log(obj[symbolKey1]);  // 1</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-심벌과-표준-빌트인-객체-확장">📁 심벌과 표준 빌트인 객체 확장</h2>
<ul>
<li><p>일반적으로 표준 빌트인 객체에 사용자 정의 메서드를 직접 추가하여 확장하는 것은 권장하지 않음. ( 읽기 전용으로 사용하는 것이 좋음 )</p>
</li>
<li><p>하지만 심벌값으로 프로퍼티를 생성하면 어떤 프로퍼티 키와도 충돌할 위험이 없이 안전하게 표준 빌트인 객체를 확장 가능.</p>
<pre><code class="language-js">// 심벌 값으로 프로퍼티 키를 동적 생성하면 다른 프로퍼티 키와 절대 충돌하지 않아 안전
Array.prototype[Symbol.for(&#39;sum&#39;)] = function () {
  return this.reduce((acc, cur) =&gt; acc + cur, 0);
};

[1, 2][Symbol.for(&#39;sum&#39;)]();  // -&gt; 3</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-well-known-symbol">📁 Well-known Symbol</h2>
<ul>
<li><p>JS가 기본 제공하는 빌트인 심벌 값.</p>
</li>
<li><p>이는 JS엔진의 내부 알고리즘에 사용됨.</p>
</li>
<li><p><code>Array</code>, <code>String</code>, <code>Map</code>, <code>Set</code>, <code>TypedArray</code>, <code>arguments</code>, <code>NodeList</code>, <code>HTMLCollection</code>과 같이 <code>for ...of</code> 문으로 순회 가능한 빌트인 이터러블은 Well-known Symbol인 <code>Symbol.iterator</code>를 키로 갖는 메서드를 가지며, <code>Symbol.iterator</code> 메서드를 호출하면 이터레이터를 반환하도록 ECMAScript 사양에 규정되어 있음.</p>
</li>
<li><p>일반 객체를 이터러블처럼 동작하도록 구현하고 싶다면 이터레이션 프로토콜을 따르면 됨.</p>
<pre><code class="language-js">const iterable = {
  // Symbol.iterator 메서드를 구현하여 이터러블 프로토콜을 준수
  [Symbol.iterator]() {
    let cur = 1;
    const max = 5;
    // Symbol.iterator 메서드는 next 메서드를 소유한 이터레이터를 반환
    return {
      next() {
        return { value: cur++, done: cur &gt; max + 1 }
      }
    };
  }
}

for (const num of iteralbe) {
  console.log(num);  // 1 2 3 4 5
}</code></pre>
</li>
<li><p>이때 이터레이션 프로토콜을 준수하기 위해 일반 객체에 추가해야 하는 메서드의 키 <code>Symbol.iterator</code>는 기존 프로퍼티 키 또는 미래에 추가될 프로퍼티 키와 절대 중복되지 않음.</p>
</li>
<li><p>이처럼 심벌은 중복되지 않는 상수 값을 생성하는 것은 물론 기존 작성된 코드에 영향을 주지 않고 새로운 프로퍼티를 추가하기 위해, 즉 하위 호환성을 보장하기 위해 도입.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 26장. ES6 함수의 추가 기능]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-26%EC%9E%A5.-ES6-%ED%95%A8%EC%88%98%EC%9D%98-%EC%B6%94%EA%B0%80-%EA%B8%B0%EB%8A%A5</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-26%EC%9E%A5.-ES6-%ED%95%A8%EC%88%98%EC%9D%98-%EC%B6%94%EA%B0%80-%EA%B8%B0%EB%8A%A5</guid>
            <pubDate>Fri, 20 Feb 2026 07:01:11 GMT</pubDate>
            <description><![CDATA[<h1 id="26장-es6-함수의-추가-기능">26장. ES6 함수의 추가 기능</h1>
<h2 id="📁-함수의-구분">📁 함수의 구분</h2>
<ul>
<li>ES6 이전의 모든 함수는 일반함수, 생성자 함수 호출이 가능. ( <code>callable</code>, <code>constructor</code> )</li>
<li>ES6 이전 모든 함수는 사용목적에 따라 명확한 구분이 없으므로 호출 방식에 특별한 제약이 없고 생성자 함수로 호출되지 않아도 프로토타입 객체를 생성함. ( 혼란스러우며 실수 유발 가능성, 불필요한 프로토타입 객체 생성으로 성능에도 좋지 않음 )</li>
<li>ES6에서는 이러한 문제를 해결하기 위해 사용 목적에 따라 세 가지 종류로 명확히 함수를 구분.</li>
</ul>
<h3 id="메서드">메서드</h3>
<ul>
<li><p>ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미.</p>
</li>
<li><p>ES6 사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 <code>non-constructor</code> 임.</p>
</li>
<li><p>메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않음.</p>
</li>
<li><p>ES6 메서드는 자신을 바인딩한 객체를 가리키는 <code>[[HomeObject]] 내부 슬롯</code>을 갖음. ( <code>super</code> 참조는 <code>[[HomeObject]] 내부 슬롯</code>을 사용하여 수퍼클래스 메서드를 참조하므로, ES6 메서드는 <code>super</code> 키워드 사용이 가능 )</p>
<pre><code class="language-js">const obj = {
  x: 1,
  foo() { return this.x; }
}

new obj.foo();  // TypeError: obj.foo is not a constructor</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-화살표-함수">📁 화살표 함수</h2>
<ul>
<li>화살표 함수는 콜백 함수 내부에서 <code>this</code>가 전역 객체를 가리키는 문제의 해결 대안으로 유용함.<h3 id="1-화살표-함수의-정의">1. 화살표 함수의 정의</h3>
<pre><code class="language-js">const arrow = (x, y) =&gt; x * y;
</code></pre>
</li>
</ul>
<p>const arrow = (x, y) =&gt; { ... };</p>
<p>const arrow = x =&gt; { ... };</p>
<p>const arrow = () =&gt; { ... };</p>
<p>const arrow = x =&gt; { return x ** 2 };</p>
<p>const arrow = () =&gt; const x = 1;  // SyntaxError: Unexpected token &#39;const&#39;
const arrow = () =&gt; { return const x = 1; };  // 이렇게 해석 됨.</p>
<p>// 함수 몸체의 문이 표현식이 아닌 문 이라면 중괄호를 생략할 수 없음.
const arrow = () =&gt; { const x = 1; };</p>
<p>// 객체 리터럴 반환의 경우 소괄호로 감싸주어야 함
const arrow = (id, content) =&gt; ({ id, content });</p>
<p>// 즉시 실행함수 사용 가능
const person = (name =&gt; ({
  sayHi() { return <code>Hi! {name}</code> }
}))(&#39;Kim&#39;);</p>
<pre><code>### 2. 화살표 함수와 일반 함수의 차이
- 인스턴스를 생성할 수 없는 `non-constructor` 임.
- 중복된 매개변수 이름을 선언할 수 없음.
  ```js
  const arrow = (a, a) =&gt; a + a;
  // SyntaxError: Duplicate parameter name not allowed in this context</code></pre><ul>
<li>함수 자체의 <code>this</code>, <code>arguments</code>, <code>super</code>, <code>new.target</code>. 바인딩을 갖지 않음.
(화살표 함수 내부에서 참조하면 스코프 체인을 통해 상위 스코프의 것을 참조함)<h3 id="3-this">3. this</h3>
</li>
<li>화살표 함수와 일반 함수의 <code>this</code>는 다르게 동작함.</li>
<li>화살표 함수는 함수 자체의 <code>this</code> 바인딩을 갖지 않음. 따라서 화살표 함수 내부에서 <code>this</code>를 참조하면 상위 스코프의 <code>this</code>를 그대로 참조함 ( <code>lexical this</code> ).</li>
<li>마치 화살표 함수의 <code>this</code>가 함수가 정의된 위치에 의해 결정되는 것 처럼 동작.<h3 id="4-super">4. super</h3>
</li>
<li><code>this</code>와 마찬가지로 상위 스코프의 <code>super</code>를 참조.<h3 id="5-arguments">5. arguments</h3>
</li>
<li><code>this</code>와 바찬가지로 상위 스코프의 <code>arguments</code>를 참조.</li>
</ul>
<br/>

<h2 id="📁-rest-파라미터">📁 Rest 파라미터</h2>
<h3 id="기본-문법">기본 문법</h3>
<ul>
<li><p>Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달 받음.</p>
</li>
<li><p>Rest 파라미터는  반드시 마지막 파라미터여야 함.</p>
</li>
<li><p>Rest 파라미터는 함수 객체의 <code>length</code> 프로퍼티(함수 정의 시 선언한 매개변수 개수)에 영향을 주지 않음.</p>
<pre><code class="language-js">function foo(...rest) {
  // 매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터임.
  console.log(rest);
}
foo(1, 2, 3, 4, 5);  // [1, 2, 3, 4, 5]

function foo(param, ...rest) {
  console.log(param);
  console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 1
// [2, 3, 4, 5]</code></pre>
<h3 id="rest-파라미터와-arguments-객체">Rest 파라미터와 arguments 객체</h3>
</li>
<li><p><code>arguments</code> 객체는 배열이 아닌 유사 배열 객체이므로 배열 메서드 사용시 <code>prototype.call</code> 또는 <code>Function.prototype.apply</code> 메서드를 사용해 배열로변환해야 하는 변거로움이 있었음.</p>
</li>
<li><p>ES6에서는 rest 파라미터를 사용하여 가변 인자 함수의 인수 목록을 배열로 직접 전달 받을 수 있음.</p>
</li>
</ul>
<br/>

<h2 id="매개변수-기본값">매개변수 기본값</h2>
<ul>
<li><p>함수 내부에서 수행하던 인수 체크 및 초기화의 간소화를 할 수 있음.</p>
</li>
<li><p>인수를 전달하지 않은 경우와 <code>undefined</code>를 전달한 경우에만 유효.</p>
<pre><code class="language-js">function sum(x = 0, y = 0) {
  return x + y;
}

console.log(sum(1, 2));  // 3
console.log(sum(1));  // 1</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 25장. 클래스]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-25%EC%9E%A5.-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-25%EC%9E%A5.-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Fri, 20 Feb 2026 06:11:35 GMT</pubDate>
            <description><![CDATA[<h1 id="25장-클래스">25장. 클래스</h1>
<p>JS는 <strong>프로토타입 기반</strong> 객체지향 언어임.
클래스는 완전히 새로운 개념이 아니라 기존 프로토타입 기반 상속을 더 명료하게 사용하기 위해 ES6 부터 도입된 <strong>문법적 설탕</strong>에 가까움.
하지만, 클래스는 생성자 함수 기반의 객체 생성 방식보다 견교하고 명료함.
특히 <code>extends</code>와 <code>super</code> 키워드는 상속 관계 구현을 더욱 간결하고 명료하게 하므로, <strong>새로운 객체 생성 매커니즘</strong>으로 보는것이 타당함.</p>
<h2 id="📁-생성자-함수-vs-클래스">📁 생성자 함수 vs 클래스</h2>
<h3 id="1-공통점">1. 공통점</h3>
<p>표면적인 문법은 다르지만, JS엔진 내부에서는 결국 동일한 매커니즘으로 동작.</p>
<ul>
<li>둘다 JS의 <strong>프로토타입 기반</strong>으로 동작.</li>
<li>동일한 구조와 메서드를 가진 여러 개의 객체(인스턴스)를 효율적으로 생성하기 위해 사용.</li>
<li>생성된 인스턴스에 대해 <code>instanceof</code> 연산자를 사용하여 출처확인 가능.</li>
<li>자식 객체가 부모 객체의 속성과 메서드를 물려받아 재사용 가능하게 함. ( 객체지향의 상속 구현 )<h3 id="2-차이점">2. 차이점</h3>
클래스는 개발자의 실수를 줄여주고 더 직관적이고 안전한 코드를 작성할 수 있도록 여러 가지 제약과 편의 기능을 추가함.</li>
</ul>
<table>
<thead>
<tr>
<th>구분</th>
<th>생성자함수</th>
<th>클래스</th>
</tr>
</thead>
<tbody><tr>
<td><code>new</code> 키워드 호출</td>
<td><code>new</code> 연산자 없이 일반 함수로 호출 가능</td>
<td><code>new</code> 연산자 없이 호출시 타입 에러(TypeError)가 발생함</td>
</tr>
<tr>
<td>호이스팅</td>
<td>함수 선언문으로 작성 시 호이스팅이 발생하여 선언 전에 호출 가능</td>
<td>호이스팅이 발생하지만, TDZ의 영향을 받아 선언 전에 접근 시 참조에러(ReferenceError) 발생.</td>
</tr>
<tr>
<td>Strict Mode</td>
<td>기본적으로 적용되지 않음. (필요시 파일 최상단이나 함수 내부에 <code>&#39;use strict&#39;</code>를 명시해야 함.)</td>
<td>클래스 내부 코드는 암묵적으로 항상 엄격모드로 실행됨.</td>
</tr>
<tr>
<td>매서드 열거 여부</td>
<td>프로토타입에 추가한 메서드는 기본적으로 열거 가능 <code>(enumerable: true)</code>하여 <code>for ...in</code> 루프에 노출됨.</td>
<td>클래스 내부에 정의된 메서드는 기본적으로 열거 불가. <code>(enumerable: false)</code></td>
</tr>
<tr>
<td>상속 구현 방식</td>
<td><code>Object.create(Parent.prototype)</code>로 체인을 연결하고, 자식 생성자에서 <code>Parent.call(this)</code>로 부모의 <code>this</code>를 바인등하는 등 수동 작업이 많음</td>
<td><code>extends</code> 키워드로 상속을 선언하고, <code>super()</code>를 호출하여 부모의 생성자와 메서드에 매우 쉽게 접근</td>
</tr>
</tbody></table>
<br/>

<h2 id="📁-클래스-정의">📁 클래스 정의</h2>
<ul>
<li><p><code>class</code> 키워드를 사용하여 정의함. (파스칼 케이스를 사용하는 것이 일반적이나 사용하지 않아도 에러 발생 X)</p>
<pre><code class="language-js">class Person {}</code></pre>
</li>
<li><p>일반적이진 않지만 함수와 마찬가지로 표현식 정의도 가능</p>
<pre><code class="language-js">// 익명 클래스 표현식
const Person = class {};

// 기명 클래스 표현식
const Person = class MyClass {};</code></pre>
</li>
<li><p>클래스에서 정의할 수 있는 메서드는 <strong>constructor(생성자), 프로토타입 메서드, 정적 메서드</strong> 세가지가 있음.</p>
<pre><code class="language-js">// 클래스 선언문
class Person {
  // 생성자
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }

  // 프로토타입 메서드
  sayHi() {
    console.log(`Hi! My name is ${this.name}`);
  }

  // 정적 매서드
  static sayHello() {
    console.log(&#39;Hello!&#39;);
  }
}

// 인스턴스 생성
const me = new Person(&#39;Kim&#39;);

// 인스턴스 프로퍼티 참조
console.log(me.name);  // Kim
// 프로토타입 메서드 호출
me.sayHi();  // Hi! My name is Kim
// 정적 메서드 호출
Person.sayHello();  // Hello!</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-클래스-호이스팅">📁 클래스 호이스팅</h2>
<ul>
<li><p>클래스는 함수로 평가되기 때문에, 클래스 선언문으로 정의한 클래스는 함수 선언문과 같이 소스코드 평가 과정(런타임 이전)에 먼저 평가되어 함수 객체를 생성함.</p>
</li>
<li><p>이때 클래스가 평가되어 생성된 함수 객체는 생성자 함수로서 호출할 수 있는 함수, 즉 <code>constructor</code>임.</p>
</li>
<li><p>생성자 함수로써 호출할 수 있는 함수는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성됨. ( 프로토타입과 생성자 함수는 언제나 쌍으로 존재하기 때문 )</p>
</li>
<li><p>단, 클래스는 클래스 정의 이전에 참조 불가. (클래스 선언문 이전에 TDZ에 빠지기 때문)</p>
<pre><code class="language-js">const Person = &#39;&#39;;

{
  console.log(Person);
  // ReferenceError: Cannot access &#39;Person&#39; before initialization

  // 클래스 선언문
  class Person {}
}</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-인스턴스-생성">📁 인스턴스 생성</h2>
<ul>
<li><p>클래스는 생성자 함수이며 <code>new</code> 연산자와 함께 호출되어 인스턴스를 생성.</p>
</li>
<li><p>생성자 함수와 달리 클래스는 인스턴스를 생성하는 것이 유일한 존재 이유이므로 <strong>반드시 <code>new</code> 연산자와 함께 호출</strong>.</p>
<pre><code class="language-js">class Person {}

const me = Person();
// TypeError: Class constructor Person cannot be invoked without &#39;new&#39;</code></pre>
</li>
<li><p>기명 함수 표현식과 마찬가지로 클래스 표현식에서 사용한 클래스 이름은 외부 코드에서 접근 불가.</p>
<pre><code class="language-js">const Person = class MyClass {};

const me = new Person();

console.log(MyClass);  // ReferenceError: MyClass is not defined

const you = new MyClass();  // ReferenceError: MyClass is not defined</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-메서드">📁 메서드</h2>
<h3 id="1-constructor">1. constructor</h3>
<ul>
<li><p>인스턴스를 생성하고 초기화하기 위한 특수한 메서드. (이름 변경 X)</p>
<pre><code class="language-js">class Person {
  // 생성자
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }
}</code></pre>
</li>
<li><p>클래스는 평가되어 함수 객체가 되기에, 클래스 또한 함수 객체의 고유의 프로퍼티를 모두 갖고 있음.</p>
</li>
<li><p>모든 함수 객체가 가지고 있는 <code>prototype</code> 프로퍼티가 가리키는 프로토타입 객체의 <code>constructor</code> 프로퍼티는 클래스 자신을 가리키고 있음. ( 클래스가 인스턴스를 생성하는 생성자 함수라는 것을 의미 )</p>
</li>
<li><p><code>constructor</code> 내부에서 <code>this</code>에 추가한 프로퍼티는 인스턴스 프로퍼티가 됨. ( 생성자 함수와 마찬가지로 <code>this</code>는 클래스가 생성한 인스턴스를 가리킴 )</p>
</li>
<li><p><code>constructor</code>는 메서드로 해석되는 것이 아닌, 클래스가 평가되어 생성된 함수 객체 코드의 일부가 됨.</p>
</li>
<li><p><strong>생성자 함수와의 차이점:</strong></p>
<ul>
<li><p>클래스 내에 오직 한 개만 존재.</p>
</li>
<li><p>생략 가능 ( 빈 <code>constructor</code>가 암묵적으로 정의됨. )</p>
</li>
<li><p>프로퍼티가 추가되어 초기화된 인스턴스를 생성하려면 <code>constructor</code> 내부에서 <code>this</code>에 인스턴스 프로퍼티를 추가.</p>
<pre><code class="language-js">class Person {
  constructor(name, address) {
    // 고정값으로 인스턴스 초기화
    this.example = example;

    // 인수로 인스턴스 초기화
    this.name = name;
    this.address = address;
  }
}

const me = new Person(&#39;Lee&#39;, &#39;Seoul&#39;);
console.log(me);  // Person { example: &quot;example&quot;, name: &quot;Lee&quot;, address: &quot;Seoul&quot; }</code></pre>
</li>
<li><p><code>constructor</code>는 별도의 반환문을 갖지 않아야함. ( <code>new</code> 연산자와 함께 클래스가 호출되면 생성자 함수가 동일하게 암묵적으로 <code>this</code>(인스턴스를 가리킴)를 반환하기 때문 )</p>
<h3 id="2-프로토타입-메서드">2. 프로토타입 메서드</h3>
</li>
</ul>
</li>
<li><p>생성자 함수와 다르게 클래스는 <code>prototype</code> 프로퍼티에 메서드를 추가하지 않아도 기본적으로 프로토타입 메서드가 됨.</p>
<pre><code class="language-js">class Person {
  // 생성자
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }

  // 프로토타입 메서드
  sayHi() {
    console.log(`Hi! My name is ${this.name}`);
  }
}

const me = new Person(&#39;Kim&#39;);
me.sayHi();  // Hi! My name is Kim</code></pre>
</li>
<li><p>생성자 함수와 마찬가지로 클래스가 생성한 인스턴스는 프로토타입 체인의 일원이 됨.</p>
<h3 id="3-정적-메서드">3. 정적 메서드</h3>
</li>
<li><p>인스턴스를 생성하지 않아도 호출할 수 있는 메서드.</p>
</li>
<li><p><code>staic</code> 키워드를 붙이면 정적 메서드가 된됨.</p>
<pre><code class="language-js">class Person {
  // 생성자
  constructor(name) {
    // 인스턴스 생성 및 초기화
    this.name = name;
  }

  // 정적 메서드
  static sayHi() {
    console.log(&#39;Hi&#39;);
  }
}

Person.sayHi();  // Hi!</code></pre>
<h3 id="4-정적-메서드와-프로토타입-메서드의-차이">4. 정적 메서드와 프로토타입 메서드의 차이</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>정적 메서드</th>
<th>프로토타입 메서드</th>
</tr>
</thead>
<tbody><tr>
<td>저장위치</td>
<td>Parent(생성자 함수 객체자체)</td>
<td>Parent.prototype</td>
</tr>
<tr>
<td><code>this</code> 바인딩</td>
<td>클래스 자체를 가리킴</td>
<td>생성된 인스턴스를 가리킴</td>
</tr>
<tr>
<td>체인구조</td>
<td>클래스 자체에 속하므로, 인스턴스의 프로토타입 체인에는 존재하지 않음. (상속시 부모 클래스 자체가 자식 클래스의 프로토타입이 됨.)</td>
<td>인스턴스 -&gt; Class.prototype -&gt; Object.prototype 순으로 탐색</td>
</tr>
<tr>
<td>### 5. 클래스에서 정의한 메서드의 특징</td>
<td></td>
<td></td>
</tr>
</tbody></table>
</li>
<li><p><code>function</code> 키워드를 생략한 메서드 축약 표현 사용.</p>
</li>
<li><p>객체 리터럴과 다르게 클래스에서 메서드를 정의할 때 콤마 사용 X.</p>
</li>
<li><p>암묵적 <code>strict mode</code>로 실행.</p>
</li>
<li><p><code>for ...in</code>문이나 <code>Object.keys</code> 메서드 등으로 열거 불가.</p>
</li>
<li><p>내부 메서드 [[Construct]]를 갖지 않는 non-constructor. ( <code>new</code> 연산자와 함꼐 호출 불가 )</p>
</li>
</ul>
<br/>

<h2 id="📁-클래스의-인스턴스-생성-과정">📁 클래스의 인스턴스 생성 과정</h2>
<h3 id="1-인스턴스-생성과-this-바인딩">1. 인스턴스 생성과 this 바인딩</h3>
<ul>
<li><code>new</code> 연산자와 함께 클래스 호출 -&gt; 빈 객체 생성(완성되지 않은 인스턴스) -&gt; 생성한 인스턴스의 프로토타입으로 클래스의 <code>prototype</code> 프로퍼티가 가리키는 객체가 설정됨 -&gt; 인스턴스는 <code>this</code>에 바인딩 됨. -&gt; 고로 <code>this</code>는 인스턴스를 가리키게 됨.<h3 id="2-인스턴스-초기화">2. 인스턴스 초기화</h3>
</li>
<li><code>constructor</code> 내부 코드 실행 -&gt; <code>this</code>에 바인딩되어 있는 인스턴스를 초기화 -&gt; 인스턴스에 프로퍼티를 추가하고 인수로 전달받은 초기값으로 인스턴스의 프로퍼티 값을 초기화. ( <code>constructor</code>가 생략되었다면 이과정이 생략됨 )<h3 id="3-인스턴스-반환">3. 인스턴스 반환</h3>
</li>
<li>클래스의 모든 처리가 끝나면 완성된 인스턴스(바인딩된 <code>this</code>)가 암묵적으로 반환됨.</li>
</ul>
<br/>

<h2 id="📁-프로퍼티">📁 프로퍼티</h2>
<h3 id="1-인스턴스-프로퍼티">1. 인스턴스 프로퍼티</h3>
<ul>
<li><p><code>constructor</code> 내부에서 정의 해야함.</p>
</li>
<li><p><code>constructor</code> 내부에서 <code>this</code>에 추가한 프로퍼티는 언제나 클래스가 생성한 인스턴스의 프로퍼티가 됨.</p>
<h3 id="2-접근자-프로퍼티">2. 접근자 프로퍼티</h3>
</li>
<li><p>자체적으로 값(<code>[[Value]] 내부슬롯</code>)을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티</p>
</li>
<li><p><code>get</code>, <code>set</code> 키워드를 동일하게 사용</p>
</li>
<li><p>클래스 메서드는 기본적으로 프로토타입 메서드 이므로, 접근자 프로퍼티 또한 인스턴스 프로퍼티가 아닌 프로토타입의 프로퍼티임.</p>
<h3 id="3-클래스-필드-정의-제안">3. 클래스 필드 정의 제안</h3>
</li>
<li><p><strong>클래스 필드:</strong> 클래스가 생성할 인스턴스의 프로퍼티를 가리키는 용어.</p>
</li>
<li><p>초기 ES6 클래스 문법에서는 클래스 몸체 안에 메서드만 선언할 수 있었으나, ES13 이후 부터는 클래스 필드를 도입하여 <code>constructor</code> 없이도 몸체에 직접 변수 선언이 가능함.</p>
<pre><code class="language-js">// 초기 ES6
class Player {
  constructor() {
    this.hp = 100;  // 인스턴스 필드
  }
}
Player.maxLevel = 99;  // 정적 필드 (밖에서 정의 해야 함)

// ES13 이후
class Player {
  hp = 100;  // Public 인스턴스 필드

  status() {
    console.log(hp);  // ReferenceError: hp is not defined
    console.log(this.hp);
  }
}</code></pre>
</li>
<li><p>인스턴스를 생성할 때 외부 초기값으로 클래스 필드를 초기화할 필요가 있다면 <code>constructor</code>에서 인스턴스 프로퍼티를 정의하고, 필요가 없다면 클래스 필드 정의 제안을 사용하는것이 기본적임.</p>
<h3 id="4-private-필드-정의-제안">4. private 필드 정의 제안</h3>
</li>
<li><p><code>private</code> 필드의 선두에 <code>#</code>을 붙여 사용. ( 참조 시에도 #을 붙여주어야 함 )</p>
</li>
<li><p><code>public</code> 필드와 다르게 <code>private</code> 필드는 클래스 내부에서만 참조할 수 있음. (접근자 프로퍼티를 통해 간접적으로 접근하는 방법은 유효 )</p>
</li>
<li><p><code>private</code> 필드는 반드시 클래스 몸체에 정의해야 함.</p>
<pre><code class="language-js">class Person {
  // private 필드 정의
  #name = &#39;&#39;;

  constructor(name) {
    this.#name = name;
  }

  get name() {
    return this.#name.trim();
  }
}

const me = new Person(&#39; Kim &#39;);
console.log(me.name);  // Kim</code></pre>
<h3 id="5-static-필드-정의-제안">5. static 필드 정의 제안</h3>
</li>
<li><p>ES22 이후 부터 정적 필드를 정의할 수 있게 됨.</p>
</li>
<li><p>단, <code>static</code> 필드는 인스턴스 프로퍼티가 아닌, 클래스의 프로퍼티임.</p>
<pre><code class="language-js">class MyMath {
  // static public 필드 정의
  static PI = 22 / 7;

  // static private 필드 정의
  static #num = 10;

  // static 메서드
  static increment() {
    return ++MyMath.#num;
  }
}</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-상속에-의한-클래스-확장">📁 상속에 의한 클래스 확장</h2>
<h3 id="1-클래스-상속과-생성자-함수-상속">1. 클래스 상속과 생성자 함수 상속</h3>
<ul>
<li><p>기존 클래스를 상속받아 새로운 클래스를 확장하여 정의하는 것.</p>
<pre><code class="language-js">class Animal {
  constructor(age, weight) {
    this.age = age;
    this.weight = weight;
  }

  eat () { return &#39;eat&#39;; }
  move () { return &#39;move&#39;; }
}

class Bird extends Animal {
  fly () { return &#39;fly&#39;; }
}

const bird = new Bird(1, 5);

console.log(bird);  // Bird { age: 1, weight: 5 }
console.log(bird instance Bird);  // true
console.log(bird instance Animal);  // true

console.log(bird.eat());  // eat
console.log(bird.move());  // move
console.log(bird.fly());  // fly</code></pre>
<h3 id="2-extends-키워드">2. extends 키워드</h3>
</li>
<li><p>상속을 통해 클래스를 확장하려면 <code>extends</code> 키워드를 사용하여 상속받을 클래스를 정의</p>
<pre><code class="language-js">// 수퍼(베이스/부모) 클래스
class Base {}

// 서브(파생/자식) 클래스
class Derived extends Base {}</code></pre>
<h3 id="3-동적-상속">3. 동적 상속</h3>
</li>
<li><p><code>extends</code> 키워드는 클래스 뿐 아니라 생성자 함수를 상속받아 클래스를 확장할 수 있음. ( 단, 상속받는 주체는 클래스여야 함. )</p>
</li>
<li><p>상속받을 주체는 클래스 뿐 아니라 <code>[[Construct]] 냅부 메서드</code>를 갖는 함수 객체로 평가될 수 있는 모든 표현식이 가능.</p>
<pre><code class="language-js">function Base1() {}

class Base2 {}

let condition = true;

class Derived extends (condition ? Base1 : Base2) {}

const derived = new Derived();
console.log(derived);  // Derived {}

console.log(derived instanceof Base1);  // true
console.log(derived instanceof Base2);  // false</code></pre>
<h3 id="4-서브클래스-constructor">4. 서브클래스 constructor</h3>
</li>
<li><p>서브클래스 또한 <code>constructor</code> 생략시 암묵적으로 정의됨.</p>
<pre><code class="language-js">// 수퍼 클래스
class Base() {}

// 서브 클래스
class Dervied extends Base {
  // 암묵적 정의 예시
  constructor(...args) { super(...args); }
}

const derived = new Derived();
console.log(derived);</code></pre>
<h3 id="5-super-키워드">5. super 키워드</h3>
</li>
<li><p><code>super</code> 키워드는 함수처럼 호출할 수도 있고 <code>this</code>와 같이 식별자처럼 참조할 수 있는 특수한 키워드임.</p>
<h4 id="🔹-super-호출">🔹 super 호출</h4>
</li>
<li><p><code>super</code>를 호출하면 수퍼클래스의 <code>constructor</code>를 호출.</p>
</li>
<li><p><strong>주의사항:</strong></p>
<ul>
<li>서브클래스에서 <code>constructor</code>를 생략하지 않는 경우 반드시 <code>super</code>를 호출해야 함.</li>
<li>서브클래스의 <code>constructor</code>에서 <code>super</code>를 호출하기 전에는 <code>this</code>를 참조할 수 없음.</li>
<li><code>super</code>는 반드시 서브클래스의 <code>constructor</code>에서만 호출<pre><code class="language-js">class Animal {
constructor(name) {
  this.name = name;
}
}
</code></pre>
</li>
</ul>
<p>class Dog extends Animal {
  constructor(name, breed) {</p>
<pre><code>// 1. 부모 클래스의 constructor(name)를 호출합니다.
// 이 작업이 끝나야만 자식 클래스에서 &#39;this&#39;를 사용할 수 있습니다.
super(name); 

// 2. 자식 클래스만의 고유 속성을 추가합니다.
this.breed = breed;</code></pre><p>  }</p>
<p>  bark() {</p>
<pre><code>console.log(`${this.name}(${this.breed})가 멍멍 짖습니다!`);</code></pre><p>  }
}</p>
<p>const myDog = new Dog(&quot;초코&quot;, &quot;푸들&quot;);
myDog.bark(); // 초코(푸들)가 멍멍 짖습니다!
```</p>
<h4 id="🔹-super-참조">🔹 super 참조</h4>
</li>
<li><p>메서드 내에서 super를 참조하면 수퍼클래스의 메서드를 호출할 수 있음.</p>
<pre><code class="language-js">class Animal {
  constructor(name) {
    this.name = name;
  }

  getName() {
    return this.name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    // 1. 부모 클래스의 constructor(name)를 호출합니다.
    // 이 작업이 끝나야만 자식 클래스에서 &#39;this&#39;를 사용할 수 있습니다.
    super(name); 

    // 2. 자식 클래스만의 고유 속성을 추가합니다.
    this.breed = breed;
  }

  bark () {
    console.log(`${super.getName()}(${this.breed})가 멍멍 짖습니다.`)
  }
}

const myDog = new Dog(&quot;초코&quot;, &quot;푸들&quot;);
myDog.bark(); // 초코(푸들)가 멍멍 짖습니다!</code></pre>
<h3 id="6-상속-클래스의-인스턴스-생성-과정">6. 상속 클래스의 인스턴스 생성 과정</h3>
<h4 id="🔹-서브클래스의-super-호출">🔹 서브클래스의 super 호출</h4>
</li>
<li><p>JS엔진은 클래스를 평가할 때 수퍼클래스와 서브클래스를 구분하기 위해 <code>&quot;base&quot;</code> 또는 <code>&quot;derived&quot;</code>를 값으로 갖는 <code>[[ConstructorKind]] 내부슬롯</code>을 갖음.</p>
</li>
<li><p>다른 클래스를 상속받지 않는 클래스(생성자 함수)는 <code>&quot;base&quot;</code>로 설정, 상속 받는경우 <code>&quot;derived&quot;</code>로 설정됨.</p>
</li>
<li><p>이를 통해 수퍼클래스와 서브클래스는 <code>new</code> 연산자와 함께 호출되었을 때 동작이 구분됨.</p>
</li>
<li><p>서브클래스는 자신이 <strong>직접 인스턴스를 생성하지 않고, 수퍼클래스에 인스턴스 생성을 위임</strong>. ( 서브클래스의 constructor에서 반드시 <code>super</code>를 호출해야 하는 이유 )</p>
<h4 id="🔹-수퍼클래스의-인스턴스-생성과-this-바인딩">🔹 수퍼클래스의 인스턴스 생성과 this 바인딩</h4>
</li>
<li><p>수퍼클래스는 인스턴스를 생성하지만, <code>new</code> 연산자와 함께 호출된 클래스가 서브 클래스 이므로, <code>new.target</code>이 가리키는 서브클래스가 생성한 것으로 처리됨.</p>
<h4 id="🔹-수퍼클래스의-인스턴스-초기화">🔹 수퍼클래스의 인스턴스 초기화</h4>
</li>
<li><p>수퍼클래스의 <code>constructor</code>가 실행되어 <code>this</code>에 바인딩되어 있는 인스턴스를 초기화함.</p>
<h4 id="🔹-서브클래스-constructor로의-복귀와-this-바인딩">🔹 서브클래스 constructor로의 복귀와 this 바인딩</h4>
</li>
<li><p><code>super</code>의 호출이 종료되고, 서브클래스의 <code>constructor</code>로 복귀. 이때 <code>super</code>가 반환한 인스턴스가 <code>this</code>에 바인딩 됨. 서브클래스는 별도의 인스턴스를 생성하지 않고 <code>super</code>가 반환한 인스턴스를 <code>this</code>에 바인딩 하여 그대로 사용.</p>
</li>
<li><p>위와 같이 동작하기 때문에 <code>super</code>가 호출되지 않으면 인스턴스가 생성되지 않으며, <code>this</code> 바인딩도 불가하기 때문에, 서브클래스에서 <code>super</code> 호출전 <code>this</code>를 참조할 수 없는 이유임.</p>
<h4 id="🔹-서브클래스의-인스턴스-초기화">🔹 서브클래스의 인스턴스 초기화</h4>
</li>
<li><p><code>super</code> 호출 이후, 서브클래스의 <code>constructor</code> 내부의 인스턴스 초기화가 실행. <code>this</code>에 바인딩 되어있는 인스턴스에 프로퍼티를 추가하고 <code>constructor</code>가 인수로 전달받은 초기값으로 인스턴스 프로퍼티를 초기화한 함.</p>
<h4 id="🔹-인스턴스-반환">🔹 인스턴스 반환</h4>
</li>
<li><p>클래스의 모든 처리가 끝나면 완성된 인스턴스(바인딩된 <code>this</code>)가 암묵적으로 반환됨.</p>
<h3 id="7-표준-빌트인-생성자-함수-확장">7. 표준 빌트인 생성자 함수 확장</h3>
</li>
<li><p><code>extends</code> 키워드의 상속의 주체는 클래스뿐만이 아니라 <code>[[Construct]] 내부 메서드</code>를 갖는 함수 객체로 평가될 수 있는 모든 표현식을 사용할 수 있으므로, <code>String</code>, <code>Number</code>, <code>Array</code>와 같은 표준 빌트인 객체도 상속 확장하여 사용이 가능.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 24장.클로저]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-24%EC%9E%A5.%ED%81%B4%EB%A1%9C%EC%A0%80</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-24%EC%9E%A5.%ED%81%B4%EB%A1%9C%EC%A0%80</guid>
            <pubDate>Thu, 12 Feb 2026 04:18:05 GMT</pubDate>
            <description><![CDATA[<h1 id="24장-클로저">24장. 클로저</h1>
<ul>
<li>클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합</li>
</ul>
<h2 id="📁-렉시컬-스코프">📁 렉시컬 스코프</h2>
<ul>
<li>JS엔진은 함수를 어디서 호출했는지가 아닌 <strong>함수를 어디에 정의했는지에 따라 상위 스코프를 결정</strong>.</li>
<li>함수의 상위 스코프를 결정한다는 것은 &#39;실행 컨텍스트&#39; 관점에서 &#39;외부 렉시컬 환경에 대한 참조&#39;에 저장할 값이 &#39;상위 렉시컬 환경에 대한 참조&#39;임.</li>
<li>즉, 상위 스코프에 대한 참조는 <strong>함수 정의가 평가되는 시점에 함수가 정의된 환경에 의해 결정</strong>됨. 이것이 렉시컬 스코프임.</li>
</ul>
<h2 id="📁-함수-객체의-내부-슬롯-environment">📁 함수 객체의 내부 슬롯 [[Environment]]</h2>
<ul>
<li>함수는 자신의 &#39;[[Environment]] 내부 슬롯&#39;에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장함.</li>
<li>또한 자신이 호출되었을때 생성될 함수 렉시컬 환경의 &#39;외부 렉시컬 환경에 대한 참조&#39;에 저장될 참조값임.</li>
<li>그렇기 때문에 함수 객체는 상위 스코프(외부 렉시컬 환경)을 자신이 존재하는 한 기억함.</li>
</ul>
<br/>

<h2 id="📁-클로저와-렉시컬-환경">📁 클로저와 렉시컬 환경</h2>
<pre><code class="language-js">const x = 1;

// (1)
function counter() {
  const x = 10;
  const inner = function () { console.log(x); };  // (2)

  return inner;
}

const innerFunc = outer();  // (3)
innerFunc();  // 10</code></pre>
<ul>
<li>(3)번에서 outer() 함수가 호출되고 inner 함수를 반환한 후 outer 함수의 실행 컨텍스트는 콜스택에서 제거되지만, 반환된 inner 함수가 innerFunc 변수에 할당 되어 여전히 &#39;내부슬롯 [[Environment]]&#39;에 outer 함수의 렉시컬 환경을 참조하고 있기 때문에 outer 함수의 렉시컬 환경 가비지 컬렉터의 대상이 되지 않기 때문에 소멸하지 않음.</li>
<li>외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명주기가 종료한 외부 함수의 변수를 참조할 수 있음. 이를 클로저라고 함.</li>
</ul>
<br/>

<h2 id="📁-클로저의-활용">📁 클로저의 활용</h2>
<ul>
<li><p>클로저는 상태를 안전하게 변경하고 유지하기 위해 사용함.</p>
</li>
<li><p>즉, <strong>상태를 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용</strong>하기 위해 사용됨.</p>
<pre><code class="language-js">function createCounter () {
  let num = 0;

  return {
    increase: () =&gt; { return ++num; },
    decrease: () =&gt; { return num &gt; 0 ? --num : 0 }
  }
}

const counter = createCounter();

counter.increase();  // 1
counter.decrease();  // 0

// 직접접근 X
console.log(counter.num);  // undefined</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-캡슐화와-정보-은닉">📁 캡슐화와 정보 은닉</h2>
<ul>
<li><p><strong>캡슐화:</strong> 객체의 상태를 나타내는 <strong>프로퍼티</strong>와 프로퍼티를 참조하고 조작할 수 있는 동작인 <strong>메서드</strong>를 하나로 묶는 것.</p>
<ul>
<li>객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 <strong>정보 은닉</strong>이라 함.</li>
</ul>
</li>
<li><p>부적절한 접근으로 부터 객체의 상태 변경을 방지하고, 객체간의 결합도를 낮추는 효과가 있음.</p>
<pre><code class="language-js">const Person = (function() {
  let _age = 0;  // private

  // 생성자 함수
  function Person(name, age) {
    this.name = name;  // public
    _age = age;
  }

  // 프로토타입 메서드
  Person.prototype.sayHi = function () {
    console.log(`Hi! My name is ${this.name}. I am ${_age}.`);
  };

  return Person;
}());

const me = new Person(&#39;Lee&#39;, 20);
me.sayHi();  // Hi! My name is Lee. I am 20.
console.log(me.name);  // Lee
console.log(me._age);  // undefined

const you = new Person(&#39;Kim&#39;, 30);
you.sayHi();  // Hi! My name is Kim. I am 30.
console.log(you.name);  // Kim
console.log(you._age);  // undefined

me.sayHi();  // Hi! My name is Lee. I am 30.</code></pre>
</li>
<li><p>위 코드를 보면 여러개의 instance를 생성시 <code>_age</code> 변수의 상태가 유지되지 않는다. 이처럼 정보은닉을 완벽하게 지원하진 않음(단순 정보은닉의 경우 Class의 <code>private</code>을 사용하자)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 23장.실행 컨텍스트]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-23%EC%9E%A5.%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-23%EC%9E%A5.%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 12 Feb 2026 02:58:42 GMT</pubDate>
            <description><![CDATA[<h1 id="23장-실행-컨텍스트">23장. 실행 컨텍스트</h1>
<h2 id="📁-소스코드의-타입">📁 소스코드의 타입</h2>
<p>소스코드(실행 가능한 코드)를 4가지 타입으로 구분하는 이유는 소스코드의 타입에 따라 실행 컨텍스트를 생성하는 과정과 관리 내용이 다르기 때문.</p>
<h3 id="🔹-전역-코드">🔹 전역 코드</h3>
<ul>
<li>전역에 존재하는 소스코드
( 전역에 정의된 함수, 클래스 등의 내부 코드는 포함 X )</li>
<li>전역 변수를 관리하기 위해 최상위 스코프인 전역 스코프를 생성해야 함.</li>
<li><code>var</code>키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수를 전역 객체의 프로퍼티와 메서드로 바인딩하고 참조하기 위해 전역 객체와 연결되어야 함.</li>
<li>전역 코드가 평가되면 전역 실행 컨텍스트가 생성됨.<h3 id="🔹-함수-코드">🔹 함수 코드</h3>
</li>
<li>함수 내부에 존재하는 소스코드
( 함수 내부에 중첨된 함수, 클래스 등의 내부코드는 포함 X )</li>
<li>지역 스코프를 생성하고 지역 변수, 매개변수, arguments 객체를 관리해야 함.</li>
<li>생성한 지역 스코프를 전역 스코프에서 시작하는 스코프 체인의 일원으로 연결해야 함.</li>
<li>함수 코드가 평가되면 함수 실행 컨텍스트가 생성됨.<h3 id="🔹-eval-코드">🔹 eval 코드</h3>
</li>
<li>빌트인 전역 함수인 <code>eval</code> 함수에 인수로 전달되어 실행되는 소스코드</li>
<li><code>strict mode</code>에서 자신만의 독자적인 스코프를 생성.</li>
<li><code>eval</code> 코드가 평가되면 <code>eval</code> 실행 컨텍스트가 생성됨.<h3 id="🔹-모듈-코드">🔹 모듈 코드</h3>
</li>
<li>모듈 내부에 존재하는 소스코드
(모듈 내부의 함수, 클래스 등의 내부 코드는 포함 X)</li>
<li>모듈별로 독립적인 모듈 스코프를 생성함.</li>
<li>모듈 스코프가 평가되면 모듈 실행 컨텍스트가 생성됨.</li>
</ul>
<br/>

<h2 id="📁-소스코드의-평가와-실행">📁 소스코드의 평가와 실행</h2>
<p>JS엔진은 소스코드를 2개의 과정, &quot;소스코드의 평가&quot;와 &quot;소스코드의 실행&quot; 과정으로 나누어 처리함.</p>
<h3 id="🔹-소스코드의-평가">🔹 소스코드의 평가</h3>
<ul>
<li>실행 컨텍스트를 생성 -&gt; <strong>변수, 함수 등의 선언문만 먼저 실행</strong> -&gt; 생성된 변수나 함수 식별자를 키로 실행 컨텍스트가 관리하는 스코프(렉시컬 환경의 환경 레코드)에 등록.<h3 id="🔹-소스코드의-실행">🔹 소스코드의 실행</h3>
</li>
<li>소스코드 평가 과정이 끝나면, 선언문을 제외한  소스코드가 순차적으로 실행(런타임의 시작)</li>
<li>소스코드 실행에 필요한 정보(변수나 함수의 참조)를 실행 컨텍스트가 관리하는 스코프에서 검색해서 취득.</li>
<li>변수 값의 변경 등 소스코드의 실행 결과는 다시 실행 컨텍스트가 관리하는 스코프에 등록됨.</li>
</ul>
<br/>

<h2 id="📁-실행-컨텍스트의-역할">📁 실행 컨텍스트의 역할</h2>
<ul>
<li>소스코드를 실행하는데 필요한 환경을 제공하고 코드의 실행 결과를 실제로 관리하는 영역.</li>
<li>식별자(변수, 함수, 클래스 덩의 이름)를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 매커니즘.</li>
<li>모든 코드는 실행 컨텍스트를 통해 실행되고 관리됨.</li>
<li>식별자와 스코프는 <strong>렉시컬 환경</strong>으로 관리하고 코드 실행 순서는 <strong>콜 스택</strong>으로 관리<h3 id="🔹-전역-코드-평가">🔹 전역 코드 평가</h3>
</li>
<li>전역 코드의 변수 선언문과 함수 선언문이 먼저 실행됨.</li>
<li>선언문 실행에 의해 생성된 전역 변수와 전역 함수가 실행 컨텍스트가 관리하는 전역 스코프에 등록됨.</li>
<li><code>var</code>키워드로 선언된 전역 변수와 함수 선언문으로 정의된 전역 함수는 전역 객체의 각각 프로퍼티와 메서드가 됨.<h3 id="🔹-전역-코드-실행">🔹 전역 코드 실행</h3>
</li>
<li>런타임이 시작되어 전역 코드가 순차적으로 실행됨.</li>
<li>전역 변수에 값이 할당되고 함수가 호출됨.</li>
<li>함수가 호출되면 순차적으로 실행되던 전역 코드의 실행을 <strong>일시 중단</strong> 하고 코드 실행 순서를 변경하여 <strong>함수 내부로 진입</strong>함.<h3 id="🔹-함수-코드-평가">🔹 함수 코드 평가</h3>
</li>
<li>매개변수와 지역 변수 선언문이 먼저 실행됨.</li>
<li>선언문 실행에 의해 생성된 매개변수와 지역 변수가 실행 컨텍스트가 관리하는 지역 스코프에 등록됨.</li>
<li>또한 함수 내부에서 지역 변수처럼 사용할 수 있는 arguments 객체가 생성되어 지역 스코프에 등록되고 <code>this</code> 바인딩도 결정됨.<h3 id="🔹-함수-코드-실행">🔹 함수 코드 실행</h3>
</li>
<li>런타임이 시작되어 함수 코드가 순차적으로 실행됨.</li>
<li>이때 매개변수와 지역 변수에 값이 할당되고 메서드가 호출됨.</li>
<li>함수 코드 실행 과정이 종료되면 함수 호출 이전으로 되돌아가 이어서 전역 코드 실행을 계속함.</li>
</ul>
<blockquote>
<p><strong>※ 코드가 실행되려면 다음과 같이 스코프, 식별자, 코드 실행 순서 등의 관리가 필요</strong></p>
</blockquote>
<ul>
<li>선언에 의해 생성된 모든 식별자(변수, 함수, 클래스 등)를 스코프를 구분하여 등록하고 상태 변화(식별자에 바인딩된 값의 변화)를 지속적으로 관리할 수 있어야 함.</li>
<li>스코프는 중첩 관계에 의해 스코프 체인을 형성해야 함. 즉, 스코프 체인을 통해 상위 스코프로 이동하여 식별자를 검색할 수 있어야 함.</li>
<li>현재 실행 중인 코드의 실행 순서를 변경(함수 호출에 의한 실행 순서 변경)할 수 있어야 하며 다시 되돌아갈 수도 있어야 함.</li>
</ul>
<br/>

<h2 id="📁-실행-컨텍스트-스택">📁 실행 컨텍스트 스택</h2>
<ul>
<li>앞서 다뤘던 것 처럼, JS엔진은 소스코드를 평가(전역 코드 평가, 함수 코드 평가 등)하여 실행 컨텍스트를 생성함.</li>
<li>이때, 생성된 실행 컨텍스트들은 스택 자료구조로 관리됨. 이를 <strong>실행 컨텍스트 스택(콜 스택)</strong>이라고 부름.</li>
<li>콜 스택은 코드의 실행 순서를 관리함.</li>
</ul>
<br/>

<h2 id="📁-렉시컬-환경">📁 렉시컬 환경</h2>
<ul>
<li>식별자와 식별자에 바인딩된 값. 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트임.</li>
<li>렉시컬 환경은 스코프와 식별자를 관리</li>
<li>렉시컬 환경은 키와 값을 갖는 객체 형태의 스코프(전역, 함수, 블록)를 생성하여 식별자를 키로 등록하고 식별자에 바인딩된 값을 관리.</li>
<li>렉시컬 환경은 스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을 하는 렉시컬 스코프의 실체임.</li>
</ul>
<br/>

<h2 id="📁-실행-컨텍스트의-생성과-식별자-검색-과정">📁 실행 컨텍스트의 생성과 식별자 검색 과정</h2>
<h3 id="🔹-전역-객체-생성">🔹 전역 객체 생성</h3>
<ul>
<li>전역 객체는 전역 코드가 평가되기 이전에 생성됨.</li>
<li>이때, 전역 객체에는 빌트인 전역 프로퍼티와 빌트인 전역 함수, 그리고 표준 빌트인 객체가 추가되며 동작 환경 또는 특정 환경을 위한 호스트 객체를 포함함.</li>
<li>생성된 전역 객체도 <code>Object.prototype</code>을 상속 받음. 즉, 전역 객체도 프로토타입 체인의 일원임.<h3 id="🔹-전역-코드-평가-1">🔹 전역 코드 평가</h3>
</li>
<li>소스코드가 로드되면 JS엔진은 전역 코드를 평가함.</li>
<li><strong>1️⃣ 전역 실행 컨텍스트 생성</strong><ul>
<li>전역 실행 컨텍스트를 생성하여 콜스택에 푸시함.</li>
</ul>
</li>
<li><strong>2️⃣ 전역 렉시컬 환경 생성</strong><ul>
<li>전역 렉시컬 환경을 생성하고 전역 실행 컨텍스트에 바인딩함.</li>
<li>렉시컬 환경은 &#39;환경 레코드&#39;와 &#39;외부 렉시컬 환경에 대한 참조&#39;로 구성됨.</li>
</ul>
</li>
<li><strong>3️⃣ 전역 환경 레코드 생성</strong><ul>
<li>전역 변수를 관리하는 전역 스코프, 전역 객체의 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체를 제공함.<ul>
<li>전역 코드에서 <code>this</code>는 전역 객체를 가리키므로 전역 객체가 바인딩됨.</li>
</ul>
</li>
<li><strong>객체 환경 레코드:</strong><ul>
<li>기존 <code>var</code> 키워드로 선언한 전역 변수와 함수 선언문으로 정의한 전역함수, 빌트인 전역 프로퍼티와 빌트인 전역 함수, 표준 빌트인 객체를 관리.</li>
<li>전역 객체의 <code>BindingObject</code>와 연결됨.
(이를 통해 전역 코드 평가 과정에서 선언된 전역변수와 전역함수가 전역 객체의 프로퍼티와 메서드가 됨)</li>
</ul>
</li>
<li><strong>선언적 환경 레코드:</strong><ul>
<li><code>let</code>, <code>const</code> 키워드로 선언한 전역 변수를 관리.</li>
</ul>
</li>
</ul>
</li>
<li><strong>4️⃣ <code>this</code> 바인딩</strong><ul>
<li>&#39;전역 환경 레코드&#39;의 &#39;[[GlobalThisValue]] 내부 슬롯&#39;에 <code>this</code>가 바인딩됨.</li>
</ul>
</li>
<li><strong>5️⃣ 외부 렉시컬 환경에 대한 참조 결정</strong><ul>
<li>현재 평가 중인 소스코드를 포함하는 외부 소스코드의 렉시컬 환경, 즉 상위 스코프를 가리킴.</li>
<li>전역 코드를 포함하는 소스코드는 없으므로 <code>null</code>이 할당됨.<h3 id="🔹-전역-코드-실행-1">🔹 전역 코드 실행</h3>
</li>
</ul>
</li>
<li>이제 전역 코드가 순차적으로 실행됨.</li>
<li>변수 할당문이 있는 경우 변수에 값이 할당됨.<ul>
<li>식별자 결정을 위해 &#39;실행 중인 실행 컨텍스트&#39;에서 식별자를 검색하기 시작.</li>
<li>&#39;실행중인 실행 컨텍스트&#39;의 &#39;렉시컬 환경&#39;에서 식별자를 검색할 수 없는 경우, &#39;외부 렉시컬 환경에 대한 참조&#39;가 가리키는 렉시컬 환경, 즉 상위 스코프로 이동하여 식별자를 검색.<h3 id="🔹-함수-코드-평가-1">🔹 함수 코드 평가</h3>
</li>
</ul>
</li>
<li>함수 호출이 되면, JS엔진은 함수 코드의 평가를 시작함.</li>
<li><strong>1️⃣ 함수 실행 컨텍스트 생성</strong><ul>
<li>함수 실행 컨텍스트를 생성하여 콜스택에 푸시함.</li>
</ul>
</li>
<li><strong>2️⃣ 함수 렉시컬 환경 생성</strong><ul>
<li>함수 렉시컬 환경을 생성하고 함수 실행 컨텍스트에 바인딩함.</li>
<li><strong>함수 환경 레코드 생성:</strong><ul>
<li>매개변수, arguments 객체, 함수 내부에서 선언한 지역 변수와 중첩 함수를 등록하고 관리.</li>
</ul>
</li>
<li><strong>this 바인딩:</strong><ul>
<li>&#39;함수 환경 레코드&#39;의 [[ThisValue]] 내부 슬롯에 <code>this</code>가 바인딩됨.</li>
<li>이 때에 <code>this</code>는 호출 방식에 따라 결정됨.</li>
</ul>
</li>
<li><strong>외부 렉시컬 환경에 대한 참조 결정:</strong><ul>
<li>현재 실행중인 실행 컨텍스트의 <strong>렉시컬 환경의 참조</strong>가 할당됨.</li>
<li>함수 객체의 &#39;내부 슬롯 [[Environment]]&#39;에 현재 실행 중인 실행 컨텍스트의 렉시컬 환경을 저장함.<h3 id="🔹-함수-코드-실행-1">🔹 함수 코드 실행</h3>
</li>
</ul>
</li>
</ul>
</li>
<li>호출된 함수의 소스코드가 순차적으로 실행됨.</li>
<li>매개변수에 인수가 할당되고, 변수 할당문이 실행되어 지역 변수에 값이 할당됨.<h3 id="🔹-함수-코드-실행-종료">🔹 함수 코드 실행 종료</h3>
</li>
<li>콜스택에서 함수 실행 컨텍스트가 팝되어 제거되고, 전역 실행 컨텍스트가 &#39;실행 중인 실행 컨텍스트&#39;가 됨.<h3 id="🔹-전역-코드-실행-종료">🔹 전역 코드 실행 종료</h3>
</li>
<li>더는 실행할 전역 코드가 없으면 전역 코드의 실행이 종료되고 전역 실행 컨텍스트도 콜스택에서 팝되어 콜스택은 비어있게 됨.</li>
</ul>
<br/>

<h2 id="📁-실행-컨텍스트와-블록-레벨-스코프">📁 실행 컨텍스트와 블록 레벨 스코프</h2>
<ul>
<li><code>let</code>, <code>const</code> 키워드로 선언한 변수는 모든 코드 블록을 지역 스코프로 인정하는 블록 레벨 스코프를 따름.</li>
<li>코드 블록이 실행되면, 다음과 같이 동작하게됨.<ul>
<li><strong>1️⃣ 블록 렉시컬 환경 생성</strong><ul>
<li><strong>선언적 환경 레코드:</strong><ul>
<li>블록 레벨 스코프 안의 변수들을 관리.</li>
</ul>
</li>
<li><strong>외부 렉시컬 환경에 대한 참조 결정:</strong><ul>
<li>코드블록이 실행되기 이전의 렉시컬 환경을 가리킴.</li>
</ul>
</li>
</ul>
</li>
<li><strong>2️⃣ &#39;현재 실행중인 실행 컨텍스트&#39;의 렉시컬 환경을 교체:</strong><ul>
<li>코드블록 실행 동안만 생성된 블록 렉시컬 환경으로 바인딩.</li>
</ul>
</li>
<li><strong>3️⃣ 코드블록 종료</strong><ul>
<li>블록 렉시컬 환경의 &#39;외부 렉시컬 환경에 대한 참조&#39;를 통하여 현재 실행중인 실행 컨텍스트&#39;의 렉시컬 환경을 되돌림.</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 22장.this]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-22%EC%9E%A5.this</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-22%EC%9E%A5.this</guid>
            <pubDate>Mon, 09 Feb 2026 03:52:03 GMT</pubDate>
            <description><![CDATA[<h1 id="22장-this">22장. this</h1>
<h2 id="📁-this-키워드">📁 this 키워드</h2>
<ul>
<li><p><code>this</code>는 <strong>자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수</strong>임.</p>
</li>
<li><p><code>this</code>는 JS엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조가 가능. 함수를 호출하게 되면 <code>arguments 객체</code>와 <code>this</code>가 암묵적으로 함수 내부에 전달됨.</p>
</li>
<li><p><code>this</code>가 가리키는 값(<code>this</code> 바인딩)은 <strong>함수 호출 방식에 의해 동적으로 결정</strong>됨.</p>
<pre><code class="language-js">// 생성자 함수
function Circle(radius) {
  // this는 생성자 함수가 생성할 인스턴스를 가리킴
  this.radius = radius;
}

Circle.prototype.getDiameter = function () {
  // this는 생성자 함수가 생성할 인스턴스를 가리킴
  return 2 * this.radius;
}

// 인스턴스 생성
const circle = new Circle(5);
console.log(circle.getDiameter());  // 10</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-함수-호출-방식과-this-바인딩">📁 함수 호출 방식과 this 바인딩</h2>
<pre><code class="language-js">// this 바인딩은 함수 호출 방식에 따라 동적으로 결정됨
const foo = function () {
  console.dir(this);
};

// 1. 일반 함수 호출
foo();  // window

// 2. 메서드 호출
const obj = { foo };
obj.foo();  // obj

// 3. 생성자 함수 호출
new foo();  // foo {}</code></pre>
<h3 id="일반-함수-호출">일반 함수 호출</h3>
<ul>
<li><p>기본적으로 <code>this</code>에는 전역 객체가 바인딩 됨.</p>
<pre><code class="language-js">function foo() {
  console.log(&quot;foo&#39;s this: &quot;, this);  // window

  function bar() {
    console.log(&quot;bar&#39;s this: &quot;, this);  // window
  }
  bar();
}
foo();</code></pre>
</li>
<li><p><code>strict mode</code>가 적용된 일반 함수 내부의 <code>this</code>에는 <code>undefined</code>가 바인딩됨.</p>
<pre><code class="language-js">function foo() {
  &#39;use strict&#39;;

  console.log(&quot;foo&#39;s this: &quot;, this);  // undefined

  function bar() {
    console.log(&quot;bar&#39;s this: &quot;, this);  // undefined
  }
  bar();
}
foo();</code></pre>
</li>
<li><p>일반 함수로 호출된 모든 함수(중첩 함수, 콜백 함수 포함) 내부의 <code>this</code>에는 전역 객체가 바인딩 됨.</p>
<pre><code class="language-js">var value = 1;

const obj = {
  value: 100,
  foo() {
    console.log(&quot;foo&#39;s this: &quot;, this);  // {value: 100, foo: ⨍}
    // 콜백 함수 내부의 this에는 전역 객체가 바인딩 됨
    setTimeout(function () {
      console.log(&quot;callback&#39;s this: &quot;, this);  // window
      console.log(&quot;callback&#39;s this.value&quot;, this.value);  // 1
    }, 100);
  }
};

obj.foo();</code></pre>
</li>
<li><p>화살표 함수 내부의 this는 상위 스코프의 this를 가리킴</p>
<pre><code class="language-js">var value = 1;

const obj = {
  value: 100,
  foo() {
    // 화살표 함수 내부의 this는 상위 스코프의 this를 가리킴
    setTimeout(() =&gt; console.log(this.value), 100);  // 100
  }
};</code></pre>
<h3 id="메서드-호출">메서드 호출</h3>
</li>
<li><p>메서드 내부의 <code>this</code>는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩 됨.</p>
<pre><code class="language-js">const person = {
  name: &#39;Lee&#39;,
  getName() {
    // 메서드 내부의 this는 메서드를 호출한 객체에 바인딩됨
    return this.name;
  }
};

// 메서드 getName을 호출한 객체는 person임
console.log(person.getName());  // Lee

const anotherPerson = {
  name: &#39;Kim&#39;
};

// getName 메서드를 anotherPerson 객체의 메서드로 할당
anotherPerson.getName = person.getName;

// getName 메서드를 호출한 객체는 anotherPerson
console.log(anotherPerson.getName());  // Kim

// getName 메서드를 변수에 할당
const getName = person.getName;

// getName 메서드를 일반 함수로 호출
console.log(getName());  // &#39;&#39;</code></pre>
</li>
<li><p>프로토타입 메서드 내부에서 사용된 <code>this</code>도 일반 메서드와 마찬가지로 해당 메서드를 호출한 객체에 바인딩 됨.</p>
<pre><code class="language-js">function Person(name) {
  this.name = name;
}

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

const me = new Person(&#39;Lee&#39;);

// getName 메서드를 호출한 객체는 me
console.log(me.getName());  // Lee

Person.prototype.name = &#39;Kim&#39;;

// getName 메서드를 호출한 객체는 Person.prototype
console.log(Person.prototype.getName());  // Kim</code></pre>
<h3 id="생성자-함수-호출">생성자 함수 호출</h3>
</li>
<li><p>생성자 함수 내부의 <code>this</code>에는 생성자 함수가 생성할 인스턴스가 바인딩됨.</p>
<pre><code class="language-js">// 생성자 함수
function Circle(radius) {
  // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킴
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.radius;
  };
}

// 반지름 5인 Circle 객체를 생성
const circle1 = new Circle(5);
// 반지름 10인 Circle 객체를 생성
const circle2 = new Circle(10);

console.log(circle1.getDiameter());  // 10
console.log(circle2.getDiameter());  // 20</code></pre>
<h3 id="functionprototypeapplycallbind-메서드에-의한-간접-호출">Function.prototype.apply/call/bind 메서드에 의한 간접 호출</h3>
</li>
<li><p><code>apply</code>, <code>call</code>, <code>bind</code> 메서드는 <code>Function.prototype</code>의 메서드임.(모든 함수가 상속받아 사용 가능)</p>
<pre><code class="language-js">const user = { name: &quot;현석&quot; };

function greet(greeting, punctuation) {
  // 원래라면 this는 전역 객체(window)겠지만, call/apply/bind로 user를 가리키게 함
  console.log(`${greeting}, ${this.name}${punctuation}`);
}

// 1. call 사용 (인수를 쉼표로 나열하여 즉시 실행)
greet.call(user, &quot;안녕하세요&quot;, &quot;!&quot;); 
// 출력: &quot;안녕하세요, 현석!&quot;

// 2. apply 사용 (인수를 배열로 묶어 전달하며 즉시 실행)
greet.apply(user, [&quot;반갑습니다&quot;, &quot;!!&quot;]); 
// 출력: &quot;반갑습니다, 현석!!&quot;

// 3. bind 사용 (this가 바인딩된 &#39;새로운 함수&#39;를 반환, 즉시 실행 X)
const boundGreet = greet.bind(user); 

// 원하는 시점에 호출 (인수는 이때 전달하거나, bind 시 미리 전달 가능)
boundGreet(&quot;어서오세요&quot;, &quot;...&quot;); 
// 출력: &quot;어서오세요, 현석...&quot;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 21장.빌트인 객체]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-21%EC%9E%A5.%EB%B9%8C%ED%8A%B8%EC%9D%B8-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-21%EC%9E%A5.%EB%B9%8C%ED%8A%B8%EC%9D%B8-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Mon, 09 Feb 2026 02:20:41 GMT</pubDate>
            <description><![CDATA[<h1 id="21장-빌트인-객체">21장. 빌트인 객체</h1>
<h2 id="📁-자바스크립트-객체의-분류">📁 자바스크립트 객체의 분류</h2>
<ul>
<li><strong>표준 빌트인 객체:</strong><ul>
<li>ECMAScript 사양에 정의된 객체.</li>
<li>전역의 공통 기능을 제공.</li>
<li>ECMAScript 사양에 정의된 객체이므로 JS 실행 환경(브라우저 또는 Node.js 환경)과 관계없이 사용 가능.</li>
<li>표준 빌트인 객체는 전역 객체의 프로퍼티로서 제공됨. 따라서 별도의 선언 없이 전역 변수처럼 언제나 참조 가능.</li>
</ul>
</li>
<li><strong>호스트 객체:</strong><ul>
<li>ECMAScript 사양에 정의되어 있지 않지만 JS 실행환경에서 추가로 제공하는 객체.</li>
<li>브라우저 환경: DOM, BOM, Canvas, XMLHttpRequest, fetch, requestAnimationFrame, SVG, Web Storage, Web Component, Web Worker와 같은 클라이언트 사이드 Web API를 호스트 객체로 제공.</li>
<li>Node.js: Node.js 고유의 API를 호스트 객체로 제공.</li>
</ul>
</li>
<li><strong>사용자 정의 객체:</strong><ul>
<li>사용자가 직접 정의한 객체</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-표준-빌트인-객체">📁 표준 빌트인 객체</h2>
<ul>
<li>JS는 <strong>Object, String, Number, Boolean, Symbol, Date, Math, RegExp, Array, Map/Set, WeakMap/WeakSet, Function, Promise, Reflect, Proxy, JSON, Error</strong> 등 40여 개의 표준 빌트인 객체를 제공.</li>
<li><strong>Math, Reflect, JSON</strong>을 제외한 표준 빌트인 객체는 모두 생성자 함수 객체임.</li>
<li>생성자 함수 객체인 표준 빌트인 객체는 프로토타입 메서드와 정적 메서드를 제공.</li>
</ul>
<br/>

<h2 id="📁-원시값과-래퍼-객체">📁 원시값과 래퍼 객체</h2>
<ul>
<li><p>야래 코드를 보면 원시값은 객체가 아니므로 프로퍼티나 메서드를 가질 수 없는데, 원시값인 문자열이 마치 객체처럼 동작함.</p>
<pre><code class="language-js">const str = &#39;hello&#39;;

// 원시 타입인 문자열이 프로퍼티와 메서드를 갖고 있는 객체처럼 동작
console.log(str.length);  // 5
console.log(str.toUpperCase());  // HELLO</code></pre>
</li>
<li><p>원시값에 대해 객체처럼 접근하면 생성되는 임시 객체를 <strong>래퍼 객체</strong>라 함.</p>
</li>
<li><p><strong>동작원리:</strong> 원시값에 대해 마침표 표기법(또는 대괄호 표기법)으로 접근 -&gt; JS엔진이 일시적으로 원시값과 연관된 객체의 인스턴스 생성 -&gt; 생성된 래퍼 객체의 내부 슬롯에 원시값 할당 -&gt; 사용 종료시 내부 슬롯의 원시값으로 되돌림 -&gt; 생성되었던 래퍼 객체는 가비지 컬렉션의 대상이 됨.</p>
</li>
<li><p>위와 같은 동작으로 생성된 래퍼 객체의 인스턴스는 프로토타입 메서드를 상속받아 사용할 수 있게 됨.</p>
</li>
<li><p><code>null</code>과 <code>undefined</code>는 래퍼 객체를 생성하지 않음.</p>
</li>
</ul>
<br/>

<h2 id="📁-전역-객체">📁 전역 객체</h2>
<ul>
<li>코드가 실행되기 이전 JS엔진에 의해 어떤 객체보다 먼저 생성되는 특수한 객체. (어떤 객체에도 속하지 않는 최상위 객체)</li>
<li>JS환경에 따라 지칭하는 이름이 제각각<ul>
<li>브라우저: window, self, this, frames</li>
<li>Node.js: global</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>globalThis:</strong> ECMAScript2020에서 도입된 전역 객체를 가리키던 다양한 식별자를 통일한 식별자. globalThis는 표준 사양이므로 ECMAScript 표준 사양을 준수하는 모든 환경에서 사용 가능.</p>
</blockquote>
<ul>
<li>전역객체는 <strong>표준 빌트인 객체</strong>, <strong>호스트 객체</strong>, var 키워드로 선언한 전역 변수와 전역함수를 프로퍼티로 갖음.</li>
<li>전역 객체는 계층적 구조상 어떤 객체에도 속하지 않은 모든 빌트인 객체의 최상위 객체(단, 이는 프로토타입 상속 관계상 최상위 객체란 의미와는 다름)</li>
<li>전역 객체는 개발자가 의도적으로 생성할 수 없음. 전역 객체를 생성할 수 있는 생성자 함수는 제공되지 않음.</li>
<li>전역 객체의 프로퍼티를 참조할 때 식별자를 생략할 수 있음.<h3 id="빌트인-전역-프로퍼티">빌트인 전역 프로퍼티</h3>
</li>
<li>빌트인 전역 프로퍼티는 전역 객체의 프로퍼티를 의미. 주로 애플리케이션 전역에서 사용하는 값을 제공</li>
<li>Infinity:<ul>
<li>Infinity 프로퍼티는 무한대를 나타내는 숫자값 Infinity를 갖음.</li>
</ul>
</li>
<li>NaN:<ul>
<li>NaN 프로퍼티는 숫자가 아님을 나타내는 숫자값 NaN을 갖음.</li>
</ul>
</li>
<li>undefined:<ul>
<li>undefined 프로퍼티는 원시 타입 undefined를 값으로 갖음.<h3 id="빌트인-전역-함수">빌트인 전역 함수</h3>
</li>
</ul>
</li>
<li>빌트인 전역 함수는 애플리케이션 전역에서 호출할 수 있는 빌트인 함수로서 전역 객체의 메서드임.</li>
<li>eval:<ul>
<li>eval 함수는 JS 코드를 나타내는 문자열을 인수로 전달 받음.</li>
<li>전달받은 문자열 코드가 표현식이라면 런타임에 평가하여 값을 생성하고, 전달받은 인수가 표현식이 아닌 문이라면 문자열 코드를 런타임에 실행함.</li>
<li>보안 이슈로 사용 금지.</li>
</ul>
</li>
<li>isFinite:<ul>
<li>전달받은 인수가 정상적인 유한수인지 검사하여 유한수이면 <code>true</code>, 무한수이면 <code>false</code>를 반환. NaN으로 평가되는 값이면 <code>false</code>를 반환.</li>
</ul>
</li>
<li>isNaN:<ul>
<li>전달받은 인수가 NaN인지 검사하여 그 결과를 불리언 타입으로 반환. 전달받은 인수가 숫자가 아닌 경우 숫자 타입을 변환 후 검사를 수행.</li>
</ul>
</li>
<li>parseInt:<ul>
<li>전달받은 문자열 인수를 정수로 해석하여 반환.</li>
<li>두 번째 인수로 진법을 나타내는 기수 전달 가능.</li>
<li>첫번째 인수가 두 번째 인수인 지수로 변환이 불가능 한 경우 NaN을 반환.</li>
</ul>
</li>
<li>parseFloat:<ul>
<li>전달받은 문자열 인수를 부동 소수점 숫자, 실수로 해석하여 반환</li>
</ul>
</li>
<li>encodeURI / decodeURI:<ul>
<li>encodeURI 함수는 완전한 URI를 문자열로 전달받아 이스케이프 처리를 위해 인코딩 함.</li>
<li>decodeURI 함수는 인코딩된 URI를 인수로 전달받아 이스케이프 처리 이전으로 디코딩함.</li>
</ul>
</li>
<li>encodeURIComponent / decodeURIComponent<ul>
<li>encodeURIComponent 함수는 URI 구성 요소를 인수로 전달받아 인코딩 함.</li>
<li>decodeURIComponent 함수는 매개변수로 전달된 URI 구성 요소를 디코딩함.<h3 id="암묵적-전역">암묵적 전역</h3>
</li>
</ul>
</li>
<li>JS엔진은 할당문을 만날 시 스코프 체인으로 스코프 어디에서도 변수 선언을 찾을 수 없으면 전역 객체에 프로퍼티를 동적으로 생성함. 이를 <strong>암묵적 전역</strong> 이라고 함.</li>
<li>이때 생성되는 프로퍼티는 변수가 아니므로 호이스팅이 발생하지 않음.</li>
<li>또한 변수가 아니라 단지 프로퍼티 이므로 <code>delete</code> 연산자로 삭제가 가능 (전역 변수는 프로퍼티이지만 <code>delete</code> 연산자로 삭제가 불가능)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 20장.strict mode]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-20%EC%9E%A5.strict-mode</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-20%EC%9E%A5.strict-mode</guid>
            <pubDate>Mon, 09 Feb 2026 01:25:52 GMT</pubDate>
            <description><![CDATA[<h1 id="20장-strict-mode">20장. strict mode</h1>
<h2 id="📁-strict-mode">📁 strict mode</h2>
<ul>
<li><p>아래 코드를 보면 전역 스코프에 x변수의 선언이 존재하지 않아 <code>RefferenceError</code>를 발생시킬 것 같지반 JS 엔진은 암묵적으로 전역 객체에 <code>x</code> 프로퍼티를 동적 생성함.
이러한 현상을 <strong>암묵적 전역</strong>이라 함.</p>
<pre><code class="language-js">function foo() {
  x = 10;
}
foo();

console.log(x);</code></pre>
</li>
<li><p>ES5 부터 JS문법을 좀 더 엄격히 적용하여 오류를 발생시킬 가능성이 높거나 JS엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시킬 수 있는 <code>strict mode(엄격 모드)</code>가 추가됨.</p>
</li>
<li><p>ES6에서 도입된 클래스와 모듈은 기본적으로 <code>strict mode</code>가 적용됨.</p>
</li>
<li><p><code>strict mode</code> 보단 린트 도구의 사용을 지향.</p>
</li>
</ul>
<br/>

<h2 id="📁-strict-mode의-적용">📁 strict mode의 적용</h2>
<ul>
<li><p>전역의 선두 또는 함수 몸체의 선두에 <code>&#39;use strict&#39;;</code>를 추가.</p>
<pre><code class="language-js">&#39;use strict&#39;;

function foo() {
  x = 10;  // ReferenceError: x is not defined
}
foo();</code></pre>
<pre><code class="language-js">function foo() {
  &#39;use strict&#39;;

  x = 10;  // ReferenceError: x is not defined
}
foo();</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-전역에-strict-mode를-적용하는-것은-피하자">📁 전역에 strict mode를 적용하는 것은 피하자</h2>
<ul>
<li><p>전역에 적용한 <code>strict mode</code>는 스크립트 단위로 적용됨.</p>
</li>
<li><p><code>strict mode</code>와 <code>non-strict mode</code> 스크립트를 혼용하는 것은 오류를 발생시킬 수 있고, 특히 서드파티 라이브러리를 사용하는 경우 라이브러리가 <code>non-strict mode</code>인 경우도 있기 때문에 전역에 <code>strict mode</code>를 적용하는 것은 바람직 하지 않음. (이러한 경우는 즉시 실행 함수로 스크립트 전체를 감싸서 스코프를 구분하고 즉시 실행 함수의 선두에 strict mode를 적용)</p>
<pre><code class="language-js">(function () {
  &#39;use strict&#39;;

  // Do something...
}());</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-함수-단위로-strict-mode를-적용하는-것도-피하자">📁 함수 단위로 strict mode를 적용하는 것도 피하자</h2>
<ul>
<li>함수 단위로 <code>strict mode</code>를 적용할 수 있으나, 어떤 함수는 적용하고 어떤 함수는 미적용 하는 것은 바람직하지 않으며 모든 함수에 일일이 <code>strict mode</code>를 적용하는 것은 번거로운 일임. 그리고 <code>strict mode</code>가 적용된 함수가 참조할 함수 외부의 컨텍스트에 <code>strict mode</code>를 적용하지 않는다면 이 또한 문제를 발생시킬 수 있음.</li>
<li><code>strict mode</code>는 즉시 실행 함수로 감싼 스크립트 단위로 적용하는 것이 바람직함.</li>
</ul>
<br/>

<h2 id="📁-strict-mode가-발생시키는-에러">📁 strict mode가 발생시키는 에러</h2>
<h3 id="암묵적-전역">암묵적 전역</h3>
<pre><code class="language-js">(function () {
  &#39;use strict&#39;;

  x = 1;
  console.log(x);  // ReferenceError: x is not defined
}());</code></pre>
<h3 id="변수-함수-매개변수의-삭제">변수, 함수, 매개변수의 삭제</h3>
<ul>
<li><p><code>delete</code> 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError가 발생.</p>
<pre><code class="language-js">(function () {
  &#39;use strict&#39;;

  var x = 1;
  delete x;  // SyntaxError: Delete of an unqualified identifier in strict mode.

  function foo(a) {
    delete a;  // SyntaxError: Delete of an unqualified identifier in strict mode.
  }
  delete foo;  // SyntaxError: Delete of an unqualified identifier in strict mode.
}());</code></pre>
<h3 id="매개변수-이름의-중복">매개변수 이름의 중복</h3>
</li>
<li><p>중복된 매개변수 이름을 사용하면 SyntaxError가 발생.</p>
<pre><code class="language-js">(function () {
  &#39;use strict&#39;;

  // SyntaxError: Duplicate parameter name not allowed in this context
  function foo(x, x) {
    return x + x;
  }
  console.log(foo(1, 2));
}());</code></pre>
<h3 id="with-문의-사용">with 문의 사용</h3>
</li>
<li><p><code>with</code>문을 사용하면 SyntaxError가 발생.</p>
</li>
<li><p><code>with</code>문은 전달된 객체를 스코프 체인에 추가한다. 동일한 객체의 프로퍼티를 반복해서 사용할 때 객체 이름을 생략할 수 있어서 코드가 간단해지는 효과가 있지만, 성능과 가독성이 나빠지므로 사용하지 않는 것이 좋음.</p>
<pre><code class="language-js">(function () {
  &#39;use clinet&#39;;

  // SyntaxError: Strict mode code may not include a with statement
  with({ x: 1 }) {
    console.log(x);     
  }
}());</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-strict-mode-적용에-의한-변화">📁 strict mode 적용에 의한 변화</h2>
<h3 id="일반-함수의-this">일반 함수의 this</h3>
<ul>
<li><p><code>strict mode</code>에서 함수를 일반 함수로서 호출하면 <code>this</code>에 <code>undefined</code>가 바인딩 됨.</p>
</li>
<li><p>생성자 함수가 아닌 일반 함수 내부에서 <code>this</code>를 사용할 필요가 없기 때문. (에러는 발생하지 않음)</p>
<pre><code class="language-js">(function () {
  &#39;use strict&#39;;

  function foo() {
    console.log(this);  // undefined
  }
  foo();

  function Foo() {
    console.log(this);  // Foo
  }
  new Foo();
}());</code></pre>
<h3 id="arguments-객체">arguments 객체</h3>
</li>
<li><p><code>strict mode</code>에서는 매개변수에 전달된 인수를 재할당하여 변경해도 <code>arguments 객체</code>에 반영되지 않음.</p>
<pre><code class="language-js">(function (a) {
  &#39;use strict&#39;;
  // 매개변수에 전달된 인수를 재할당하여 변경
  a = 2;

  // 변경된 인수가 arguments 객체에 반영되지 않음
  console.log(arguments);  // { 0: 1, length: 1 }
}(1));</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 19장.프로토타입]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-19%EC%9E%A5.%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-19%EC%9E%A5.%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85</guid>
            <pubDate>Mon, 02 Feb 2026 04:05:10 GMT</pubDate>
            <description><![CDATA[<h1 id="19장-프로토타입">19장. 프로토타입</h1>
<h2 id="📁-객체지향-프로그래밍">📁 객체지향 프로그래밍</h2>
<ul>
<li><strong>실체:</strong> 특징이나 성질을 나타내는 <strong>속성</strong>을 가지고 있고, 이를 통해 실체를 인식하거나 구별 가능.</li>
<li><strong>추상화:</strong> 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 내어 표현하는 것.</li>
<li><strong>객체:</strong> 속성을 통해 여러 개의 값을 하나의 단위로 구성한 복합적인 자료구조.</li>
<li><strong>객체지향 프로그래밍:</strong> 이러한 독립적인 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임.<ul>
<li>객체의 <strong>상태</strong>를 나타내는 데이터와 상태 데이터를 조작할 수 있는 <strong>동작</strong>을 하나의 논리적 단위로 묶어서 생각함.</li>
<li>객체는 <strong>상태 데이터와 동작을 하나의 논리적인 단위로 묶은 복합적인 자료구조</strong>라 할 수 있음.</li>
<li><strong>프로퍼티:</strong> 객체의 상태, <strong>메서드:</strong> 객체의 동작</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-상속과-프로토타입">📁 상속과 프로토타입</h2>
<ul>
<li><p>객체지향 프로그래밍의 핵심 개념으로, 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것.</p>
<pre><code class="language-js">// 생성자 함수
function Circle(radius) {
  this.radius = radius;
  this.getArea = function () {
    return Math.PI * this.radius ** 2;
  }
}

const circle1 = new Cirecle(1);
const circle2 = new Cirecle(2);

// Circle 생성자 함수는 인스턴스를 생성할 때마다 동일한 동작을 하는
// getArea 메서드를 중복 생성하고 모든 인스턴스가 중복 소유함.
// getArea 메서드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직함.
console.log(circle1.getArea === circle2.getArea);  // false</code></pre>
</li>
<li><p>JS는 <strong>프로토타입을 기반으로 상속을 구현</strong>하여 불필요한 중복을 제거.</p>
<pre><code class="language-js">// 생성자 함수
function Circle(radius) {
  this.radius = radius;
}

// Circle 생성자 함수가 생성한 모든 인스턴스가 getArea 메서드를
// 공유해서 사용할 수 있도록 프로토타입에 추가.
// 프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩 되어있음.
Circle.prototype.getArea = function () {
  return Math.PI * this.radius ** 2;
}

const circle1 = new Cirecle(1);
const circle2 = new Cirecle(2);

console.log(circle1.getArea === circle2.getArea);  // true</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-프로토타입-객체">📁 프로토타입 객체</h2>
<ul>
<li><p>객체 간 상속을 구현하기 위해 사용됨.</p>
</li>
<li><p>어떠한 객체의 부모 객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티(메서드 포함)를 제공함.</p>
</li>
<li><p>프로토타입 객체를 상속받은 자식 객체는 부모 객체의 프로퍼티를 자신의 프로퍼티처럼 자유롭게 사용 가능.</p>
</li>
<li><p>모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조임. [[Prototype]]에 저장되는 프로토타입은 객체의 생성 방식에 따라 결정됨.</p>
</li>
<li><p>모든 객체는 하나의 프로토타입을 갖고, 그리고 모든 프로토타입은 생성자 함수와 연결되어 있음.</p>
</li>
<li><p>[[Prototype]] 내부 슬롯에 직접 접근할 수 없지만, <code>__proto__</code> 접근자 프로퍼티를 통해 자신의 프로토타입에 간접적으로 접근 가능.</p>
</li>
<li><p>프로토타입은 자신의 <code>constructor</code> 프로퍼티를 통해 생성자 함수에 접근할 수 있고, 생성자 함수는 자신의 <code>prototype</code> 프로퍼티를 통해 프로토타입에 접근할 수 있음.</p>
<pre><code>[1. 생성자 함수 (Person)]
      |
      | (prototype 프로퍼티: &quot;내 파트너는 쟤야&quot;)
      | ➡️ 참조값 저장
      |
      v
[2. 프로토타입 객체 (Person.prototype)]
      |
      | (constructor 프로퍼티: &quot;나를 만든 건 쟤야&quot;)
      | ➡️ 참조값 저장 (역참조)
      |
      ^
      |
      | (__proto__ 접근자: &quot;내 부모님은 쟤야&quot;)
      | ➡️ 참조값 매핑 (상속)
      |
[3. 인스턴스 (me)]</code></pre></li>
<li><p>헷갈릴수 있는 포인트</p>
<ul>
<li>생성자 함수를 사용하게 되면, 생성된 인스턴스의 [[prototype]] 내부슬롯은 <code>부모 객체.prototype</code>을 참조하게 됨.</li>
<li>즉, 인스턴스의 진짜 상속의 대상은 생성자 함수가 아닌, 그 생성자 함수의 <code>prototype</code> 객체임.<h3 id="__proto__-접근자-프로퍼티"><code>__proto__</code> 접근자 프로퍼티</h3>
</li>
</ul>
</li>
<li><p>내부 슬롯은 프로퍼티가 아니기 때문에, JS는 원칙적으로 내부 슬롯과 내부 메서드에 직접적으로 접근하거나 호출 할 수 없음.</p>
</li>
<li><p>모든 객체는 <code>__proto__</code> 접근자 프로퍼티를 통해 자신의 프로토타입 객체, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있음.</p>
<h4 id="__proto__-접근자-프로퍼티다"><code>__proto__</code> 접근자 프로퍼티다.</h4>
</li>
<li><p>접근자 프로퍼티는 자체적으로 값([[Value]] 프로퍼티 어트리뷰트)를 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수, [[Get]], [[Set]] 프로퍼티 어트리뷰트로 구성된 프로퍼티임.</p>
</li>
<li><p><code>__proto__</code> 프로퍼티를 통해 프로토타입에 접근하면 내부적으로 [[Get]]이 호출, 새로운 프로토타입을 할당하면, [[Set]]이 호출됨.</p>
<pre><code class="language-js">const obj = {};
const parent = { x: 1 };

obj.__proto__;
obj.__proto__ = parent;

console.log(obj.x);  // 1;</code></pre>
<h4 id="__proto__-접근자-프로퍼티는-상속을-통해-사용됨"><code>__proto__</code> 접근자 프로퍼티는 상속을 통해 사용됨.</h4>
</li>
<li><p><code>__proto__</code> 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아닌 <code>Object.prototype</code>의 프로퍼티임.</p>
</li>
<li><p>모든 객체는 상속을 통해 <code>Object.prototype.__proto__</code> 프로퍼티를 사용할 수 있음.</p>
<pre><code class="language-js">const person = { name: &#39;Lee&#39; };

// person 객체는 직접적으로 __proto__ 프로퍼티를 소유하지 않음.
console.log(person.hasOwnProperty(&#39;__proto__&#39;));  // false

// 모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속 받아 사용.
console.log({}.__proto__ === Object.prototype);  // true
console.log({}.__proto__ === person.__proto__);  // true</code></pre>
<h4 id="__proto__-접근자-프로퍼티를-통해-프로토타입에-접근하는-이유"><code>__proto__</code> 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유</h4>
</li>
<li><p>상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서임.</p>
<pre><code class="language-js">const parent = {};
const child = {};

child.__proto__ = parent;
parent.__proto__ = child;  // TypeError: Cyclic __proto__ value</code></pre>
</li>
<li><p>위 코드 처럼 서로가 자신의 프로토타입이 되는 비정상적인 프로토타입 체인(순환 참조)이 만들어지기 전 <code>__proto__</code> 접근자 프로퍼티는 에러를 발생시킴.</p>
<h4 id="__proto__-접근자-프로퍼티를-코드-내에-직접-사용하는-것은-권장하지-않음"><code>__proto__</code> 접근자 프로퍼티를 코드 내에 직접 사용하는 것은 권장하지 않음.</h4>
</li>
<li><p><code>Object.getPrototypeOf</code> 메서드와 <code>Object.setPrototypeOf</code> 메서드를 사용하는 것을 권장.</p>
<pre><code class="language-js">// 상속 받는 곳이 없는 순수 객체 생성
const obj = Object.create(null);

console.log(obj.__proto__);  // undefined</code></pre>
<pre><code class="language-js">const obj = {};
const parent = { x: 1 };

Object.getPrototypeOf(obj);  // obj.__proto
Object.setPrototypeOf(obj, parent)  // obj.__proto__ = parent

console.log(obj);  // 1</code></pre>
<h3 id="함수-객체의-prototype-프로퍼티">함수 객체의 prototype 프로퍼티</h3>
</li>
<li><p>함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킴.</p>
</li>
<li><p>책이 너무 어렵게 설명하고 있는 거 같음.
어렵게 생각하지말고, 상속될 주체가 prototype이니까 함수에 의해 생성될 인스턴스가 가져갈 프로토타입을 갖는다 생각하자.</p>
</li>
<li><p><strong>proto</strong> 접근자 프로퍼티는 모두가 갖고 있음. 왜? 부모 프로토타입에 접근하기 위해.</p>
</li>
<li><p>prototype 프로퍼티는 생성자 함수만 갖음.(화살표 함수를 제외한 함수가 다 갖고 있지만 생성자 함수가 아닌 함수들은 쓸모 없음) 왜? 자식 인스턴스에게 상속해야 되니까.</p>
</li>
</ul>
<h3 id="프로토타입의-constructor-프로퍼티와-생성자-함수">프로토타입의 constructor 프로퍼티와 생성자 함수</h3>
<ul>
<li><p>모든 프로토타입 객체는 <code>constructor</code> 프로퍼티를 갖음.</p>
</li>
<li><p>자신을 참조하고 있는 생성자 함수를 가리키려고.</p>
<pre><code class="language-js">// 생성자 함수
function Person(name) {
  this.name = name;
}

const me = new Person(&#39;Kim&#39;);

// me 객체의 생성자 함수는 Person
console.log(me.constructor === Person);  // true

const member1 = new Person(&#39;철수&#39;);

// member1이 뭘로 만들어졌는지 모르겠지만, 
// 걔를 만든 기계(constructor)를 가져와서 영희를 또 찍어내자!
const member2 = new member1.constructor(&#39;영희&#39;);

console.log(member2.name); // &#39;영희&#39;
console.log(member2 instanceof Person); // true</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-리터럴-표기법에-의해-생성된-객체의-생성자-함수와-프로토타입">📁 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입</h2>
<ul>
<li><p>책에서 겁나 어렵게 써있는데... JS엔진은 추상 연산을 통해 그에 맞는 생성자 함수와 프로토타입을 지정해 준다로 알고 넘어가면 될듯함.</p>
<table>
<thead>
<tr>
<th>리터럴 표기법</th>
<th>내부적으로 연결되는 생성자 함수</th>
<th>상속받는 프로토타입</th>
</tr>
</thead>
<tbody><tr>
<td>객체 <code>{}</code></td>
<td>Object</td>
<td>Object.prototype</td>
</tr>
<tr>
<td>함수 <code>function() {}</code></td>
<td>Function</td>
<td>Function.prototype</td>
</tr>
<tr>
<td>배열 <code>[]</code></td>
<td>Array</td>
<td>Array.prototype</td>
</tr>
<tr>
<td>정규표현식 <code>/abc/</code></td>
<td>RegExp</td>
<td>RegExp.prototype</td>
</tr>
</tbody></table>
</li>
<li><p>리터럴로 생성해도 생성자 함수와 같이 <code>constructor</code>와 <code>__proto__</code>가 연결됨.</p>
<pre><code class="language-js">// 1. 객체 리터럴
const obj = {};
console.log(obj.constructor === Object); // true
console.log(obj.__proto__ === Object.prototype); // true

// 2. 배열 리터럴
const arr = [1, 2, 3];
console.log(arr.constructor === Array); // true
console.log(arr.__proto__ === Array.prototype); // true

// 3. 함수 리터럴
const func = function() {};
console.log(func.constructor === Function); // true
console.log(func.__proto__ === Function.prototype); // true</code></pre>
</li>
<li><p>프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재.</p>
</li>
</ul>
<br/>

<h2 id="📁-프로토타입의-생성-시점">📁 프로토타입의 생성 시점</h2>
<ul>
<li>프로토타입 객체는 생성자 함수가 생성되는 시점에 더불어 생성됨.</li>
<li>생성자 함수는 &#39;빌트인 생성자 함수&#39;와 &#39;사용자 정의 생성자 함수&#39;로 구분.<h3 id="사용자-정의-생성자-함수와-프로토타입-생성-시점">사용자 정의 생성자 함수와 프로토타입 생성 시점</h3>
</li>
<li>화살표 함수나, 메서드 축약 표현으로 정의 하지 않은 일반 함수로 정의한 함수 객체는 <code>new</code> 연산자와 함께 생성자 함수로 호출 가능.</li>
<li>생성자 함수로 호출할 수 있는 함수는 <strong>함수 정의가 평가되어 함수 객체를 생성하는 시점</strong>에, <code>constructor</code>를 프로퍼티로 갖는 <code>프로토타입 객체</code>도 더불어 생성됨.</li>
<li>이때 생성된 <code>프로토타입 객체</code>는 <code>constructor</code> 프로퍼티만을 갖는 객체이며, 생성된 프로토타입의 프로토타입은 <code>Object.prototype</code>임.<h3 id="빌트인-생성자-함수와-프로토타입-생성-시점">빌트인 생성자 함수와 프로토타입 생성 시점</h3>
</li>
<li>모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성되며, 각 생성된 프로토타입 객체는 빌트인 생성자 함수의 <code>prototype</code> 프로퍼티에 바인딩되 있음.</li>
<li>이후 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면, 프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당됨.</li>
</ul>
<br/>

<h2 id="📁-객체-생성-방식과-프로토타입의-결정">📁 객체 생성 방식과 프로토타입의 결정</h2>
<ul>
<li>모든 객체는 추상 연산 <code>OrdinaryObjectCreate</code>에 의해 생성된다는 공통점이 있음.</li>
<li>이는 자신이 생성할 객체의 프로토타입을 인수로 전달 받고,<ul>
<li>빈 객체를 먼저 생성.</li>
<li>인수로 전달된 프로퍼티 목록을 객체에 추가.</li>
<li>인수로 전달된 프로토타입을 생성한 객체의 [[Prototype]] 내부 슬롯에 할당.</li>
<li>생성된 객체를 반환.</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-프로토타입-체인">📁 프로토타입 체인</h2>
<ul>
<li>JS는 객체의 프로퍼티에 접근하려고 할때 해당 객체에 <strong>접근하려는 프로퍼티가 없다면</strong> [[Prototype]] 내부 슬롯의 참조를 따라 <strong>자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색</strong>.</li>
<li>프로토타입 체인의 최상위에 위치하는 객체는 언제나 <code>Object.prototype</code> 임.</li>
</ul>
<br/>

<h2 id="📁-오버라이딩과-프로퍼티-섀도잉">📁 오버라이딩과 프로퍼티 섀도잉</h2>
<pre><code class="language-js">const Person = (function() {
  // 생성자 함수
  function Person(name) {
    this.name = name;
  }

  // 프로토타입 메서드
  Person.prototype.sayHello = function () {
    console.log(`Hi! My name is ${this.name}`)
  };

  // 생성자 함수를 반환
  return Person;
}());

const me = new Person(&#39;Kim&#39;);

// 인스턴스 메서드
me.sayHello = function () {
  console.log(`Hey! My name is ${this.name}`);
};

// 인스턴스 메서드가 호출됨. 프로토타입 메서드는 인스턴스 메서드에 의해 가려짐.
me.sayHello();  // Hey! My name is Kim</code></pre>
<ul>
<li>프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 프로토타입 체인을 따라 프로토타입 프로퍼티를 검색하여 <u>프로토타입 프로퍼티를 덮어쓰는 것이 아닌 인스턴스 프로퍼티로 추가</u>함.</li>
<li>이때 인스턴스 메서드 sayHello는 프로토타입 메서드 sayHello를 오버라이딩 했고, 프로토타입 메서드 sayHello는 가려지게 됨.</li>
<li>이를 프로퍼티 섀도잉이라고 함.<pre><code class="language-js">// 인스턴스 메서드 삭제
delete me.sayHello;
</code></pre>
</li>
</ul>
<p>me.sayHello();  // Hi! My name is Kim</p>
<pre><code>- 당연하게 프로토타입 메서드가 아닌 인스턴스 메서드 sayHello가 삭제됨.
```js
// 프로토타입 체인을 통해 프로토타입 메서드는 삭제되지 않음
delete me.sayHello;

me.sayHello();  // Hi! My name is Kim</code></pre><ul>
<li>하위 객체를 통해 프로토타입의 프로퍼티를 변경/삭제는 불가능.<pre><code class="language-js">// 프로토타입 메서드 변경
Person.prototype.sayHello = function () {
console.log(`Hey! My name is ${this.name}`);
};
me.sayHello();  // Hey! My name is Lee
</code></pre>
</li>
</ul>
<p>// 프로토타입 메서드 삭제
delete Person.prototype.sayHello;
me.sayHello();  // TypeError: me.sayHello is not a function</p>
<pre><code>- 프로토타입 프로퍼티를 변경/삭제 하려면 하위 객체를 통해 프로토타입 체인 접근이 아닌 프로토타입에서 직접 접근해야 함.

&lt;br/&gt;

## 📁 프로토타입의 교체
![](https://velog.velcdn.com/images/van_lan/post/06d0f1d9-ca84-41bd-a5fe-651ba5a02aed/image.png)

&lt;br/&gt;

## 📁 instanceof 연산자
```js
객체 instanceof 생성자 함수</code></pre><ul>
<li>어렵게 생각하지말고, 우변인 생성자 함수의 prototype 프로퍼티가 가리키는 객체가 좌변인 객체의 프로토타입 체인 상에 존재하는지(<code>__proto__</code> 접근자로 타고 올라가 접근이 가능한지)를 판별하는 거라고 보면 됨.</li>
</ul>
<br/>

<h2 id="📁-직접-상속">📁 직접 상속</h2>
<h3 id="objectcreate에-의한-직접-상속">Object.create에 의한 직접 상속</h3>
<ul>
<li><p>첫 번째 인자: 부모가 될 객체 (필수)</p>
</li>
<li><p>두 번째 인자: 태어날 객체의 속성 정의 (선택, 좀 복잡함)</p>
<pre><code class="language-js">// 부모가 될 객체
const myProto = { x: 10 };

// 1. &quot;myProto를 부모로 삼는 객체 obj를 만들어라!&quot;
// (두 번째 인자는 생략 가능하지만, 쓴다면 이렇게 디스크립터로 써야 함)
const obj = Object.create(myProto, {
  y: { value: 20, writable: true, enumerable: true, configurable: true }
});

console.log(obj.x); // 10
console.log(obj.y); // 20
console.log(Object.getPrototypeOf(obj) === myProto); // true</code></pre>
</li>
</ul>
<h3 id="객체-리터럴-내부에서-proto에-의한-직접-상속">객체 리터럴 내부에서 <strong>proto</strong>에 의한 직접 상속</h3>
<ul>
<li><p>가장 쉽고 직관적인 방법</p>
<pre><code class="language-js">const myProto = { x: 10 };

// &quot;객체를 만드는데, 내 부모(__proto__)는 myProto로 설정할게.&quot;
const obj = {
  y: 20,
  __proto__: myProto // 👈 여기서 바로 상속 지정!
};

console.log(obj.x); // 10 (상속됨)
console.log(Object.getPrototypeOf(obj) === myProto); // true</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-정적-프로퍼티메서드">📁 정적 프로퍼티/메서드</h2>
<ul>
<li><p>생성자 함수로 인스턴스를 생성하지 않아도 참조/호출할 수 있는 프로퍼티/메서드를 말함.</p>
<pre><code class="language-js">// 생성자 함수
function Person(name) {
  this.name = name;
}

// 프로토타입 메서드
Person.prototype.sayHello = function () {
  console.log(`Hi! My name is ${this.name}`);
};

// 정적 프로퍼티
Person.staticProps = &#39;static prop&#39;;

// 정적 메서드
Person.staticMethod = function () {
  console.log(&#39;staticMethod&#39;);
}

const me = new Person(&#39;Kim&#39;);

// 생성자 함수에 추가한 정적 프로퍼티/메서드는 생성자 함수로 참조/호출
Person.staticMethod();

// 정적 프로퍼티/메서드는 인스턴스로는 참조/호출 불가
me.staticMethod();  // TypeError: me.staticMethod is not a function</code></pre>
</li>
<li><p>생성자 함수가 생성한 인스턴스는 자신의 프로토타입 체인에 속한 객체의 프로퍼티/메서드에는 접근할 수 있지만, 정적 프로퍼티/메서드는 인스턴스의 프로토타입 체인에 속한 객체의 프로퍼티/메서드가 아니기 때문에 접근이 불가함.</p>
</li>
</ul>
<br/>

<h2 id="📁-프로퍼티-존재-확인">📁 프로퍼티 존재 확인</h2>
<h3 id="in-연산자">in 연산자</h3>
<pre><code class="language-js">key in object

// in 연산자 대신 Reflect.has 메서드를 사용할 수도 있음
Reflect.has(object, key);</code></pre>
<h3 id="objectprototypehasownpropery-메서드">Object.prototype.hasOwnPropery 메서드</h3>
<ul>
<li>인수로 전달받은 프로퍼티 키가 <strong>객체의 고유의 프로퍼티 키인 경우</strong>에만 <code>true</code>를 반환</li>
<li>상속 받은 프로토타입의 프로퍼티 키인 경우 <code>false</code>를 반환 함.</li>
</ul>
<br/>

<h2 id="📁-프로퍼티-열거">📁 프로퍼티 열거</h2>
<h3 id="for--in-문">for ... in 문</h3>
<ul>
<li>객체의 모든 프로퍼티를 순회하며 열거.<pre><code class="language-js">const person = {
name: &#39;Kim&#39;,
address: &#39;Seoul&#39;
};
</code></pre>
</li>
</ul>
<p>for (const key in person) {
  console.log(key + &#39;: &#39; + person[key]);
}</p>
<pre><code>- 프로퍼티의 프로퍼티 어트리뷰트 [[Enumerable]]의 값이 `true`인 것들만 순회하며 열거.
- 프로퍼티 키가 심벌인 프로퍼티는 열거하지 않음.
- 상속받은 프로퍼티는 제외하고 객체 자신의 프로퍼티만 열거하려면 `Object.prototype.hasOwnPropery` 메서드를 사용하여 조건부 확인 해야함.
- 프로퍼티를 열거할 때 순서를 보장하지 않음. (모던 브라우저는 순서를 보장)

### Object.keys/values/entries 메서드
```js
const person = {
  name: &#39;Kim&#39;,
  address: &#39;Seoul&#39;,
  __proto__: { age: 20 }
};

console.log(Object.keys(person));  // [&quot;name&quot;, &quot;address&quot;]
console.log(Object.values(person));  // [&quot;Kim&quot;, &quot;Seoul&quot;]
console.log(Object.entries(person));  // [[&quot;name&quot;, &quot;Kim&quot;], [&quot;address&quot;, &quot;Seoul&quot;]]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 15장.let, const 키워드와 블록 레벨 스코프]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-15%EC%9E%A5.-let-const-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%99%80-%EB%B8%94%EB%A1%9D-%EB%A0%88%EB%B2%A8-%EC%8A%A4%EC%BD%94%ED%94%84</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-15%EC%9E%A5.-let-const-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%99%80-%EB%B8%94%EB%A1%9D-%EB%A0%88%EB%B2%A8-%EC%8A%A4%EC%BD%94%ED%94%84</guid>
            <pubDate>Fri, 30 Jan 2026 02:56:07 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-var-키워드로-선언한-변수의-문제점">📁 <code>var</code> 키워드로 선언한 변수의 문제점</h2>
<h3 id="변수-중복-선언-허용">변수 중복 선언 허용</h3>
<ul>
<li><code>var</code> 키워드로 선언한 변수는 중복 선언이 가능.</li>
<li>이는 동일한 이름의 변수가 이미 선언되어 있는 것을 모르고 변수를 중복 선언하면서 값의 할당했다면 의도치 않게 먼저 선언된 변수 값이 변경되는 부작용이 발생.</li>
</ul>
<h3 id="함수-레벨-스코프">함수 레벨 스코프</h3>
<ul>
<li><code>var</code> 키워드로 선언한 변수는 오로지 함수의 코드 블록만을 지역 스코프로 인정하게 됨.</li>
<li>고로, 함수 외부에서 <code>var</code> 키워드로 선언한 변수는 코드 블록(조건문, 반복문 등) 내에서 선언해도 모두 전역 변수가 됨.</li>
<li>함수 레벨 스코프는 전역 변수를 남발할 가능성을 높이고, 이로 인해 의도치 않게 전역 변수가 중복 선언되는 경우가 발생할 수 있음.</li>
</ul>
<h3 id="변수-호이스팅">변수 호이스팅</h3>
<ul>
<li><code>var</code> 키워드로 변수를 선언하면 호이스팅에 의해 변수 선언문 이전에 변수를 참조할 수 있음.</li>
<li>이는 에러를 발생시키지는 않지만 프로그램의 흐름상 맞지 않을 뿐더러 가독성을 떨어뜨리고 오류 발생의 여지를 남김.</li>
</ul>
<br/>

<h2 id="📁-let-키워드">📁 <code>let</code> 키워드</h2>
<h3 id="변수-중복-선언-금지">변수 중복 선언 금지</h3>
<ul>
<li><p><code>let</code> 키워드로 이름이 같은 변수를 중복 선언하면 문법 에러가 발생.</p>
<pre><code class="language-js">var foo = 123;
var foo = 456;

let bar = 123;
let bar = 456;  // SyntaxError: Identifier &#39;bar&#39; has already declared</code></pre>
<h3 id="블록-레벨-스코프">블록 레벨 스코프</h3>
</li>
<li><p><code>let</code> 키워드로 선언한 변수는 모든 코드 블록(함수, 조건문, 반복문, try/catch 등)을 지역 스코프로 인정하는 블록 레벨 스코프를 따름.</p>
<pre><code class="language-js">let foo = 1;  // 전역 변수
{
  let foo = 2;  // 지역 변수
  let bar = 3;  // 지역 변수
}

console.log(foo);  // 1
console.log(bar);  // ReferenceError: bar is not defined</code></pre>
<h3 id="변수-호이스팅-1">변수 호이스팅</h3>
</li>
<li><p><code>var</code> 키워드와 달리 <code>let</code> 키워드로 선언한 변수는 호이스팅이 발생하지 않는 것처럼 동작함.</p>
</li>
<li><p><code>let</code> 키워드로 선언한 변수는 <strong>&quot;선언단계&quot;와 &quot;초기화 단계&quot;가 분리</strong>되어 진행.</p>
</li>
<li><p>&quot;초기화 단계&quot;가 실행되기 이전에 변수에 점근하려고 하면, 참조 에러가 발생.</p>
<pre><code class="language-js">console.log(foo);  // ReferenceError: foo is not defined

let foo;  // 변수 선언문에서 초기화 단계가 실행
console.log(foo);  // undefined

foo = 1;  // 할당문에서 할당 단계가 실행
console.log(foo);  // 1</code></pre>
<blockquote>
<p><strong>※ 일시적 사각지대(TDZ):</strong> <code>let</code> 키워드로 선언한 변수는 &quot;스코프의 시작 지점&quot;부터 &quot;초기화 시작 지점&quot;까지 변수를 참조할 수 없는 구간</p>
</blockquote>
</li>
<li><p>위와 같은 이유로 호이스팅은 발생하지만, 호이스팅이 발생하지 않는 것처럼 동작.</p>
</li>
</ul>
<h3 id="전역-객체와-let">전역 객체와 let</h3>
<ul>
<li><code>var</code> 키워드와 달리 <code>let</code> 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아님.</li>
<li><code>let</code> 전역 변수는 보이지 않는 개념적인 블록(전역 렉시컬 환경의 선언적 환경 레코드) 내에 존재하게 됨.</li>
</ul>
<br/>

<h2 id="📁-const-키워드">📁 <code>const</code> 키워드</h2>
<ul>
<li><code>const</code> 키워드의 특징은 <code>let</code> 키워드와 대부분 동일함.<h3 id="선언과-초기화">선언과 초기화</h3>
</li>
<li><code>const</code> 키워드로 선언한 변수는 <strong>선언과 동시에 반드시 초기화</strong> 해줘야 함.<pre><code class="language-js">const foo;  // SyntaxError: Missing initializer in const declaration</code></pre>
<h3 id="재할당-금지">재할당 금지</h3>
</li>
<li><code>const</code> 키워드로 선언한 변수는 <strong>재할당이 금지</strong>됨.<pre><code class="language-js">const foo = 1;
foo = 2;  // TypeError: Assignment to constant variable.</code></pre>
<h3 id="상수">상수</h3>
</li>
<li>재할당이 금지된 변수를 말함.</li>
<li><code>const</code> 키워드로 선언된 변수에 원시 값을 할당한 경우 원시 값은 변경할 수 없는 값이고, <code>const</code> 키워드에 의해 재할당이 금지되므로 할당된 값을 변경할 수 있는 방법은 없음.</li>
<li>일반적으로 상수의 이름은 대문자로 선언해 상수임을 명확이 나타내야 함.</li>
</ul>
<h3 id="const-키워드와-객체">const 키워드와 객체</h3>
<ul>
<li><code>const</code> 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경할 수 있음.</li>
<li><code>const</code> 키워드는 <strong>재할당을 금지</strong>할 뿐 &quot;불변&quot;을 의미하지 않음.<pre><code class="language-js">const person = {
name: &#39;Lee&#39;
};
</code></pre>
</li>
</ul>
<p>// 객체는 변경 가능한 값이기 때문에 재할당 없이 변경 가능
person.name = &#39;Kim&#39;;</p>
<p>console.log(person);  // {name: &quot;Kim&quot;}</p>
<p>// 재할당이 일어남으로 불가
person = {
  ...person
}  // TypeError: Assignment to constant variable.</p>
<p>```</p>
<h2 id="📁-var-vs-let-vs-const">📁 <code>var</code> vs <code>let</code> vs <code>const</code></h2>
<ul>
<li>ES6를 사용한다면 <code>var</code> 키워드 사용 금지</li>
<li>재할당이 필요한 경우에 한정해 <code>let</code> 키워드 사용. (변수의 스코프는 최대한 좀게)</li>
<li>변경이 발생하지 않고 긿기 전용으로 사용하는 원시 값과 객체는 <code>const</code> 키워드를 사용.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 14장. 전역 변수의 문제점]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-14%EC%9E%A5.-%EC%A0%84%EC%97%AD-%EB%B3%80%EC%88%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-14%EC%9E%A5.-%EC%A0%84%EC%97%AD-%EB%B3%80%EC%88%98%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90</guid>
            <pubDate>Fri, 30 Jan 2026 02:14:49 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-변수의-생명-주기">📁 변수의 생명 주기</h2>
<h3 id="지역-변수의-생명-주기">지역 변수의 생명 주기</h3>
<ul>
<li><p>함수 내부에서 선언된 지역 변수는 함수가 호출되면 생성되고 함수가 종료하면 소멸.</p>
</li>
<li><p>지역 변수의 생명 주기는 함수의 생명 주기와 대부분 일치.</p>
<pre><code class="language-js">function foo() {
  var x = &#39;local&#39;;  // 변수 x 생성/할당
  console.log(x);
  return x;  // 변수 x 소멸
}

foo();
console.log(x);  // ReferenceError: x is not defined</code></pre>
</li>
<li><p>호이스팅은 스코프를 단위로 동작함.</p>
<pre><code class="language-js">var x = &#39;global&#39;;

function foo() {
  console.log(x);  // undefined
  var x = &#39;local&#39;;
}

foo();
console.log(x);  // global</code></pre>
<h3 id="전역-변수의-생명-주기">전역 변수의 생명 주기</h3>
</li>
<li><p><code>var</code> 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 됨. (전역 변수의 생명주기가 전역 객체의 생명 주기와 일치)</p>
<blockquote>
<p><strong>※ 전역 객체</strong>: 코드가 실행되기 이전 단계에 JS엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체.
클라이언트 사이드: window, 서버사이드: global
전역 객체는 표준 빌트인 객체(Object, String, Number, Function, Array, ...)와 환경에 따른 호스트 객체, var 키워드로 선언한 전역 변수와 전역 함수를 프로퍼티로 갖음.</p>
</blockquote>
</li>
</ul>
<br/>

<h2 id="📁-전역-변수의-문제점">📁 전역 변수의 문제점</h2>
<h3 id="암묵적-결합">암묵적 결합</h3>
<ul>
<li>모든 코드가 전역 변수를 참조하고 변결할 수 있는 암묵적 결합이 허용됨.</li>
<li>변수의 유효 범위가 크면 클 수록 코드의 가독성은 나빠지고 의도치 않게 상태가 변경될 수 있는 위험성도 높아짐.</li>
</ul>
<h3 id="긴-생명-주기">긴 생명 주기</h3>
<ul>
<li>전역 변수는 생명주기가 길기 때문에, 메모리 리소스도 오랜 기간 소모하게 됨.</li>
<li>생명 주기가 긴 만큼 변수 이름이 중복될 가능성이 있어, 의도치 않은 재할당이 이뤄질 수 있음.</li>
</ul>
<h3 id="스코프-체인-상에서-종점에-존재">스코프 체인 상에서 종점에 존재</h3>
<ul>
<li>JS엔진이 스코프 체인을 따라 변수를 검색할 때 가장 마지막에 검색됨. (전역 변수의 검색이 가장 느림, 검색 속도의 차이는 그다지 크지 않지만 속도의 차이는 분명하게 있음)</li>
</ul>
<h3 id="네임스페이스-오염">네임스페이스 오염</h3>
<ul>
<li>JS는 파일이 분리되어 있다고 해도, 하나의 전역 스코프를 공유하게 됨.</li>
<li>다른 파일 내에서 동일한 이름으로 명명된 전역 변수나 전역 함수가 같은 스코프 내에 존재할 경우 의도치 않은 결과를 가져올 수 있음.</li>
</ul>
<br/>

<h2 id="📁-전역-변수의-사용을-억제하는-방법">📁 전역 변수의 사용을 억제하는 방법</h2>
<ul>
<li>전역 변수를 <strong>반드시 사용해야할 이유</strong>가 없다면, <strong>지역 변수</strong>를 사용.</li>
<li>변수의 스코프는 좁을수록 좋음.</li>
</ul>
<h3 id="즉시-실행-함수">즉시 실행 함수</h3>
<ul>
<li><p>함수 정의와 동시에 호출되는 즉시 실행 함수는 단 한번만 호출됨.</p>
</li>
<li><p>모든 코드를 즉시 실행 함수로 감싸면 <strong>모든 변수는 즉시 실행 함수의 지역 변수</strong>가 됨.</p>
<pre><code class="language-js">(function () {
  var foo = 10;  // 즉시 실행 함수의 지역 변수
}());

console.log(foo);  // ReferenceError: foo is not defined</code></pre>
</li>
<li><p>주로 라이브러리에서 사용됨.</p>
<h3 id="네임스페이스-객체">네임스페이스 객체</h3>
</li>
<li><p>전역에 네임스페이스 역할을 담당할 객체를 생성하고 전역 변수처럼 사용하고 싶은 변수를 프로퍼티로 추가하는 방법.</p>
</li>
<li><p>네임스페이스 객체에 또 다른 네임스페이스 객체를 프로퍼티로 추가해서 계층적으로 구성 가능.</p>
<pre><code class="language-js">var MYAPP = {};  // 전역 네임스페이스 객체

MYAPP.person = {
  name: &#39;Lee&#39;,
  address: &#39;Seoul&#39;
}

console.log(MYAPP.person.name);  // Lee</code></pre>
<h3 id="모듈-패턴">모듈 패턴</h3>
</li>
<li><p>JS의 강력한 기능인 클로저를 기반으로 동작함.</p>
</li>
<li><p>모듈 패턴의 특징은 전역 변수의 억제는 물론 캡슐화까지 구현할 수 있다는 것임.</p>
<blockquote>
<p><strong>※ 캡슐화:</strong> 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것.
객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 <strong>정보 은닉</strong>이라 함.</p>
</blockquote>
<pre><code class="language-js">var Counter = (function () {
  // private 변수
  var num = 0;

  // 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return --num;
    }
  };
}());

// private 변수는 외부로 노출되지 않음
console.log(Counter.num);  // undefined

console.log(Counter.increase());  // 1
console.log(Counter.decrease());  // 0</code></pre>
</li>
</ul>
<h3 id="es6-모듈">ES6 모듈</h3>
<ul>
<li>ES6 모듈은 파일 자체의 독자적인 모듈 스코프를 제공함.</li>
<li>모듈 내에서 var 키워드로 선언한 변수는 더는 전역 변수가 아니며 전역 객체의 프로퍼티도 아님.</li>
</ul>
<br/>

<h2 id="📁-의문점">📁 의문점</h2>
<ul>
<li><p>그렇다면, 현대의 Vite와 Webpack들은 모듈과 ES6 모듈을 어떻게 사용하는 걸까?</p>
<ul>
<li><p>개발 환경 (Vite): &quot;진짜 ES6 모듈을 쓴다&quot;</p>
<ul>
<li><code>npm run dev</code>시, Vite는 번들링을 하지 않음.</li>
<li>Native ESM: ES6 모듈을 그대로 사용(import/export)</li>
<li>동작: 브라우저가 <script type="module" src="...">을 만나면, 필요한 파일을 그때그때 서버에 요청.</li>
<li>스코프: 파일 자체가 독립적이므로, 브라우저가 ES6 모듈 스코프 규칙을 직접 적용함.</li>
<li>개발 서버일 경우 브라우저가 모듈이므로 전역 변수를 만들지 않음.</li>
</ul>
</li>
<li><p>배포 환경: "모듈인척 연기한다"</p>
<ul>
<li><p><code>npm run build</code>시 성능을 위해 코드를 하나(또는 몇 개)의 파일로 합침. 이를 번들링이라 함.</p>
</li>
<li><p>번들러는 파일을 합치면서 <strong>모듈 스코프가 유지되는 것처럼 코드를 변형</strong>.</p>
</li>
<li><p>예시:</p>
<pre><code class="language-js">// bundle.js (함수 껍데기를 벗기고 하나로 합침)

// a.js의 내용
var x$1 = 1;  // 충돌을 피하기 위해 뒤에 $1을 붙임

// b.js의 내용
var x$2 = 2;  // 여기는 $2를 붙임

console.log(x$1 + x$2);</code></pre>
</li>
<li><p>결과: 겉으로 보기엔 그냥 쭉 이어진 코드 같지만, 번들러가 식별자를 바꿔달아서 논리적 모듈 스코프(격리)를 유지시킴.</p>
</li>
<li><p>결론: 형태는 달라졌지만, <strong>외부와 격리시킨다</strong>는 모듈 패턴 철학은 그대로 구현됨.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 13장.스코프]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-13%EC%9E%A5.%EC%8A%A4%EC%BD%94%ED%94%84</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-13%EC%9E%A5.%EC%8A%A4%EC%BD%94%ED%94%84</guid>
            <pubDate>Fri, 30 Jan 2026 01:19:32 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-스코프란">📁 스코프란?</h2>
<ul>
<li>모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 자신을 참조할 수 있는 유효 범위가 결정됨. 이를 스코프라 함.</li>
<li>스코프는 <strong>식별자가 유효한 범위</strong>를 말함.</li>
</ul>
<br/>

<h2 id="📁-스코프의-종류">📁 스코프의 종류</h2>
<pre><code class="language-js">var x = &quot;global x&quot;;
var y = &quot;global y&quot;;

function outer() {
  var z = &quot;outer&#39;s local z&quot;;

  console.log(x);  // global x
  console.log(y);  // global y
  console.log(z);  // outer&#39;s local z

  function inner() {
    var x = &quot;inner&#39;s local x&quot;;

    console.log(x);  // inner&#39;s local x
    console.log(y);  // global y
    console.log(z);  // outer&#39;s local z
  }

  inner();
}

outer();

console.log(x);  // global x;
console.log(z);  // ReferenceError z is not defined</code></pre>
<h3 id="전역과-전역-스코프">전역과 전역 스코프</h3>
<ul>
<li><strong>전역:</strong> 코드의 가장 바깥 영역</li>
<li>전역은 전역 스코프를 만들고, 전역에 변수를 선언하면 전역 스코프를 갖는 전역 변수가 됨. (<strong>전역 변수는 어디서든지 참조 가능</strong>)</li>
</ul>
<h3 id="지역과-지역-스코프">지역과 지역 스코프</h3>
<ul>
<li><strong>지역:</strong> 함수 몸체 내부</li>
<li>지역은 지역 스코프를 만들고, 지역에 변수를 선언하면 지역 스코프를 갖는 지역 변수가 됨. ( <strong>지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서만 유효</strong> )</li>
</ul>
<br/>

<h2 id="📁-스코프-체인">📁 스코프 체인</h2>
<ul>
<li><p>함수는 중첩될 수 있으므로 지역 스코프 또한 중첩될 수 있음. (<strong>스코프가 함수의 중첩에 의해 계층적 구조를 갖음</strong>)</p>
</li>
<li><p>변수를 찾모할 때 JS엔진은 스코프 체인을 통해 <strong>변수를 참조하는 코드의 스코프에서 시작하여 상위 스포크 방향으로 이동</strong>하며 선언된 변수를 검색.
<img src="https://velog.velcdn.com/images/van_lan/post/322fcf56-cf8c-4f41-bedd-4a7c9d0602ab/image.png" alt=""></p>
</li>
<li><p>스코프 체인은 물리적 실체로 존재</p>
</li>
<li><p>JS엔진은 코드를 실행하기전에 <strong>렉시컬 환경</strong>을 실제로 생성 -&gt; 변수 선언시 변수 식별자가 렉시컬 환경에 키로 등록 -&gt; 변수 할당시 등록된 변수 식별자의 값을 변경</p>
</li>
<li><p>변수의 검색도 생성된 렉시컬 환경안에서 이루어짐.</p>
<blockquote>
<p><strong>※ 렉시컬 환경:</strong> 스코프 체인은 실행 컨텍스트의 렉시컬 환경을 단방향으로 연결한 것. 전역 렉시컬 환경은 코드가 로드되면 곧바로 생성되고 함수의 렉시컬 환경은 함수가 호출되면 곧바로 생성됨.</p>
</blockquote>
</li>
</ul>
<h3 id="스코프-체인에-의한-변수-검색">스코프 체인에 의한 변수 검색</h3>
<ul>
<li>JS엔진은 스코프 체인을 따라 <strong>변수를 참조하는 코드의 스코프에서 시작</strong>해서 <strong>상위 스코프 방향으로 이동</strong>하며 선언된 변수를 검색.</li>
<li>상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조할 수 있지만, 하위 스코프에서 유효한 변수를 상위 스코프에서 참조 할 수 없음.</li>
</ul>
<h3 id="스코프-체인에-의한-함수-검색">스코프 체인에 의한 함수 검색</h3>
<pre><code class="language-js">// 전역 함수
function foo() {
  console.log(&#39;global function foo&#39;);
}

function bar() {
  // 중첩 함수
  function foo() {
    console.log(&#39;local function foo&#39;);
  }

  foo();
}

bar();</code></pre>
<ul>
<li>함수 선언문으로 함수를 정의하면 런타임 이전에 함수 객체가 먼저 생성됨. 그리고 JS 엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 선언하고 생성된 함수 객체를 할당함.</li>
<li>이처럼 함수도 식별자에 할당되기 때문에 스코프를 갖게됨. 따라서 변수에 의한 검색과 마찬가지로 동작되게 됨.</li>
</ul>
<br/>

<h2 id="📁-함수-레벨-스코프">📁 함수 레벨 스코프</h2>
<ul>
<li><p><code>var</code> 키워드로 선언된 변수는 오로지 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정함.</p>
</li>
<li><p>이러한 특성을 <strong>함수 레벨 스코프</strong>라 함. (현대적인 개발에서는 사용을 지양하며, 레거시 코드 해석을 위한 과거의 유산 정도로 이해하면 됨)</p>
<pre><code class="language-js">var x = 1;

if (true) {
  // var 키워드로 선언된 변수는 코드 블록 내에 선언되었다 할지라도 모두 전역 변수
  var x = 10;
}

console.log(x);  // 10</code></pre>
</li>
<li><p><code>let</code>, <code>const</code> 키워드는 블록레벨 스코프를 지원함.</p>
</li>
</ul>
<h2 id="📁-렉시컬-스코프">📁 렉시컬 스코프</h2>
<ul>
<li><strong>동적 스코프</strong>: 함수가 <strong>호출되는 시점</strong>에 동적으로 상위 스코프를 결정.</li>
<li><strong>렉시컬 스코프</strong>: 함수가 <strong>정의되고 평가되는 시점</strong>에 상위 스코프가 정적으로 결정.</li>
<li>JS는 렉시컬 스코프를 따르므로 함수가 어디서 정의했는지에 따라 상위 스코프를 결정함. 함수가 호출된 위치는 상위 스코프 결정에 어떠한 영향도 주이 않으며, 함수의 상위 스코프는 언제나 자신이 정의된 스코프임.</li>
<li>함수 정의가 실행되어 생성된 함수 객체는 [[Environment]] 내부 슬롯에 상위 스코프를 저장하여 기억함. 이로 인해 외부 함수가 종료되더라도 상위 스코프가 메모리에서 해제되지 않고 유지되는 현상이 발생하는데, 이를 클로저라고 함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 12장.함수]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-12%EC%9E%A5.%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-12%EC%9E%A5.%ED%95%A8%EC%88%98</guid>
            <pubDate>Mon, 26 Jan 2026 01:27:56 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-함수란">📁 함수란?</h2>
<ul>
<li><p>일련의 과정을 문으로 구현하고 코드 블록을 감싸서 하나의 실행 단위로 정의한 것.</p>
</li>
<li><p><strong>함수 정의</strong>를 통해 생성됨.</p>
<pre><code class="language-js">// 함수 정의
function add(x, y) {
  return x + y;
}</code></pre>
</li>
<li><p><strong>함수 호출</strong>을 해야 실행됨.</p>
<pre><code class="language-js">// 함수 호출
const result = add(2, 5);

// 함수 add에 인수 2, 5를 전달하면서 호출하면 반환값 7을 반환
console.log(result);</code></pre>
</li>
</ul>
<br/>

<h2 id="📁-함수를-사용하는-이유">📁 함수를 사용하는 이유</h2>
<ul>
<li>코드의 재사용 용이, 유지보수의 편의성, 코드의 가독성 향상.</li>
</ul>
<h2 id="📁-함수-리터럴">📁 함수 리터럴</h2>
<ul>
<li>JS에서의 함수는 객체 타입의 값.</li>
<li>함수 리터럴은 function 키워드, 함수 이름, 매개 변수 목록, 함수 몸체로 구성<pre><code class="language-js">const f = function add(x, y) {
  return x + y;
}</code></pre>
</li>
<li>구성 요소:<ul>
<li>함수 이름<ul>
<li>함수 이름은 식별자 이므로, 식별자 네이밍 규칙을 준수.</li>
<li>함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자.</li>
<li>함수 이름 생략 가능 (기명 함수, 무명/익명 함수)</li>
</ul>
</li>
<li>매개변수 목록<ul>
<li>0개 이상의 매개변수를 소괄호로 감싸고 쉼표로 구분.</li>
<li>각 매개변수에는 함수를 호출할 때 지정한 인수가 순서대로 할당됨. (순서에 의미가 있음)</li>
<li>매개변수는 함수 몸체 내에서 변수와 동일하게 취급됨. (매개변수도 식별자 네이밍 규칙을 준수)</li>
</ul>
</li>
<li>함수 몸체<ul>
<li>함수가 호출됬을 때 일괄적으로 실행될 문들을 하나의 실행 단위로 정의한 코드 블록.</li>
<li>함수 몸체는 함수 호출에 의해 실행됨.</li>
</ul>
</li>
</ul>
</li>
</ul>
<br/>

<h2 id="📁-함수-정의">📁 함수 정의</h2>
<h3 id="🗒️-함수-선언문">🗒️ 함수 선언문</h3>
<pre><code class="language-js">// 함수 선언문
function add(x, y) {
  return x + y;
}

// 함수 참조
console.dir(add);  // ⨍ add(x, y)

// 함수 호출
console.log(add(2, 5));  // 7</code></pre>
<ul>
<li>함수 선언문은 함수 이름을 <u>생략 불가</u>.</li>
<li>함수 선언문은 표현식이 아닌 문임.</li>
<li>함수는 함수 이름으로 호출되는 것이 아닌 <strong>함수 객체를 가리키는 식별자로 호출</strong>함.</li>
<li>JS엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 <strong>암묵적으로 생성</strong>하고, 함수를 할당.</li>
</ul>
<h3 id="🗒️-함수-표현식">🗒️ 함수 표현식</h3>
<ul>
<li><p>JS의 함수는 일급 객체(값의 성질을 갖는 객체).</p>
<pre><code class="language-js">// 함수 표현식
const add = function (x, y) {
  return x + y;
}

console.log(add(2, 5));  // 7</code></pre>
</li>
<li><p>함수를 호출할 때는 함수 이름이 아닌 <strong>함수 객체를 가리키는 식별자</strong>를 사용.</p>
<pre><code class="language-js">// 기명 함수 표현식
const add = function foo(x, y) {
  return x + y;
}

// 함수 객체를 가리키는 식별자로 호출
console.log(add(2, 5));  // 7

// 함수 이름으로 호출시 ReferenceError가 발생
console.log(foo(2, 5));  // ReferenceError: foo is not defined</code></pre>
</li>
</ul>
<h3 id="🗒️-함수-생성-시점과-함수-호이스팅">🗒️ 함수 생성 시점과 함수 호이스팅</h3>
<ul>
<li><p>함수 선언문으로 함수 정의시 런타임 이전에 함수 객체가 먼저 생성됨.</p>
</li>
<li><p>그리고 JS엔진은 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고 생성된 함수 객체를 할당.</p>
</li>
<li><p>이처럼 함수 선언문이 코드의 선두로 끌어 올려진 것 처럼 동작하는 JS 고유의 특징을 <strong>함수 호이스팅</strong>이라 함.</p>
<pre><code class="language-js">// 함수 참조
console.dir(add);  // ⨍ add(x, y)

// 함수 호출
console.log(add(2, 5));  // 7

// 함수 선언문
function add(x, y) {
  return x + y;
}</code></pre>
</li>
<li><p>함수 표현식은 변수에 할당되는 값이 함수 리터럴인 문임.</p>
</li>
<li><p>변수 선언은 런타임 이전에 실행되어 <code>undefined</code>로 초기화 되지만, 변수 할당문의 값은 <strong>런타임에 평가</strong>되므로 함수 표현식의 함수 리터럴도 할당문이 실행되는 시점에 평가되어 함수 객체가 됨.</p>
<pre><code class="language-js">// 함수 참조
console.log(sub);  // undefined

// 함수 호출
console.log(sub(2, 5));  // TypeError: sub is not a function

// 함수 표현식
var sub = function(x, y) {
  return x - y;
};</code></pre>
</li>
<li><p>위 처럼 함수 표현식으로 함수를 정의하면, 함수 호이스팅이 발생하는 것이 아닌 변수 호이스팅이 발생.</p>
</li>
</ul>
<h3 id="🗒️-화살표-함수">🗒️ 화살표 함수</h3>
<ul>
<li><code>function</code> 키워드 대신 화살표(<code>=&gt;</code>)를 사용해 좀 더 간략한 방법으로 함수 선언 가능.<pre><code class="language-js">// 화살표 함수
const add = (x, y) =&gt; x + y;
console.log(add(2, 5));  // 7</code></pre>
</li>
<li>기존 함수와 <code>this</code> 바인딩 방식이 다르고, <code>prototype 프로퍼티</code>가 없으며 <code>arguments 객체</code>를 생성하지 않음.</li>
</ul>
<br/>

<h2 id="📁-함수-호출">📁 함수 호출</h2>
<ul>
<li>함수 호출시 현재의 실행 흐름을 중단하고 호출된 함수로 실행 흐름을 옮김.</li>
<li>매개변수에 인수가 순서대로 할당되고 함수 몸체의 문들을 실행.</li>
</ul>
<h3 id="🗒️-매개변수와-인수">🗒️ 매개변수와 인수</h3>
<ul>
<li><p>매개 변수는 함수를 정의할 때 선언하며, 함수 몸체 내부에서 변수와 동일하게 취급됨.</p>
</li>
<li><p>함수 몸체 내에서 암묵적으로 매개변수가 생성되고 일반 변수와 마찬가지로 <code>undefined</code>로 초기화된 후 인수가 순서대로 할당됨.</p>
</li>
<li><p>매개변수는 함수 몸체 내부에서만 참조할 수 있고 외부에서는 참조 불가.</p>
</li>
<li><p>함수는 매개변수의 개수와 인수의 개수가 일치하는지 체크하지 않음.</p>
<pre><code class="language-js">function add(x, y) {
  return x + y;
}

// add 함수의 매개변수 x, y는 함수 몸체 내부에서만 참조 가능
console.log(x, y);  // ReferenceError: x is not defined

// 인수가 부족해 할당 되지 않는 매개변수의 값은 undefined 임
console.log(add(2));  // NaN

// 매개변수 보다 인수가 더 많은 경우 초과된 인수는 무시됨
console.log(add(2, 5, 10));  // 7</code></pre>
</li>
<li><p>모든 인수는 암묵적으로 arguments 객체의 프로퍼티에 보관됨.</p>
<pre><code class="language-js">function add(x, y) {
  console.log(arguments);
  // Arguments(3) [2, 5, 10, callee: ⨍, Symbol(Symbol.iterator): ⨍]

  return x + y;
}

add(2, 5, 10);</code></pre>
</li>
</ul>
<h3 id="🗒️-인수-확인">🗒️ 인수 확인</h3>
<ul>
<li><p>JS의 경우 함수를 정의할 때 적절한 인수가 전달되었는지 확인할 필요가 있음.</p>
<pre><code class="language-js">function add(x, y) {
  if(typeof x !== &#39;number&#39; || typeof y !== &#39;number&#39;) {
    // 매개변수를 통해 전달된 인수의 타입이 부적절한 경우 에러를 발생 시킴.
    throw new TypeError(&#39;인수는 모두 숫자 값이어야 합니다.&#39;);
  }

  return x + y;
}

console.log(add(2));  // TypeError: 인수는 모두 숫자 값이어야 합니다.
console.log(add(&#39;a&#39;, &#39;b&#39;));  // TypeError: 인수는 모두 숫자 값이어야 합니다.</code></pre>
</li>
<li><p>매개변수에 기본값을 사용할 수 있음.</p>
<pre><code class="language-js">function add(a = 0, b = 0, c = 0) {
  return a + b + c;
}

console.log(add(1, 2, 3));  // 6
console.log(add(1, 2));  // 3
console.log(add());  // 0</code></pre>
</li>
</ul>
<h3 id="🗒️-매개변수의-최대-개수">🗒️ 매개변수의 최대 개수</h3>
<ul>
<li>이상적 함수는 <strong>한 가지 일</strong>만 해야 하며 <strong>가급적 작게</strong> 작성해야 함.</li>
<li>매개변수는 최대 3개 이상 넘지 않는 것을 권장하며, 그 이상의 매개변수가 필요할 시 하나의 매개변수를 선언하고 객체를 인수로 전달하는 것이 유리.</li>
</ul>
<h3 id="🗒️-반환문">🗒️ 반환문</h3>
<ul>
<li><code>return</code> 키워드를 사용해 실행 결과를 함수 외부로 반환 시킬 수 있음.</li>
<li>함수 호출은 반환한 표현식의 평가 결과, 즉 반환값으로 평가됨.</li>
<li><code>return</code> 키워드 뒤의 표현식을 비워두거나, 생략할 경우 <code>undefined</code>를 반환.</li>
</ul>
<br/>

<h2 id="📁-참조에-의한-전달과-외부-상태의-변경">📁 참조에 의한 전달과 외부 상태의 변경</h2>
<pre><code class="language-js">// 매개변수 primitive는 원시 값을 전달받고 매개변수 obj는 객체를 전달 받음
function changeVal(primitive, obj) {
  primitive += 100;
  obj.name = &#39;Kim&#39;;
}

// 외부 상태
var num = 100;
var person = { name: &#39;Lee&#39; };

console.log(num);  // 100
console.log(person);  // {name: &quot;Lee&quot;}

// 원시 값은 값 자체가 복사되어 전달되고 객체는 참조 값이 복사되어 전달됨
changeVal(num, person);

// 원시 값은 원본이 훼손되지 않음
console.log(num);  // 100

// 객체는 원본이 훼손 됨
console.log(person);  // {name: &quot;Kim&quot;}</code></pre>
<br/>

<h2 id="📁-다양한-함수의-형태">📁 다양한 함수의 형태</h2>
<h3 id="🗒️-즉시-실행-함수">🗒️ 즉시 실행 함수</h3>
<ul>
<li><p>함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수라고 함.</p>
</li>
<li><p>단 한번만 호출되며 다시 호출 불가.</p>
<pre><code class="language-js">// 익명 즉시 실행 함수
(function () {
  var a = 3;
  var b = 5;
  return a * b;
}());

// 기명 즉시 실행 함수
(function foo() {
  var a = 3;
  var b = 5;
  return a * b;
}());

foo();  // ReferenceError: foo is not defined</code></pre>
</li>
<li><p>일반 함수처럼 값을 반환할 수 있고 인수를 전달 할 수도 있음.</p>
<pre><code class="language-js">// 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있음
var res = (function () {
  var a = 3;
  var b = 5;
  return a * b;
}());

// 즉시 실행 함수에도 일반 함수처럼 인수를 전달 가능
res = (function (a, b) {
  return a * b;
}(3, 5));

console.log(res);  // 15</code></pre>
</li>
<li><p>즉시 실행 함수 내에 코드를 모아 두면 혹시 있을 수도 있는 변수나 함수 이름의 충돌을 방지할 수 있음.</p>
</li>
</ul>
<h3 id="🗒️-재귀-함수">🗒️ 재귀 함수</h3>
<ul>
<li><p>함수가 자기 자신을 호출하는 것을 재귀 호출이라 함.</p>
</li>
<li><p>반복 처리를 위해 주로 사용.</p>
<pre><code class="language-js">// 팩토리얼은 1부터 자신까지의 모든 양의 정수의 곱
// n! = 1 * 2 * ... * (n-1) * n
function factorial(n) {
  if(n &lt;= 1) return 1;

  return n * factorial(n - 1);
}

console.log(factorial(3));  // 3! = 3 * 2 * 1 = 6</code></pre>
</li>
<li><p>반드시 <strong>탈출 조건</strong>을 만들어야 함. 없을 시 무한 호출되어 스택 오버플로에러가 발생.</p>
</li>
<li><p>대부분의 재귀 함수는 반복문을 통해 구현이 가능함. 재귀 함수를 사용하는 편이 더 직관적으로 이해하기 쉬울 때만 한정적으로 사용해야 함. (무한 반복의 위험성 때문)</p>
</li>
</ul>
<h3 id="🗒️-중첩-함수">🗒️ 중첩 함수</h3>
<ul>
<li><p>함수 내부에 정의된 함수를 <strong>중첩 함수</strong> 또는 <strong>내부 함수</strong>라 부름.</p>
</li>
<li><p>중첩 함수는 외부 함수 내부에서만 호출 가능. 일반적으로 중첩 함수는 자신을 포함한 외부 함수의 헬퍼 함수의 역할.</p>
<pre><code class="language-js">function outer() {
  var x = 1;

  // 중첩 함수
  function inner() {
    var y = 2;
    // 외부 함수의 변수를 참조할 수 있음
    console.log(x + y);  // 3
  }

  inner()
}

outer()</code></pre>
</li>
<li><p>호이스팅으로 인해 혼란이 발생할 수 있으므로 <code>if</code>문이나 <code>for</code>문 등의 코드 블록에서 함수 선언문을 통해 함수를 정의하는 것은 바람직 하지 않음.</p>
</li>
<li><p>중첩 함수는 스코프와 클로저에 깊은 관련이 있음.</p>
</li>
</ul>
<h3 id="🗒️-콜백-함수">🗒️ 콜백 함수</h3>
<ul>
<li><p>함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수라고 부름.</p>
</li>
<li><p>매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수라고 부름.</p>
</li>
<li><p>고차 함수는 콜백 함수를 자신의 일부분으로 합성.</p>
<pre><code class="language-js">// 외부에서 전달받은 ⨍을 n만큼 반복 호출
function repeat(n, f) {
  for(var i = 0; i &lt; n; i++) {
    logOdds(i);
  }
}

// logOdds 함수는 단 한번만 생성
var logOdds = function (i) {
  if (i % 2) console.log(i);
}

// 고차 함수에 함수 참조를 전달
repeat(5, logOdds);  // 1 3</code></pre>
</li>
</ul>
<h3 id="🗒️-순수-함수와-비순수-함수">🗒️ 순수 함수와 비순수 함수</h3>
<ul>
<li><p>어떤 외부 상태에 의존하지도 않고 변경하지도 않는, 부수 효과가 없는 함수를 순수 함수라 부름.</p>
<pre><code class="language-js">var count = 0;  // 현재 카운트를 나타내는 상태

// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환
function increase(n) {
  return ++n;
}

// 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경
count = increase(count);
console.log(count);  // 1

count = increase(count);
console.log(count);  // 2</code></pre>
</li>
<li><p>외부 상태를 변경하는, 부수 효과가 있는 함수를 비순수 함수라고 부름.</p>
<pre><code class="language-js">var count = 0;  // 현재 카운트를 나타내는 상태: increase 함수에 의해 변화

// 비순수 함수
function increase() {
  return ++count;
}

// 비순수 함수는 외부 상태(count)를 변경하므로 상태 변화를 추적하기 어려워짐
increase();
console.log(count);  // 1

increase();
console.log(count);  // 2</code></pre>
</li>
<li><p>함수가 외부 상태를 변경하면 상태 변화를 추적하기 어려워짐. 따라서 함수 외부 상태의 변경을 지양하는 순수 함수 사용을 하는 것이 좋음.</p>
</li>
<li><p>비순수 함수를 최대한 줄이는 것은 부수 효과를 최대한 억제하는 것과 같음.</p>
</li>
<li><p>함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최소화해 불변성을 지향하는 프로그래밍 패러다임임.</p>
</li>
<li><p>로직 내에 존재하는 조건문과 반복문을 제거해서 복잡성을 해결하며, 변수 사용을 억제하거나 생명주기를 최소화해서 상태 변경을 피해 오률 최소하는 것을 목표로 함.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 11장.원시 값과 객체의 비교]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-11%EC%9E%A5.%EC%9B%90%EC%8B%9C-%EA%B0%92%EA%B3%BC-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-11%EC%9E%A5.%EC%9B%90%EC%8B%9C-%EA%B0%92%EA%B3%BC-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Wed, 21 Jan 2026 22:25:04 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-원시값">📁 원시값</h2>
<h3 id="🗒️-변경-불가능한-값-불변성">🗒️ 변경 불가능한 값 (불변성)</h3>
<ul>
<li><p>한번 생성된 원시 값은 읽기 전용 값으로서 변경 불가.</p>
</li>
<li><p>이는 변수에 대한게 아니라 <u>값에 대한 진술</u>임.</p>
</li>
<li><p><strong>불변성</strong>을 갖는 원시 값을 할당한 변수는 <strong>재할당</strong> 이외에 변수 값을 변경할 방법이 없음.</p>
<h3 id="🗒️-문자열과-불변성">🗒️ 문자열과 불변성</h3>
</li>
<li><p>문자열은 유사 배열 객체이면서 이터러블이므로 배열과 유사하게 각 문자에 접근 가능.</p>
<pre><code class="language-js">const str = &#39;string&#39;;

console.log(str[0]);  // s

console.log(str.length);  // 6
console.log(str.toUpperCase());  // STRING</code></pre>
</li>
<li><p>원시 객체이므로 문자열은 불변성을 갖음.</p>
<pre><code class="language-js">let str = &#39;string&#39;;

// 문자열은 원시 값이므로 변경 불가. 에러가 발생하진 않음.
str[0] = &#39;S&#39;;

console.log(str);  // string</code></pre>
</li>
<li><p>예기치 못한 변경으로 부터 자유롭고, 이로 인해 신뢰성이 보장됨.</p>
<h3 id="🗒️-값에-의한-전달">🗒️ 값에 의한 전달</h3>
</li>
<li><p>변수에 원시 값을 갖는 변수를 할당하면 할당받는 변수에는 할당되는 변수의 메모리 주소가 전달 됨.</p>
</li>
<li><p>아래 코드를 보면 두 변수의 값은 서로 같은 메모리 주소를 참조 하지만, 값의 재할당을 통해 참조하는 메모리 주소가 변경되어 서로 다른 별개의 값을 참조하게 됨.</p>
<pre><code class="language-js">let score = 80;
let copy = score;

console.log(score);  // 80
console.log(copy);  // 80

score = 100;

console.log(score);  // 100
console.log(copy);  // 80</code></pre>
</li>
</ul>
<h2 id="📁-객체">📁 객체</h2>
<h3 id="🗒️-변경-가능한-값">🗒️ 변경 가능한 값</h3>
<ul>
<li><p>객체는 변경 가능한 값이므로 <strong>재할당 없이</strong> 객체를 직접 변경이 가능.</p>
</li>
<li><p>메모리에 저장된 객체를 직접 수정하고, 재할당 하지 않았으므로 할당한 변수의 참조 값은 변하지 않음.</p>
</li>
<li><p><strong>단점</strong>: 여러 개의 식별자가 <u>하나의 객체를 공유</u>할 수 있다는 점.</p>
<h3 id="🗒️-참조에-의한-전달">🗒️ 참조에 의한 전달</h3>
</li>
<li><p>객체를 할당한 변수를 다른 변수에 할당하게 되면, 하나의 객체를 참조하게 됨.</p>
<pre><code class="language-js">const person = {
  name: &#39;Lee&#39;
}

const copy = person;

console.log(copy === person);  // true

copy.name = &#39;Kim&#39;;
person.address = &#39;Seoul&#39;;

console.log(person);  // {name: &quot;Kim&quot;, address: &quot;Seoul&quot;}
console.log(copy);  // {name: &quot;Kim&quot;, address: &quot;Seoul&quot;}</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[모딥다] 10장.객체 리터럴]]></title>
            <link>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-10%EC%9E%A5.%EA%B0%9D%EC%B2%B4-%EB%A6%AC%ED%84%B0%EB%9F%B4</link>
            <guid>https://velog.io/@van_lan/%EB%AA%A8%EB%94%A5%EB%8B%A4-10%EC%9E%A5.%EA%B0%9D%EC%B2%B4-%EB%A6%AC%ED%84%B0%EB%9F%B4</guid>
            <pubDate>Wed, 21 Jan 2026 21:33:35 GMT</pubDate>
            <description><![CDATA[<h2 id="📁-객체란">📁 객체란?</h2>
<ul>
<li><p>다양한 타입의 값(원시 값 또는 다른 객체)를 하나의 단위로 구성한 복합적인 자료구조.</p>
</li>
<li><p>원시 값은 변경 불가능한 값 이지만 객체는 <u>변경 가능한 값</u>.</p>
</li>
<li><p>0개 이상의 프로퍼티로 구성된 집합이며, 프로퍼티는 키와 값으로 구성.</p>
</li>
<li><p>프로퍼티의 값이 함수일 경우, 일반 함수와 구분하기 위해 <code>메서드</code>라 부름.</p>
<ul>
<li>프로퍼티: 객체의 상태를 나타내는 값</li>
<li>메서드: 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작</li>
</ul>
<pre><code class="language-js">const counter = {
  num: 0,  // 프로퍼티 -&gt; key: value
  increse: function () {
    this.num++;
  }
}</code></pre>
</li>
</ul>
<h2 id="📁-객체-리터럴에-의한-객체-생성">📁 객체 리터럴에 의한 객체 생성</h2>
<ul>
<li><p>중괄호(<code>{...}</code>) 내에 0개 이상의 프로퍼티를 정의</p>
<pre><code class="language-js">const person = {
  name: &#39;Kim&#39;,
  sayHello: function () {
    console.log(`Hello! My name is ${this.name}.`);
  }
};

console.log(typeof person);  // object
console.log(person);  // {name: &quot;Kim&quot;, sayHello: ⨍}

const empty = {};  // 빈 객체
console.log(typeof empty);  // object</code></pre>
</li>
</ul>
<h2 id="📁-프로퍼티">📁 프로퍼티</h2>
<ul>
<li><p>프로퍼티 키와 프로퍼티 값으로 구성하며 쉼표(<code>,</code>)로 구분.</p>
<ul>
<li>키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값.</li>
<li>값: JS에서 사용할 수 있는 모든 값.</li>
</ul>
</li>
<li><p>프로퍼티 키가 식별자 네이밍 규칙을 따르지 않는 이름에는 <u>반드시 따옴표</u>를 사용.</p>
<h3 id="🗒️-프로퍼티-접근">🗒️ 프로퍼티 접근</h3>
</li>
<li><p>마침표 표기법, 대괄호 표기법이 존재.</p>
<pre><code class="language-js">const person = {
  name: &#39;HyounSeok&#39;,
  &#39;last-name&#39;: &#39;Kim&#39;,
  1: 10
};

// 마침표 표기법
person.name;  // -&gt; HyounSeok

// 대괄호 표기법
person[&#39;name&#39;];  // -&gt; HyounSeok

// 존재하지 않는 프로퍼티
person.age;  // -&gt; undefined

// 식별자 네이밍 규칙을 따르지 않는 프로퍼티
person.&#39;last-name&#39;;  // -&gt; SyntaxError: Unexpected string
person.last-name;  // -&gt; 브라우저 환경: NaN
                   // -&gt; Node.js 환경: last is not defined
person[&#39;last-name&#39;];  // -&gt; Kim

// 프로퍼티 키가 숫자로 이루어진 문자열
person.1;  // -&gt; SyntaxError: Unexpected number
person.&#39;1&#39;;  // -&gt; SyntaxError: Unexpected string
person[1];  // -&gt; 10
person[&#39;1&#39;];  // -&gt; 10</code></pre>
<h3 id="🗒️-프로퍼티-값-갱신">🗒️ 프로퍼티 값 갱신</h3>
</li>
<li><p>이미 존재하는 프로퍼티 값을 할당하면 프로퍼티 값이 갱신 됨.</p>
<pre><code class="language-js">const person = {
  name: &#39;Kim&#39;
}

person.name = &#39;Lee&#39;;

console.log(person);  // {name: &quot;Lee&quot;}</code></pre>
<h3 id="🗒️-프로퍼티-동적-생성">🗒️ 프로퍼티 동적 생성</h3>
</li>
<li><p>존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당 됨.</p>
<pre><code class="language-js">const person = {
  name: &#39;Kim&#39;
}

person.age = 20;

console.log(person);  // {name: &quot;Kim&quot;, age: 20}</code></pre>
<h3 id="🗒️-프로퍼티-삭제">🗒️ 프로퍼티 삭제</h3>
</li>
<li><p><code>delete</code> 연산자를 사용.</p>
</li>
<li><p>존재하지 않는 프로퍼티를 삭제하면 아무 에러없이 무시 됨.</p>
<pre><code class="language-js">const person = {
  name: &#39;Kim&#39;
}

person.age = 20;

delete person.age;
delete person.address;

console.log(person);  // {name: &quot;Kim&quot;}</code></pre>
</li>
</ul>
<h2 id="📁-메서드">📁 메서드</h2>
<ul>
<li><p>JS의 함수는 객체(일급 객체)이므로 값으로 취급할 수 있기 때문에 프로퍼티 값으로 사용 가능.</p>
</li>
<li><p>프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 <u>메서드</u>라 부름.</p>
<pre><code class="language-js">const circle = {
  radius: 5,
  getDiameter: function () {
    return 2 * this.radius;
  }
};

console.log(circle.getDiameter());  // 10</code></pre>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>