<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>grace's dev_note</title>
    <link>https://meercat.tistory.com/</link>
    <description>기술 및 회고 블로그</description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 19:23:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor> Grace</managingEditor>
    <image>
      <title>grace's dev_note</title>
      <url>https://tistory1.daumcdn.net/tistory/5429921/attach/f791799df0f04e63b1bd77dde1b82bc1</url>
      <link>https://meercat.tistory.com</link>
    </image>
    <item>
      <title>실행 컨텍스트(Execution Context) 완벽 이해</title>
      <link>https://meercat.tistory.com/507</link>
      <description>&lt;p data-end=&quot;256&quot; data-start=&quot;182&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트를 조금 깊게 공부하다 보면&lt;br /&gt;&lt;b&gt;&amp;ldquo;실행 컨텍스트(Execution Context)&amp;rdquo;&lt;/b&gt; 라는 용어가 꼭 등장합니다.&lt;/p&gt;
&lt;p data-end=&quot;342&quot; data-start=&quot;258&quot; data-ke-size=&quot;size16&quot;&gt;이 개념은 스코프(Scope), 클로저(Closure), this 바인딩 같은&lt;br /&gt;자바스크립트의 핵심 원리를 이해하기 위한 &lt;b&gt;기초 중의 기초&lt;/b&gt;예요.&lt;/p&gt;
&lt;hr data-end=&quot;347&quot; data-start=&quot;344&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;364&quot; data-start=&quot;349&quot; data-ke-size=&quot;size26&quot;&gt;  실행 컨텍스트란?&lt;/h2&gt;
&lt;blockquote data-end=&quot;392&quot; data-start=&quot;366&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;392&quot; data-start=&quot;368&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;ldquo;자바스크립트 코드가 실행되는 환경&amp;rdquo;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;478&quot; data-start=&quot;394&quot; data-ke-size=&quot;size16&quot;&gt;조금 더 구체적으로 말하자면,&lt;br /&gt;자바스크립트 엔진이 코드를 실행할 때&lt;br /&gt;&lt;b&gt;변수, 함수, this, 스코프 정보 등을 관리하기 위한 객체&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-end=&quot;560&quot; data-start=&quot;480&quot; data-ke-size=&quot;size16&quot;&gt;즉, 어떤 코드가 &lt;b&gt;&amp;ldquo;어디서, 어떤 환경에서, 어떤 변수들을 가지고 실행되는가&amp;rdquo;&lt;/b&gt;&lt;br /&gt;를 결정하는 일종의 &lt;b&gt;실행 박스&lt;/b&gt;라고 보면 됩니다.&lt;/p&gt;
&lt;hr data-end=&quot;565&quot; data-start=&quot;562&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;584&quot; data-start=&quot;567&quot; data-ke-size=&quot;size26&quot;&gt;⚙️ 실행 컨텍스트의 종류&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 88px;&quot; border=&quot;1&quot; data-end=&quot;856&quot; data-start=&quot;586&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;&lt;b&gt;종류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot; data-end=&quot;690&quot; data-start=&quot;614&quot;&gt;
&lt;td style=&quot;height: 22px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;645&quot; data-start=&quot;614&quot;&gt;&lt;b&gt;전역 컨텍스트 (Global Context)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot; data-end=&quot;690&quot; data-start=&quot;645&quot; data-col-size=&quot;md&quot;&gt;코드가 처음 실행될 때 단 한 번 생성. 전역 변수, 함수 선언이 등록됨.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot; data-end=&quot;778&quot; data-start=&quot;691&quot;&gt;
&lt;td style=&quot;height: 22px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;724&quot; data-start=&quot;691&quot;&gt;&lt;b&gt;함수 컨텍스트 (Function Context)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot; data-end=&quot;778&quot; data-start=&quot;724&quot; data-col-size=&quot;md&quot;&gt;함수가 호출될 때마다 새로 생성. 함수 내 지역 변수, 매개변수, 내부 함수 등이 등록됨.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot; data-end=&quot;856&quot; data-start=&quot;779&quot;&gt;
&lt;td style=&quot;height: 22px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;810&quot; data-start=&quot;779&quot;&gt;&lt;b&gt;Eval 컨텍스트 (Eval Context)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 22px;&quot; data-end=&quot;856&quot; data-start=&quot;810&quot; data-col-size=&quot;md&quot;&gt;eval() 실행 시 만들어지지만, 실제 코드에서는 거의 사용하지 않음.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;861&quot; data-start=&quot;858&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;883&quot; data-start=&quot;863&quot; data-ke-size=&quot;size26&quot;&gt;  실행 컨텍스트의 내부 구성&lt;/h2&gt;
&lt;p data-end=&quot;919&quot; data-start=&quot;885&quot; data-ke-size=&quot;size16&quot;&gt;하나의 실행 컨텍스트는 다음 세 가지로 이루어져 있습니다  &lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1399&quot; data-start=&quot;921&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;921&quot;&gt;&lt;b&gt;Variable Environment (변수 환경)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1036&quot; data-start=&quot;962&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;994&quot; data-start=&quot;962&quot;&gt;var로 선언된 변수와 함수 선언을 저장합니다.&lt;/li&gt;
&lt;li data-end=&quot;1036&quot; data-start=&quot;998&quot;&gt;코드가 실행되기 전에 미리 메모리에 등록됩니다. (  호이스팅)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1199&quot; data-start=&quot;1038&quot;&gt;&lt;b&gt;Lexical Environment (렉시컬 환경)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1199&quot; data-start=&quot;1079&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1121&quot; data-start=&quot;1079&quot;&gt;let, const로 선언된 변수나 함수 표현식이 저장됩니다.&lt;/li&gt;
&lt;li data-end=&quot;1199&quot; data-start=&quot;1125&quot;&gt;외부 환경 참조(Outer Environment Reference)를 포함하고 있어&lt;br /&gt;&lt;b&gt;스코프 체인&lt;/b&gt;을 형성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1399&quot; data-start=&quot;1201&quot;&gt;&lt;b&gt;This Binding (this 바인딩)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1399&quot; data-start=&quot;1237&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1399&quot; data-start=&quot;1237&quot;&gt;실행 컨텍스트가 &amp;ldquo;어떤 객체를 this로 바라볼지&amp;rdquo; 결정합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1399&quot; data-start=&quot;1282&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1330&quot; data-start=&quot;1282&quot;&gt;전역 실행 시: window(브라우저) or global(Node.js)&lt;/li&gt;
&lt;li data-end=&quot;1366&quot; data-start=&quot;1336&quot;&gt;함수 호출 시: 호출한 주체(객체)에 따라 다름&lt;/li&gt;
&lt;li data-end=&quot;1399&quot; data-start=&quot;1372&quot;&gt;생성자 함수 실행 시: 새로 만들어진 인스턴스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;1404&quot; data-start=&quot;1401&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1430&quot; data-start=&quot;1406&quot; data-ke-size=&quot;size26&quot;&gt;  실행 컨텍스트의 생성과 동작 과정&lt;/h2&gt;
&lt;p data-end=&quot;1466&quot; data-start=&quot;1432&quot; data-ke-size=&quot;size16&quot;&gt;함수가 호출될 때 실행 컨텍스트는 아래 순서로 동작합니다  &lt;/p&gt;
&lt;h3 data-end=&quot;1498&quot; data-start=&quot;1468&quot; data-ke-size=&quot;size23&quot;&gt;1️⃣ 생성 단계 (Creation Phase)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1564&quot; data-start=&quot;1499&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1518&quot; data-start=&quot;1499&quot;&gt;새 실행 컨텍스트가 만들어짐&lt;/li&gt;
&lt;li data-end=&quot;1548&quot; data-start=&quot;1519&quot;&gt;변수와 함수 선언이 메모리에 등록 (호이스팅)&lt;/li&gt;
&lt;li data-end=&quot;1564&quot; data-start=&quot;1549&quot;&gt;this 바인딩 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;1615&quot; data-start=&quot;1566&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1615&quot; data-start=&quot;1568&quot; data-ke-size=&quot;size16&quot;&gt;이 단계에서는 변수들이 &lt;b&gt;초기화는 되어 있지만 값은 undefined 상태&lt;/b&gt;예요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;1648&quot; data-start=&quot;1617&quot; data-ke-size=&quot;size23&quot;&gt;2️⃣ 실행 단계 (Execution Phase)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1686&quot; data-start=&quot;1649&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1686&quot; data-start=&quot;1649&quot;&gt;코드가 한 줄씩 실행되며 실제 값이 할당되고 로직이 수행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1691&quot; data-start=&quot;1688&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1722&quot; data-start=&quot;1693&quot; data-ke-size=&quot;size26&quot;&gt;  실행 컨텍스트 스택 (Call Stack)&lt;/h2&gt;
&lt;p data-end=&quot;1803&quot; data-start=&quot;1724&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 엔진은 실행 컨텍스트를 &lt;b&gt;스택(Stack)&lt;/b&gt; 구조로 관리합니다.&lt;br /&gt;가장 위에 있는 컨텍스트가 &amp;ldquo;현재 실행 중인 코드&amp;rdquo;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760764523773&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function a() {
  console.log('A');
  b();
}
function b() {
  console.log('B');
}
a();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1919&quot; data-start=&quot;1909&quot; data-ke-size=&quot;size23&quot;&gt;실행 순서:&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;2063&quot; data-start=&quot;1920&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1942&quot; data-start=&quot;1920&quot;&gt;전역 컨텍스트 생성 (Global)&lt;/li&gt;
&lt;li data-end=&quot;1970&quot; data-start=&quot;1943&quot;&gt;a() 호출 &amp;rarr; a 컨텍스트 push&lt;/li&gt;
&lt;li data-end=&quot;1998&quot; data-start=&quot;1971&quot;&gt;b() 호출 &amp;rarr; b 컨텍스트 push&lt;/li&gt;
&lt;li data-end=&quot;2016&quot; data-start=&quot;1999&quot;&gt;b() 종료 &amp;rarr; pop&lt;/li&gt;
&lt;li data-end=&quot;2034&quot; data-start=&quot;2017&quot;&gt;a() 종료 &amp;rarr; pop&lt;/li&gt;
&lt;li data-end=&quot;2063&quot; data-start=&quot;2035&quot;&gt;프로그램 종료 &amp;rarr; Global 컨텍스트 pop&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-end=&quot;2142&quot; data-start=&quot;2065&quot; data-ke-size=&quot;size16&quot;&gt;이런 구조 덕분에&lt;br /&gt;자바스크립트는 함수 실행 순서를 추적하고,&lt;br /&gt;비동기 처리나 에러 스택 트레이스 등을 효율적으로 관리할 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;2147&quot; data-start=&quot;2144&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2163&quot; data-start=&quot;2149&quot; data-ke-size=&quot;size26&quot;&gt;  예시로 이해하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760764574451&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const x = 1;

function foo() {
  let y = 2;

  function bar() {
    console.log(x + y);
  }

  bar();
}

