<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dr7204.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 24 Apr 2025 10:19:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dr7204.log</title>
            <url>https://velog.velcdn.com/images/js-park/profile/661072fa-3882-4cd4-942c-bbc68cf67297/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dr7204.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/js-park" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[모듈/번들러/트랜스파일러]]></title>
            <link>https://velog.io/@js-park/%EB%AA%A8%EB%93%88%EB%B2%88%EB%93%A4%EB%9F%AC%ED%8A%B8%EB%9E%9C%EC%8A%A4%ED%8C%8C%EC%9D%BC%EB%9F%AC-uhuni6f9</link>
            <guid>https://velog.io/@js-park/%EB%AA%A8%EB%93%88%EB%B2%88%EB%93%A4%EB%9F%AC%ED%8A%B8%EB%9E%9C%EC%8A%A4%ED%8C%8C%EC%9D%BC%EB%9F%AC-uhuni6f9</guid>
            <pubDate>Thu, 24 Apr 2025 10:19:30 GMT</pubDate>
            <description><![CDATA[<h2 id="모듈">모듈</h2>
<blockquote>
<p>개발하는 애플리케이션의 크기가 커지고 프로그램의 내부를 <strong>기능별로 분할한 부분</strong>을 “모듈”이라 부른다</p>
</blockquote>
<h3 id="모듈화의-장점">모듈화의 장점</h3>
<ul>
<li><strong>유지보수</strong><ul>
<li>기능들이 모듈화가 잘 되어있다면 의존성을 줄일 수 있어 유지보수가 편리하다.</li>
</ul>
</li>
<li><strong>네임스페이스화</strong><ul>
<li>모듈화를 하면 모듈만의 네임스페이스를 가지기 떄문에 중복 변수명으로부터 자유로워진다.</li>
</ul>
</li>
<li><strong>재사용성</strong><ul>
<li>재사용 가능한 로직을 모듈로 분리시켜 필요할 때마다 사용할 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="모듈-시스템">모듈 시스템</h2>
<blockquote>
<p>JavaScript 프로그램을 모듈로 개발하고 배포할 수 있게 하기 위해 만들어짐</p>
</blockquote>
<h3 id="cjs-commonjs">CJS (CommonJS)</h3>
<blockquote>
<p>모듈 시스템이 없던 초기의 자바스크립트는 브라우저에서는 큰 문제가 없었지만 서버 사이드에서 사용하기에는 여러 기능들을 모듈화 없이 유지보수하는 것은 거의 불가능에 가까웠다. 파일을 나누는 것은 가능하지만 스코프가 전역(Global)이라서 충돌 위험이 너무 컸다.</p>
</blockquote>
<blockquote>
<p>하지만 클라이언트와 서버 측에서 같은 언어를 쓸 때의 많은 이점으로 인해 수요는 늘어갔고, 이로 인해 탄생한 것이 <strong>ServerJS(CommonJS)</strong> 이다.</p>
</blockquote>
<pre><code class="language-jsx">// 내보내기
module.exports = function add(a, b) { return a + b }

// 가져오기
const add = require(&quot;./add&quot;);</code></pre>
<ul>
<li>구) ServerJS</li>
<li>Node.js에서 기본적으로 사용하는 모듈 시스템이다.</li>
<li>서버 사이드에서 사용하며, 동기적으로 작동한다. (위에서 아래로 순차적으로 실행)<ul>
<li>서버 애플리케이션은 파일 시스템에 직접적으로 접근할 수 있고, 필요한 모듈이나 데이터를 로컬에서 빠르게 로드할 수 있다.</li>
<li>이러한 방식은 네트워크 지연 시간이 거의 없기 때문에 동기적으로 작동해도 문제가 없다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>브라우저의 경우, 네트워크를 통해 모듈이나 라이브러리를 로드하기 떄문에 동기적 로딩은 웹페이지의 로딩 시간을 크게 증가시킬 수 있다.
규모가 클수록 더 많은 영향을 받았고, 브라우저 환경을 고려한 <strong>비동기로 동작하는 모듈 시스템 AMD</strong>가 탄생하게 되었다.</p>
</blockquote>
<h3 id="amd-asynchronous-module-definition">AMD (Asynchronous Module Definition)</h3>
<blockquote>
<p>AMD 그룹은 브라우저 환경을 위한 브라우저 모듈의 표준을 만들고자 했으며, 자바스크립트 모듈과 의존성을 비동기적으로 로드하는 방법을 정의하는 개방형 표준을 공개했다. 이 표준을 기반으로 모듈 시스템을 위한 다양한 라이브러리가 탄생했다.</p>
</blockquote>
<p><a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">amdjs-api/AMD.md at master · amdjs/amdjs-api</a></p>
<ul>
<li>RequireJS</li>
<li>클라이언트에서 주로 사용하며(서버 사이드에서 사용 가능), 비동기적으로 작동한다.</li>
<li><code>define</code>을 통해 모듈을 정의하고, <code>require</code>을 통해 모듈을 비동기적으로 불러와 사용한다.</li>
</ul>
<h3 id="umd-universal-module-definition">UMD (Universal Module Definition)</h3>
<blockquote>
<p>자바스크립트 생태계가 점점 넓어지며, CommonJS와 AMD 모듈 시스템을 모두 지원해야 하는 상황이 생기게 되었고 두 모듈 방식을 좀 더 효율적으로 구성하기 위해 <strong>모듈 관리 패턴 UMD</strong>가 탄생하게 되었다.</p>
</blockquote>
<pre><code class="language-jsx">(function (root, factory) {
  if (typeof module === &#39;object&#39; &amp;&amp; module.exports) {
    // CommonJS
    module.exports = factory();
  } else if (typeof define === &#39;function&#39; &amp;&amp; define.amd) {
    // AMD
    define([], factory);
  } else {
    // 브라우저 글로벌
    root.myLibrary = factory();
  }
}(this, function () {
  return {
    hello: function() { console.log(&quot;Hello!&quot;); }
  };
}));</code></pre>
<ul>
<li>모듈 선언을 위해 즉시실행함수(IIFE)를 사용한다.</li>
<li>보통 라이브러리를 배포할 떄 많이 사용한다.</li>
<li>다양한 환경에서 실행할 수 있는 유연한 구조이다.<ul>
<li>CommonJS 모듈을 사용할 수 있는지 확인</li>
<li>그렇지않다면 AMD에서 사용하는 define 함수를 사용할 수 있는지 확인</li>
<li>둘 다 아니라면 브라우저라 판단</li>
</ul>
</li>
</ul>
<h3 id="esm-es-module">ESM (ES Module)</h3>
<blockquote>
<p>모듈화를 위한 다양한 움직임 끝에 ECMAScripts2015 표준 명세에 ECMA Modules가 등장하며, 자바스크립트 자체 모듈 시스템을 사용할 수 있게 되었다.</p>
</blockquote>
<pre><code class="language-jsx">// 내보내기
export function add (a, b) { return a + b }

// 가져오기
import { add } from &quot;/add.js&quot;</code></pre>
<ul>
<li>현재는 브라우저와 Node.js 모두에서 기본적으로 지원한다.</li>
<li>비동기 로딩과 명확한 의존성 파악이 가능하다.</li>
<li>트리 쉐이킹(tree-shaking)을 통해 사용하지 않는 코드를 제거할 수 있다.</li>
<li>브라우저에서는 <code>&lt;script type=”module”&gt;</code>을 통해 직접 사용할 수 있다.</li>
<li>Node.js에서는 package.json 에 <code>“type”: “module”</code>을 추가하면 된다.</li>
</ul>
<blockquote>
<p>브라우저는 기본적으로 <strong>ESM만 인식</strong>한다.
따라서 다른 모듈 시스템을 제공하는 라이브러리를 사용하기 위해서는 <strong>ESM 형식으로 변환(트랜스파일)</strong> 해주는 과정이 필요하다.
이러한 작업은 보통 Webpack, Rollup 같은 <strong>번들러 도구</strong>들이 처리해준다.</p>
</blockquote>
<h2 id="번들러bundler">번들러(Bundler)</h2>
<blockquote>
<p>웹 애플리케이션 개발에 필요한 HTML, CSS, JS 등의 모듈화된 자원들을 모아서, 하나 혹은 최적의 소수 파일로 결합(번들링)하는 도구이다.</p>
</blockquote>
<h3 id="결합-전-수행-작업">결합 전 수행 작업</h3>
<p>개발자의 작업 효율성을 높이고, 브라우저 호환성이나 성능을 개선하는데 크게 도움을 준다.</p>
<ul>
<li>불필요한 주석이나 공백 제거</li>
<li>난독화</li>
<li>파일 압축</li>
<li>최신 문법이나 기타 개발에 필요한 특수 기능 등을 브라우저가 지원하는 형태로 변환(트랜스파일링)</li>
</ul>
<blockquote>
<p>요즘의 번들러는 단순히 파일을 묶는 기능 뿐만 아니라, 트랜스파일링 작업도 포함한 종합적인 빌드 도구로 발전했다. 이에 해당하는 예시로는 Webpack, Rollup 등이 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/js-park/post/00e73ed8-c218-4a96-894d-d2870ab1164a/image.png" alt=""></p>
<h3 id="webpack">Webpack</h3>
<blockquote>
<p>대표적인 자바스크립트 번들러로, 많은 기능과 확장성으로 좀 더 복잡한 프로젝트에서도 효율적으로 모듈을 관리할 수 있도록 도와준다.</p>
</blockquote>
<ul>
<li><strong>모듈 번들링 (Module Bundling)</strong><ul>
<li>진입점에 연결된 파일을 단일 파일로 묶어줌</li>
</ul>
</li>
<li><strong>번들 최적화 (Automatic Bundle Optimization)</strong><ul>
<li>번들 최적화를 통해. 보다 더 작은 번들을 생성하고 그만큼 빠르게 로딩할 수 있다.</li>
</ul>
</li>
<li><strong>코드 스플리팅 (Code Splitting)</strong><ul>
<li>모듈을 청크(chunk)로 분리하여, 동적으로 필요한 모듈만 로딩할 수 있다.</li>
</ul>
</li>
<li><strong>트리 쉐이킹 (Tree Shaking)</strong><ul>
<li>사용하지 않는 코드를 제거해서 번들의 크기를 줄이고 성능을 향상시킨다.</li>
</ul>
</li>
<li><strong>개발 서버 시행 (Development Server)</strong><ul>
<li>코드가 변경될 때마다 브라우저에 반영(HMR)되는 개발용 서버를 실행할 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="rollup">Rollup</h3>
<blockquote>
<p>경량화와 번들 최적화를 중점에 둔 ES Module 번들러이다.</p>
</blockquote>
<ul>
<li><strong>ESM 중심</strong><ul>
<li>ES 모듈을 기본으로 지원한다.</li>
<li>최신 JS 문법에 최적화되어 있어서 Tree Shaking 효과가 좋다</li>
</ul>
</li>
<li><strong>Tree Shaking 최적화</strong><ul>
<li>Webpack보다 더 깔끔하게 제거하는 경우가 많다.</li>
</ul>
</li>
<li><strong>라이브러리 번들링에 최적화</strong><ul>
<li>앱보다는 라이브러리(npm 패키지 등)을 번들링할 때 더 많이 사용된다.</li>
<li>작은, 최적화된 번들을 만드는 데 강점이 있다</li>
</ul>
</li>
</ul>
<h3 id="esbuild">ESBuild</h3>
<blockquote>
<p>노드기반 번들러보다 10~100배 빠른 빌드를 제공하는 번들러이다.</p>
</blockquote>
<ul>
<li>Go 언어 기반<ul>
<li>Go로 구현되어 병렬 처리가 최적화되어 있어서 수백 개 파일도 몇 초안에 번들링이 가능하다.</li>
</ul>
</li>
</ul>
<h2 id="트랜스파일러tranpsiler">트랜스파일러(Tranpsiler)</h2>
<blockquote>
<p>소스 코드를 한 프로그래밍 언어에서 다른 프로그래밍 언어로 변환해주는 도구이다. 주로 최신 버전의 언어를 구형 버전의 언어로 변경하거나, 다른 언어로 변경하는데 사용된다.</p>
</blockquote>
<p>자바스크립트를 대상으로 하는 트랜스파일러는 Babel, TSC, ESBuild 등이 있다.</p>
<ul>
<li>ES6 → ES5 (Babel)</li>
<li>typescript  → javascript (TypeScript Compiler)</li>
<li>sass / scss → css</li>
</ul>
<h3 id="babel">Babel</h3>
<blockquote>
<p>대표적인 자바스크립트 트랜스파일러로, 최신 버전의 자바스크립트 코드를 오래된 버전의 자바스크립트 코드로 변환해주는 역할을 한다.</p>
</blockquote>
<ul>
<li>구) 6to5</li>
<li>ES5 문법으로의 변환을 통해, 모든 브라우저에서 일관적 동작을 보장해준다. (크로스 브라우징)</li>
<li>플러그인과 프리셋 시스템을 제공하여 개발자가 원하는 변환 규칙을 추가하고 설정할 수 있다.</li>
<li>소스 변환 과정이 추가되기 때문에 빌드 시간을 증가시킬 수 있다.</li>
<li>파싱(parsing) → 변환(transformation) → 출력(print)의 세 단계를 걸쳐서 코드를 변환한다.<ul>
<li><strong>파싱</strong> : 코드를 읽어서 AST(추상 구문 트리)로 변환</li>
<li><strong>변환</strong> : AST를 정해진 규칙에 따라 다시 변환(ES6 → ES5)</li>
<li><strong>출력</strong> : 변환된 AST를 다시 소스 코드로 출력</li>
</ul>
</li>
</ul>
<h3 id="swc">SWC</h3>
<blockquote>
<p>Speedy Web Compiler의 약자로, JS와 TS를 빠르게 트랜스파일링하는 도구이다.</p>
</blockquote>
<ul>
<li><strong>초고속 트랜스파일링</strong><ul>
<li>Rust로 작성되어서, JavaScript/TypeScript 트랜스파일링 속도가 매우 빠르다.</li>
</ul>
</li>
<li><strong>TypeScript 지원</strong><ul>
<li>별도로 추가 설정 없이 TypeScript 파일을 바로 컴파일할 수 있다.</li>
</ul>
</li>
<li><strong>React + TS 환경에서 유용</strong><ul>
<li>React 프로젝트에 맞는 설정과 트랜스파일링이 간단하다.</li>
</ul>
</li>
<li>Babel보다 생태계가 작다.</li>
</ul>
<blockquote>
<p>지금은 대부분의 빌드 도구가 두 역할을 동시에 처리하기 때문에 옛날에 비해 트랜스파일러와 모듈러의 경계가 흐려졌다. 이제는 도구의 “정체성”보다는 <strong>“무엇을 해결해주는가(문법 변환? 모듈 결합? 최적화?)”</strong>를 중심으로 이해하는게 더 실용적이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[비동기(Asyncronous)]]></title>
            <link>https://velog.io/@js-park/%EB%B9%84%EB%8F%99%EA%B8%B0Asyncronous</link>
            <guid>https://velog.io/@js-park/%EB%B9%84%EB%8F%99%EA%B8%B0Asyncronous</guid>
            <pubDate>Wed, 23 Apr 2025 00:03:19 GMT</pubDate>
            <description><![CDATA[<h1 id="비동기asynchronous">비동기(Asynchronous)</h1>
<p>특정 코드가 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 실행하는 것</p>
<h2 id="콜백-기반callback-based">콜백 기반(Callback-based)</h2>
<p>무언가를 비동기적으로 수행하는 함수는 <strong>함수 내 동작이 모두 처리된 후 실행</strong>되어야 하는 함수가 들어갈 <code>콜백</code>을 인수로 반드시 제공해야 한다.</p>
<pre><code class="language-jsx">function loadScript(src, callback) {
  let script = document.createElement(&#39;script&#39;);
  script.src = src;
  script.onload = () =&gt; callback(script);
  document.head.append(script);
}

loadScript(&#39;https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js&#39;, script =&gt; {
  alert(`${script.src}가 로드되었습니다.`);
  alert( _ ); // 스크립트에 정의된 함수
});</code></pre>
<h3 id="콜백-지옥">콜백 지옥</h3>
<p>언뜻 봤을 때는 꽤 쓸만해보이지만, 꼬리에 꼬리를 무는 비동기 동작의 경우 문제가 될 수 있다.</p>
<ul>
<li><p>콜백 지옥 예시</p>
<pre><code class="language-jsx">  loadScript(&#39;1.js&#39;, function(error, script) {

    if (error) {
      handleError(error);
    } else {
      // ...
      loadScript(&#39;2.js&#39;, function(error, script) {
        if (error) {
          handleError(error);
        } else {
          // ...
          loadScript(&#39;3.js&#39;, function(error, script) {
            if (error) {
              handleError(error);
            } else {
              // 모든 스크립트가 로딩된 후, 실행 흐름이 이어집니다. (*)
            }
          });

        }
      })
    }
  });</code></pre>
