JavaScript 가이드
언어 내부, 런타임, 프레임워크 — 코드 레벨로 동작 원리 정리
⚙️ 언어 내부
이벤트 루프 — setTimeout(fn, 0)이 즉시 실행되지 않는 이유
Call Stack, Task Queue, Microtask Queue의 실행 순서
JavaScript는 싱글 스레드인데 비동기가 되는 이유: 이벤트 루프가 Call Stack이 비었을 때 Task Queue에서 콜백을 꺼내서 실행하기 때문. Promise의 then은 Microtask Queue에 들어가서 일반 Task보다 먼저 실행된다.
클로저와 스코프 체인 — 함수가 외부 변수를 기억하는 원리
Lexical Environment 객체가 만드는 스코프 체인의 내부 구조
클로저는 함수가 생성된 시점의 Lexical Environment를 캡처해서 보존하는 것이다. 함수가 외부 스코프의 변수를 참조하면, 그 Lexical Environment 객체가 가비지 컬렉션되지 않고 살아남는다.
프로토타입 체인 — class가 없던 시절의 상속
__proto__, prototype, Object.create()의 관계
JavaScript의 class는 문법적 설탕이다. 내부적으로 프로토타입 체인으로 동작한다. 객체의 __proto__가 부모 객체를 가리키고, 프로퍼티를 못 찾으면 체인을 따라 올라간다.
Promise 내부 — then()이 Microtask Queue에 들어가는 과정
Promise의 3가지 상태와 thenable 체이닝의 실행 메커니즘
Promise는 pending/fulfilled/rejected 3가지 상태를 가진 상태 머신이다. resolve() 호출 시 then에 등록된 콜백이 Microtask Queue에 들어간다. async/await는 이 Promise의 문법적 설탕.
🔷 TypeScript
TypeScript 타입 시스템 — 컴파일 후 전부 사라진다
구조적 타이핑(Structural Typing)이 뭔지, 왜 Java의 명목적 타이핑과 다른지
TypeScript의 타입은 컴파일 시점에만 존재하고, 런타임 JavaScript에는 흔적도 남지 않는다. Java와 달리 "이름"이 아닌 "구조"로 타입 호환성을 판단한다(Structural Typing).
TypeScript 제네릭 패턴 — T가 뭔지 한 번에 이해하기
함수/클래스/인터페이스에서 "나중에 결정되는 타입"을 쓰는 법
T는 "아직 모르는 타입"의 자리표시자다. 함수를 호출하는 시점에 T가 구체 타입으로 결정된다. 제네릭 없이는 any를 쓰게 되고, any를 쓰면 TypeScript를 쓰는 의미가 없다.
판별 유니언 — TypeScript에서 enum 대신 쓰는 패턴
type 필드로 분기하면 TypeScript가 각 분기의 타입을 자동으로 좁혀준다
공통 필드(discriminant)로 유니언 타입을 구분하는 패턴. switch/if로 분기하면 TypeScript가 해당 분기에서 타입을 자동으로 좁혀준다. Rust의 enum + match와 비슷한 효과.
🟢 Node.js
Node.js 이벤트 루프 — 브라우저와 다른 6단계 페이즈
timers → pending → idle → poll → check → close, 그리고 process.nextTick의 위치
Node.js의 이벤트 루프(libuv)는 브라우저와 다르게 6개 페이즈를 순회한다. setTimeout은 timers 페이즈, setImmediate은 check 페이즈, process.nextTick은 모든 페이즈 사이에 실행.
Node.js Streams — 대용량 데이터를 메모리 폭발 없이 처리하는 법
Readable, Writable, Transform + backpressure의 동작 원리
10GB 파일을 fs.readFile()로 읽으면 메모리가 터진다. Stream은 데이터를 chunk 단위로 흘려보내서 메모리를 일정하게 유지한다. Backpressure는 소비자가 느릴 때 생산자를 멈추는 메커니즘.
ESM vs CommonJS — require와 import가 다른 이유
동기 로딩 vs 비동기 로딩, 그리고 "type": "module"의 의미
CommonJS(require)는 동기 로딩, ESM(import)은 비동기 로딩. Node.js에서 두 시스템이 공존하면서 생기는 호환성 문제와 해결법.
🌐 브라우저 API
Web Workers — JavaScript에서 멀티스레드를 쓰는 법
postMessage의 구조화된 복제(Structured Clone)와 SharedArrayBuffer
Web Worker는 메인 스레드와 별도의 스레드에서 JavaScript를 실행한다. DOM 접근 불가, postMessage로 통신. 무거운 계산을 Worker에 넘기면 UI가 안 멈춘다.
Service Worker 생명주기 — install, activate, fetch의 순서
PWA의 핵심, 오프라인 캐시가 동작하는 메커니즘
Service Worker는 브라우저와 네트워크 사이에 프록시로 동작한다. install → activate → fetch 순서로 생명주기가 진행되며, Cache API로 리소스를 저장해서 오프라인에서도 앱이 작동하게 만든다.
Intersection Observer — 스크롤 이벤트 없이 요소 가시성 감지
lazy loading, 무한 스크롤, 애니메이션 트리거의 성능 좋은 구현 방법
Intersection Observer는 요소가 뷰포트에 들어오거나 나갈 때 콜백을 실행한다. scroll 이벤트 + getBoundingClientRect()보다 성능이 좋고, 브라우저가 최적화된 타이밍에 실행해준다.
Popover API — JavaScript 없이 툴팁을 만들 수 있게 된 이유
popover 속성 하나로 열기/닫기, Esc 처리, 접근성이 자동으로 동작하는 브라우저 네이티브 UI
기존 툴팁은 이벤트 리스너, 상태 관리, ARIA 속성 수동 동기화가 전부 필요했다. Popover API는 이걸 브라우저 네이티브로 대체한다. popover 속성과 popovertarget만으로 열기/닫기, Esc 키, 키보드 내비게이션이 자동 동작한다.
🔬 오픈소스 분석
background-removal-js — 브라우저에서 배경 제거가 돌아가는 진짜 구조
IS-Net ONNX 모델 + WASM 추론 + Canvas API, 서버 없이 클라이언트에서 완결되는 파이프라인
imgly의 background-removal-js는 이미지를 넣으면 배경이 투명한 PNG가 나오는 라이브러리다. ONNX Runtime WASM으로 브라우저 안에서 IS-Net 모델을 돌린다. 서버 불필요. Star 7천개.
OpenGenerativeUI — Claude의 시각 자료 생성을 오픈소스로 재현한 구조
CopilotKit Deep Agents + LangGraph + 샌드박스 iframe, AI가 차트·3D·다이어그램을 실시간 생성하는 파이프라인
CopilotKit이 Claude의 인터랙티브 시각 자료 생성 기능을 오픈소스로 구현했다. Next.js 16 프론트엔드 + Python LangGraph 에이전트가 HTML/SVG/Chart.js/Three.js 코드를 생성하고, 샌드박스 iframe에서 렌더링한다. MIT 라이선스. Star 1.1K.