foo(); // 3&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;331&quot; data-start=&quot;314&quot; data-ke-size=&quot;size23&quot;&gt;  실행 흐름 살펴보기&lt;/h3&gt;
&lt;p data-end=&quot;356&quot; data-start=&quot;333&quot; data-ke-size=&quot;size16&quot;&gt;1️⃣ &lt;b&gt;전역 실행 컨텍스트 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;514&quot; data-start=&quot;357&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;388&quot; data-start=&quot;357&quot;&gt;전역 변수 x와 함수 foo가 등록됩니다.&lt;/li&gt;
&lt;li data-end=&quot;474&quot; data-start=&quot;389&quot;&gt;x는 const로 선언되었기 때문에 &lt;b&gt;TDZ(Temporal Dead Zone)&lt;/b&gt; 를 거쳐&lt;br /&gt;실제 코드 실행 시 값이 할당됩니다.&lt;/li&gt;
&lt;li data-end=&quot;514&quot; data-start=&quot;475&quot;&gt;함수 foo는 선언 자체가 호이스팅되어 메모리에 등록됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;556&quot; data-start=&quot;516&quot; data-ke-size=&quot;size16&quot;&gt;2️⃣ &lt;b&gt;foo() 호출 &amp;rarr; 새로운 함수 실행 컨텍스트 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;663&quot; data-start=&quot;557&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;613&quot; data-start=&quot;557&quot;&gt;foo의 렉시컬 환경이 만들어지고, 지역 변수 y와 내부 함수 bar가 등록됩니다.&lt;/li&gt;
&lt;li data-end=&quot;663&quot; data-start=&quot;614&quot;&gt;y는 let으로 선언되었기 때문에 &lt;b&gt;블록 스코프 내에서만 유효&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;704&quot; data-start=&quot;665&quot; data-ke-size=&quot;size16&quot;&gt;3️⃣ &lt;b&gt;bar() 호출 &amp;rarr; 또 하나의 실행 컨텍스트 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;816&quot; data-start=&quot;705&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;736&quot; data-start=&quot;705&quot;&gt;bar 내부에서는 x와 y를 찾습니다.&lt;/li&gt;
&lt;li data-end=&quot;816&quot; data-start=&quot;737&quot;&gt;x는 전역 스코프(outer environment reference)에서,&lt;br /&gt;y는 foo의 렉시컬 환경에서 발견됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;851&quot; data-start=&quot;818&quot; data-ke-size=&quot;size16&quot;&gt;4️⃣ &lt;b&gt;console.log(x + y) 실행&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;910&quot; data-start=&quot;852&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;889&quot; data-start=&quot;852&quot;&gt;탐색 순서: bar &amp;rarr; foo &amp;rarr; 전역(Global)&lt;/li&gt;
&lt;li data-end=&quot;910&quot; data-start=&quot;890&quot;&gt;최종 결과: 1 + 2 = 3&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;2582&quot; data-start=&quot;2579&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2595&quot; data-start=&quot;2584&quot; data-ke-size=&quot;size26&quot;&gt;✨ 마무리 요약&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;구분내용
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2787&quot; data-start=&quot;2597&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2787&quot; data-start=&quot;2625&quot;&gt;
&lt;tr data-end=&quot;2654&quot; data-start=&quot;2625&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2630&quot; data-start=&quot;2625&quot;&gt;정의&lt;/td&gt;
&lt;td data-end=&quot;2654&quot; data-start=&quot;2630&quot; data-col-size=&quot;sm&quot;&gt;코드 실행에 필요한 정보를 담은 환경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2676&quot; data-start=&quot;2655&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2660&quot; data-start=&quot;2655&quot;&gt;종류&lt;/td&gt;
&lt;td data-end=&quot;2676&quot; data-start=&quot;2660&quot; data-col-size=&quot;sm&quot;&gt;전역, 함수, eval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2720&quot; data-start=&quot;2677&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2685&quot; data-start=&quot;2677&quot;&gt;구성 요소&lt;/td&gt;
&lt;td data-end=&quot;2720&quot; data-start=&quot;2685&quot; data-col-size=&quot;sm&quot;&gt;Variable Env, Lexical Env, this&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2753&quot; data-start=&quot;2721&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2729&quot; data-start=&quot;2721&quot;&gt;동작 순서&lt;/td&gt;
&lt;td data-end=&quot;2753&quot; data-start=&quot;2729&quot; data-col-size=&quot;sm&quot;&gt;생성(호이스팅) &amp;rarr; 실행(코드 수행)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2787&quot; data-start=&quot;2754&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2762&quot; data-start=&quot;2754&quot;&gt;관리 방식&lt;/td&gt;
&lt;td data-end=&quot;2787&quot; data-start=&quot;2762&quot; data-col-size=&quot;sm&quot;&gt;스택(Call Stack) 구조로 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;2792&quot; data-start=&quot;2789&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-end=&quot;2913&quot; data-start=&quot;2794&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2867&quot; data-start=&quot;2796&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;결국, 실행 컨텍스트를 이해하면&lt;/b&gt;&lt;br /&gt;자바스크립트의 스코프, 호이스팅, 클로저, this가 한눈에 연결됩니다.&lt;/p&gt;
&lt;p data-end=&quot;2913&quot; data-start=&quot;2874&quot; data-ke-size=&quot;size16&quot;&gt;즉, 실행 컨텍스트는 자바스크립트 엔진의 &amp;ldquo;두뇌&amp;rdquo;라고 할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>매일메일</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/507</guid>
      <comments>https://meercat.tistory.com/507#entry507comment</comments>
      <pubDate>Sat, 18 Oct 2025 14:18:47 +0900</pubDate>
    </item>
    <item>
      <title>브라우저 렌더링 최적화: Reflow와 Repaint 완벽 이해</title>
      <link>https://meercat.tistory.com/506</link>
      <description>&lt;p data-end=&quot;274&quot; data-start=&quot;138&quot; data-ke-size=&quot;size16&quot;&gt;웹 성능을 이야기할 때 꼭 등장하는 단어가 있습니다.&lt;br /&gt;바로 &lt;b&gt;Reflow(리플로우)&lt;/b&gt; 와 &lt;b&gt;Repaint(리페인트)&lt;/b&gt; 입니다.&lt;br /&gt;이 두 개념은 브라우저가 화면을 그리는 과정의 핵심이며,&lt;br /&gt;렌더링 성능 최적화의 출발점이기도 합니다.&lt;/p&gt;
&lt;hr data-end=&quot;279&quot; data-start=&quot;276&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;307&quot; data-start=&quot;281&quot; data-ke-size=&quot;size26&quot;&gt;  Reflow란? (Layout 단계)&lt;/h2&gt;
&lt;p data-end=&quot;408&quot; data-start=&quot;309&quot; data-ke-size=&quot;size16&quot;&gt;Reflow는 브라우저가 &lt;b&gt;요소의 크기나 위치를 다시 계산하는 과정&lt;/b&gt;이에요.&lt;br /&gt;즉, DOM 구조나 CSS 속성 중 &lt;b&gt;레이아웃에 영향을 주는 변화&lt;/b&gt;가 있을 때 발생합니다.&lt;/p&gt;
&lt;p data-end=&quot;442&quot; data-start=&quot;410&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 다음과 같은 상황이 Reflow를 유발합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;564&quot; data-start=&quot;443&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;492&quot; data-start=&quot;443&quot;&gt;요소의 width, height, margin, padding 변경&lt;/li&gt;
&lt;li data-end=&quot;515&quot; data-start=&quot;493&quot;&gt;새로운 DOM 요소 추가 / 제거&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;516&quot;&gt;display 속성 변경&lt;/li&gt;
&lt;li data-end=&quot;548&quot; data-start=&quot;536&quot;&gt;폰트 크기 변경&lt;/li&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;549&quot;&gt;창 크기 조절(리사이즈)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;696&quot; data-start=&quot;566&quot; data-ke-size=&quot;size16&quot;&gt;Reflow는 화면의 구조를 완전히 다시 계산해야 하므로&lt;br /&gt;&lt;b&gt;비용이 크고, 성능 저하의 주요 원인&lt;/b&gt;이 됩니다.&lt;br /&gt;특히 부모 요소의 레이아웃 변경은 자식 요소 전체에 영향을 주어&lt;br /&gt;연쇄적으로 Reflow가 발생할 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;701&quot; data-start=&quot;698&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;732&quot; data-start=&quot;703&quot; data-ke-size=&quot;size26&quot;&gt;  Repaint란? (Painting 단계)&lt;/h2&gt;
&lt;p data-end=&quot;822&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;Repaint는 &lt;b&gt;요소의 크기나 위치는 그대로지만, 외형이 바뀔 때&lt;/b&gt; 발생합니다.&lt;br /&gt;즉, 시각적인 스타일(appearance)만 다시 그리는 과정이에요.&lt;/p&gt;
&lt;p data-end=&quot;850&quot; data-start=&quot;824&quot; data-ke-size=&quot;size16&quot;&gt;다음과 같은 변경이 Repaint를 일으킵니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;961&quot; data-start=&quot;851&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;901&quot; data-start=&quot;851&quot;&gt;color, background-color, border-color 변경&lt;/li&gt;
&lt;li data-end=&quot;921&quot; data-start=&quot;902&quot;&gt;visibility 토글&lt;/li&gt;
&lt;li data-end=&quot;961&quot; data-start=&quot;922&quot;&gt;box-shadow, outline 등 시각적 속성 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1032&quot; data-start=&quot;963&quot; data-ke-size=&quot;size16&quot;&gt;Repaint는 Reflow보다는 가볍지만,&lt;br /&gt;잦은 스타일 변경이나 애니메이션에서는 여전히 성능에 영향을 줄 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;1037&quot; data-start=&quot;1034&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1069&quot; data-start=&quot;1039&quot; data-ke-size=&quot;size26&quot;&gt;⚖️ Reflow vs Repaint 한눈에 비교&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1347&quot; data-start=&quot;1071&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;Reflow&lt;/td&gt;
&lt;td&gt;Repaint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1208&quot; data-start=&quot;1162&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1170&quot; data-start=&quot;1162&quot;&gt;발생 조건&lt;/td&gt;
&lt;td data-end=&quot;1188&quot; data-start=&quot;1170&quot; data-col-size=&quot;sm&quot;&gt;레이아웃(위치, 크기) 변경&lt;/td&gt;
&lt;td data-end=&quot;1208&quot; data-start=&quot;1188&quot; data-col-size=&quot;sm&quot;&gt;외형(색상, 그림자 등) 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1242&quot; data-start=&quot;1209&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1218&quot; data-start=&quot;1209&quot;&gt;렌더링 단계&lt;/td&gt;
&lt;td data-end=&quot;1230&quot; data-start=&quot;1218&quot; data-col-size=&quot;sm&quot;&gt;Layout 단계&lt;/td&gt;
&lt;td data-end=&quot;1242&quot; data-start=&quot;1230&quot; data-col-size=&quot;sm&quot;&gt;Paint 단계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1268&quot; data-start=&quot;1243&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1251&quot; data-start=&quot;1243&quot;&gt;성능 비용&lt;/td&gt;
&lt;td data-end=&quot;1259&quot; data-start=&quot;1251&quot; data-col-size=&quot;sm&quot;&gt;높음 ⚠️&lt;/td&gt;
&lt;td data-end=&quot;1268&quot; data-start=&quot;1259&quot; data-col-size=&quot;sm&quot;&gt;중간 정도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1347&quot; data-start=&quot;1269&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1274&quot; data-start=&quot;1269&quot;&gt;예시&lt;/td&gt;
&lt;td data-end=&quot;1308&quot; data-start=&quot;1274&quot; data-col-size=&quot;sm&quot;&gt;width, display, font-size&lt;/td&gt;
&lt;td data-end=&quot;1347&quot; data-start=&quot;1308&quot; data-col-size=&quot;sm&quot;&gt;color, background, visibility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1352&quot; data-start=&quot;1349&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1368&quot; data-start=&quot;1354&quot; data-ke-size=&quot;size26&quot;&gt;  성능 최적화 팁&lt;/h2&gt;
&lt;h3 data-end=&quot;1388&quot; data-start=&quot;1370&quot; data-ke-size=&quot;size23&quot;&gt;1️⃣ Reflow 최소화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1568&quot; data-start=&quot;1389&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1443&quot; data-start=&quot;1389&quot;&gt;DOM 접근/변경은 &lt;b&gt;한 번에 묶어서&lt;/b&gt; 처리 (documentFragment 사용)&lt;/li&gt;
&lt;li data-end=&quot;1507&quot; data-start=&quot;1444&quot;&gt;layout 관련 속성(offsetWidth, clientHeight)을 &lt;b&gt;반복해서 읽지 않기&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1568&quot; data-start=&quot;1508&quot;&gt;CSS 애니메이션은 &lt;b&gt;transform, opacity 중심으로 구성&lt;/b&gt;해 GPU 가속 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1589&quot; data-start=&quot;1570&quot; data-ke-size=&quot;size23&quot;&gt;2️⃣ Repaint 최소화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1754&quot; data-start=&quot;1590&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1666&quot; data-start=&quot;1590&quot;&gt;시각적 변화가 잦은 요소는&lt;br /&gt;&lt;b&gt;will-change: opacity, transform&lt;/b&gt; 속성으로 GPU 레이어 분리&lt;/li&gt;
&lt;li data-end=&quot;1754&quot; data-start=&quot;1667&quot;&gt;보이지 않게 할 때 display:none 대신&lt;br /&gt;opacity: 0 + pointer-events: none 사용 (Reflow 방지)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1759&quot; data-start=&quot;1756&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1772&quot; data-start=&quot;1761&quot; data-ke-size=&quot;size26&quot;&gt;✨ 마무리 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1934&quot; data-start=&quot;1774&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1815&quot; data-start=&quot;1774&quot;&gt;&lt;b&gt;Reflow&lt;/b&gt;는 &amp;ldquo;레이아웃 재계산&amp;rdquo;으로, 가장 비싼 연산이다.&lt;/li&gt;
&lt;li data-end=&quot;1857&quot; data-start=&quot;1816&quot;&gt;&lt;b&gt;Repaint&lt;/b&gt;는 &amp;ldquo;시각적 변경&amp;rdquo;으로, 상대적으로 덜 비싸다.&lt;/li&gt;
&lt;li data-end=&quot;1893&quot; data-start=&quot;1858&quot;&gt;둘 다 빈번하게 일어나면 성능 저하의 주요 원인이 된다.&lt;/li&gt;
&lt;li data-end=&quot;1934&quot; data-start=&quot;1894&quot;&gt;가능한 한 DOM 변경을 묶고, GPU 가속 가능한 속성을 사용하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;1939&quot; data-start=&quot;1936&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-end=&quot;2032&quot; data-start=&quot;1941&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2032&quot; data-start=&quot;1943&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;결국 핵심은 &amp;ldquo;언제 브라우저가 다시 그려지는가&amp;rdquo;를 이해하는 것.&lt;/b&gt;&lt;br /&gt;이 원리를 이해하면, 자연스럽게 성능 좋은 UI 코드를 작성할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>매일메일</category>
      <category>Reflow</category>
      <category>Repaint</category>
      <category>리페인트</category>
      <category>리플로우</category>
      <category>브라우저렌더링</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/506</guid>
      <comments>https://meercat.tistory.com/506#entry506comment</comments>
      <pubDate>Sat, 18 Oct 2025 14:11:56 +0900</pubDate>
    </item>
    <item>
      <title>클로저(Closure) 완벽 정리 &amp;mdash; 자바스크립트 개발자라면 반드시 알아야 할 핵심 개념</title>
      <link>https://meercat.tistory.com/505</link>
      <description>&lt;p data-end=&quot;92&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클로저(Closure)&lt;/b&gt;는 자바스크립트의 핵심 개념 중 하나로, &lt;b&gt;함수가 선언될 때의 환경(스코프)을 기억하는 함수&lt;/b&gt;를 말합니다.&lt;/p&gt;