</li>
</ul>
<p>위의 예시와 같이 계속된 호출로 인해 <strong>깊은 중첩 코드</strong>가 만들어지는 패턴을 <strong>콜백 지옥</strong> 혹은 멸<strong>망의 피라미드</strong>라고 부른다.</p>
<p>이를 해결하기위해 독립적 함수들로 분리할 수는 있지만, 코드의 진행 순서를 읽기가 불편해진다는 점과 재사용하지 않을 함수들을 각각 선언하면서 네임스페이스가 복잡해져버린다.</p>
<ul>
<li><p>독립적 함수로 분리 예시</p>
<pre><code class="language-jsx">  loadScript(&#39;1.js&#39;, step1);

  function step1(error, script) {
    if (error) {
      handleError(error);
    } else {
      // ...
      loadScript(&#39;2.js&#39;, step2);
    }
  }

  function step2(error, script) {
    if (error) {
      handleError(error);
    } else {
      // ...
      loadScript(&#39;3.js&#39;, step3);
    }
  }

  function step3(error, script) {
    if (error) {
      handleError(error);
    } else {
      // 모든 스크립트가 로딩되면 다른 동작을 수행합니다. (*)
    }
  };</code></pre>
</li>
</ul>
<h2 id="프로미스promise">프로미스(Promise)</h2>
<p>자바스크립트의 비동기 작업을 처리하기 위한 객체</p>
<h3 id="state">state</h3>
<ul>
<li><strong>pending(보류) :</strong>  지정한 작업을 수행중인 상태</li>
<li><strong>fulfilled(이행) :</strong> 작업이 성공적으로 마무리된 상태</li>
<li><strong>rejected(거절) :</strong> 작업에 문제가 생겨 오류가 발생한 상태</li>
</ul>
<h3 id="producer">producer</h3>
<p>원하는 기능을 <strong>비동기적으로 실행</strong>하는 Promise</p>
<pre><code class="language-jsx">const promise = new Promise((resolve, reject) =&gt; {
    console.log(&quot;promise.execute!&quot;);
});</code></pre>
<p>프로미스 생성자를 통해 promise 객체를 생성하며, 매개변수로는 <strong>executor</strong>라는 callback 함수를 전달해줘야한다.</p>
<p>executor 함수는 프로미스가 생성되는 동시에 <strong>바로 실행</strong>된다.</p>
<p>executor 함수는 두 가지 <strong>매개변수</strong>를 갖는다.</p>
<ul>
<li><strong>resolve(value)</strong> : 일이 성공적으로 끝난 경우, 그 결과를 나타내는 value와 함께 호출<ul>
<li>resolve가 호출되면 프로미스 객체의 상태(state)는 <strong>fulfilled</strong>로 변경된다.</li>
</ul>
</li>
<li><strong>reject(error)</strong> : 에러 발생 시, 에러 객체를 나타내는 error와 함께 호출<ul>
<li>reject가 호출되면 프로미스 객체의 상태는 <strong>rejected</strong>로 변경된다.</li>
</ul>
</li>
</ul>
<h3 id="consumer">consumer</h3>
<p>producer가 제공한 <strong>데이터를 소비</strong>하는 것</p>
<p><strong>then, catch, finally</strong> 를 이용하여 값을 받아올 수 있다.</p>
<ul>
<li><p><strong>then :</strong> 프로미스에서 <strong>가장 중요하고 기본</strong>이 되는 메서드다.</p>
<pre><code class="language-jsx">  promise.then(
    result =&gt; alert(result),
    error =&gt; alert(error) 
  );</code></pre>
<ul>
<li>첫번째 매개변수는 프로미스가 <strong>이행</strong>되었을 때 실행되는 함수이고,</li>
<li>두번째 매개변수는 프로미스가 <strong>거부</strong>되었을 때 실행되는 함수이다.</li>
</ul>
</li>
<li><p><strong>catch</strong> : <strong>에러가 발생</strong>한 경우만 다루고 싶을 때 사용되는 메서드다.</p>
<pre><code class="language-jsx">  let promise = new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; reject(new Error(&quot;에러 발생!&quot;)), 1000);
  });

  // .catch(f)는 promise.then(null, f)과 동일하게 작동한다.
  promise.catch(alert); //바로 아래 코드와 같은 의미
  //promise.catch((error) =&gt; alert(error));</code></pre>
</li>
</ul>
<ul>
<li><p><strong>finally</strong> : <strong>프로미스를 처리한 후</strong>(이행되거나, 거부된 후) <strong>호출할 함수</strong>를 예약하는 메서드다.</p>
<pre><code class="language-jsx">  new Promise((resolve, reject) =&gt; {
    /* 시간이 걸리는 어떤 일을 수행하고, 그 후 resolve, reject를 호출함 */
  })
    // 성공·실패 여부와 상관없이 프라미스가 처리되면 실행됨
    .finally(() =&gt; 로딩 인디케이터 중지)
    .then(result =&gt; result와 err 보여줌 =&gt; error 보여줌)</code></pre>
</li>
</ul>
<h2 id="프로미스-api">프로미스 API</h2>
<h3 id="promiseall">Promise.all</h3>
<p>배열 안의 프로미스가 모두 처리되면 새로운 프로미스가 이행되는데, <strong>배열 안 프로미스 결과값을 담은 배열</strong>이 새로운 프로미스의 result가 된다.</p>
<pre><code class="language-jsx">let promise = Promise.all([...promises...]);</code></pre>
<ul>
<li>배열 result의 요소 순서는 이행 순서가 아닌, 매개변수로 전달된 프라미스의 순서에 상응한다.</li>
<li>전달되는 프로미스 중 하나라도 거부되면, Promise.all이 반환하는 프로미스는 에러와 함께 거부된다.</li>
</ul>
<h3 id="promiseallsettled">Promise.allSettled</h3>
<p>모든 프로미스가 처리될 때까지 기다렸다가 이행(거부) 여부와 상관없이 그 결과(객체)를 담은 배열을 반환한다.</p>
<pre><code class="language-jsx">let urls = [
  &#39;https://api.github.com/users/iliakan&#39;,
  &#39;https://api.github.com/users/Violet-Bora-Lee&#39;,
  &#39;https://no-such-url&#39;
];

Promise.allSettled(urls.map(url =&gt; fetch(url)))
  .then(results =&gt; { // (*)
    results.forEach((result, num) =&gt; {
      if (result.status == &quot;fulfilled&quot;) {
        alert(`${urls[num]}: ${result.value.status}`);
      }
      if (result.status == &quot;rejected&quot;) {
        alert(`${urls[num]}: ${result.reason}`);
      }
    });
  });</code></pre>
<p>결과</p>
<pre><code class="language-jsx">[
  {status: &#39;fulfilled&#39;, value: ...응답...},
  {status: &#39;fulfilled&#39;, value: ...응답...},
  {status: &#39;rejected&#39;, reason: ...에러 객체...}
]</code></pre>
<h3 id="promiserace">Promise.race</h3>
<p>Promise.all과 비슷하지만, <strong>가장 먼저 처리</strong>되는 프라미스의 결과를 반환한다는 점이 다르다.</p>
<pre><code class="language-jsx">let promise = Promise.race(iterable);</code></pre>
<p>전달된 프라미스 중 하나가 먼저 이행(거부)된다면, 나머지 프로미스의 이행(거부) 여부의 상관 없이 첫번째 프로미스의 결과만 반환한다.</p>
<h2 id="asyncawait">async/await</h2>
<p>프로미스를 조금 더 편하게 사용할 수 있는 문법이다.</p>
<h3 id="async">async</h3>
<p>함수 앞에 async 키워드를 붙이면 해당 함수는 <strong>항상 프로미스를 반환</strong>한다.</p>
<pre><code class="language-jsx">async function f() {
  return 1;
}
f().then(alert); // 1</code></pre>
<h3 id="await">await</h3>
<p>async 함수 안에서만 동작한다.</p>
<p>자바스크립트는 await 키워드를 만나면 프라미스가 처리될 때까지 기다린다. 결과는 그 이후 반환된다.</p>
<pre><code class="language-jsx">async function f() {

  let promise = new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; resolve(&quot;완료!&quot;), 1000)
  });

  let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)

  alert(result); // &quot;완료!&quot;
}