&lt;hr data-end=&quot;97&quot; data-start=&quot;94&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;113&quot; data-start=&quot;99&quot; data-ke-size=&quot;size26&quot;&gt;  1. 기본 개념&lt;/h2&gt;
&lt;p data-end=&quot;316&quot; data-start=&quot;114&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트에서는 &lt;b&gt;함수가 선언될 때의 스코프(lexical scope)&lt;/b&gt; 를 기억합니다.&lt;br /&gt;이때, &lt;b&gt;내부 함수(inner function)&lt;/b&gt; 가 &lt;b&gt;자신을 둘러싼 외부 함수(outer function)&lt;/b&gt; 의 변수에 접근할 수 있을 때,&lt;br /&gt;그 &lt;b&gt;관계를 유지한 채로 외부 함수가 종료된 이후에도 접근 가능한 구조&lt;/b&gt; &amp;mdash; 이것이 바로 클로저입니다.&lt;/p&gt;
&lt;hr data-end=&quot;321&quot; data-start=&quot;318&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;343&quot; data-start=&quot;323&quot; data-ke-size=&quot;size26&quot;&gt;  2. 예시 코드로 이해하기&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760233933439&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function makeCounter() {
  let count = 0; // 외부 함수의 지역 변수

  return function() { // 내부 함수 (클로저)
    count++;
    return count;
  };
}

const counter = makeCounter();

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;632&quot; data-start=&quot;610&quot; data-ke-size=&quot;size23&quot;&gt;  무슨 일이 일어나고 있을까?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;891&quot; data-start=&quot;633&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;679&quot; data-start=&quot;633&quot;&gt;makeCounter()가 실행되면 지역 변수 count가 생성됩니다.&lt;/li&gt;
&lt;li data-end=&quot;746&quot; data-start=&quot;680&quot;&gt;내부 함수가 return되며, 이 함수는 count에 접근할 수 있는 &lt;b&gt;권한&lt;/b&gt;을 가진 채 밖으로 나갑니다.&lt;/li&gt;
&lt;li data-end=&quot;838&quot; data-start=&quot;747&quot;&gt;makeCounter()의 실행은 끝났지만, 내부 함수가 count를 &lt;b&gt;참조 중이기 때문에 GC(가비지 컬렉터)&lt;/b&gt; 가 그 변수를 제거하지 않습니다.&lt;/li&gt;
&lt;li data-end=&quot;891&quot; data-start=&quot;839&quot;&gt;그 결과, counter()를 호출할 때마다 count 값이 유지되고 증가합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-end=&quot;896&quot; data-start=&quot;893&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;917&quot; data-start=&quot;898&quot; data-ke-size=&quot;size26&quot;&gt;  3. 클로저의 특징 요약&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1161&quot; data-start=&quot;919&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1008&quot; data-start=&quot;947&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;956&quot; data-start=&quot;947&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1008&quot; data-start=&quot;956&quot; data-col-size=&quot;md&quot;&gt;함수가 선언될 당시의 스코프를 기억하여, 외부 함수의 변수에 접근할 수 있는 내부 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1032&quot; data-start=&quot;1009&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1018&quot; data-start=&quot;1009&quot;&gt;&lt;b&gt;형태&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1032&quot; data-start=&quot;1018&quot; data-col-size=&quot;md&quot;&gt;함수 안의 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1069&quot; data-start=&quot;1033&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1045&quot; data-start=&quot;1033&quot;&gt;&lt;b&gt;생성 시점&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1069&quot; data-start=&quot;1045&quot; data-col-size=&quot;md&quot;&gt;함수가 &lt;b&gt;선언될 때(정의 시점)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1123&quot; data-start=&quot;1070&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1082&quot; data-start=&quot;1070&quot;&gt;&lt;b&gt;소멸 시점&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1123&quot; data-start=&quot;1082&quot; data-col-size=&quot;md&quot;&gt;외부 함수가 끝나도 내부 함수가 참조 중이면 &lt;b&gt;메모리에서 유지&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1161&quot; data-start=&quot;1124&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1136&quot; data-start=&quot;1124&quot;&gt;&lt;b&gt;주요 효과&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;1161&quot; data-start=&quot;1136&quot; data-col-size=&quot;md&quot;&gt;데이터 은닉, 상태 유지, 모듈화 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-end=&quot;1166&quot; data-start=&quot;1163&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;1192&quot; data-start=&quot;1168&quot; data-ke-size=&quot;size26&quot;&gt;  4. 클로저의 대표적인 활용 예시&lt;/h2&gt;
&lt;h3 data-end=&quot;1220&quot; data-start=&quot;1194&quot; data-ke-size=&quot;size23&quot;&gt;✅ (1) &lt;b&gt;데이터 은닉 / 캡슐화&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234065205&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function createAccount() {
  let balance = 0;

  return {
    deposit(amount) {
      balance += amount;
    },
    getBalance() {
      return balance;
    }
  };
}

const account = createAccount();
account.deposit(1000);
console.log(account.getBalance()); // 1000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1569&quot; data-start=&quot;1497&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 외부에서는 balance를 직접 수정할 수 없고, 오직 deposit() / getBalance()로만 접근 가능.&lt;/p&gt;
&lt;hr data-end=&quot;1574&quot; data-start=&quot;1571&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1605&quot; data-start=&quot;1576&quot; data-ke-size=&quot;size23&quot;&gt;✅ (2) &lt;b&gt;이벤트 핸들러에서 상태 유지&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234103903&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function createClickCounter(button) {
  let count = 0;

  button.addEventListener('click', function() {
    count++;
    console.log(`Clicked ${count} times`);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1815&quot; data-start=&quot;1784&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 각 버튼마다 클릭 횟수를 &amp;ldquo;기억&amp;rdquo;하는 클로저를 가짐.&lt;/p&gt;
&lt;hr data-end=&quot;1820&quot; data-start=&quot;1817&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1866&quot; data-start=&quot;1822&quot; data-ke-size=&quot;size23&quot;&gt;✅ (3) &lt;b&gt;React에서의 예시 (useState와 비슷한 원리)&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1760234136745&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function useCounter() {
  let count = 0;

  function increment() {
    count++;
    console.log(count);
  }

  return [() =&amp;gt; count, increment];
}

const [getCount, increment] = useCounter();
increment(); // 1
increment(); // 2
console.log(getCount()); // 2&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-end=&quot;2138&quot; data-start=&quot;2135&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2154&quot; data-start=&quot;2140&quot; data-ke-size=&quot;size26&quot;&gt;⚠️ 5. 주의할 점&lt;/h2&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2354&quot; data-start=&quot;2156&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2243&quot; data-start=&quot;2184&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2197&quot; data-start=&quot;2184&quot;&gt;&lt;b&gt;메모리 누수&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;2243&quot; data-start=&quot;2197&quot; data-col-size=&quot;md&quot;&gt;클로저가 너무 많은 변수를 오래 참조하면 메모리 점유가 계속 유지될 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2307&quot; data-start=&quot;2244&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2262&quot; data-start=&quot;2244&quot;&gt;&lt;b&gt;의도치 않은 값 공유&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;2307&quot; data-start=&quot;2262&quot; data-col-size=&quot;md&quot;&gt;반복문 안에서 var를 사용하면 모든 클로저가 같은 변수를 참조하게 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2354&quot; data-start=&quot;2308&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2318&quot; data-start=&quot;2308&quot;&gt;&lt;b&gt;해결법&lt;/b&gt;&lt;/td&gt;
&lt;td data-end=&quot;2354&quot; data-start=&quot;2318&quot; data-col-size=&quot;md&quot;&gt;let 사용 또는 즉시실행함수(IIFE)로 스코프 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234198930&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (var i = 0; i &amp;lt; 3; i++) {
  setTimeout(() =&amp;gt; console.log(i), 1000); // 3 3 3
}

for (let i = 0; i &amp;lt; 3; i++) {
  setTimeout(() =&amp;gt; console.log(i), 1000); // 0 1 2
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-start=&quot;948&quot; data-end=&quot;951&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;864&quot; data-start=&quot;830&quot; data-ke-size=&quot;size26&quot;&gt;⚛️ 6. React / TypeScript 실전 예제&lt;/h2&gt;
&lt;p data-end=&quot;946&quot; data-start=&quot;866&quot; data-ke-size=&quot;size16&quot;&gt;React에서는 클로저가 &lt;b&gt;매우 자주&lt;/b&gt; 사용됩니다.&lt;br /&gt;특히 useEffect, useState, 이벤트 핸들러, 비동기 로직에서요.&lt;/p&gt;
&lt;h3 data-end=&quot;981&quot; data-start=&quot;953&quot; data-ke-size=&quot;size23&quot;&gt;✅ 예제 1: useEffect와 클로저&lt;/h3&gt;
&lt;pre id=&quot;code_1760234430491&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() =&amp;gt; {
    const interval = setInterval(() =&amp;gt; {
      console.log(&quot;count:&quot;, count); // ⚠️ 클로저 발생
    }, 1000);

    return () =&amp;gt; clearInterval(interval);
  }, []);

  return (
    &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;
      Count: {count}
    &amp;lt;/button&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;1423&quot; data-start=&quot;1400&quot; data-ke-size=&quot;size20&quot;&gt;  여기서 무슨 일이 일어날까?&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1618&quot; data-start=&quot;1424&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1471&quot; data-start=&quot;1424&quot;&gt;useEffect는 &lt;b&gt;mount 시점에 한 번만 실행&lt;/b&gt;됩니다 ([]).&lt;/li&gt;
&lt;li data-end=&quot;1538&quot; data-start=&quot;1472&quot;&gt;따라서 setInterval 안의 함수는 &lt;b&gt;초기 렌더링 당시의 count&lt;/b&gt;를 기억하는 클로저를 만듭니다.&lt;/li&gt;
&lt;li data-end=&quot;1618&quot; data-start=&quot;1539&quot;&gt;이후 버튼을 눌러도 count가 증가해도,&lt;br /&gt;console.log(&quot;count:&quot;, count)는 &lt;b&gt;0만 계속 찍습니다!&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1651&quot; data-start=&quot;1620&quot; data-ke-size=&quot;size16&quot;&gt;이건 바로 클로저의 &amp;ldquo;환경을 기억하는 성질&amp;rdquo; 때문이에요.&lt;/p&gt;
&lt;h4 data-end=&quot;1665&quot; data-start=&quot;1653&quot; data-ke-size=&quot;size20&quot;&gt;✅ 해결 방법&lt;/h4&gt;
&lt;p data-end=&quot;1719&quot; data-start=&quot;1666&quot; data-ke-size=&quot;size16&quot;&gt;현재의 count 값이 필요하다면 &lt;b&gt;함수형 업데이트&lt;/b&gt;나 &lt;b&gt;ref&lt;/b&gt;를 이용해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1760234448028&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  const interval = setInterval(() =&amp;gt; {
    setCount(c =&amp;gt; {
      console.log(&quot;count:&quot;, c);
      return c + 1;
    });
  }, 1000);
  return () =&amp;gt; clearInterval(interval);
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1996&quot; data-start=&quot;1930&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 setCount의 인자 (c)가 매번 최신 상태를 전달받기 때문에 클로저 문제를 피할 수 있습니다.&lt;/p&gt;
&lt;hr data-end=&quot;2001&quot; data-start=&quot;1998&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2030&quot; data-start=&quot;2003&quot; data-ke-size=&quot;size23&quot;&gt;✅ 예제 2: 이벤트 핸들러에서 상태 유지&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234520503&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;

export default function ToggleButton() {
  const [isOn, setIsOn] = useState(false);

  function handleClick() {
    // handleClick이 선언될 때의 스코프를 기억함 (클로저)
    console.log(&quot;현재 상태:&quot;, isOn);
    setIsOn(!isOn);
  }

  return &amp;lt;button onClick={handleClick}&amp;gt;{isOn ? &quot;ON&quot; : &quot;OFF&quot;}&amp;lt;/button&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;2377&quot; data-start=&quot;2364&quot; data-ke-size=&quot;size20&quot;&gt;  동작 설명&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2556&quot; data-start=&quot;2378&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2418&quot; data-start=&quot;2378&quot;&gt;handleClick 함수는 렌더링될 때마다 새롭게 만들어집니다.&lt;/li&gt;
&lt;li data-end=&quot;2478&quot; data-start=&quot;2419&quot;&gt;하지만 이벤트 핸들러 내부의 isOn은 &lt;b&gt;그 함수가 생성된 당시의 state 값을 기억&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li data-end=&quot;2556&quot; data-start=&quot;2479&quot;&gt;React는 매 렌더마다 새로운 클로저를 만들기 때문에,&lt;br /&gt;이벤트가 트리거될 때 &lt;b&gt;현재 렌더의 상태값&lt;/b&gt;을 참조하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-end=&quot;2620&quot; data-start=&quot;2558&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2620&quot; data-start=&quot;2560&quot; data-ke-size=&quot;size16&quot;&gt;즉, React는 클로저를 매 렌더마다 새로 만들어서 &amp;ldquo;이전 상태 유지&amp;rdquo; 대신 &amp;ldquo;현재 상태 반영&amp;rdquo;을 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2625&quot; data-start=&quot;2622&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2656&quot; data-start=&quot;2627&quot; data-ke-size=&quot;size23&quot;&gt;✅ 예제 3: 비동기 요청에서 클로저 주의하기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234614535&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  let isMounted = true;

  async function fetchData() {
    const res = await fetch(&quot;/api/data&quot;);
    const data = await res.json();

    if (isMounted) {
      setData(data);
    }
  }

  fetchData();

  return () =&amp;gt; {
    isMounted = false;
  };
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;2962&quot; data-start=&quot;2944&quot; data-ke-size=&quot;size20&quot;&gt;⚠️ 왜 이렇게 하냐면:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;3110&quot; data-start=&quot;2963&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;3025&quot; data-start=&quot;2963&quot;&gt;fetchData가 실행되는 동안 컴포넌트가 언마운트되면 setData()를 호출하면 에러가 납니다.&lt;/li&gt;
&lt;li data-end=&quot;3110&quot; data-start=&quot;3026&quot;&gt;isMounted 변수가 &amp;ldquo;현재 컴포넌트가 살아 있는지&amp;rdquo;를 &lt;b&gt;클로저로 기억&lt;/b&gt;하고,&lt;br /&gt;cleanup에서 false로 바꿔주는 패턴이에요.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-start=&quot;948&quot; data-end=&quot;951&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;193&quot; data-start=&quot;142&quot; data-ke-size=&quot;size26&quot;&gt;⚛️ 7. 클로저, 그리고 useCallback / useMemo / 비동기 버그의 진짜 이유&lt;/h2&gt;
&lt;h3 data-end=&quot;224&quot; data-start=&quot;200&quot; data-ke-size=&quot;size23&quot;&gt;  1️⃣ 클로저와 React의 관계&lt;/h3&gt;
&lt;p data-end=&quot;322&quot; data-start=&quot;226&quot; data-ke-size=&quot;size16&quot;&gt;React 컴포넌트는 &lt;b&gt;렌더링될 때마다 함수가 새로 호출&lt;/b&gt;됩니다.&lt;br /&gt;즉, 컴포넌트 내부의 &lt;b&gt;모든 변수, 함수, state 참조&lt;/b&gt;가 매 렌더마다 새롭게 만들어집니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;415&quot; data-start=&quot;324&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;415&quot; data-start=&quot;326&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 따라서 &amp;ldquo;이전 렌더의 변수나 state를 참조하는 클로저&amp;rdquo;가 발생할 수 있어요.&lt;br /&gt;React의 모든 훅은 사실상 &amp;ldquo;클로저 위에서 작동하는 구조&amp;rdquo;입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;420&quot; data-start=&quot;417&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;467&quot; data-start=&quot;422&quot; data-ke-size=&quot;size23&quot;&gt;⚙️ 2️⃣ useCallback / useMemo에서 클로저가 중요한 이유&lt;/h3&gt;
&lt;h4 data-end=&quot;507&quot; data-start=&quot;469&quot; data-ke-size=&quot;size20&quot;&gt;  (1) useCallback은 함수를 &amp;ldquo;메모이제이션&amp;rdquo;한다&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234912760&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handleClick = useCallback(() =&amp;gt; {
  console.log(count);
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;600&quot; data-start=&quot;590&quot; data-ke-size=&quot;size18&quot;&gt;❌ 문제:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;719&quot; data-start=&quot;601&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;658&quot; data-start=&quot;601&quot;&gt;[] 의존성 배열이 비어 있으면 count의 &lt;b&gt;초기값만 기억한 클로저&lt;/b&gt;가 유지됩니다.&lt;/li&gt;
&lt;li data-end=&quot;719&quot; data-start=&quot;659&quot;&gt;즉, 이후 count가 바뀌어도 handleClick은 &lt;b&gt;옛날 count를 콘솔에 찍습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;731&quot; data-start=&quot;721&quot; data-ke-size=&quot;size18&quot;&gt;✅ 해결:&lt;/p&gt;
&lt;p data-end=&quot;798&quot; data-start=&quot;732&quot; data-ke-size=&quot;size16&quot;&gt;의존성 배열에 count를 넣어야, React가 &lt;b&gt;새로운 count를 클로저에 캡처한 새 함수&lt;/b&gt;를 만들어줍니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234929313&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handleClick = useCallback(() =&amp;gt; {
  console.log(count);
}, [count]);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;891&quot; data-start=&quot;887&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;984&quot; data-start=&quot;892&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;930&quot; data-start=&quot;892&quot;&gt;useCallback은 클로저의 &amp;ldquo;스냅샷&amp;rdquo;을 저장하는 훅,&lt;/li&gt;
&lt;li data-end=&quot;984&quot; data-start=&quot;931&quot;&gt;deps는 &amp;ldquo;이 클로저를 언제 새로 만들어야 하는가&amp;rdquo;를 React에게 알려주는 장치예요.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;989&quot; data-start=&quot;986&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1024&quot; data-start=&quot;991&quot; data-ke-size=&quot;size20&quot;&gt;⚙️ (2) useMemo도 똑같이 클로저를 기억한다&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234944304&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const doubled = useMemo(() =&amp;gt; {
  console.log('memoized');
  return count * 2;
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1216&quot; data-start=&quot;1125&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1176&quot; data-start=&quot;1125&quot;&gt;[]로 두면 &lt;b&gt;처음 count만 기억&lt;/b&gt;하고, 이후 변경돼도 다시 계산하지 않아요.&lt;/li&gt;
&lt;li data-end=&quot;1216&quot; data-start=&quot;1177&quot;&gt;[count]를 넣으면 &lt;b&gt;새 count로 다시 계산&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1290&quot; data-start=&quot;1218&quot; data-ke-size=&quot;size16&quot;&gt;  useMemo의 콜백도 결국 클로저입니다.&lt;br /&gt;React는 &amp;ldquo;의존성 배열을 기준으로 클로저를 새로 만들지 말지&amp;rdquo;를 결정하죠.&lt;/p&gt;
&lt;hr data-end=&quot;1295&quot; data-start=&quot;1292&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1332&quot; data-start=&quot;1297&quot; data-ke-size=&quot;size23&quot;&gt;⚠️ 3️⃣ stale closure(오래된 클로저) 문제&lt;/h3&gt;
&lt;h4 data-end=&quot;1343&quot; data-start=&quot;1334&quot; data-ke-size=&quot;size20&quot;&gt;  개념&lt;/h4&gt;
&lt;blockquote data-end=&quot;1426&quot; data-start=&quot;1344&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1426&quot; data-start=&quot;1346&quot; data-ke-size=&quot;size16&quot;&gt;Stale Closure란, 오래된 변수 값을 기억하는 클로저 때문에&lt;br /&gt;&lt;b&gt;최신 state나 props를 읽지 못하는 버그&lt;/b&gt;를 말합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;1431&quot; data-start=&quot;1428&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;1477&quot; data-start=&quot;1433&quot; data-ke-size=&quot;size20&quot;&gt;  예제: setTimeout 안에서 발생하는 stale closure&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234963016&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Timer() {
  const [count, setCount] = useState(0);

  const start = () =&amp;gt; {
    setTimeout(() =&amp;gt; {
      console.log(&quot;Count:&quot;, count); // ❌ 항상 오래된 count!
    }, 2000);
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={start}&amp;gt;Start&amp;lt;/button&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1842&quot; data-start=&quot;1836&quot; data-ke-size=&quot;size16&quot;&gt;  원인:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2003&quot; data-start=&quot;1843&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1891&quot; data-start=&quot;1843&quot;&gt;start 함수는 &lt;b&gt;렌더링 시점의 count&lt;/b&gt;를 기억하는 클로저를 만듭니다.&lt;/li&gt;
&lt;li data-end=&quot;2003&quot; data-start=&quot;1892&quot;&gt;2초 후 콜백 실행 시점엔 이미 여러 번 렌더링이 일어났을 수 있지만,&lt;br /&gt;setTimeout 내부 클로저는 여전히 **&amp;ldquo;start 버튼을 눌렀던 순간의 count&amp;rdquo;**만 가지고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-end=&quot;2008&quot; data-start=&quot;2005&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2042&quot; data-start=&quot;2010&quot; data-ke-size=&quot;size23&quot;&gt;  4️⃣ stale closure 방지 패턴 정리&lt;/h3&gt;
&lt;h4 data-end=&quot;2077&quot; data-start=&quot;2044&quot; data-ke-size=&quot;size20&quot;&gt;✅ (1) 최신 값을 가져오려면 함수형 업데이트 사용&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760234983978&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setCount(c =&amp;gt; c + 1);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2190&quot; data-start=&quot;2111&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이 패턴은 &lt;b&gt;React가 내부적으로 최신 state를 전달&lt;/b&gt;해주기 때문에,&lt;br /&gt;클로저에 오래된 state가 남아 있어도 안전합니다.&lt;/p&gt;
&lt;hr data-end=&quot;2195&quot; data-start=&quot;2192&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2225&quot; data-start=&quot;2197&quot; data-ke-size=&quot;size20&quot;&gt;✅ (2) useRef로 최신 값을 추적하기&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760235006052&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Timer() {
  const [count, setCount] = useState(0);
  const countRef = useRef(count);

  useEffect(() =&amp;gt; {
    countRef.current = count; // 항상 최신값으로 갱신
  }, [count]);

  const start = () =&amp;gt; {
    setTimeout(() =&amp;gt; {
      console.log(&quot;Count:&quot;, countRef.current); // ✅ 항상 최신값
    }, 2000);
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={start}&amp;gt;Start&amp;lt;/button&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;2775&quot; data-start=&quot;2703&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;2775&quot; data-start=&quot;2705&quot; data-ke-size=&quot;size16&quot;&gt;  useRef는 렌더링과 무관하게 &lt;b&gt;변수를 지속적으로 유지&lt;/b&gt;하므로, stale closure를 방지할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;2780&quot; data-start=&quot;2777&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;2833&quot; data-start=&quot;2782&quot; data-ke-size=&quot;size20&quot;&gt;✅ (3) useEvent (React 19+ or useCallbackRef 패턴)&lt;/h4&gt;
&lt;p data-end=&quot;2900&quot; data-start=&quot;2834&quot; data-ke-size=&quot;size16&quot;&gt;React 19부터 공식적으로 useEvent 훅이 추가됩니다.&lt;br /&gt;이는 &amp;ldquo;항상 최신 클로저를 보장&amp;rdquo;하는 훅입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760235017772&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useEvent } from &quot;react&quot;;

function Timer() {
  const [count, setCount] = useState(0);

  const onTimeout = useEvent(() =&amp;gt; {
    console.log(&quot;Count:&quot;, count); // ✅ 항상 최신 count
  });

  const start = () =&amp;gt; setTimeout(onTimeout, 2000);

  return &amp;lt;button onClick={() =&amp;gt; setCount(c =&amp;gt; c + 1)}&amp;gt;+1&amp;lt;/button&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-end=&quot;3283&quot; data-start=&quot;3226&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;3283&quot; data-start=&quot;3228&quot; data-ke-size=&quot;size16&quot;&gt;⚡️ useEvent는 렌더링 시점을 새로 캡처하지 않고, 내부적으로 최신 클로저를 유지합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-end=&quot;3288&quot; data-start=&quot;3285&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-end=&quot;3323&quot; data-start=&quot;3290&quot; data-ke-size=&quot;size20&quot;&gt;✅ (4) 커스텀 훅으로 안전한 비동기 로직 관리하기&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760235032986&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function useSafeAsync(callback: () =&amp;gt; void, deps: any[]) {
  const callbackRef = useRef(callback);

  useEffect(() =&amp;gt; {
    callbackRef.current = callback;
  }, [callback]);

  return useCallback((...args: any[]) =&amp;gt; {
    callbackRef.current(...args);
  }, []);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3607&quot; data-start=&quot;3601&quot; data-ke-size=&quot;size16&quot;&gt;사용 예시:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1760235045039&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const safeLog = useSafeAsync(() =&amp;gt; console.log(count), [count]);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3736&quot; data-start=&quot;3685&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 이렇게 하면, 오래된 클로저가 아닌 &lt;b&gt;항상 최신 상태를 참조하는 함수&lt;/b&gt;를 반환합니다.&lt;/p&gt;
&lt;hr data-end=&quot;2537&quot; data-start=&quot;2534&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-end=&quot;2550&quot; data-start=&quot;2539&quot; data-ke-size=&quot;size26&quot;&gt;  요약 정리&lt;/h2&gt;
&lt;p data-end=&quot;155&quot; data-start=&quot;94&quot; data-ke-size=&quot;size16&quot;&gt;클로저는 단순히 &amp;ldquo;함수 안의 함수&amp;rdquo;가 아니라,&lt;br /&gt;&lt;b&gt;함수가 선언될 당시의 스코프를 기억하는 함수&lt;/b&gt;예요.&lt;/p&gt;
&lt;p data-end=&quot;235&quot; data-start=&quot;157&quot; data-ke-size=&quot;size16&quot;&gt;이를 통해 함수 외부에서 접근할 수 없는 변수를 &lt;b&gt;안전하게 유지&lt;/b&gt;하고,&lt;br /&gt;필요할 때마다 그 값을 &lt;b&gt;참조하거나 수정&lt;/b&gt;할 수 있죠.&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;237&quot; data-ke-size=&quot;size16&quot;&gt;즉, 클로저는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;357&quot; data-start=&quot;247&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;267&quot; data-start=&quot;247&quot;&gt;&lt;b&gt;상태를 기억하는 함수&lt;/b&gt;,&lt;/li&gt;
&lt;li data-end=&quot;289&quot; data-start=&quot;268&quot;&gt;&lt;b&gt;데이터를 은닉하는 도구&lt;/b&gt;,&lt;/li&gt;
&lt;li data-end=&quot;357&quot; data-start=&quot;290&quot;&gt;그리고 &lt;b&gt;React의 useCallback / useMemo 같은 훅에서 핵심적으로 작동하는 메커니즘&lt;/b&gt;이에요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;359&quot; data-ke-size=&quot;size16&quot;&gt;하지만 너무 많은 변수를 참조하면 메모리 누수가 생길 수 있으니,&lt;br /&gt;&lt;b&gt;의도를 명확히 하고 꼭 필요한 경우에만 사용하는 습관&lt;/b&gt;이 중요합니다.&lt;/p&gt;
&lt;p data-end=&quot;448&quot; data-start=&quot;443&quot; data-ke-size=&quot;size16&quot;&gt;결국,&lt;/p&gt;
&lt;blockquote data-end=&quot;500&quot; data-start=&quot;449&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;500&quot; data-start=&quot;451&quot; data-ke-size=&quot;size16&quot;&gt;클로저를 이해한다는 건 자바스크립트의 &amp;ldquo;함수&amp;rdquo;와 &amp;ldquo;스코프&amp;rdquo;를 진짜로 이해한다는 뜻이에요.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>매일메일</category>
      <category>closure</category>
      <category>클로저</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/505</guid>
      <comments>https://meercat.tistory.com/505#entry505comment</comments>
      <pubDate>Sun, 12 Oct 2025 12:04:02 +0900</pubDate>
    </item>
    <item>
      <title>[RN]  에러일지 - iOS17에서 App Crash 생기는 이유</title>
      <link>https://meercat.tistory.com/504</link>
      <description>&lt;p data-pm-slice=&quot;1 3 []&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;paragraph&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-size=&quot;size16&quot;&gt;iOS 17 이상에서 &lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;UIGraphicsBeginImageContext()&lt;/span&gt;를 시도할 때, 이미지 사이즈가 (0, 0)인 경우 강제종료될 수 있으므로 &lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;UIGraphicsImageRenderer&lt;/span&gt;를 쓰는 것이 권장된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;bulletList&quot; data-prosemirror-content-type=&quot;node&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;문제 패키지: &lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;react-native-fast-image&lt;/span&gt;, &lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;react-native-linear-gradient&lt;/span&gt;&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;react-native-linear-gradient v2.6.2 &amp;rarr; v.2.8.3 upgrade&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;react-native-fast-image 는 현재 문제 메서드가 deprecated 되서는 안되는 환경 문제 이슈로 patch-package 사용해서 수정.&lt;/li&gt;
&lt;li data-prosemirror-node-block=&quot;true&quot; data-prosemirror-node-name=&quot;listItem&quot; data-prosemirror-content-type=&quot;node&quot;&gt;iOS 내부에서 &lt;span data-prosemirror-mark-name=&quot;code&quot; data-prosemirror-content-type=&quot;mark&quot;&gt;UIGraphicsBeginImageContext() &lt;/span&gt;사용된 함수 수정&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>FrontEnd/ReactNative</category>
      <category>ios17 crash</category>
      <category>React Native</category>
      <category>react-native-fast-image</category>
      <category>react-native-linear-gradient</category>
      <category>rn</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/504</guid>
      <comments>https://meercat.tistory.com/504#entry504comment</comments>
      <pubDate>Wed, 24 Sep 2025 22:19:30 +0900</pubDate>
    </item>
    <item>
      <title>[RN]  에러일지 - exception while building Json A problem occurred starting process 'command ...</title>
      <link>https://meercat.tistory.com/502</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;m1 혹은 m2 칩 맥에서 빌드 시 발생하는 에러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드 충돌을 방지하기 위해 rosseta 설치하기&lt;/p&gt;
&lt;pre id=&quot;code_1702946485695&quot; class=&quot;jboss-cli&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 라이센스 동의 필요
softwareupdate --install-rosetta


// 2. 라이선스 자동 동의
/usr/sbin/softwareupdate --install-rosetta --agree-to-license&lt;/code&gt;&lt;/pre&gt;</description>
      <category>FrontEnd/ReactNative</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/502</guid>
      <comments>https://meercat.tistory.com/502#entry502comment</comments>
      <pubDate>Tue, 19 Dec 2023 09:41:37 +0900</pubDate>
    </item>
    <item>
      <title>[RN]  에러 일지 - SDK location not found. Define a valid SDK location with an ANDROID_HOME environment variable or by setting the sdk.</title>
      <link>https://meercat.tistory.com/501</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;말 그대로 SDK 경로를 찾을 수 없어서 발생하며,&amp;nbsp;&lt;br /&gt;주로 맥 -&amp;gt; 윈도,&amp;nbsp; 윈도 -&amp;gt; 맥으로 프로젝트를 옮길 때 자주 발생하는 에러입니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;안드로이드 스튜디오에 내 프로젝트 디렉터리로 가셔서&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;local.properties&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 한번 찾아보세요!&lt;br /&gt;존재하지 않거나 경로가 잘못되어있을 가능성이 큽니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;경로가 잘못되어 있다면 내 PC에 맞게 변경해주시면 됩니다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;보통 윈도의 경우&amp;nbsp;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;c:\Users\'사용자 이름'\AppData\Local\android\adk&lt;br /&gt;&lt;/span&gt;그리고 맥의 경우&amp;nbsp;&lt;span style=&quot;background-color: #9feec3;&quot;&gt;/Users/'사용자 이름'/Library/Android/sdk&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cc7832;&quot;&gt;sdk.dir&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: #6a8759;&quot;&gt;/Users/luna/Library/Android/sdk&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이런 식으로 변경해주시면 됩니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>FrontEnd/ReactNative</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/501</guid>
      <comments>https://meercat.tistory.com/501#entry501comment</comments>
      <pubDate>Tue, 19 Dec 2023 09:30:24 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 그래프</title>
      <link>https://meercat.tistory.com/500</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개념 및 용어&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프 G는 하나 이상의 정점(혹은 노드)을 포함하는 집합 V와 두 정점의 쌍으로 구성되는 간선을 포함하는 집합 E의 순서쌍으로 정의함 (&lt;b&gt;G = (V, E)&lt;/b&gt;)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간선(인접한다)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 정점을 연결하는 선&lt;/li&gt;
&lt;li&gt;두 정점 쌍으로 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;무방향 그래프
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간선의 방향성이 없음&lt;/li&gt;
&lt;li&gt;정점 쌍이 순서를 나타낼 필요가 없으므로 {v1, v2}로 나타냄&lt;/li&gt;
&lt;li&gt;n개의 정점을 갖을 때 최대 간선 개수: n(n-1)/2&lt;/li&gt;
&lt;li&gt;차수: 정점에 연결된 간선들의 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;방향 그래프
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간선의 방향성이 있음&lt;/li&gt;
&lt;li&gt;순서쌍 (v1, v2)&lt;/li&gt;
&lt;li&gt;n개의 정점을 갖을 때 최대 간선 개수: n(n-1)&lt;/li&gt;
&lt;li&gt;진입 차수: 주어진 정점으로 향한 간선의 개수&lt;/li&gt;
&lt;li&gt;진출 차수: 주어진 정점에서 시작하는 간선의 개수&lt;/li&gt;
&lt;li&gt;정점의 차수: 진출 차수와 진입 차수의 합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다중 그래프: 두 정점을 잇는 간선이 여러 개인 그래프&lt;/li&gt;
&lt;li&gt;방향 다중 그래프: 방향성을 갖는 간선으로 이루어진 다중 그래프&lt;/li&gt;
&lt;li&gt;무방향 다중 그래프: 방향성이 없는 간선으로 이루어진 다중 그래프&lt;/li&gt;
&lt;li&gt;가중 그래프: 간선이 가중치를 갖는 그래프&lt;/li&gt;
&lt;li&gt;완전 그래프: 모든 정점들이 간선으로 서로 연결된 그래프&lt;/li&gt;
&lt;li&gt;독립 정점: 다른 어떤 정점과도 인접하지 않은 정점&lt;/li&gt;
&lt;li&gt;널(null) 그래프: 독립 정점만으로 구성한 그래프( E가 공집합 )&lt;/li&gt;
&lt;li&gt;경로: 임의의 두 정점을 연결하는 어떤 간선의 끝 정점(해당 간선의 머리)에서 그 간선의 시작 정점(해당 간선의 꼬리)으로 이러이즌 간선의 연속(열)&lt;/li&gt;
&lt;li&gt;경로 길이: 경로에 있는 간선의 수&lt;/li&gt;
&lt;li&gt;단순 경로: 경로 상에 있는 모든 정점이 서로 다른 경로&lt;/li&gt;
&lt;li&gt;기본 경로: 경로 상에 있는 모든 간선이 서로 다른 경로&lt;/li&gt;
&lt;li&gt;사이클: 출발점과 도착점이 동일한 단순 경로&lt;/li&gt;
&lt;li&gt;사이클 그래프: 사이클이 있는 그래프&lt;/li&gt;
&lt;li&gt;루프: 간선의 시작점과 끝점이 같은 정점인 길이가 1인 그래프&lt;/li&gt;
&lt;li&gt;무사이클 그래프: 사이클이 없는 그래프 (혹은 트리)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추상 자료형&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 정의: 정점과 간선의 유한 집합&lt;/li&gt;
&lt;li&gt;연산:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Graph Create() ::= 그래프 생성&lt;/li&gt;
&lt;li&gt;Destroy(Graph) ::= 그래프 기억장소 반납&lt;/li&gt;
&lt;li&gt;Graph Copy_Tree(Graph) ::= 그래프 복사&lt;/li&gt;
&lt;li&gt;InsertVertex() ::= 그래프에 정점 삽입 InsertEdge() ::= 그래프에 간선 추가&lt;/li&gt;
&lt;li&gt;DeleteVertex() ::= 정점 삭제 DeleteEdge() ::= 간선 삭제&lt;/li&gt;
&lt;li&gt;Search() ::= 정점 탐색&lt;/li&gt;
&lt;li&gt;IsAdjacent() ::= 인접 정점 여부 확인&lt;/li&gt;
&lt;li&gt;ExistPath() ::= 경로가 존재하는지 확인&lt;/li&gt;
&lt;li&gt;PathLength() ::= 경로 길이 계산&lt;/li&gt;
&lt;li&gt;BFS() ::= 너비 우선 탐색&lt;/li&gt;
&lt;li&gt;DFS() ::= 깊이 우선 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래프 탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프 G=(V, E)와 V(G)에 있는 정점 v가 주어졌을 때, 정점 v에 도달할 때까지 G의 정점을 방문하는 연산 &amp;rarr; 만일 그래프 내에 정점이 v가 없다면, 그래프의 모든 정점을 방문한 후 종료함&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;깊이 우선 탐색(Depth First Search, DFS)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작: 출발점 v를 방문&lt;/li&gt;
&lt;li&gt;다음으로 v에 인접하고 아직 방문하지 않은 정점 w를 선택하여 w를 출발점으로 다시 깊이 우선 탐색(인접하고 아직 방문하지 않은 정점을 선택)&lt;/li&gt;
&lt;li&gt;위의 두 과정을 모든 정점을 한 번씩 방문할 때까지 반복&lt;/li&gt;
&lt;li&gt;만약 인접한 모든 정점들이 이미 방문한 정점인 경우, 가장 최근에 방문했던 정점 중에서 방문하지 않은 정점 w를 가진 정점을 선택하여 정점 w로부터 다시 깊이 우선 탐색 시작 &amp;rarr; 스택을 사용하여 가장 최근에 선택의 지점에 있던 정점을 찾아냄&lt;/li&gt;
&lt;li&gt;방문하지 않은 정점이 없으면 탐색 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 순환 호출
void DFS(Graph* g, int s) {
	int i, adjacent;
	g -&amp;gt; visited[s] = 1;
	printf(&quot;%d&quot;, s);

	for(adjacent = 0; adjacent &amp;lt; g -&amp;gt; nv; adjacent++) {
		if(g -&amp;gt; adj[s][adjacent] &amp;amp;&amp;amp; !g -&amp;gt; visited[adjacent]) {
			g -&amp;gt; visited[adjacent] = 1;
			DFS(g, adjacent);
		}
	}
}

// 스택 직접 운영
void DFS(int s) {
	int v, w;
	extern struct stack *st;
	extern int visited[];
	InitializeStack(st);
	push(st, s);
	visited[s] = 1;
	while((v=pop(st)) &amp;gt;= 0) {
		visited[v] = 1;
		while(v에 인접한 모든 노드 w)
			if(!visited[w]) push(st, w);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;너비 우선 탐색(Breadth First Search, BFS)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시작: 출발점 v를 방문&lt;/li&gt;
&lt;li&gt;다음으로 v에 인접한 정점 w를 모두 방문한 후, 다시 w에 인접한 방문하지 않은 정점들을 차례로 방문&lt;/li&gt;
&lt;li&gt;두 과정을 모든 정점을 한 번씩 방문할 때까지 반복&lt;/li&gt;
&lt;li&gt;인접 정점을 모두 방문하기 때문에 큐를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void BFS(Graph* g, int s) {
	int i, adjacent;
	int visited[MAX_VERTICES];
	for(i=0; i&amp;lt; g-&amp;gt;nv; i++) visited[i]=0;
	
	int queue[MAX_VERTICES];
	int front=0, rear=0;

	visited[s]=1;
	queue[rear++]=s;

	while(front != rear) {
		s=queue[front++];
		printf(&quot;%d&quot;, s);
		for(adjacent=0; adjacent &amp;lt; g-&amp;gt;nv; adjacent++) {
			if(g-&amp;gt;adj[s][adjacent] &amp;amp;&amp;amp; !visited[adjacent]) {
				visited[adjacent]=1;
				queue[rear++]=adjacent;
			}
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;최소 비용 신장 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리: 사이클이 없는 단순 그래프&lt;/li&gt;
&lt;li&gt;트리는 그래프이기는 하지만 루트를 가지기 때문에 (일반 그래프에는 없는) 계층 개념이 있고, 사이클이 없어서 한 정점에서 다른 정점으로 가는 경로가 유일한 구조&lt;/li&gt;
&lt;li&gt;신장 트리(spanning tree): 그래프 G의 모든 정점과 간선의 일부(또는 전부)를 포함하는 트리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 그래프의 정점을 모두 포함함&lt;/li&gt;
&lt;li&gt;n-1개의 간선으로 구성한 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;G의 최소 부분 그래프: 그래프 G의 부분 그래프 중에서 간선의 수가 가장 작은 것&lt;/li&gt;
&lt;li&gt;최소 비용 신장 트리: 가중치 그래프 G의 가중치가 작은 간선을 선택하여 구성된 신장 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프림(Prim) 알고리즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개의 정점을 갖는 연결 그래프 G에 대한 최소 비용 신장 트리 T를 구하는 알고리즘&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래프 전체에서 최소 비용을 갖는 간선 {u, v}를 선택하여 이 간선을 T에 추가함&lt;/li&gt;
&lt;li&gt;이 간선을 T에 추가할 때 사이클을 형성하지 않으면 추가하고 아니면 무시함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;r&quot;&gt;&lt;code&gt;void prim() {
	T = &amp;Oslash;;
	W = &amp;Oslash;;
	E로부터 최소 비용인 간선 {v, w}를 선택;
	while(T는 n-1개 이하의 간선 포함 &amp;amp;&amp;amp; E는 공집합 아님) {
		E에서 간선 {v, w}를 제거;
		if({v, w}가 T 내에서 사이클을 생성 안함) {
			T = T &amp;cup; {{v, w}}; // 선택한 간선 추가
			W = W &amp;cup; {v, w}; // 선택한 정점 추가
		}
		else 간선 {v, w}를 버림;
		E로부터 W 내의 정점과 최소 비용으로 연결된 간선 {v, w}를 선택;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;크루스컬(Kruskal) 알고리즘&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;남은 간선 중에서 무조건 최소 비용인 간선을 선택한 후 사이클을 형성하지 않으면 그 간선을 선택함&lt;/li&gt;
&lt;li&gt;중간 과정에 있는 T는 하나의 트리가 아니고 여러 개의 분산된 트리, 즉 숲일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;r&quot;&gt;&lt;code&gt;void kruskal() {
	while(T는 n-1개 이하의 간선 포함 &amp;amp;&amp;amp; E는 공집합 아님) {
		E로부터 최소 비용인 간선 {v, w}를 선택;
		E에서 간선 {v, w}를 제거;
		if({v, w}가 T 내에서 사이클을 생성 안함) T = T &amp;cup; {{v, w}};
		else 간선 {v, w}를 버림;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;솔린(Sollin) 알고리즘&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;간선이 하나도 없는 그래프의 모든 정점들로 구성된 숲에서 시작함&lt;/li&gt;
&lt;li&gt;단계가 거듭되면서 숲 내의 트리들이 최소 비용을 갖는 간선으로 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;r&quot;&gt;&lt;code&gt;void sollin() {
	// 집합 E의 초기 상태는 주어진 그래프의 간선 집합
	// 집합 F의 초기 상태는 그래프의 모든 정점들로 구성된 간선이 없는 숲

	T=&amp;Oslash;;
	while(T는 완전한 하나의 트리가 아님 &amp;amp;&amp;amp; E는 공집합 아님) {
		for(F 내의 각각의 트리 T에 대하여) {
			T와 다른 트리를 연결하는 E의 간선 {v, w} 중에서 최소비용 간선 {v, w}를 선택;
			T = T &amp;cup; {{v, w}};
			E에서 간선 {v, w}를 제거;
		}
		T에 새로 추가된 간선을 포함하여 F를 수정;
	}
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>DataScience/Data Structure</category>
      <category>BFS</category>
      <category>dfs</category>
      <category>최소비용 신장 트리</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/500</guid>
      <comments>https://meercat.tistory.com/500#entry500comment</comments>
      <pubDate>Wed, 6 Dec 2023 15:59:28 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 멀티웨이 탐색 트리</title>
      <link>https://meercat.tistory.com/499</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/84Vl3/btsBrMMgl4P/zM4IfTXe5VGjZOnyNRPWGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/84Vl3/btsBrMMgl4P/zM4IfTXe5VGjZOnyNRPWGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/84Vl3/btsBrMMgl4P/zM4IfTXe5VGjZOnyNRPWGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F84Vl3%2FbtsBrMMgl4P%2FzM4IfTXe5VGjZOnyNRPWGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;604&quot; height=&quot;340&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;m원 탐색 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리의 노드가 m개 이하의 가지를 가질 수 있는 탐색 트리 &amp;rarr; 같은 수의 노드를 갖는 &lt;b&gt;이진 탐색 트리보다 낮은 높이의 m원 트리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이진 탐색 트리의 확장된 형태임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색 트리의 제한&lt;/b&gt;을 따르면서, &lt;b&gt;2개 이상 ~ m개 이하의 자식 노드&lt;/b&gt;를 가질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;노드의 구조&lt;/h3&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;struct Mnode {
	int n;
	struct Rectype {
		struct Mnode * ptr,
		int key;
		struct Rectype *addr,
	} keyptrs[n-1];
	struct Mnode *keyptrn;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;탐색 연산&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 노드의 가지 개수가 많을수록(서브 트리가 많을수록) 최대 탐색 시간이 짧아짐(트리의 깊이가 얕으므로 더 빨리 찾을 수 있음)&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;struct Mnode *nodeptr;
struct Rectype *recptr;
struct Rectype *Search(int skey, struct Mnode *r) {
	int i;
	extern struct Mnode node;
	if(r == NULL) return(NULL);
	else {
		i = 0;
		while(i &amp;lt; r-&amp;gt;n &amp;amp;&amp;amp; skey &amp;gt; r -&amp;gt; keyptrs[i].key) i++;
		if(i &amp;lt; r-&amp;gt;n &amp;amp;&amp;amp; key == r-&amp;gt;keyptrs[i].key) return (r -&amp;gt; keyptrs[i].addr);
		else if(i &amp;lt; r-&amp;gt;n) return (Search(skey, r-&amp;gt;keyptrs[i].ptr));
		else return (Search(skey, r-&amp;gt;keyptrn));
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;m원 탐색 트리는 서브 트리의 균형에 대해서는 특별히 제한하지 않음&lt;/li&gt;
&lt;li&gt;각 노드가 자식을 많이 갖게 하여 트리의 높이를 줄이고 전체적으로 균형을 유지한다면 탐색 성능을 더욱 향상할 수 있음&lt;/li&gt;
&lt;li&gt;인덱스 구조를 구현하는데 일반적으로 사용&lt;/li&gt;
&lt;li&gt;조건
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루트와 잎 노드를 제외한 트리의 각 노드는 최소 [m/2] 개의 서브 트리를 갖음&lt;/li&gt;
&lt;li&gt;모든 잎 노드는 같은 레벨에 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;키를 삽입하는 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;1. 삽입할 위치를 찾기 위해 노드의 키 값을 왼쪽에서 오른쪽으로 탐색
	(B 트리에서 모든 노드는 잎 노드에서 삽입 시작)
2. 노드에 빈자리가 있으면 삽입 후 종료
3. 노드가 꽉 찼으면 노드를 2개로 분리하고 키와 포인터를 새 노드에 반씩 할당
	3-1. 잎 노드 키 값과 삽입 노드 키 값 중에서 중간 값을 선택
	3-2. 선택된 중간 값보다 작은 키 값을 갖는 것은 왼쪽 노드에 넣고 큰 것은 오른쪽 노드에 삽입
	3-3. 중간 값을 가지는 노드의 키 값과 포인터를 부모 노드에 삽입
		만일 부모 노드가 루트 노드면 두 노드를 카리키도록 (자식 노드가 되도록) 수정&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키를 삭제하는 알고리즘 - 잎 노드에서 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 삭제할 키 값을 포함한 노드를 찾는다.
2. 노드에서 키 값을 삭제한다.
3. 필요하면 재배열한다.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키를 삭제하는 알고리즘 - 내부 노드에서 삭제 내부 노드의 키 값은 하위 노드에 대한 기준값(중간값)이기 때문에 삭제 시, 대체할 수 있는 적절한 값을 찾아야 한다. 보통 왼쪽 서브 트리의 가장 큰 값 또는 오른쪽 서브 트리의 가장 작은 키 값으로 대체할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;1. 새로운 기준값(삭제된 자리에 올 키 값)을 선택하여 해당 (잎) 노드에서 삭제하고 그 값을 
	현재 키 값을 삭제한 자리로 옮긴다. 즉, 대체한 것이다.
2. 기준 값으로 대체하기 위해 키를 삭제한 잎 노드가 정해진 개수의 키 값을 갖지 않으면 
	트리를 재배열한다.
	2-1. 키 값이 부족한 노드의 오른쪽 형제가 존재하고 키가 정해진 최소 개수보다 많다면
		왼쪽으로 회전한다.
		2-1-1. 부모 노드의 기준(키) 값을 개수가 부족한 노드의 끝으로 이동한다. 즉,
			기준 값을 한 단계 아래로 내려 개수를 채운다.
		2-1.2. 부모 노드의 기준 값을 오른쪽 형제의 첫 번째 키로 수정해 균형을 맞춘다.
	2-2. 키 값이 부족한 노드의 왼쪽 형제가 존재하고 키가 정해진 최소 개수보다 많다면
		오른쪽으로 회전한다.
		2-2-1. 부모 노드의 기준(키) 값을 개수가 부족한 노드의 끝으로 이동한다.
		2-2-2. 부모 노드의 기준 값을 왼쪽 형제의 마지막 키로 수정해 균형을 맞춘다.
	2-3. 좌우 형제가 최소 개수의 키를 가지고 있다면 좌우 형제를 합친다.
		2-3-1. 부모 노드의 기준(키) 값을 왼쪽 노드의 마지막에 복사한다.
		2-3-2. 오른쪽 노드의 모든 키 값을 왼쪽 노드로 옮긴다.
			(왼쪽 노드가 최대 개수의 키를 갖는다)
		2-3-3. 키를 갖지 않는 오른쪽 노드는 삭제한다.
		2-3-4. 부모 노드가 루트이면서 키를 더 이상 갖지 않으면 합쳐진 노드가 새로운
			루트가 된다. 그렇지 않고 부모 노드의 키 개수가 정해진 최소 개수보다 작으면
			부모 노드를 재배열한다.&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B* 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드의 약 2/3 이상이 채워지는 B트리&lt;/li&gt;
&lt;li&gt;노드가 꽉 차면 분리하지 않고 키와 포인터를 재배치하여 다른 형제 노드로 옮김 &amp;rarr; B 트리와 동일한 수의 노드를 갖는다면 높이가 낮고, 삽입/삭제 시 발생하는 노드 분리를 줄이려고 고안&lt;/li&gt;
&lt;li&gt;차수가 m인 B* 트리의 조건
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공집합이거나 높이가 1 이상인 m원 탐색 트리&lt;/li&gt;
&lt;li&gt;루트 노드는 2개 이상 2[(2m-2)/3]+1 개 이하의 자식 노드를 갖는다&lt;/li&gt;
&lt;li&gt;내부 노드는 최소한 [(2m-1)/3]개의 자식 노드를 갖느다&lt;/li&gt;
&lt;li&gt;모든 잎 노드는 동일한 레벨에 놓인다&lt;/li&gt;
&lt;li&gt;포인터가 k개이면서 잎 노드가 아닌 노드는 k-1개의 키를 갖는다(루트 노드 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;B+ 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;탐색 트리로 구성하면 매우 빠르게 탐색할 수 있지만, 전체 데이터를 차례로 처리하기는 불편함&lt;/li&gt;
&lt;li&gt;매번 왼쪽인지 오른쪽인지 비교해가면서 다음 노드를 찾아가면서 처리해야 함&lt;/li&gt;
&lt;li&gt;인덱스된 순차 파일을 구성하는 데 사용&lt;/li&gt;
&lt;li&gt;각 노드의 키가 적어도 1/2 채워져야 함&lt;/li&gt;
&lt;li&gt;잎 노드를 순차적으로 연결하는 포인터 집합이 있다는 점에서 다름&lt;/li&gt;
&lt;li&gt;잎 노드의 마지막 포인터를 다음 키 값을 갖는 노드를 가리킴&lt;/li&gt;
&lt;li&gt;순차 처리를 할 때는 이 포인터를 이용해서 (키 값을 비교하지 않고) 차례로 다음 데이터에 접근해서 처리&lt;/li&gt;
&lt;li&gt;모든 키 값이 잎 노드에 있고 그 키 값에 대응하는 실제 데이터에 대한 주소를 잎 노드만이 가지고 있음&lt;/li&gt;
&lt;li&gt;직접 탐색은 잎 노드에 도달해야 종료&lt;/li&gt;
&lt;li&gt;노드 삽입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;잎 노드가 2개의 노드로 분리될 때는 키 값 순서에 따라 배치하고 중간 키 값은 부모 노드에 올려놓음&lt;/li&gt;
&lt;li&gt;새 노드는 순서에 맞게 잎 노드에 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;노드 삭제: 키 값을 잎 노드에서 삭제할 때, 키 값이 직접 탐색에 쓰이기 때문에 트리의 내부 노드에서도 삭제할 필요는 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-3 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;차수가 2 또는 3인 내부 노드를 갖는 탐색 트리&lt;/li&gt;
&lt;li&gt;2-노드(2개의 자식노드; 차수가 2)와 3-노드(3개의 자식노드; 차수가 3)만으로 구성되는 특수한 형태의 B트리&lt;/li&gt;
&lt;li&gt;2-노드 혹은 3-노드라는 제약이 &lt;b&gt;내부 노드&lt;/b&gt;에만 해당함 &amp;rarr; &lt;b&gt;모든 잎 노드는 같은 레벨에 있어야 한다는 제약만 존재&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;구조의 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef struct two_three *two_three_ptr;
struct two_three {
	int lkey, rkey;
	two_three_ptr lchild, mchild, rchild;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리의 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;two_three_ptr search23(two_three_ptr t, int x) {
	while(t)
		switch(compare(x, t)) {
			case 1: t = t -&amp;gt; lchild;
				break;
			case 2: t = t -&amp;gt; mchild;
				break;
			case 3: t = t -&amp;gt; rchild;
				break;
			case 4: return (t);
		}
	return(NULL);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리의 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void insert23(two_trhee_ptr t, int y) {
	two_three_ptr q, p, r;
	if(!(*t)) new_root(t, y, NULL);
	else {
		p = find_node(*t, y);
		if(!p) {
			printf(stderr, &quot;The Key is currently in the tree₩n&quot;);
			exit(1);
		}
		
		q = NULL;
		for(;;)
			if(p -&amp;gt; rkey == INT_MAX) {
				put_in(&amp;amp;p, y, q);
				break;
			} else {
				split(p, &amp;amp;y, q);
				if(p == *t) {
					new_root(t, y, q);
					break;
				}
				else p = delete();
			}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리의 삭제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2-3 트리의 삭제에서 잎 노드가 아닌 노드의 키를 삭제하면 그 곳을 다른 키로 대체해야 함&lt;/li&gt;
&lt;li&gt;일반적으로 삭제한 키의 왼쪽 서브 트리에서 가장 큰 키 값이나 오른쪽 서브 트리에서 가장 작은 키 값을 선택하여 대체함&lt;/li&gt;
&lt;li&gt;회전: 3-노드인 형제가 있는 경우, 키 값 중 하나를 부모로 올리고 대신 부모로부터 키 값 하나를 가져다 빈 노드를 채우는 것&lt;/li&gt;
&lt;li&gt;결합: 하나의 노드를 삭제하고 형제와 합치는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-3-4 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2-3 트리를 확장하여 4개의 자식을 가진 4-노드를 허용하는 탐색 트리&lt;/li&gt;
&lt;li&gt;2-3 트리보다 삽입과 삭제가 용이함&lt;/li&gt;
&lt;li&gt;2-노드과 3-노드에 대한 트리 재구성 확률이 2-3 트리에서 보다 작기 때문에 삽입 및 삭제 연산을 수행하는 데 더 효율적임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2-3-4 트리의 조건&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lchild, mchild는 각각 2-노드의 왼쪽 자식 노드 및 좌중간 자식 노드라 하고, lkey를 키 값이라고 하면, 루트가 lchild인 모든 2-3-4 서브트리 키 값은 lkey보다 작고, 루트가 mchild인 모든 2-3-4 서브트리 키 값은 lkey보다 크다&lt;/li&gt;
&lt;li&gt;lchild, mchild 및 rchild를 각각 3-노드의 왼쪽 자식 노드, 좌중간 자식 노드 및 우중간 자식 노드라 하고, lkey, mkey를 이 노드의 키 값이라 하면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lkey &amp;lt; mkey&lt;/li&gt;
&lt;li&gt;루트가 lchild인 모든 2-3-4 서브트리 키 값은 lkey보다 작다&lt;/li&gt;
&lt;li&gt;루트가 lmchild인 모든 2-3-4 서브트리 키 값은 lkey보다 크고 mkey 보다 작다&lt;/li&gt;
&lt;li&gt;루트가 rmchild인 모든 2-3-4 서브트리 키 값은 mkey 보다 크다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;lchild, lmchild, rmchild 및 rchild를 각각 4-노드의 왼쪽, 좌중간, 우중간 및 오른쪽 자식 노드라 하고, lkey, mkey 및 rkey를 이 노드의 키 값이라 하면
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lkey &amp;lt; mkey &amp;lt; rkey&lt;/li&gt;
&lt;li&gt;루트가 lchild인 모든 2-3-4 서브트리 키 값은 lkey보다 작다&lt;/li&gt;
&lt;li&gt;루트가 lmchild인 모든 2-3-4 서브트리 키 값은 lkey보다 크고 mkey 보다 작다&lt;/li&gt;
&lt;li&gt;루트가 rmchild인 모든 2-3-4 서브트리 키 값은 mkey 보다 크고 rkey보다 작다&lt;/li&gt;
&lt;li&gt;루트가 rchild인 모든 2-3-4 서브트리 키 값은 rkey보다 크다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모든 잎 노드들은 같은 레벨에 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입 연산&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2-노드와 3-노드에 대한 트리 재구성의 확률이 2-3 트리에서 보다 작기 때문에 삽입/삭제 연산이 효율적임&lt;/li&gt;
&lt;li&gt;삽입 연산의 문제가 되는 4-노드는 그 위치에 따라 다음과 같이 분류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4-노드가 루트인 경우&lt;/li&gt;
&lt;li&gt;4-노드의 부모가 2-노드인 경우&lt;/li&gt;
&lt;li&gt;4-노드의 부모가 3-노드인 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 연산:&lt;/b&gt; 잎 노드에 있는 키 값은 단순히 삭제하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;레드 블랙 트리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;효율적인 기억 장소 사용을 위하여 2-3-4 트리를 이진 트리로 나타낸 탐색 트리&lt;/li&gt;
&lt;li&gt;레드 간선: 2-3-4 트리의 한 노드 내에 있던 노드의 관계&lt;/li&gt;
&lt;li&gt;블랙 간선: 2-3-4 트리의 부모-자식 관계&lt;/li&gt;
&lt;li&gt;레드 블랙 트리의 탐색 방법은 보통의 이진 탐색 트리의 탐색 알고리즘과 동일함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>DataScience/Data Structure</category>
      <category>2-3 트리</category>
      <category>2-3-4 트리</category>
      <category>b*트리</category>
      <category>b+트리</category>
      <category>b트리</category>
      <category>m원 탐색 트리</category>
      <category>레드 블랙 트리</category>
      <category>멀티웨이 탐색 트리</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/499</guid>
      <comments>https://meercat.tistory.com/499#entry499comment</comments>
      <pubDate>Wed, 6 Dec 2023 13:11:38 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍 언어론] 객체지향과 다형성</title>
      <link>https://meercat.tistory.com/498</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;추상 자료형&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로그래밍 언어의 추상화&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상화(abstraction)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 대상을 간략하게 나타내는 것&lt;/li&gt;
&lt;li&gt;추상화 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추리기: 대상의 관심 있는 부분만 추려서 나타냄&lt;/li&gt;
&lt;li&gt;삭제하기: 특별히 관심 없는 부분은 삭제하여 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그래밍 언어의 추상화 종료
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제어 추상화(control abstraction): 복잡한 제어 과정을 단순하게 제공&lt;/li&gt;
&lt;li&gt;자료 추상화(data abstraction): 복잡한 자료 구조를 단순하게 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그래밍 언어의 추상화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍 언어의 추상화 지원
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제어 추상화: 제어 구조, 서브프로그램으로 지원 &amp;rarr; 어떻게 수행되는지는 숨기고 무엇이 수행되는지 나타냄&lt;/li&gt;
&lt;li&gt;자료 추상화: 자료 구조, 추상 자료형으로 지원 &amp;rarr; 자료 표현과 더불어 관련된 연산을 묶어서 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그래밍 언어의 추상화 발전
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 프로그래밍 언어는 제어 추상화를 추구&lt;/li&gt;
&lt;li&gt;자료 구조와 더불어 연산을 묶는 방법이 제시됨에 따라 자료 추상화 개념이 등장하였으며 추상 자료형으로 발전&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;캡슐화 및 정보 은닉&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캡슐화(encapsulation): 여러 대상을 하나의 단위로 묶을 수 있는 기능&lt;/li&gt;
&lt;li&gt;정보 은닉(information hiding): 구현 세부 사항을 숨기고 인터페이스만 제공하는 기능&lt;/li&gt;
&lt;li&gt;캡슐화와 정보 은닉의 관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캡슐화와 정보 은닉은 같은 의미로 사용되기도 함&lt;/li&gt;
&lt;li&gt;엄밀하게는 약간 다른 개념
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;캡슐화: 여러 요소를 하나로 묶는 기능&lt;/li&gt;
&lt;li&gt;정보 은닉: 외부에 공개하지 않는 원칙&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추상 자료형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상자료형(ADT: Abstract Data Type)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자료 집합과 적용 가능한 연산을 함께 선언한 자료형&lt;/li&gt;
&lt;li&gt;자료가 어떻게 구성되는지, 연산이 어떻게 구현되는지 세부 사항은 숨김&lt;/li&gt;
&lt;li&gt;연산을 수행하려면 어떻게 해야 하는지 사용법(interface)만 기술&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;추상 자료형의 장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정 용이성: 자료형 사용 부분을 바꾸지 않고 구현 코드를 바꿀 수 있음&lt;/li&gt;
&lt;li&gt;재사용성: 여러 다른 상황에서 같은 코드를 재사용할 수 있음&lt;/li&gt;
&lt;li&gt;보안성: 구현 세부 사항을 프로그램의 다른 곳에서 바꾸지 못하도록 보호함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자료 표현이 없는 추상 자료형
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구체적인 자료 구조를 가정하지 않고 자료형을 생각할 수 있음&lt;/li&gt;
&lt;li&gt;극단적으로 연산만으로 자료형을 나타낼 수 있음&lt;/li&gt;
&lt;li&gt;자료 표현이 없는 추상 자료형의 경우, 자료형 연산 사이에 만족해야 하는 법칙이 있는 경우가 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대수적 자료형(algebraic data type)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 자체에 적용 가능한 연산을 통해 만든 새로운 타입&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입 자체에 대한 연산을 정의&lt;/li&gt;
&lt;li&gt;이 연산을 하나 이상의 타입에 적용함으로써 만든 새로운 자료형&lt;/li&gt;
&lt;li&gt;데카크트 곱: 데카르트 곱을 둘 이상의 자료형에 적용하면 튜플 자료형을 얻을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체와 클래스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 지향 개념의 발전
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시뮬레이션
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 객체지향 언어는 시뮬레이션 분야에서 발전함&lt;/li&gt;
&lt;li&gt;시뮬레이션을 위해서는 실제 세계에 존재하는 대상을 추상화해야 함&lt;/li&gt;
&lt;li&gt;이 대상은 어떤 상태를 가지고 있으며 주위 요구에 반응해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GUI(Graphical User Interface)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 GUI는 책상을 모형화하였음&lt;/li&gt;
&lt;li&gt;책상 위에 새로운 책을 펼치고 이를 넘기거나 공책을 열고 기록하는 등의 작업을 화면 위에 나타내고자 하였음&lt;/li&gt;
&lt;li&gt;책, 공책 등을 윈도에 대응시켰으며 넘기거나 기록하는 등의 작업은 이벤트로 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체와 클래스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 상태를 유지하고 있으며 외부 접근에 반응하는 대상&lt;/li&gt;
&lt;li&gt;필요에 따라 상태가 바뀔 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클래스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 생성하는 기본이 되는 틀&lt;/li&gt;
&lt;li&gt;인스턴스: 어떤 클래스를 통해 생성된 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;메타 클래스: 클래스를 인스턴스로 하는 객체&lt;/li&gt;
&lt;li&gt;타입과 클래스
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향 언어의 타입 지원: 객체지향 언어는 정적 타입을 지원할 수도 있고 그렇지 않을 수도 있음&lt;/li&gt;
&lt;li&gt;정적 타입 객체지향 언어: 클래스 = 타입
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 타입을 지원하는 언어의 경우 클래스를 타입으로 취급&lt;/li&gt;
&lt;li&gt;이 경우 객체는 해당 타입의 원소가 되며 같은 필드와 메소드로 구성&lt;/li&gt;
&lt;li&gt;통상 필드는 변수로 구현하며, 메소드는 함수로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동적 타입 객체지향 언어: 객체가 지원하는 메소드에 따라서 타입이 결정되는 타입 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;생성자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 생성하는 데 사용되는 특별한 메소드&lt;/li&gt;
&lt;li&gt;직접 호출하지 않고 new 연산자나 다른 방법에 의해 자동으로 호출됨&lt;/li&gt;
&lt;li&gt;생성자는 통상 중복정의가 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;소멸자
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 소멸하는 데 사용되는 특별한 메소드&lt;/li&gt;
&lt;li&gt;직접 호출하지 않고 delete 연산자나 영역 탈출 등에 의해 자동으로 호출됨&lt;/li&gt;
&lt;li&gt;소멸자는 중복정의되지 않음&lt;/li&gt;
&lt;li&gt;소멸자를 직접 지원하지 않는 경우에는 garbage collector가 무효 객체를 수거함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체지향 언어 구현 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향의 핵심
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체와 연관된 메소드를 객체에 따라 호출할 수 있다는 것&lt;/li&gt;
&lt;li&gt;이를 위해서는 메소드 바인딩이 최대한 늦춰져야 함(늦은 바인딩)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;늦은 바인딩의 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향의 늦은 바인딩을 구현하기 위해서 통상 VTab(가상함수 테이블)을 이용함&lt;/li&gt;
&lt;li&gt;각 객체마다 가상함수 테이블을 정의하고 메소드 호출이 있을 때, 가상함수 테이블에 정의된 메소드를 호출하는 방식으로 늦은 바인딩 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;늦은 바인딩은 다형성을 구현하는 한 가지 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다형성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 타입의 데이터를 같은 이름으로 처리할 수 있는 특성&lt;/li&gt;
&lt;li&gt;함수 수준에서도, 자료형 수준에서도 활용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다형성 종류&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다형성 지원 수준에 따른 다형성 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다형 서브프로그램: 여러 타입을 다룰 수 있는 서브프로그램&lt;/li&gt;
&lt;li&gt;다형 타입: 타입을 인수로 받는 타입&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서브프로그램의 다형성 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경험적 다형성&lt;/li&gt;
&lt;li&gt;매개변수적 다형성&lt;/li&gt;
&lt;li&gt;서브타입 다형성(순수 다형성)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;경험적 다형성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 구현은 다르지만 의미상 같은 개념의 서브프로그램에 같은 이름을 붙인 형태의 다형성&lt;/li&gt;
&lt;li&gt;서브프로그램 이름의 중복정의(overloading): 동일한 참조 환경 내에서 다른 서브프로그램과 이름이 같은 서브프로그램&lt;/li&gt;
&lt;li&gt;연산자 중복정의(overloading): 피연산자의 타입에 따라 구현이 달라지는 연산자&lt;/li&gt;
&lt;li&gt;중복정의와 기본 인수는 충돌될 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복정의의 경우 인수 개수와 타입을 통해 호출 함수를 결정함&lt;/li&gt;
&lt;li&gt;인수 기본값이 주어졌을 때 호출 함수를 결정하는 방식과 충돌될 수 있음&lt;/li&gt;
&lt;li&gt;이런 경우에 시그니처 매칭 알고리즘 수행 중 오류가 발생함 &amp;rarr; 시그니처 매칭 알고리즘: 중복 정의된 함수나 연산자의 실제 구현을 결정할 때 사용되는 알고리즘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;매개변수적 다형성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입을 매개변수로 전달하는 형태의 다형성: 타입 인수는 명시적으로 전달할 수도 있지만 암시적으로 전달될 수도 있음&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;순수 다형성(서브타입 다형성)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IS-A 관계로 대변되는 클래스 상속 관계에 의해 지원되는 다형성&lt;/li&gt;
&lt;li&gt;적합 상속: IS-A 의미를 만족하는 상속&lt;/li&gt;
&lt;li&gt;상속 관계는 클래스 사이 뿐 아니라 인터페이스 사이에도 성립함&lt;/li&gt;
&lt;li&gt;추상 클래스: 극도로 추상화되어 직접 객체를 생성할 수 없는 클래스 &amp;rarr; 상속 계층의 상위에 존재하며 다형성을 지원하는 기능을 함&lt;/li&gt;
&lt;li&gt;구상 클래스: 직접 객체를 생성할 수 있는 클래스&lt;/li&gt;
&lt;li&gt;하위 구상 클래스의 인스턴스는 추상 클래스의 객체로 간주할 수 있으므로 &amp;ldquo;추상 클래스의 객체를 생성할 수 없다&amp;rdquo;고 단정할 수는 없음&lt;/li&gt;
&lt;li&gt;다중 상속
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 상속: 순수 다형성을 지원하기 위해서는 통상 한 클래스로부터 상속받으면 됨&lt;/li&gt;
&lt;li&gt;다중 상속
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 경우에는 IS-A 관계가 여러 부모 클래스에 대해 정의되기도 함&lt;/li&gt;
&lt;li&gt;이 경우 다이아몬드 상속 문제가 발생하기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다이아몬드 상속 문제
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브클래스에서 필드마 메소드를 호출할 때, 필드나 메소드 참조가 모호해지는 문제&lt;/li&gt;
&lt;li&gt;다중 상속을 허용할 경우에는 어떤 슈퍼클래스의 필드나 메소드가 여러 경로를 통해 중복하여 상속될 수 있으므로 필드나 메소드 참조가 모호해질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인터페이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상 메소드의 집합으로만 구성된 타입&lt;/li&gt;
&lt;li&gt;구체적인 메소드 구현은 구상 클래스에 의해 구현되어야 함&lt;/li&gt;
&lt;li&gt;인터페이스는 추상 클래스와 유사한 개념이나 차이 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상 클래스는 클래스 계층에 활용&lt;/li&gt;
&lt;li&gt;인터페이스는 클래스 계층과 독립적으로 존재할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트레잇(trait)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스와 매우 유사&lt;/li&gt;
&lt;li&gt;일부 메소드는 구현되어 있을 수 있음&lt;/li&gt;
&lt;li&gt;트레잇은 상속된다거나 구현한다고 하지 않고 사용(use)한다고 함&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CS</category>
      <category>객체</category>
      <category>다형성</category>
      <category>추상 자료형</category>
      <category>클래스</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/498</guid>
      <comments>https://meercat.tistory.com/498#entry498comment</comments>
      <pubDate>Tue, 5 Dec 2023 22:30:12 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍 언어론] 서브프로그램 구현</title>
      <link>https://meercat.tistory.com/497</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;서브프로그램 구현 개요&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서브프로그램 연결&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브프로그램 호출(call) 작업과 복귀(return) 작업&lt;/li&gt;
&lt;li&gt;서브프로그램 호출 시 해야 할 작업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출하는 서브프로그램의 상태 저장&lt;/li&gt;
&lt;li&gt;인수 전달&lt;/li&gt;
&lt;li&gt;복귀할 주소 저장&lt;/li&gt;
&lt;li&gt;호출되는 프로그램으로 분기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서브프로그램 복귀 시 해야 할 작업
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요에 따라 형식인수 값 복사(out parameter)&lt;/li&gt;
&lt;li&gt;함수의 경우, 반환값 전달&lt;/li&gt;
&lt;li&gt;호출한 서브프로그램의 상태 복귀&lt;/li&gt;
&lt;li&gt;호출한 서브프로그램으로 분기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;활성 레코드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브프로그램 호출에 필요한 공간
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출자의 상태 정보를 보관할 공간&lt;/li&gt;
&lt;li&gt;인수를 저장할 공간&lt;/li&gt;
&lt;li&gt;함수의 경우 반환값을 저장할 공간&lt;/li&gt;
&lt;li&gt;복귀할 주소를 저장할 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;활성 레코드(activation record)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수행 중인 서브프로그램에서 코드를 제외한 데이터 부분이 저장되는 형태&lt;/li&gt;
&lt;li&gt;활성 레코드 틀 자체는 정적으로 결정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;활성 레코드 인스턴스(activation record instance)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성 레코드의 구체적인 예&lt;/li&gt;
&lt;li&gt;활성 레코드 틀 형태로 저장된 데이터&lt;/li&gt;
&lt;li&gt;활성 레코드 인스턴스는 실행 시 필요에 따라 생성, 소멸됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서브프로그램 관련 용어 정리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 체인(dynamic chain, call chain)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성 레코드 스택 상에서 인접한 동적 링크들을 차례로 연결한 것&lt;/li&gt;
&lt;li&gt;리스트 형태임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 체인(static chain)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성 레코드 스택 상에서 정적 링크들로 연결된 체인&lt;/li&gt;
&lt;li&gt;트리 형태임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;지역 변위(local offset)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성 레코드 시작 부분에서 스택 동적 변수 위치까지의 변위&lt;/li&gt;
&lt;li&gt;컴파일 시간에 계산 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정적 체인과 동적 체인&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정적 체인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 깊이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 영역의 중첩 깊이&lt;/li&gt;
&lt;li&gt;자신을 감싸고 있는 정적 영역의 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;체인 변위
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비지역변수가 참조되는 지점의 정적 깊이와 해당 비지역변수가 선언된 지점의 정적 깊이의 차&lt;/li&gt;
&lt;li&gt;체인 변위만큼 정적 체인을 거슬로 올라가면 비지역변수를 찾을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변수 참조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임의의 변수 주소는 (체인 변위, 지역 변위) 순서쌍으로 표현 가능&lt;/li&gt;
&lt;li&gt;지역변수와 비지역변수 모두 가능&lt;/li&gt;
&lt;li&gt;체인을 거슬러 올라가는 비용은 체인 변위가 클수록 높아짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 체인 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브 프로그램 호출 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;활성 레코드 인스턴스 구축&lt;/li&gt;
&lt;li&gt;동적 링크는 이전 프레임을 가리키도록 설정&lt;/li&gt;
&lt;li&gt;정적 링크는 정적 부모의 가장 최근 활성 레코드를 가리키도록 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 부모의 최근 활성 레코드 탐색 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 링크를 계속 거슬러 올라감&lt;/li&gt;
&lt;li&gt;호출자와 피호출자의 정적 깊이 차이를 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 체인 방법의 평가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현이 쉬움&lt;/li&gt;
&lt;li&gt;각 활성 레코드에 하나의 링크만 유지하면 되므로 공간 낭비가 적음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조되는 비지역변수가 선언된 블록의 중첩 깊이와 참조 문장을 포함한 중첩 깊이의 차이가 크다면 비지역변수 참조 시간 부담이 커짐&lt;/li&gt;
&lt;li&gt;비지역변수 참조 시간이 변수에 따라 다르기 때문에, 응답 시간이 빨라야 하는 프로그램을 작성할 때는 불리함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동적 체인&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 영역 규칙을 구현하기 위한 방법&lt;/li&gt;
&lt;li&gt;비지역변수를 자신의 호출자에서 찾아야 함&lt;/li&gt;
&lt;li&gt;깊은 참조(deep access)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 변수를 찾을 때까지 동적 링크를 계속 거슬러 올라감&lt;/li&gt;
&lt;li&gt;거슬러 올라갈 체인 길이가 정해져 있지 않음&lt;/li&gt;
&lt;li&gt;활성 레코드에 변수 이름을 저장해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;실시간 탐색이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기타 서브프로그램 구현 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디스플레이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 체인 방법을 대체할 수 있는 방법&lt;/li&gt;
&lt;li&gt;수행 중 참조할 수 있는 모든 정적 링크를 별도의 스택(디스플레이)에 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스플레이(display): 현재 수행 중인 블록과 이 블록의 정적 조상에 대한 활성 레코드를 가리키는 포인터로 이루어진 스택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;참조 환경의 모든 변수는 이 스택이 가리키는 활성 레코드 내에 존재함&lt;/li&gt;
&lt;li&gt;변수 참조 표기법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순서쌍: (디스플레이 변위, 지역 변위)&lt;/li&gt;
&lt;li&gt;디스플레이 변위(display offset)는 해당 변수가 선언된 서브프로그램의 정적 깊이와 동일&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변수 참조 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스플레이 변위를 이용하여 참조할 변수를 포함하는 활성 레코드 선택&lt;/li&gt;
&lt;li&gt;지역 변위(local offset)를 이용하여 해당 활성 레코드 내의 변수 위치 선책&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디스플레이 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 깊이와 디스플레이 크기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스플레이 변위는 정적 깊이와 동일&lt;/li&gt;
&lt;li&gt;현재 수행 중인 서브프로그램의 정적 깊이가 p라면 디스플레이 내에는 p+1개의 항목이 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서브프로그램 호출 시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출되는 서브프로그램의 정적 깊이가 q라면&lt;/li&gt;
&lt;li&gt;디스플레이의 q번째 항목(D[q])를 새로 생성된 활성 레코드 인스턴스의 특정 위치에 백업하고&lt;/li&gt;
&lt;li&gt;새로 생성된 활성 레코드 인스턴스 주소를 D[q]에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서브 프로그램 복귀 시 현재 활성 레코드 내에 백업되었던 D[q] 항목을 다시 복구함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적 체인과 디스플레이 비교정적 체인 디스플레이
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;지역변수 참조&lt;/td&gt;
&lt;td&gt;두 방법 모두 비슷한 비용&lt;/td&gt;
&lt;td&gt;두 방법 모두 비슷한 비용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비지역변수 참조&lt;/td&gt;
&lt;td&gt;한 단계 떨어진 경우, 디스플레이와 같은 비용&lt;/td&gt;
&lt;td&gt;멀리 떨어져 있는 경우에 유리함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서브프로그램 호출&lt;/td&gt;
&lt;td&gt;정적 깊이 차가 적으면 유리&lt;/td&gt;
&lt;td&gt;정적 깊이 차가 크면 유리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;서브프로그램 복귀&lt;/td&gt;
&lt;td&gt;상수 시간(약간 빠름)&lt;/td&gt;
&lt;td&gt;상수 시간(백업 복구 필요)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변수 스택과 중앙 테이블&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 영역 규칙 구현의 또 다른 방법&lt;/li&gt;
&lt;li&gt;얕은 참조
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비지역변수와 지역변수를 구별하지 않음&lt;/li&gt;
&lt;li&gt;참조되는 모든 변수의 정보는 한 군데 존재해야 함&lt;/li&gt;
&lt;li&gt;변수 스택: 변수 이름마다 스택이 존재함&lt;/li&gt;
&lt;li&gt;중앙 테이블: 모든 변수의 값을 한 곳에서 관리함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;과거 민감(history-sensitive) 서브 프로그램&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이전 호출 내용을 기억하는 서브프로그램: 서브프로그램이 종료되어도 서브프로그램의 상태 정보 일부가 기억됨&lt;/li&gt;
&lt;li&gt;과거 민감 서브프로그램 구현
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역변수 이용: 전역변수를 이용하여 서브프로그램 상태 정보를 기억함. 정보 은닉이 보장되지 않음&lt;/li&gt;
&lt;li&gt;정적 지역변수 이용: 서브프로그램 종료 후에도 할당이 해제되지 않는 정적 지역변수 이용. 정보 은닉이 보장됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코루틴(coroutine)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 진입 위치를 스스로 관리하는 서브프로그램&lt;/li&gt;
&lt;li&gt;코루틴은 &amp;lsquo;호출된다&amp;rsquo;고 하지 않고 &amp;lsquo;재개된다(resumed, 계속된다)&amp;rsquo;고 함&lt;/li&gt;
&lt;li&gt;서브프로그램 호출이 종속적이 아닌 대칭적임(대칭적 제어 모델)&lt;/li&gt;
&lt;li&gt;프로그램 수행이 번갈아 이루어짐(유사 병렬성)&lt;/li&gt;
&lt;li&gt;코루틴의 흐름제어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 유닛이 첫 번째 코루틴을 재개함&lt;/li&gt;
&lt;li&gt;코루틴이 서로를 재개함(무한 재개되는 경우가 많음)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코루틴의 활용: 생산자-소비자 시뮬레이션, 카드 게임 시뮬레이션 등&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CS</category>
      <category>동적 체인</category>
      <category>디스플레이</category>
      <category>변수 스택</category>
      <category>서브프로그램</category>
      <category>정적 체인</category>
      <category>중앙 테이블</category>
      <category>코루틴</category>
      <author> Grace</author>
      <guid isPermaLink="true">https://meercat.tistory.com/497</guid>
      <comments>https://meercat.tistory.com/497#entry497comment</comments>
      <pubDate>Tue, 5 Dec 2023 21:22:06 +0900</pubDate>
    </item>
  </channel>
</rss>