f();</code></pre>
<blockquote>
<p>awiat은 최상위 레벨 코드에서 작동하지 않는다.</p>
</blockquote>
<p>프로미스가 정상적으로 이행되면 프라미스 객체의 result에 저장된 값을 반환한다.</p>
<p>반면 프로미스가 거부되면 마치 throw문처럼 에러가 던져진다.</p>
<pre><code class="language-jsx">async function f() {

  try {
    let response = await fetch(&#39;http://유효하지-않은-주소&#39;);
    let user = await response.json();
  } catch(err) {
    // fetch와 response.json에서 발행한 에러 모두를 여기서 잡습니다.
    alert(err);
  }
}

f();</code></pre>
<p>위와 같이 코드를 작성할 경우,</p>
<p>여러 줄의 코드에서도 오류를 감지 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모듈/번들러/트랜스파일러]]></title>
            <link>https://velog.io/@js-park/%EB%AA%A8%EB%93%88%EB%B2%88%EB%93%A4%EB%9F%AC%ED%8A%B8%EB%9E%9C%EC%8A%A4%ED%8C%8C%EC%9D%BC%EB%9F%AC</link>
            <guid>https://velog.io/@js-park/%EB%AA%A8%EB%93%88%EB%B2%88%EB%93%A4%EB%9F%AC%ED%8A%B8%EB%9E%9C%EC%8A%A4%ED%8C%8C%EC%9D%BC%EB%9F%AC</guid>
            <pubDate>Tue, 22 Apr 2025 10:03:38 GMT</pubDate>
            <description><![CDATA[<h2 id="모듈">모듈</h2>
<blockquote>
<p>개발하는 애플리케이션의 크기가 커지고 프로그램의 내부를 <strong>기능별로 분할한 부분</strong>을 “모듈”이라 부른다</p>
</blockquote>
<h3 id="모듈화의-장점">모듈화의 장점</h3>
<ul>
<li><strong>유지보수</strong><ul>
<li>기능들이 모듈화가 잘 되어있다면 의존성을 줄일 수 있어 유지보수가 편리하다.</li>
</ul>
</li>
<li><strong>네임스페이스화</strong><ul>
<li>모듈화를 하면 모듈만의 네임스페이스를 가지기 떄문에 중복 변수명으로부터 자유로워진다.</li>
</ul>
</li>
<li><strong>재사용성</strong><ul>
<li>재사용 가능한 로직을 모듈로 분리시켜 필요할 때마다 사용할 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="모듈-시스템">모듈 시스템</h2>
<blockquote>
<p>JavaScript 프로그램을 모듈로 개발하고 배포할 수 있게 하기 위해 만들어짐</p>
</blockquote>
<h3 id="cjs-commonjs">CJS (CommonJS)</h3>
<blockquote>
<p>모듈 시스템이 없던 초기의 자바스크립트는 브라우저에서는 큰 문제가 없었지만 서버 사이드에서 사용하기에는 여러 기능들을 모듈화 없이 유지보수하는 것은 거의 불가능에 가까웠다. 파일을 나누는 것은 가능하지만 스코프가 전역(Global)이라서 충돌 위험이 너무 컸다.</p>
</blockquote>
<blockquote>
<p>하지만 클라이언트와 서버 측에서 같은 언어를 쓸 때의 많은 이점으로 인해 수요는 늘어갔고, 이로 인해 탄생한 것이 <strong>ServerJS(CommonJS)</strong> 이다.</p>
</blockquote>
<pre><code class="language-jsx">// 내보내기
module.exports = function add(a, b) { return a + b }

// 가져오기
const add = require(&quot;./add&quot;);</code></pre>
<ul>
<li>구) ServerJS</li>
<li>Node.js에서 기본적으로 사용하는 모듈 시스템이다.</li>
<li>서버 사이드에서 사용하며, 동기적으로 작동한다. (위에서 아래로 순차적으로 실행)<ul>
<li>서버 애플리케이션은 파일 시스템에 직접적으로 접근할 수 있고, 필요한 모듈이나 데이터를 로컬에서 빠르게 로드할 수 있다.</li>
<li>이러한 방식은 네트워크 지연 시간이 거의 없기 때문에 동기적으로 작동해도 문제가 없다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>브라우저의 경우, 네트워크를 통해 모듈이나 라이브러리를 로드하기 떄문에 동기적 로딩은 웹페이지의 로딩 시간을 크게 증가시킬 수 있다.
규모가 클수록 더 많은 영향을 받았고, 브라우저 환경을 고려한 <strong>비동기로 동작하는 모듈 시스템 AMD</strong>가 탄생하게 되었다.</p>
</blockquote>
<h3 id="amd-asynchronous-module-definition">AMD (Asynchronous Module Definition)</h3>
<blockquote>
<p>AMD 그룹은 브라우저 환경을 위한 브라우저 모듈의 표준을 만들고자 했으며, 자바스크립트 모듈과 의존성을 비동기적으로 로드하는 방법을 정의하는 개방형 표준을 공개했다. 이 표준을 기반으로 모듈 시스템을 위한 다양한 라이브러리가 탄생했다.</p>
</blockquote>
<p><a href="https://github.com/amdjs/amdjs-api/blob/master/AMD.md">amdjs-api/AMD.md at master · amdjs/amdjs-api</a></p>
<ul>
<li>RequireJS</li>
<li>클라이언트에서 주로 사용하며(서버 사이드에서 사용 가능), 비동기적으로 작동한다.</li>
<li><code>define</code>을 통해 모듈을 정의하고, <code>require</code>을 통해 모듈을 비동기적으로 불러와 사용한다.</li>
</ul>
<h3 id="umd-universal-module-definition">UMD (Universal Module Definition)</h3>
<blockquote>
<p>자바스크립트 생태계가 점점 넓어지며, CommonJS와 AMD 모듈 시스템을 모두 지원해야 하는 상황이 생기게 되었고 두 모듈 방식을 좀 더 효율적으로 구성하기 위해 <strong>모듈 관리 패턴 UMD</strong>가 탄생하게 되었다.</p>
</blockquote>
<pre><code class="language-jsx">(function (root, factory) {
  if (typeof module === &#39;object&#39; &amp;&amp; module.exports) {
    // CommonJS
    module.exports = factory();
  } else if (typeof define === &#39;function&#39; &amp;&amp; define.amd) {
    // AMD
    define([], factory);
  } else {
    // 브라우저 글로벌
    root.myLibrary = factory();
  }
}(this, function () {
  return {
    hello: function() { console.log(&quot;Hello!&quot;); }
  };
}));</code></pre>
<ul>
<li>모듈 선언을 위해 즉시실행함수(IIFE)를 사용한다.</li>
<li>보통 라이브러리를 배포할 떄 많이 사용한다.</li>
<li>다양한 환경에서 실행할 수 있는 유연한 구조이다.<ul>
<li>CommonJS 모듈을 사용할 수 있는지 확인</li>
<li>그렇지않다면 AMD에서 사용하는 define 함수를 사용할 수 있는지 확인</li>
<li>둘 다 아니라면 브라우저라 판단</li>
</ul>
</li>
</ul>
<h3 id="esm-es-module">ESM (ES Module)</h3>
<blockquote>
<p>모듈화를 위한 다양한 움직임 끝에 ECMAScripts2015 표준 명세에 ECMA Modules가 등장하며, 자바스크립트 자체 모듈 시스템을 사용할 수 있게 되었다.</p>
</blockquote>
<pre><code class="language-jsx">// 내보내기
export function add (a, b) { return a + b }

// 가져오기
import { add } from &quot;/add.js&quot;</code></pre>
<ul>
<li>현재는 브라우저와 Node.js 모두에서 기본적으로 지원한다.</li>
<li>비동기 로딩과 명확한 의존성 파악이 가능하다.</li>
<li>트리 쉐이킹(tree-shaking)을 통해 사용하지 않는 코드를 제거할 수 있다.</li>
<li>브라우저에서는 <code>&lt;script type=”module”&gt;</code>을 통해 직접 사용할 수 있다.</li>
<li>Node.js에서는 package.json 에 <code>“type”: “module”</code>을 추가하면 된다.</li>
</ul>
<blockquote>
<p>브라우저는 기본적으로 <strong>ESM만 인식</strong>한다.
따라서 다른 모듈 시스템을 제공하는 라이브러리를 사용하기 위해서는 <strong>ESM 형식으로 변환(트랜스파일)</strong> 해주는 과정이 필요하다.
이러한 작업은 보통 Webpack, Rollup 같은 <strong>번들러 도구</strong>들이 처리해준다.</p>
</blockquote>
<h2 id="번들러bundler">번들러(Bundler)</h2>
<blockquote>
<p>웹 애플리케이션 개발에 필요한 HTML, CSS, JS 등의 모듈화된 자원들을 모아서, 하나 혹은 최적의 소수 파일로 결합(번들링)하는 도구이다.</p>
</blockquote>
<h3 id="결합-전-수행-작업">결합 전 수행 작업</h3>
<p>개발자의 작업 효율성을 높이고, 브라우저 호환성이나 성능을 개선하는데 크게 도움을 준다.</p>
<ul>
<li>불필요한 주석이나 공백 제거</li>
<li>난독화</li>
<li>파일 압축</li>
<li>최신 문법이나 기타 개발에 필요한 특수 기능 등을 브라우저가 지원하는 형태로 변환(트랜스파일링)</li>
</ul>
<blockquote>
<p>요즘의 번들러는 단순히 파일을 묶는 기능 뿐만 아니라, 트랜스파일링 작업도 포함한 종합적인 빌드 도구로 발전했다. 이에 해당하는 예시로는 Webpack, Rollup 등이 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/js-park/post/3ab054b2-b18e-4221-aeb6-27da46646ab0/image.png" alt=""></p>
<h3 id="webpack">Webpack</h3>
<blockquote>
<p>대표적인 자바스크립트 번들러로, 많은 기능과 확장성으로 좀 더 복잡한 프로젝트에서도 효율적으로 모듈을 관리할 수 있도록 도와준다.</p>
</blockquote>
<ul>
<li><strong>모듈 번들링 (Module Bundling)</strong><ul>
<li>진입점에 연결된 파일을 단일 파일로 묶어줌</li>
</ul>
</li>
<li><strong>번들 최적화 (Automatic Bundle Optimization)</strong><ul>
<li>번들 최적화를 통해. 보다 더 작은 번들을 생성하고 그만큼 빠르게 로딩할 수 있다.</li>
</ul>
</li>
<li><strong>코드 스플리팅 (Code Splitting)</strong><ul>
<li>모듈을 청크(chunk)로 분리하여, 동적으로 필요한 모듈만 로딩할 수 있다.</li>
</ul>
</li>
<li><strong>트리 쉐이킹 (Tree Shaking)</strong><ul>
<li>사용하지 않는 코드를 제거해서 번들의 크기를 줄이고 성능을 향상시킨다.</li>
</ul>
</li>
<li><strong>개발 서버 시행 (Development Server)</strong><ul>
<li>코드가 변경될 때마다 브라우저에 반영(HMR)되는 개발용 서버를 실행할 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="rollup">Rollup</h3>
<blockquote>
<p>경량화와 번들 최적화를 중점에 둔 ES Module 번들러이다.</p>
</blockquote>
<ul>
<li><strong>ESM 중심</strong><ul>
<li>ES 모듈을 기본으로 지원한다.</li>
<li>최신 JS 문법에 최적화되어 있어서 Tree Shaking 효과가 좋다</li>
</ul>
</li>
<li><strong>Tree Shaking 최적화</strong><ul>
<li>Webpack보다 더 깔끔하게 제거하는 경우가 많다.</li>
</ul>
</li>
<li><strong>라이브러리 번들링에 최적화</strong><ul>
<li>앱보다는 라이브러리(npm 패키지 등)을 번들링할 때 더 많이 사용된다.</li>
<li>작은, 최적화된 번들을 만드는 데 강점이 있다</li>
</ul>
</li>
</ul>
<h3 id="esbuild">ESBuild</h3>
<blockquote>
<p>노드기반 번들러보다 10~100배 빠른 빌드를 제공하는 번들러이다.</p>
</blockquote>
<ul>
<li>Go 언어 기반<ul>
<li>Go로 구현되어 병렬 처리가 최적화되어 있어서 수백 개 파일도 몇 초안에 번들링이 가능하다.</li>
</ul>
</li>
</ul>
<h2 id="트랜스파일러tranpsiler">트랜스파일러(Tranpsiler)</h2>
<blockquote>
<p>소스 코드를 한 프로그래밍 언어에서 다른 프로그래밍 언어로 변환해주는 도구이다. 주로 최신 버전의 언어를 구형 버전의 언어로 변경하거나, 다른 언어로 변경하는데 사용된다.</p>
</blockquote>
<p>자바스크립트를 대상으로 하는 트랜스파일러는 Babel, TSC, ESBuild 등이 있다.</p>
<ul>
<li>ES6 → ES5 (Babel)</li>
<li>typescript  → javascript (TypeScript Compiler)</li>
<li>sass / scss → css</li>
</ul>
<h3 id="babel">Babel</h3>
<blockquote>
<p>대표적인 자바스크립트 트랜스파일러로, 최신 버전의 자바스크립트 코드를 오래된 버전의 자바스크립트 코드로 변환해주는 역할을 한다.</p>
</blockquote>
<ul>
<li>구) 6to5</li>
<li>ES5 문법으로의 변환을 통해, 모든 브라우저에서 일관적 동작을 보장해준다. (크로스 브라우징)</li>
<li>플러그인과 프리셋 시스템을 제공하여 개발자가 원하는 변환 규칙을 추가하고 설정할 수 있다.</li>
<li>소스 변환 과정이 추가되기 때문에 빌드 시간을 증가시킬 수 있다.</li>
<li>파싱(parsing) → 변환(transformation) → 출력(print)의 세 단계를 걸쳐서 코드를 변환한다.<ul>
<li><strong>파싱</strong> : 코드를 읽어서 AST(추상 구문 트리)로 변환</li>
<li><strong>변환</strong> : AST를 정해진 규칙에 따라 다시 변환(ES6 → ES5)</li>
<li><strong>출력</strong> : 변환된 AST를 다시 소스 코드로 출력</li>
</ul>
</li>
</ul>
<h3 id="swc">SWC</h3>
<blockquote>
<p>Speedy Web Compiler의 약자로, JS와 TS를 빠르게 트랜스파일링하는 도구이다.</p>
</blockquote>
<ul>
<li><strong>초고속 트랜스파일링</strong><ul>
<li>Rust로 작성되어서, JavaScript/TypeScript 트랜스파일링 속도가 매우 빠르다.</li>
</ul>
</li>
<li><strong>TypeScript 지원</strong><ul>
<li>별도로 추가 설정 없이 TypeScript 파일을 바로 컴파일할 수 있다.</li>
</ul>
</li>
<li><strong>React + TS 환경에서 유용</strong><ul>
<li>React 프로젝트에 맞는 설정과 트랜스파일링이 간단하다.</li>
</ul>
</li>
<li>Babel보다 생태계가 작다.</li>
</ul>
<blockquote>
<p>지금은 대부분의 빌드 도구가 두 역할을 동시에 처리하기 때문에 옛날에 비해 트랜스파일러와 모듈러의 경계가 흐려졌다. 이제는 도구의 “정체성”보다는 <strong>“무엇을 해결해주는가(문법 변환? 모듈 결합? 최적화?)”</strong>를 중심으로 이해하는게 더 실용적이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[OOP(객체 지향 프로그래밍)]]></title>
            <link>https://velog.io/@js-park/OOP%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@js-park/OOP%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Tue, 22 Apr 2025 08:14:51 GMT</pubDate>
            <description><![CDATA[<h2 id="객체-지향-설계와-프로그래밍">객체 지향 설계와 프로그래밍</h2>
<ul>
<li>객체들이 모여서 상호 협력하면서 데이터를 처리하는 방식</li>
</ul>
<blockquote>
<p>최신 프론트엔드 트렌드는 함수형 프로그래밍이 강조되고 있지만, 객체지향 프로그래밍도 알아두면 좋을 것 같다.</p>
</blockquote>
<h3 id="용어">용어</h3>
<ul>
<li><p><strong>클래스</strong></p>
<ul>
<li>객체 지향 프로그래밍을 지원하기 위해 <code>ES6</code>에서 도입된 기능이다.</li>
<li>객체를 생성하는 <strong>템플릿, 설계도</strong> 역할을 하며, <strong>프로토타입</strong> 기반의 객체 지향 패턴을 보다 명확하고 쉽게 사용할 수 있게 해준다.</li>
</ul>
</li>
<li><p><strong>객체</strong></p>
<ul>
<li>객체는 원시타입과 달리 <strong>다양한 데이터</strong>를 담을 수 있는 데이터 타입이다.<ul>
<li>원시 데이터 타입, 객체, 함수, 배열, Date, 정규표현식, 심볼 등</li>
</ul>
</li>
<li><strong>키</strong>(<code>key</code>)와 <strong>값</strong>(<code>value</code>)로 구성된 <strong>프로퍼티</strong>(<code>Property</code>)들의 집합이다.</li>
<li><strong>‘클래스의 인스턴스’</strong>라고도 부른다.</li>
</ul>
</li>
<li><p><strong>인스턴스</strong></p>
<ul>
<li>설계도를 바탕으로 소프트웨어 세계에 구현된 <strong>구체적인 실체</strong>이다.</li>
<li>인스턴스는 객체에 포함된다고 볼 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="프로그래밍-구조">프로그래밍 구조</h3>
<ul>
<li><p><strong>프로퍼티와 메소드</strong></p>
<ul>
<li><p><strong>프로퍼티</strong>(<code>property</code>)</p>
<ul>
<li>객체에는 <strong>‘키 : 값’</strong> 쌍으로 구성된 프로퍼티가 들어간다.</li>
<li>프로퍼티 값엔 모든 데이터 타입이 올 수 있다.</li>
<li>하지만 몇몇 데이터 타입은 어떤 경우에 동작하지 않거나 원치 않은 결과를 불러올 수 있다.<ul>
<li>NaN, Infinity, BigInt, undefined, null</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>메서드</strong>(<code>method</code>)</p>
<ul>
<li><p>객체 안에 프로퍼티로 정의된 <strong>함수</strong>를 메서드라고 한다.</p>
<pre><code class="language-jsx">const obj = {
f1 : function () {
 console.log(&quot;hi!&quot;)
},
f2(){
 console.log(&quot;hi!&quot;)   
}</code></pre>
<p>기존에는 <code>f1</code>의 형태처럼, 프로퍼티를 정의할 때와 동일하게 선언했었는데,</p>
<p><code>ES6</code>에서는 <code>f2</code>와 같이 : 를 생략한 축약 표현을 사용할 수 있다.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>     &gt;ES6 이후의 코드를 작성할 때는 더 간결한 축약 메서드 구문을 사용하는 것이 일반적이다.</code></pre><ul>
<li><p><strong>캡슐화</strong></p>
<ul>
<li><p>비슷한 관련된 역할을 하는 속성과 메소드들을 <strong>하나의 캡슐</strong>로 만들어 외부로 부터 보호하는 것을 말한다.</p>
</li>
<li><p><strong>이유</strong></p>
<ul>
<li><strong>데이터 보호</strong> : 외부로 부터 각 객체에 정의된 속성과 기능을 보호</li>
<li><strong>데이터 은닉</strong> : 내부의 동작을 감추고 필요한 부분만 노출시키기 위함</li>
</ul>
</li>
<li><p><strong>프라이빗 필드</strong></p>
<ul>
<li><code>#</code>을 사용하여 클래스 내에서만 접근 가능한 프라이빗 필드를 정의할 수 있다.</li>
<li>이는 클래스 외부에서 필드에 직접 접근 및 수정하지 못하도록 한다.</li>
<li>단점은 클래스의 상속 구조에서 <strong>자식</strong> 클래스가 <strong>부모</strong> 클래스의 프라이빗 필드에 <strong>접근할 수 없다</strong>는 점을 고려해야 한다는 것이다.</li>
</ul>
</li>
<li><p><strong>getter/setter</strong></p>
<ul>
<li><p>예시</p>
<pre><code class="language-jsx">  class Person {
    #name; 
    #age;   

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

    // Getter
    get name() {
      return this.#name;
    }

    get age() {
      return this.#age;
    }

    // Setter
    set name(newName) {
      this.#name = newName;
    }

    set age(newAge) {
      if (newAge &gt; 0) {
        this.#age = newAge;
      }
    }
  }

  const person = new Person(&#39;John&#39;, 30);

  console.log(person.name);  // &quot;John&quot;
  console.log(person.age);   // 30

  person.name = &#39;Jane&#39;;  // setter 호출
  person.age = 35;       // setter 호출

  console.log(person.name);  // &quot;Jane&quot;
  console.log(person.age);   // 35</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>상속</strong></p>
<ul>
<li>객체가 다른 객체를 상속 받아 해당 객체의 요소를 사용하는 것을 의미한다.</li>
<li>상속 받은 객체는 <strong>자식</strong>, 상속된 객체는 <strong>부모</strong>라 칭한다.</li>
<li>상속을 통해 프로젝트의 <strong>생산성, 유지보수성, 재사용성</strong>을 높일 수 있다.</li>
</ul>
</li>
<li><p><strong>다형성</strong></p>
<ul>
<li>동일한 메시지나 인터페이스가 여러 가지 형태로 동작할 수 있는 것을 의미한다.</li>
<li><strong>메서드 오버로딩</strong>(<code>Method Overloading</code>)<ul>
<li>같은 이름의 메서드를 여러 개 정의하되, 각 메서드는 서로 다른 매개변수 목록을 가진다.</li>
<li>자바스크립트에서는 이를 직접 지원하지 않지만, 매개변수의 개수와 타입을 체크하며 직접 구현할 수 있다.</li>
</ul>
</li>
<li><strong>메서드 오버라이딩</strong>(<code>Method Overriding</code>)<ul>
<li>상속을 통해 자식 클래스에서 부모 클래스의 메서드를 재정의하여 사용한다.</li>
</ul>
</li>
<li>상속과 마찬가지로 <strong>생산성, 유지보수성, 재사용성</strong>을 높일 수 있다.</li>
</ul>
</li>
</ul>
<h2 id="객체-표현-방식">객체 표현 방식</h2>
<h3 id="객체표현---1-리터럴-표기법-literal-notation">객체표현 - 1. 리터럴 표기법 (Literal Notation)</h3>
<ul>
<li>중괄호를 사용하여 객체를 정의하며, 속성과 값음 <code>key : value</code> 형식으로 나열한다.</li>
</ul>
<pre><code class="language-jsx">const healthObj = {
  name : &quot;달리기&quot;,
  lastTime : &quot;PM10:12&quot;,
  showHealth() {
    console.log(this.name + &quot;님, 오늘은 &quot; + this.lastTime + &quot;에 운동을 하셨네요&quot;);
  }
}

healthObj.showHealth();</code></pre>
<h3 id="객체표현---2-생성자-함수-constructor-function">객체표현 - 2. 생성자 함수 (Constructor Function)</h3>
<ul>
<li>객체의 템플릿을 정의하고, new 키워드로 객체를 생성한다. 생성자 함수의 첫 글자는 보통 대문자를 사용하는 것이 관례이다.</li>
</ul>
<pre><code class="language-jsx">const Health = function(name,healthTime) {
  this.name = name;
  this.healthTime = healthTime;
  this.showHealth = function() {
    console.log(this.name + &quot;님, 오늘은 &quot; + this.healthTime + &quot;에 운동을 하셨네요&quot;);
  }
}

const ho = new Health(&quot;crong&quot;, &quot;12:12&quot;);
ho.showHealth();
</code></pre>
<h3 id="객체표현---3-클래스-문법-class-syntax">객체표현 - 3. 클래스 문법 (Class Syntax)</h3>
<ul>
<li>ES6부터 도입된 문법으로, 생성자 함수보다 직관적이고 상속과 같은 객체 지향적인 개념을 쉽게 사용할 수 있다.</li>
</ul>
<pre><code class="language-jsx">const Health = class {
  constructor(name, healthTime) {
    this.name = name;
    this.healthTime = healthTime;
  }

  showHealth(){
     console.log(this.name + &quot;님, 오늘은 &quot; + this.healthTime + &quot;에 운동을 하셨네요&quot;);
  }

}

const ho = new Health(&quot;crong&quot;, &quot;12:12&quot;);
ho.showHealth();
</code></pre>
<h2 id="this와-super-키워드-차이점">this와 super 키워드 차이점</h2>
<h3 id="this">this</h3>
<ul>
<li><p><strong>인스턴스 변수와 로컬 변수 구별</strong></p>
<ul>
<li><p>인스턴스 변수와 로컬 변수의 이름이 같을 때, <code>this</code> 키워드를 사용하며 인스턴스 변수를 구분할 수 있다.</p>
</li>
<li><p>예시</p>
<pre><code class="language-jsx">  class Example {
    constructor(value) {
      this.value = value;  // 인스턴스 변수
    }
    showValue() {
      let value = 10;  // 로컬 변수
      console.log(value); // 출력 : 로컬 변수
      console.log(this.value); // 출력 : 인스턴스 변수
    }
  }</code></pre>
</li>
</ul>
</li>
<li><p><strong>현재 객체 반환</strong></p>
</li>
<li><p><strong>현재 객체의 메서드 호출</strong></p>
<ul>
<li>같은 클래스 내에서 다른 메서드를 호출</li>
</ul>
</li>
</ul>
<h3 id="super">super</h3>
<ul>
<li><strong>부모 클래스의 생성자, 메서드를 호출하거나 인스턴스 변수를 참조할 때 사용된다.</strong></li>
</ul>
<h2 id="solid-원칙">SOLID 원칙</h2>
<h3 id="srpsingle-responsibility-principle-단일-책임-원칙">SRP(Single Responsibility Principle) 단일 책임 원칙</h3>
<ul>
<li><strong>한 클래스는 하나의 책임을 가져야 한다</strong>는 원칙</li>
<li><strong>클래스가 변경되어야 하는 이유</strong>가 단 하나만 있어야 한다는 것이다.</li>
<li><strong>목적</strong> :<ul>
<li><strong>유지보수성 향상</strong></li>
<li><strong>변경의 용이성</strong></li>
<li><strong>재사용성 증가</strong></li>
</ul>
</li>
<li>코드 길이가 길어졌다 하더라도, 하나의 클래스를 사용하는 것보다 여러 개의 클래스를 사용하는 것이 더 효율적이다.</li>
</ul>
<ol>
<li><strong>클래스명은 책임의 소재를 알 수 있게 작명</strong></li>
<li><strong>책임을 분리할 때 항상 결합도, 응집도를 따져가며</strong><ol>
<li><strong>응집도</strong>란 한 프로그램 요소가 얼마나 <strong>뭉쳐 있는가</strong>를 나타내는 척도</li>
<li><strong>결합도</strong>는 프로그램 구성 요소들 사이가 얼마나 <strong>의존적 인지</strong>를 나타내는 척도</li>
</ol>
</li>
</ol>
<h3 id="lspliskov--substitution-principle-리스코프-교환원칙">LSP(Liskov- Substitution Principle) 리스코프 교환원칙</h3>
<ul>
<li><strong>프로그램에서 상위 타입의 객체를 하위 타입의 객체로 치환해도 프로그램의 동작이 바뀌지 않아야 한다</strong>는 원칙</li>
<li>자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있어야 한다는 것이다.</li>
<li>사실상 <strong>다형성 원리</strong>를 얘기하는 것이다.</li>
<li><strong>목적 :</strong><ul>
<li><strong>신뢰성 향상</strong></li>
<li><strong>유연성 증가</strong></li>
<li><strong>유지보수성 개선</strong></li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 엔진 동작 원리]]></title>
            <link>https://velog.io/@js-park/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@js-park/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Tue, 22 Apr 2025 05:41:05 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.lydiahallie.com/blog/event-loop?ref=dailydev">JavaScript Visualized - Event Loop, Web APIs, (Micro)task Queue</a></p>
<h2 id="자바스크립트-런타임-구성요소">자바스크립트 런타임 구성요소</h2>
<p><img src="https://velog.velcdn.com/images/js-park/post/1ca3962a-5ba1-4b7b-bead-fd34a6a62c87/image.png" alt=""></p>
<h3 id="콜-스택call-stack"><strong>콜 스택(Call Stack)</strong></h3>
<ul>
<li><p>함수가 호출되었을 떄 생성되는 실행 컨텍스트들이 여기에 <strong>push</strong> 된다.</p>
</li>
<li><p>FILO(First-In-Last-Out) 방식으로 처리</p>
</li>
<li><p>함수의 실행이 종료되면 컨텍스트가 <strong>pop</strong> 된다.</p>
</li>
<li><p>자바스크립트는 <strong>싱글 쓰레드(Single Thread)</strong>의 형태로 단 하나의 콜스택을 가지기 때문에 굉장히 많은 시간을 잡아먹는 작업이 있을 경우, 프로그램 작동이 막힐 수가 있다.</p>
<pre><code class="language-jsx">  function longRunnigTask() {
      let count = 0;
      for (let j = 0; j &lt; 1e9; j++) {
          count++;
      }
      console.log(&quot;Long task done!&quot;);
  }

  function importantTask() {
      console.log(&quot;Important!&quot;);
  }

  longRunningTask();
  importantTask();</code></pre>
<p>  콜 스택은 <strong>longRunningTask</strong> 함수가 끝날 때까지 <strong>importantTask</strong> 함수를 실행할 수 없기 때문에, 중요한 작업이 오랫동안 미뤄질 수가 있다.</p>
<p>  이런 긴 실행 작업이 필요할 때, 프로그램의 진행이 멈추지 않도록 Javascript 에서는 <strong>web APIs</strong>를 통해 일부 기능을 제공한다.</p>
</li>
</ul>
<h3 id="web-apis">Web APIs</h3>
<ul>
<li><p>브라우저가 활용하는 기능과 상호작용할 수 있는 인터페이스 세트를 제공한다.</p>
</li>
<li><p>여기에는 자주 사용하는 Document Object Model, fetch, setTimeout 등이 포함된다.</p>
</li>
<li><p>자바스크립트 런타임과 브라우저 기능 간의 다리 역할을 한다.</p>
</li>
<li><p>비동기 작업이 시작되면 이를 Web APIs로 전달하고, 콜 스택의 해당 실행 컨텍스트는 제거된다.</p>
</li>
<li><p>여기서 비동기 작업은 <strong>callback 형태</strong>와 <strong>promise 형태</strong>로 나누어진다.</p>
</li>
</ul>
<blockquote>
<p>모든 Web APIs가 비동기 작업을 다루는 것은 아니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/js-park/post/60f4ad73-6e7a-4921-8c44-0b64217fa96d/image.png" alt=""></p>
<ul>
<li><strong>Callback-based APIs</strong><ul>
<li>위의 <strong>getCurrentPosition</strong> 메서드의 경우, API가 원하는 값을 받았을 때의 success callback과 받지 못했을 때의 error callback으로 이루어져있다.</li>
<li>해당 메서드를 호출하면 실행 컨텍스트가 콜 스택에 추가되고, 이 컨텍스트는 <strong>콜백을 웹 API에 등록하고 브라우저에 작업을 넘기는 역할</strong>을 한 후 종료된다.</li>
<li>브라우저에서 사용자가 상호작용하는 동안에도 콜 스택은 이와 상관없이 다른 작업을 할 수 있다.(non-blocking task)</li>
<li>web APIs의 상호작용이 종료된 후에 callback은 콜 스택이 아닌 <strong>Task Queue</strong>에 추가된다.</li>
</ul>
</li>
<li><strong>Promise-based APIs</strong><ul>
<li>콜백 함수가 아닌, <strong>promise를 리턴</strong>하는 API 작업들이 해당한다.</li>
<li>이 작업들은 Task Queue가 아닌 <strong>Microtask Queue</strong>에 추가된다.</li>
</ul>
</li>
</ul>
<h3 id="태스크-큐task-queue">태스크 큐(Task Queue)</h3>
<ul>
<li>Web API의 콜백 또는 이벤트 핸들러가 실행 대기하게 되는 저장소이다.</li>
<li><strong>FIFO(First-In-First-Out)</strong></li>
</ul>
<h3 id="마이크로-태스크-큐microtask-queue">마이크로 태스크 큐(Microtask Queue)</h3>
<ul>
<li><code>then(callback), catch(callback), finally(callback)</code>같은 <strong>프로미스 핸들러</strong>의 콜백 함수</li>
<li><code>async</code> 함수 내의 <code>await</code>뒤 따라오는 작업</li>
<li><code>MutationObserver</code> 콜백 함수</li>
<li><code>queueMicrotask</code> 콜백 함수</li>
<li>태스크 큐보다 높은 <strong>우선 순위</strong>를 가짐</li>
<li><strong>FIFO(First-In-First-Out)</strong></li>
</ul>
<h3 id="이벤트-루프event-loop">이벤트 루프(Event Loop)</h3>
<ol>
<li><strong>콜 스택이 빌 떄</strong>까지 지속적으로 확인한다.</li>
<li>만약 콜 스택에서 실행 중인 작업이 없다면 <strong>마이크로 태스크 큐의 작업을 최우선</strong>으로 찾는다.<ol>
<li>마이크로 태스크 큐의 작업이 <strong>있을 경우</strong>, 가장 먼저 들어온 <strong>첫번째 작업</strong>을 실행한다.</li>
<li>마이크로 태스크 큐에 작업이 <strong>없을 경우</strong>, <strong>태스크 큐의 첫번째 작업</strong>을 실행한다.</li>
</ol>
</li>
<li>콜 스택이 빌 때마다 계속해서 <strong>반복</strong>한다.</li>
</ol>
<p>[javascript-questions/ko-KR/README-ko_KR.md at master · lydiahallie/javascript-questions]</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[this란?]]></title>
            <link>https://velog.io/@js-park/this%EB%9E%80</link>
            <guid>https://velog.io/@js-park/this%EB%9E%80</guid>
            <pubDate>Mon, 21 Apr 2025 03:08:56 GMT</pubDate>
            <description><![CDATA[<h2 id="this란">this란?</h2>
<p>함수를 호출할 때 생성되는 <strong>실행 컨텍스트 객체</strong>를 말한다.</p>
<p><code>this</code>는 실행 컨텍스트가 생성될 때 결정되며, 함수가 호출되는 방식에 따라 다르게 바인딩된다.</p>
<h3 id="전역-컨텍스트-global-context">전역 컨텍스트 (Global Context)</h3>
<p>전역에서 <code>this</code>를 참조하면 브라우저에서는 <strong>전역</strong>(<strong>window) 객체</strong>를 가리킨다.</p>
<pre><code class="language-jsx">console.log(this); //window</code></pre>
<h3 id="일반-함수-호출-default-binding">일반 함수 호출 (Default Binding)</h3>
<p>함수 내부에서 <code>this</code>를 사용하면, <strong>전역</strong>(<strong>window) 객체</strong>를 가리킨다.</p>
<p><strong>non-strict mode</strong> 에서는 전역 객체를, <strong>strict mode</strong> 에서는 undefined</p>
<pre><code class="language-jsx">function foo() {
    console.log(this); //window
}
foo();</code></pre>
<h3 id="메서드-호출-implicit-binding">메서드 호출 (Implicit Binding)</h3>
<p><strong>객체의 메소드</strong>로 호출되었을 경우, <code>this</code>는 그 객체를 가리킨다.</p>
<pre><code class="language-jsx">const obj = {
    name: &quot;Peter&quot;,
    funcD: () {
        console.log(this.name);
    }
}

obj.funcD();
//Peter</code></pre>
<h3 id="생성자-함수-new-binding">생성자 함수 (New Binding)</h3>
<p><code>new</code> 키워드를 사용하여 함수를 호출하면, <strong>새로운 객체</strong>가 생성되면 <strong><code>this</code></strong>가 <strong>그 객체를</strong> 가리킨다.</p>
<pre><code class="language-jsx">function Person(name) {
    this.name = name;
}
const me = new Person(&#39;Alice&#39;);
console.log(me.name); // &quot;Alice&quot;
****</code></pre>
<h3 id="명시적-바인딩-explicit-binding">명시적 바인딩 (Explicit Binding)</h3>
<p><code>.call()</code>, <code>.apply()</code>, <code>.bind()</code> 메서드를 사용하면 <code>this</code>를 <strong>명시적으로 지정</strong>할 수 있다.</p>
<pre><code class="language-jsx">function greet() {
    console.log(this.name);
}

const user = { name: &#39;Bob&#39; };
greet.call(user);  // &quot;Bob&quot;
greet.apply(user); // &quot;Bob&quot;

const boundGreet = greet.bind(user);
boundGreet();      // &quot;Bob&quot;
</code></pre>
<ul>
<li><code>call()</code>과 <code>apply()</code> 는 즉시 실행하며, 첫 번째 인자로 <code>this</code>를 지정한다.</li>
<li><code>bind()</code>는 새로운 함수를 반환하여 나중에 실행할 수 있도록 한다.</li>
</ul>
<h3 id="화살표-함수-lexical-binding">화살표 함수 (Lexical Binding)</h3>
<p><strong>화살표 함수</strong>의 경우, this를 바인딩하지 않고 <strong>선언된 위치</strong>에서 <code>this</code>를 <strong>상속</strong>한다.</p>
<p>즉 자신을 감싸고 있는 <strong>상위 스코프</strong>의 <code>this</code>를 그대로 사용한다.</p>
<ol>
<li><strong>객체에서 사용</strong>되었을 경우, 해당 객체가 아니고 <strong>상위 스코프인 전역 객체</strong>를 참조한다.</li>
</ol>
<pre><code class="language-jsx">const obj = {
  name: &quot;Alice&quot;,
  funcD: () =&gt; {
    console.log(this.name);
  },
};

obj.funcD(); 
//undefined</code></pre>
<ol>
<li><strong>객체의 메서드</strong>를 외부 함수로 <strong>내부</strong>에서 사용되었을 경우</li>
</ol>
<pre><code class="language-jsx">const obj = {
  name: &quot;Alice&quot;,
  funcD: function () {
      setTimeout(() =&gt; {
      console.log(this.name);
      }, 1000)
  },
};

obj.funcD();
//Alice</code></pre>
<p>상위 스코프인 <strong>funcD 함수의 this</strong>를 상속받는다.</p>
<p>funcD는 obj 객체의 메소드이기 때문에, <code>this</code>는 ****obj 객체에 바인딩되어있다.</p>
<blockquote>
<p>DOM <code>addEventListener()</code> 의 경우, <code>this</code>는 e.currentTarget과 같다.</p>
</blockquote>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th><strong>호출 방식</strong></th>
<th><strong>this 값</strong></th>
</tr>
</thead>
<tbody><tr>
<td>전역 실행</td>
<td>window (브라우저) / global (Node.js)</td>
</tr>
<tr>
<td>일반 함수 호출</td>
<td>window (strict mode에서는 undefined)</td>
</tr>
<tr>
<td>메서드 호출</td>
<td>호출한 객체</td>
</tr>
<tr>
<td>생성자 함수 호출</td>
<td>새로 생성된 객체</td>
</tr>
<tr>
<td>call / apply / bind 사용</td>
<td>명시적으로 지정된 객체</td>
</tr>
<tr>
<td>화살표 함수</td>
<td>상위 스코프의 this</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTMCollection vs NodeList]]></title>
            <link>https://velog.io/@js-park/HTMCollection-vs-NodeList</link>
            <guid>https://velog.io/@js-park/HTMCollection-vs-NodeList</guid>
            <pubDate>Mon, 21 Apr 2025 02:04:44 GMT</pubDate>
            <description><![CDATA[<h2 id="html-collection">HTML Collection</h2>
<ul>
<li>HTML 문서 내에서 <strong>선택한 요소만</strong>을 ****정렬된 순서대로 모아둔 집합</li>
<li>요소를 배열의 항목처럼 유사하게 다룰 수 있는 객체이며, 이를 <strong>유사 배열 객체</strong>라고 부른다.</li>
<li><code>for ...of</code>문으로 순회 가능한 <strong>이터러블(iterable) 객체</strong>이기도 하다.</li>
</ul>
<h3 id="html-collection-객체를-반환">HTML Collection 객체를 반환</h3>
<ul>
<li><strong>getElementsByTagName()</strong></li>
<li><strong>getElementsByClassName()</strong></li>
</ul>
<blockquote>
<p><strong>getElementsByName()</strong> 은 비슷하게 생겼으나 NodeList를 반환한다.</p>
</blockquote>
<h3 id="특징">특징</h3>
<ul>
<li><p><strong>유사 배열 객체</strong></p>
<ul>
<li><strong>인덱스</strong>를 통해 요소에 접근할 수 있다.</li>
<li><strong>length</strong>를 통해 요소의 수를 확인할 수 있다.</li>
<li>하지만 진짜 배열처럼 <strong>배열 메서드</strong>(push, pop, forEach, map, filter)를 <strong>사용할 수 없다</strong>.</li>
<li><code>const elimentsArray = Array.from(HTMLCollection)</code></li>
<li>대신 <strong>Array.from</strong> 메서드를 이용하면 <strong>배열로 변환</strong>하여 배열 메서드를 사용할 수 있다.</li>
</ul>
</li>
<li><p><strong>이터러블 객체</strong></p>
<ul>
<li><code>const elimentsArray = [...HTMLCollection]</code></li>
<li>이터러블 객체이기 때문에 <strong>스프레드 문법</strong>을 통해 배열로 만드는 방법도 있다.</li>
</ul>
</li>
<li><p><strong>live DOM 객체</strong></p>
<ul>
<li><p>DOM의 변경 사항을 <strong>실시간으로 반영</strong>하는 객체이다.</p>
</li>
<li><p><strong>객체가 생성된 후</strong>에 DOM이 변경되면 <strong>객체 또한 변경</strong>된다는 것을 의미한다.</p>
<pre><code class="language-jsx">const divs = document.getElementsByTagName(&quot;div&quot;);
console.log(divs.length); // 현재 div 개수 출력

// 새로운 div 추가
const newDiv = document.createElement(&quot;div&quot;);
document.body.appendChild(newDiv);

console.log(divs.length); // 새 div가 추가되었으므로 값이 변경됨 (Live 특성)</code></pre>
</li>
<li><p>변경을 방지하기 위해서는 NodeList를 사용할 수도 있고, Array.from 메서드를 통해 Live 특성을 지우고 배열로 사용하는 방법도 있다.</p>
</li>
</ul>
</li>
</ul>
<h2 id="nodelist">NodeList</h2>
<ul>
<li>요소 객체뿐만 아니라 텍스트, 주석, 속성 등의 <strong>모든 노드</strong>를 정렬된 순서대로 모아둔 집합</li>
<li>HTMLCollection과 마찬가지로 <strong>요소 배열 객체</strong>이면서 <strong>이터러블 객체</strong>이다.</li>
</ul>
<h3 id="nodelist-객체를-반환">NodeList 객체를 반환</h3>
<ul>
<li><strong>querySelectorAll()</strong></li>
<li><strong>getElementsByName()</strong></li>
<li><strong>Node.childNodes</strong></li>
</ul>
<h3 id="특징-1">특징</h3>
<ul>
<li><strong>유사 배열 객체</strong></li>
<li><strong>이터러블 객체</strong></li>
<li><strong>forEach 메서드 사용 가능</strong><ul>
<li>NodeList.prototype 에 forEach 메서드가 정의되어 있기 때문이다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>일부 오래된 브라우저(IE11 이하)는 NodeList가 forEach 메서드를 지원하지 않는다.</p>
</blockquote>
<ul>
<li><strong>non-live DOM 객체</strong><ul>
<li>DOM의 변경사항을 <strong>실시간으로 반영하지 않는다.</strong></li>
</ul>
</li>
</ul>
<pre><code>&gt;Node.childNodes는 위와 별개로 live DOM 객체이다.


```jsx
const divs = document.querySellectorAll(&quot;div&quot;);
console.log(divs.length); // 현재 div 개수 출력

// 새로운 div 추가
const newDiv = document.createElement(&quot;div&quot;);
document.body.appendChild(newDiv);

console.log(divs.length); // 새 div가 추가되었으나 값이 변경되지 않음
```</code></pre><h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>속성</th>
<th>NodeList (<code>querySelectorAll</code>)</th>
<th>NodeList (<code>childNodes</code>)</th>
<th>HTMLCollection</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Live(동적) 여부</strong></td>
<td>❌ (정적)</td>
<td>✅ (동적)</td>
<td>✅ (동적)</td>
</tr>
<tr>
<td><strong>배열 메서드 사용 (<code>forEach()</code>)</strong></td>
<td>✅ 가능</td>
<td>✅ 가능</td>
<td>❌ 불가능</td>
</tr>
<tr>
<td><strong>DOM 변경 반영 여부</strong></td>
<td>❌ 반영 안 됨</td>
<td>✅ 자동 반영</td>
<td>✅ 자동 반영</td>
</tr>
<tr>
<td><strong>반환 메서드</strong></td>
<td><code>querySelectorAll()</code></td>
<td><code>childNodes</code></td>
<td><code>getElementsByTagName()</code> 등</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Scope]]></title>
            <link>https://velog.io/@js-park/Scope</link>
            <guid>https://velog.io/@js-park/Scope</guid>
            <pubDate>Mon, 21 Apr 2025 01:08:46 GMT</pubDate>
            <description><![CDATA[<h2 id="scope란">Scope란?</h2>
<p>스코프는 <strong>참조 대상 식별자(identifier)</strong>를 찾아내기 위한 규칙이다.</p>
<p>간단하게 설명하면 ‘<strong>변수에 접근할 수 있는 범위</strong>’라고 말할 수 있다.</p>
<h2 id="스코프의-구분">스코프의 구분</h2>
<p>스코프는 크게 두 가지로 나눌 수 있다.</p>
<ul>
<li><strong>전역 스코프(Global Scope)</strong><ul>
<li>최상위 레벨의 스코프</li>
<li>전체 코드 어디에서든 접근 가능</li>
</ul>
</li>
<li><strong>지역 스코프(Local Scope)</strong><ul>
<li>특정 함수에 해당하는 스코프</li>
<li>해당 함수와 하위 함수에서만 접근이 가능하다.</li>
</ul>
</li>
</ul>
<h3 id="전역-스코프global-scope">전역 스코프(Global Scope)</h3>
<p>브라우저에서 실행되는 JavaScript에서는 <strong>window 객체</strong>가 담당한다.</p>
<p>전역에서 변수를 선언하면 전역 스코프를 갖는 <strong>전역 변수</strong>가 된다.</p>
<pre><code class="language-jsx">n0=&#39;n0&#39;; //암묵적 전역
var v0=&#39;v0&#39;;
let l0=&#39;l0&#39;;
const c0 = &#39;c0&#39;;
console.log(v0, n0, l0, c0);
console.log(window.v0, window.n0, window.l0, window.c0);</code></pre>
<p><strong>var 키워드</strong>로 선언한 전역 변수(v0)나 <strong>전역 함수</strong>, <strong>암묵적 전역</strong>의 경우 모두 전역 객체 <strong>window의 프로퍼티</strong>가 된다.</p>
<blockquote>
<p><strong>암묵적 전역(implicit global)</strong>
<strong>키워드 없이 변수를 선언</strong>할 경우 스코프 체인을 통해 해당하는 변수의 선언을 찾을 수 없으므로 참조 에러가 발생해야 하지만 자바스크립트 엔진이 <strong>window의 프로퍼티</strong>로 해석하여 <strong>동적으로 생성</strong>하는 것을 말한다.
이는 변수가 아닌 전역 객체의 프로퍼티이기 떄문에 <strong>호이스팅은 발생하지 않는다.</strong>
그리고 전역 객체이기때문에 함수 내에서 키워드 없이 선언하더라도, <strong>전역 스코프에서 참조</strong>할 수 있다.</p>
</blockquote>
<p><strong>let, const 키워드</strong>로 선언한 전역 변수는 <strong>Script Scope</strong>에 저장된다.</p>
<blockquote>
<p><strong>Script Scope</strong>
let이나 const로 전역변수를 선언하고 DevTools에서 이를 확인할 경우, Global Scope가 아닌 Script Scope에 변수가 저장되어있는 것을 볼 수 있다.
ES6 이전의 방식과 이후의 새로운 방식을 두 부분으로 전역 환경을 나누되, 이를 논리적으로 하나의 환경으로 간주하는 것이다. 
<a href="https://stackoverflow.com/questions/40685277/what-is-the-purpose-of-the-script-scope">https://stackoverflow.com/questions/40685277/what-is-the-purpose-of-the-script-scope</a></p>
</blockquote>
<h3 id="지역-스코프-local-scope">지역 스코프 (Local Scope)</h3>
<p>전역이 아닌 <strong>함수 내에 선언</strong>된 변수들은 지역 스코프를 가진다. </p>
<p>지역 스코프는 함수 스코프와 블록 스코프로 나누어진다.</p>
<ul>
<li><strong>함수 스코프 (Function-level Scope)</strong><ul>
<li>함수 내에서 선언한 변수는 그 함수 내에서만 접근 할 수 있다.</li>
<li>자바스크립트는 기본적으로 함수 스코프를 따른다.</li>
<li><strong>var</strong>가 이에 해당한다.</li>
</ul>
</li>
<li><strong>블록 스코프 (Block-level Scope)</strong><ul>
<li>선언된 블록 내에서만 접근 할 수 있다.</li>
<li>for문, if문, switch문 같이 <code>{,}</code> 블록이 생성되는 경우를 말한다.</li>
<li><strong>let과 const</strong>가 이에 해당한다.</li>
</ul>
</li>
</ul>
<h3 id="렉시컬정적-스코프-lexicalstatic-scope"><strong>렉시컬(=정적) 스코프 (Lexical(=Static) Scope))</strong></h3>
<p>함수가 어디서 호출되었는지가 아니라 <strong>어디서 선언</strong>하였는지에 따라 <strong>상위 스코프를 결정</strong>되는 것</p>
<pre><code class="language-jsx">var x = 1; // global

function first() {
  var x = 10;
  second();
}

function second() {
  console.log(x);
}

first(); // 1
second(); // 1</code></pre>
<p>함수 선언을 기준으로 상위 스코프가 결정되기 떄문에,</p>
<p>함수 <strong>second의 상위</strong> 스코프는 <strong>전역 스코프</strong>이고, 스코프 체인에 의해 전역 변수 x를 할당받는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Event]]></title>
            <link>https://velog.io/@js-park/Event</link>
            <guid>https://velog.io/@js-park/Event</guid>
            <pubDate>Fri, 14 Mar 2025 05:15:49 GMT</pubDate>
            <description><![CDATA[<h2 id="이벤트의-종류">이벤트의 종류</h2>
<h3 id="키보드-이벤트">키보드 이벤트</h3>
<table>
<thead>
<tr>
<th>Event</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>keydown</strong></td>
<td>사용자가 <strong>키를 눌렀을</strong> 때</td>
</tr>
<tr>
<td><strong>keyup</strong></td>
<td>사용자가 <strong>키를</strong> <strong>뗄</strong> 때</td>
</tr>
<tr>
<td><strong>keypress</strong></td>
<td>사용자가 눌렀던 키의 문자가 <strong>입력</strong>되었을 때</td>
</tr>
</tbody></table>
<h3 id="마우스-이벤트">마우스 이벤트</h3>
<table>
<thead>
<tr>
<th>Event</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>click</strong></td>
<td>사용자가 <strong>마우스를 클릭</strong>했을 때</td>
</tr>
<tr>
<td><strong>dblclick</strong></td>
<td>마우스를 <strong>더블 클릭</strong>했을 때</td>
</tr>
<tr>
<td><strong>mousedown</strong></td>
<td>마우스 버튼을 <strong>누르고 있을</strong> 때</td>
</tr>
<tr>
<td><strong>mouseup</strong></td>
<td>눌렀던 마우스 <strong>버튼을 뗄</strong> 때</td>
</tr>
<tr>
<td><strong>mousemove</strong></td>
<td>마우스가 <strong>움직였을 때</strong></td>
</tr>
<tr>
<td><strong>mouseover</strong></td>
<td><strong>요소 위로</strong> 마우스를 움직였을 때</td>
</tr>
<tr>
<td><strong>mouseout</strong></td>
<td><strong>요소 밖으로</strong> 마우스를 움직였을 때</td>
</tr>
</tbody></table>
<h3 id="폼-이벤트">폼 이벤트</h3>
<table>
<thead>
<tr>
<th>Event</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>input</strong></td>
<td>input, textarea, select 요소의 값이 <strong>변경될때마다</strong></td>
</tr>
<tr>
<td><strong>change</strong></td>
<td>input, textarea, select 요소의 값의 <strong>변경이 완료된 후</strong></td>
</tr>
<tr>
<td><strong>submit</strong></td>
<td>form을 <strong>제출</strong>할 때</td>
</tr>
<tr>
<td><strong>reset</strong></td>
<td><strong>reset 버튼</strong>을 눌렀을 때</td>
</tr>
</tbody></table>
<p><strong>input event와 change event</strong>의 공통점</p>
<p>type이 checkbox인 경우, 체크하거나 해제할 때마다 이벤트 발생</p>
<p>type이 radio인 경우, 요소가 체크될 때만 이벤트 발생</p>
<p><strong>input event와 change event</strong>의 차이점</p>
<p>텍스트 입력의 경우,</p>
<p>input event는 글자가 <strong>수정될 때마다</strong> 발생하고 </p>
<p>change event는 수정 후 <strong>커서 포커스</strong>가 <strong>밖</strong>에 있을 때 발생</p>
<h2 id="이벤트-리스너event-listener">이벤트 리스너(Event Listener)</h2>
<p>이벤트가 발생했을 때 이를 잡아내고, 지정된 함수를 실행하는 것을 Event Hanlder라 부른다.</p>
<p>자바스크립트에서는 세 가지 방법으로 이벤트를 잡아낸다.</p>
<h3 id="❌inline-event-handler">❌Inline Event Handler</h3>
<p>사용하지 않기로 하자</p>
<pre><code class="language-html">&lt;button onclick=&quot;alert(&quot;Hello&quot;)&quot;&gt; 버튼 &lt;/button&gt; </code></pre>
<p>우선 HTML 파일에 JavaScript를 동시에 작업해야하기 때문에 가독성이 나빠지며,</p>
<p>100개의 버튼이 있으면 100개의 속성을 입력해야해서 유지보수 또한 비효율적이다.</p>
<h3 id="event-handler-properties">Event Handler Properties</h3>
<p>효율적이진 않지만 사용할만하다.</p>
<pre><code class="language-jsx">btn.onclick = ( ) =&gt; {alert(&quot;Hello&quot;)};</code></pre>
<p>HTML의 속성은 property를 통해 접근할 수 있다.</p>
<p>이를 이용하면 인라인이 아니어도 script 파일에서 직접적으로 이벤트를 적용할 수 있다.</p>
<p>하지만 property를 이용하면 <strong>하나의 이벤트에 두 가지 함수를 실행할 수 없다</strong>는 단점이 있다.</p>
<pre><code class="language-jsx">element.onclick = function1; //(x)
element.onclick = function2; </code></pre>
<h3 id="️addeventlistner">‼️addEventListner</h3>
<p>가장 권장되는 방식이다.</p>
<pre><code class="language-jsx">const btn = document.querySelector(&quot;button&quot;);

btn.addEventListener(&quot;click&quot;, () =&gt; {
    alert(&quot;Hello&quot;);
})</code></pre>
<p>이 메소드는 두 개의 매개변수를 가지는데, </p>
<p>첫 번째는 <strong>어떤 이벤트</strong>가 발생하면 함수를 실행할지를 나타내는 <strong>문자열</strong>이고</p>
<p>두 번째는 이벤트 발생 후 <strong>실행될 콜백 함수</strong>이다.</p>
<p>추가로 하나의 이벤트에 두 개 이상의 Listener를 등록할 수 있다.</p>
<pre><code class="language-jsx">btn.addEventListener(&quot;click&quot;, functionA);
btn.addEventListener(&quot;click&quot;, functionB);</code></pre>
<p>이미 등록된 listener를 삭제하는 방법도 있다.</p>
<pre><code class="language-jsx">btn.removeEventListener(&quot;click&quot;, changeBackground);</code></pre>
<h2 id="event-object">Event Object</h2>
<p>event handler를 사용하다보면 콜백 함수에 <code>event</code> <code>evt</code> <code>e</code> 를 매개변수로 사용하는 경우가 있는데 이를 <strong>이벤트 객체</strong>라고 부른다.</p>
<p>처음부터 handler에 바로 주어지며, 이 객체는 여러 기능과 정보를 담고 있다.</p>
<p>가장 많이 쓰는 예로는 아래와 같이 있다.</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>e.target</strong></td>
<td>이벤트가 위임되어 <strong>발생하는 자식</strong>의 위치/<strong>내가 클릭한 자식</strong> 요소를 반환</td>
</tr>
<tr>
<td><strong>e.currentTarget</strong></td>
<td><strong>이벤트 핸들러가 부착</strong>된 요소를 반환</td>
</tr>
<tr>
<td><strong>e.preventDefault()</strong></td>
<td>브라우저의 <strong>기본 동작을 차단</strong></td>
</tr>
<tr>
<td><strong>e.stopPropagation()</strong></td>
<td>이벤트의 <strong>버블링 단계가 진행되지 않도록</strong> 차단</td>
</tr>
</tbody></table>
<h2 id="event-bubbling--capturing">Event Bubbling &amp; Capturing</h2>
<p><img src="https://velog.velcdn.com/images/js-park/post/c1cd97d6-dd72-4b63-8900-ae07da79b4a7/image.png" alt=""></p>
<p>이벤트가 자식으로부터 부모로 위임되는 것을 <strong>Bubbling</strong>이라고 하고,</p>
<p>부모로부터 자식으로 위임되는 것을 <strong>capturing</strong>이라고 부른다.</p>
<p><strong>Bubbling(버블링)</strong></p>
<pre><code class="language-html">&lt;body&gt;
  &lt;div id=&quot;container&quot;&gt;
    &lt;button&gt;Click me!&lt;/button&gt;
  &lt;/div&gt;
  &lt;pre id=&quot;output&quot;&gt;&lt;/pre&gt;
&lt;/body&gt;</code></pre>
<pre><code class="language-jsx">const output = document.querySelector(&quot;#output&quot;);
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}

const container = document.querySelector(&quot;#container&quot;);
const button = document.querySelector(&quot;button&quot;);

document.body.addEventListener(&quot;click&quot;, handleClick);
container.addEventListener(&quot;click&quot;, handleClick);
button.addEventListener(&quot;click&quot;, handleClick);</code></pre>
<p><code>body, container, button</code> 모두 click event를 가지고 있는데, 버튼을 클릭하면</p>
<p><strong>You clicked on a BUTTON element
You clicked on a DIV element
You clicked on a BODY element</strong></p>
<p><strong>자식부터 부모 순</strong>으로 이벤트가 발생하는데 </p>
<p>이를 <strong>비눗방울</strong>이 떠오르는 것처럼 표현하여 bubbling이라 말한다.</p>
<p>버블링을 강제로 중단시키고 싶다면, <strong><code>event.stopPropagation()</code></strong>을 이용하면된다. 하지만 꼭 필요한 경우가 아니라면 사용하지 않는 것이 좋다.</p>
<aside>

<p><strong>capturing</strong>은 실무에서 거의 쓰이지 않기 때문에 간단하게만 알아두자</p>
<p><strong><code>addEventListener</code></strong>의 기본 동작은 버블링이고,</p>
<p>캡처링을 사용하려면 이벤트 리스너의 <strong>세번째</strong> 인자로 <code>true</code> 를 전달해야한다.</p>
<p>그럴 경우 아래 그림과 같이 Capturing → Target → Bubbling 순으로 실행된다.</p>
</aside>]]></description>
        </item>
        <item>
            <title><![CDATA[Execution Context]]></title>
            <link>https://velog.io/@js-park/Execution-Context</link>
            <guid>https://velog.io/@js-park/Execution-Context</guid>
            <pubDate>Fri, 14 Mar 2025 05:11:52 GMT</pubDate>
            <description><![CDATA[<h2 id="실행-컨텍스트excution-context의-정의">실행 컨텍스트(Excution Context)의 정의</h2>
<ul>
<li>자바스크립트 코드가 <strong>내부적으로 실행되는 환경</strong>이다</li>
<li>실행할 코드에 제공할 <strong>환경 정보</strong>들을 모아놓은 객체</li>
</ul>
<aside>

<p>실행 컨텍스트는 <code>Closure, Hoisting, Scope, This</code> 와 같은 주요 동작 원리를 담고 있는 JavaScript 엔진의 핵심 원리이기 때문에, 반드시 공부해두자</p>
</aside>

<h2 id="실행-컨텍스트의-종류">실행 컨텍스트의 종류</h2>
<p><img src="https://velog.velcdn.com/images/js-park/post/63289d8e-30e8-4606-83ca-c00dd2963ebd/image.png" alt=""></p>
<ul>
<li><strong>전역 실행 컨텍스트(Global Execution Context) :</strong><ul>
<li><strong>전역에 존재</strong>하는 소스코드를 실행한다.</li>
<li>함수 안에서 실행되는 코드가 아니라면 모두 여기서 실행된다고 보면 된다.</li>
<li>브라우저의 경우, <strong>window 객체</strong>가 이에 해당한다.</li>
</ul>
</li>
<li><strong>함수 실행 컨텍스트(Function Execution Context) :</strong><ul>
<li><strong>함수 내부</strong>에 존재하는 소스코드를 실행한다.</li>
<li>선언된 함수가 <strong>호출이 될 때 생성</strong>이 되고, 함수가 <strong>종료되면 소멸</strong>된다.</li>
</ul>
</li>
<li><strong>Eval Function Execution Context :</strong><ul>
<li>빌트인 전역 함수인 eval 함수로 실행되는 소스코드를 실행한다.</li>
</ul>
</li>
</ul>
<h2 id="실행-컨텍스트의-단계">실행 컨텍스트의 단계</h2>
<p>자바스크립트 엔진은 소스 코드를 두 가지 과정으로 나누어 처리한다.</p>
<p>기본적으로 가장 먼저 <strong>전역 실행 컨텍스트</strong>를 생성한다. (window 객체)</p>
<h3 id="creation-phase">Creation Phase</h3>
<ol>
<li>메모리에 변수와 함수를 저장한다.</li>
<li>변수는 <strong>undefined</strong>를 값으로, 함수는 <strong>함수 참조</strong>를 저장한다.</li>
</ol>
<aside>


<p><strong>함수 선언식</strong>은 저장되지만, <strong>함수 표현식</strong>은 저장되지 않는다.</p>
<p><strong>var 변수</strong>는 <strong>선언과 초기화가 동시</strong>에 이뤄지기 때문에, undefined가 아닌 해당 값이 바로 초기화된다.</p>
</aside>

<p><img src="https://velog.velcdn.com/images/js-park/post/4ef1be50-f282-4ae3-a534-421c4a877cf0/image.png" alt=""></p>
<h3 id="excution-phase">Excution Phase</h3>
<ol>
<li><strong>위에서 아래</strong>로 코드를 순차적으로 실행한다.</li>
<li>변수가 <strong>초기화 또는 할당</strong>되면 값을 넣는다.</li>
<li>함수 선언식은 건너뛰고, 함수가 <strong>호출</strong>되면 <strong>함수 컨텍스트</strong>를 생성한다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/js-park/post/fd98df24-1835-48bc-9b0f-b916aeffa377/image.png" alt=""></p>
<ol>
<li>함수 내의 <strong>변수나 내부함수</strong>는 함수 컨텍스트 내부에 저장된다.</li>
<li>함수가 <strong>종료</strong>되거나 값을 <strong>반환</strong>하면 함수 컨텍스트는 종료된다.</li>
<li><strong>모든 코드가 끝이나면</strong>, 실행 컨텍스트 또한 종료된다.</li>
</ol>
<p><strong>이는 모든 실행 컨텍스트에서 동일하게 진행된다.</strong></p>
<h2 id="실행-컨텍스트의-구성">실행 컨텍스트의 구성</h2>
<h3 id="변수-객체variable-object">변수 객체(Variable Object)</h3>
<ul>
<li><strong>함수의 인자, 변수, 그리고 선언된 함수</strong>들이 저장된다.</li>
<li>함수 인자는 해당 함수의 실행 컨텍스트 안에서만 유효하며 함수가 실행되는 동안에만 존재한다.</li>
</ul>
<h3 id="스코프-체인scope-chain">스코프 체인(Scope Chain)</h3>
<ul>
<li>현재 실행 컨텍스트에서 <strong>접근할 수 있는 변수</strong>들의 구조</li>
<li>내부 함수에서 변수를 탐색할 때, 함수의 계층적 구조에 따라 <strong>내부 함수부터</strong> <strong>외부 함수, 전역 스코프를 단계적으로 탐색</strong>하는 과정</li>
</ul>
<h3 id="this-binding">this binding</h3>
<ul>
<li><code>this</code>는 현재 컨텍스트를 가리킨다.</li>
</ul>
<h2 id="콜-스택call-stack">콜 스택(Call Stack)</h2>
<ul>
<li>실행 컨텍스트는 콜 스택이라는 자료 구조에 의해 관리된다.</li>
<li>함수가 실행되면 해당 <strong>함수에 대한 실행 컨텍스트</strong>를 생성한 뒤 <strong>콜스택</strong>에 담는다.</li>
<li><strong>LIFO(Last-In-First-Out)</strong></li>
</ul>
<pre><code class="language-jsx">function funcA(m,n) {
    return m * n;
}

function funcB(m,n) {
    return funcA(m,n);
}

function getResult(num1, num2) {
    return funcB(num1, num2)
}

var res = getResult(5,6);

console.log(res); // 30
</code></pre>
<p><img src="https://velog.velcdn.com/images/js-park/post/f3067d3d-510c-4b72-a4ea-f1963ba02a22/image.png" alt=""></p>
<ol>
<li>가장 먼저 <strong>전역 실행 컨텍스트</strong>가 생성된다.</li>
<li>funcA, funcB, getResult 함수와 변수 res가 메모리에 저장된다. <strong>[Creation Phase]</strong></li>
<li>getResult() 함수가 호출되고, <strong>함수 실행 컨텍스트</strong>가 콜 스택에 push된다. <strong>[Excution Phase]</strong></li>
<li>내부 함수 funcB()가 호출되고, 콜 스택에 push된다.</li>
<li>내부 함수 funcA()가 호출되고, 콜 스택에 push된다.</li>
<li>각 함수의 실행이 종료되면 <strong>반환값을 상위 함수에 전달</strong>하고, 실행 컨텍스트는 pop되어 사라진다.</li>
<li>모든 함수 실행 컨텍스트가 종료되면 변수 res에 최종 반환값이 저장되고 이를 출력한다.</li>
<li>마지막으로 <strong>페이지를 나가거나 브라우저를 종료</strong>하면 <strong>전역 실행 컨텍스트</strong>가 종료된다.</li>
</ol>
<h3 id="참조">참조</h3>
<p><a href="https://www.datoybi.com/execution-context/">https://www.datoybi.com/execution-context/</a></p>
<p><a href="https://www.nextree.io/execution-context/">https://www.nextree.io/execution-context/</a></p>
<p><a href="https://www.freecodecamp.org/news/how-javascript-works-behind-the-scene-javascript-execution-context/">https://www.freecodecamp.org/news/how-javascript-works-behind-the-scene-javascript-execution-context/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS-Margin Collapsing]]></title>
            <link>https://velog.io/@js-park/MarginCollapsing</link>
            <guid>https://velog.io/@js-park/MarginCollapsing</guid>
            <pubDate>Thu, 06 Mar 2025 09:10:00 GMT</pubDate>
            <description><![CDATA[<p><code>css</code>를 쓰다 보니,
<code>Block</code> 타입 요소 간의 <code>margin</code>이 겹치는 경우가 있다.</p>
<pre><code>/* html */
&lt;div class=&quot;margin_collapse&quot;&gt;
   &lt;div class=&quot;block_box&quot;&gt;Block&lt;/div&gt;
   &lt;div class=&quot;block_box&quot;&gt;Block&lt;/div&gt;
   &lt;div class=&quot;block_box&quot;&gt;Block&lt;/div&gt;
&lt;/div&gt;

/* css */
.block_box {
    width: 100px;
    height: 100px;
    margin: 50px;
    border: 1px solid #000;
    text-align: center;
}</code></pre><p>위와 같이, 세 개의 <code>div</code> 요소에 <code>margin</code> 값을 똑같이 <code>50px</code>로 주었는데 결과를 보면</p>
<p><img src="https://velog.velcdn.com/images/js-park/post/417cfbc4-6af6-44c7-b72b-23bc81dd89c9/image.png" alt=""></p>
<p><code>margin</code>의 범위가 합쳐져 <code>100px</code>이 아닌 <code>50px</code>만큼 떨어져 있는 것을 확인할 수 있다.</p>
<p>이 현상을 <strong>마진 병합(margin collapsing)</strong>이라고 한다.</p>
<p><code>Block</code> 타입 요소들이 수직 방향으로 배치될 때 발생하는데
상위 요소와 하위 요소의 <code>margin</code>이 겹칠 경우, <strong>둘 중 더 큰 값만 적용</strong>되고 작은 값은 무시된다.</p>
<h3 id="특징">특징</h3>
<p>1) <strong>수직 방향</strong>일 때만 발생한다.</p>
<p>2) 오직 <strong>인접한</strong> 요소들 사이에서 발생한다.
-<code>&lt;/br&gt;</code>태그가 요소 사이에 끼어있다면 보이지 않더라도 병합이 발생하지 않는다.</p>
<p>3) 두 <code>margin</code> 사이에 <strong><code>border, padding, inline 컨텐츠, height, min-height, max-height</code></strong> 중 하나라도 존재한다면 발생하지 않는다.</p>
<blockquote>
<p>같은 방식으로 부모 요소에 위의 컨텐츠가 단 하나라도 없는 경우, 부모의 <code>margin</code>과 자식의 <code>margin</code>이 병합되고 병합된 여백은 부모 요소 바깥에 위치한다.</p>
</blockquote>
<pre><code>&lt;style&gt;
  p {
    margin-top: 48px;
    margin-bottom: 48px;
  }
&lt;/style&gt;

&lt;div&gt;
  &lt;p&gt;Paragraph One&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Paragraph Two&lt;/p&gt;</code></pre><p><img src="https://velog.velcdn.com/images/js-park/post/b1f5f0a8-1fd0-4844-aeb7-27b108b0763f/image.png" alt=""></p>
<p>5) <strong>같은 방향</strong>의 <code>margin</code>끼리도 병합될 수 있다.</p>
<pre><code>&lt;style&gt;
  .parent {
    margin-top: 72px;
  }

  .child {
    margin-top: 24px;
  }
&lt;/style&gt;

&lt;div class=&quot;parent&quot;&gt;
  &lt;p class=&quot;child&quot;&gt;Paragraph One&lt;/p&gt;
&lt;/div&gt;</code></pre><p><img src="https://velog.velcdn.com/images/js-park/post/1e7d8db7-71ae-45c8-8241-31feae3acaca/image.png" alt=""></p>
<p>6) <strong>3개 이상</strong>의 <code>margin</code> 도 병합될 수 있다.</p>
<p>7) <strong>음수</strong> <code>margin</code>이 병합될 때는 <strong>절대값이 더 큰 값</strong>만 적용된다.</p>
<p>8) 만약 <strong>음수와 양수</strong> <code>margin</code>이 병합된다면 서로 <strong>상쇄된 값</strong>이 남는다.</p>
<h3 id="참조">참조</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_box_model/Mastering_margin_collapsing">MDN_Web_Docs</a></p>
<p><a href="https://www.joshwcomeau.com/css/rules-of-margin-collapse/">https://www.joshwcomeau.com/css/rules-of-margin-collapse/</a></p>
]]></description>
        </item>
    </channel>
</rss>