← Blog
면접 준비

프론트엔드 면접 예상 질문 & 모범답안

핵심만 압축해서 정리했습니다. 각 답변은 "면접에서 말로 설명한다"는 가정으로 작성되었습니다.


1. JavaScript 핵심

Q. 클로저(Closure)란?

함수가 선언될 당시의 렉시컬 환경(스코프)을 기억하여, 함수가 외부 스코프 밖에서 실행되어도 그 변수에 접근할 수 있는 특성입니다. 함수와 그 함수가 선언된 환경의 조합이라고 할 수 있습니다.

활용: 데이터 은닉(private 변수), 상태 유지(카운터), 콜백/이벤트 핸들러에서 특정 값 캡처.

function counter() {
  let count = 0;
  return () => ++count; // count를 기억함
}
const c = counter();
c(); // 1
c(); // 2

주의: 반복문에서 var로 클로저를 만들면 모든 클로저가 같은 변수를 참조해 버그가 생깁니다(let으로 해결).

Q. 호이스팅(Hoisting)이란?

변수/함수 선언이 스코프 최상단으로 끌어올려진 것처럼 동작하는 현상입니다. 실제로 코드가 이동하는 게 아니라, 실행 컨텍스트 생성 단계에서 선언이 먼저 메모리에 등록되기 때문입니다.

  • var: 선언이 호이스팅되고 undefined로 초기화됨
  • let/const: 호이스팅은 되지만 초기화 전 접근 시 에러 → TDZ(Temporal Dead Zone)
  • 함수 선언문: 함수 전체가 호이스팅됨 / 함수 표현식은 변수 규칙 따름

Q. this 바인딩 규칙은?

this는 함수가 "어떻게 호출되는가"에 따라 결정됩니다.

  1. 일반 함수 호출 → 전역 객체(strict mode에서는 undefined)
  2. 메서드 호출 → 메서드를 소유한 객체
  3. 생성자 호출(new) → 새로 생성된 인스턴스
  4. call/apply/bind → 명시적으로 지정한 객체
  5. 화살표 함수 → 자신의 this가 없고, 선언된 위치의 상위 스코프 this를 그대로 사용(렉시컬)

Q. call, apply, bind 차이는?

셋 다 this를 명시적으로 지정합니다.

  • call(thisArg, arg1, arg2): 인자를 나열해서 즉시 호출
  • apply(thisArg, [args]): 인자를 배열로 받아 즉시 호출
  • bind(thisArg): 호출하지 않고 this가 고정된 새 함수를 반환

Q. 이벤트 루프와 마이크로태스크/매크로태스크?

JS는 싱글 스레드지만 이벤트 루프 덕분에 비동기를 처리합니다. 콜 스택이 비면 이벤트 루프가 태스크 큐에서 작업을 꺼내 실행합니다.

  • 매크로태스크: setTimeout, setInterval, I/O, 렌더링
  • 마이크로태스크: Promise.then, queueMicrotask, MutationObserver

우선순위가 핵심입니다. 현재 실행이 끝나면 마이크로태스크 큐를 전부 비운 뒤 매크로태스크 하나를 처리합니다.

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 출력: 1, 4, 3, 2

Q. 프로토타입(Prototype)이란?

JS는 프로토타입 기반 언어입니다. 모든 객체는 [[Prototype]] 내부 슬롯으로 다른 객체(프로토타입)를 가리키며, 객체에서 프로퍼티를 찾을 때 없으면 프로토타입 체인을 따라 올라가며 탐색합니다. 이를 통해 상속과 메서드 공유를 구현합니다.

Q. 얕은 복사 vs 깊은 복사?

  • 얕은 복사: 한 단계만 복사, 중첩 객체는 참조 공유 ({...obj}, Object.assign, slice)
  • 깊은 복사: 모든 단계를 새로 복사, 참조 끊김 (structuredClone(), JSON.parse(JSON.stringify()) — 단, 함수·undefined·순환참조 처리 불가)

Q. var / let / const 차이?

varletconst
스코프함수블록블록
재선언OXX
재할당OOX
호이스팅undefined 초기화TDZTDZ

Q. 디바운스 vs 스로틀?

둘 다 이벤트 호출 빈도를 제어합니다.

  • 디바운스(Debounce): 마지막 호출 후 일정 시간이 지나야 실행 (검색 자동완성)
  • 스로틀(Throttle): 일정 시간 간격으로 최대 한 번만 실행 (스크롤, 리사이즈)

Q. 이벤트 위임(Event Delegation)이란?

자식 요소 각각에 핸들러를 다는 대신, 부모에 하나만 등록하고 이벤트 버블링을 이용해 처리하는 패턴입니다. 동적으로 추가되는 요소도 처리할 수 있고 메모리도 절약됩니다. 버블링(자식→부모)과 캡처링(부모→자식) 단계를 이해하면 됩니다.


2. 브라우저 & 네트워크

Q. 브라우저 렌더링 과정은?

  1. HTML 파싱 → DOM 트리 생성
  2. CSS 파싱 → CSSOM 트리 생성
  3. DOM + CSSOM 결합 → 렌더 트리 (화면에 보이는 것만)
  4. 레이아웃(Reflow): 각 요소의 위치·크기 계산
  5. 페인트(Paint): 픽셀로 그리기
  6. 컴포지팅: 레이어를 합성해 최종 화면 출력

JS는 DOM 파싱을 막을 수 있어서 async/defer로 로딩을 제어합니다.

Q. Reflow vs Repaint?

  • Reflow(레이아웃): 요소의 크기·위치가 바뀌어 레이아웃을 다시 계산 (비용 큼)
  • Repaint: 위치는 그대로지만 색상 등 외형만 다시 그림

최적화: 레이아웃을 유발하는 속성(width, top 등) 대신 transform, opacity 사용(컴포지터에서 처리되어 reflow/repaint 회피). DOM 변경은 모아서 한 번에.

Q. Cookie / LocalStorage / SessionStorage 차이?

CookieLocalStorageSessionStorage
용량~4KB~5-10MB~5-10MB
만료설정 가능영구탭 닫으면 삭제
서버 전송매 요청마다 자동안 됨안 됨
용도인증 토큰, 세션지속 데이터일시적 데이터

Q. CORS란? 어떻게 해결하나?

브라우저의 동일 출처 정책(Same-Origin Policy) 때문에 다른 출처(프로토콜+도메인+포트)로의 요청이 제한되는데, 서버가 Access-Control-Allow-Origin 등의 헤더로 허용하면 통신 가능합니다.

  • 단순 요청이 아니면 브라우저가 먼저 OPTIONS로 Preflight 요청을 보냄
  • 해결: 서버에서 CORS 헤더 설정(정석), 개발 중엔 프록시 서버 사용

Q. 브라우저에 URL을 입력하면 무슨 일이?

  1. URL 파싱
  2. DNS 조회로 IP 획득
  3. TCP 연결(+ HTTPS면 TLS 핸드셰이크)
  4. HTTP 요청 전송
  5. 서버 응답 수신
  6. 브라우저 렌더링(위 과정)

Q. CSR / SSR / SSG 차이?

  • CSR(Client-Side Rendering): 빈 HTML + JS로 클라이언트에서 렌더. 초기 로딩 느리고 SEO 불리, 이후 인터랙션은 빠름
  • SSR(Server-Side Rendering): 서버에서 완성된 HTML 생성. 초기 로딩·SEO 유리, 서버 부하 있음. 하이드레이션으로 JS 연결
  • SSG(Static Site Generation): 빌드 시 HTML 미리 생성. 가장 빠르고 SEO 좋지만 데이터가 자주 바뀌면 부적합

Q. HTTP/2와 HTTP/3의 개선점?

  • HTTP/1.1: 연결당 순차 처리, HOL Blocking 문제
  • HTTP/2: 멀티플렉싱(한 연결에 여러 요청 동시), 헤더 압축, 서버 푸시
  • HTTP/3: TCP 대신 QUIC(UDP 기반) 사용 → TCP HOL Blocking 해결, 연결 수립 빠름

Q. 캐싱 전략?

  • Cache-Control: max-age, no-cache, no-store 등으로 캐시 정책 지정
  • ETag: 리소스 버전 식별자. 변경 없으면 304 Not Modified 반환해 트래픽 절약
  • 정적 자산은 파일명에 해시를 붙여 강한 캐싱 + 변경 시 무효화

3. CSS

Q. Box Model이란?

모든 요소는 content → padding → border → margin 순의 박스로 구성됩니다. box-sizing: border-box를 쓰면 width에 padding·border가 포함되어 크기 계산이 직관적입니다(기본값은 content-box).

Q. Flexbox vs Grid?

  • Flexbox: 1차원(행 또는 열) 레이아웃. 콘텐츠 정렬·분배에 강함
  • Grid: 2차원(행과 열 동시) 레이아웃. 복잡한 페이지 구조에 적합

Q. position 속성?

  • static: 기본값
  • relative: 자기 원래 위치 기준 이동, 공간 유지
  • absolute: 가장 가까운 positioned 조상 기준, 공간 차지 안 함
  • fixed: 뷰포트 기준 고정
  • sticky: 스크롤하다 임계점에서 fixed처럼 고정

Q. 선택자 우선순위(Specificity)?

인라인 스타일 > id > class/속성/가상클래스 > 태그. 같은 우선순위면 나중에 선언된 것이 적용. !important는 이를 덮어쓰지만 남용은 지양.

Q. margin collapsing(마진 병합)이란?

수직으로 인접한 블록 요소의 margin이 합쳐지지 않고 더 큰 값 하나로 병합되는 현상입니다. flex/grid 컨테이너 내부나 padding/border가 사이에 있으면 발생하지 않습니다.


4. React

Q. Virtual DOM과 동작 원리?

실제 DOM을 추상화한 JS 객체입니다. 상태가 바뀌면 새 가상 DOM을 만들고, 이전 것과 비교(diffing)해 바뀐 부분만 실제 DOM에 반영(reconciliation)합니다. 실제 DOM 조작은 비싸기 때문에 이를 최소화하는 게 목적입니다.

Q. reconciliation과 key의 역할?

React는 diffing 시 휴리스틱을 씁니다: 타입이 다르면 통째로 교체, 같으면 속성만 업데이트. 리스트에서는 key로 각 요소의 동일성을 판단합니다. 그래서 index를 key로 쓰면 순서 변경 시 잘못된 재사용으로 버그가 생길 수 있어 고유 id를 권장합니다.

Q. useEffect의 동작과 의존성 배열?

렌더링 이후 실행되는 사이드 이펙트 훅입니다.

  • 의존성 배열 []: 마운트 시 1회
  • [a, b]: a나 b가 바뀔 때마다 실행
  • 생략: 매 렌더마다 실행
  • return 함수: 클린업(언마운트 또는 다음 이펙트 전 실행)

Q. useMemo vs useCallback?

  • useMemo: 계산 결과(값)를 메모이제이션
  • useCallback: 함수 자체를 메모이제이션 (useMemo(() => fn, deps)와 동일)

자식 컴포넌트에 props로 함수를 넘길 때 불필요한 리렌더를 막기 위해 사용. 다만 무분별한 사용은 오히려 오버헤드이므로 실제 성능 문제가 있을 때 적용합니다.

Q. 리렌더링은 언제 발생하나? 최적화는?

state/props 변경, 부모 리렌더 시 발생합니다. 최적화:

  • React.memo로 props 안 바뀌면 리렌더 스킵
  • useMemo/useCallback으로 참조 안정화
  • state를 필요한 곳으로 내려 영향 범위 축소
  • 리스트에 적절한 key

Q. Hooks 규칙과 그 이유?

최상위에서만 호출하고, 조건문·반복문 안에서 호출하면 안 됩니다. React가 훅을 호출 순서로 식별하기 때문에 순서가 매번 같아야 상태가 올바르게 매칭됩니다.

Q. 상태 관리 라이브러리는 언제?

prop drilling이 심하거나 전역 상태(인증, 테마, 캐시)가 여러 컴포넌트에 필요할 때. Context는 간단한 전역 값에, Redux/Zustand 등은 복잡한 상태·비동기 흐름에. 서버 상태는 React Query 같은 도구가 적합합니다.


5. 성능 최적화

Q. Core Web Vitals?

  • LCP(Largest Contentful Paint): 가장 큰 콘텐츠 렌더 시간 (로딩) — 2.5초 이내
  • INP(Interaction to Next Paint): 상호작용 반응성 (FID 대체) — 200ms 이내
  • CLS(Cumulative Layout Shift): 레이아웃 이동 정도 (시각 안정성) — 0.1 이하

Q. 번들 사이즈를 줄이는 방법?

  • 코드 스플리팅 + lazy loading(React.lazy, dynamic import)
  • 트리 쉐이킹(사용 안 하는 코드 제거, ESM 기반)
  • 라이브러리 경량화, 필요한 모듈만 import
  • 이미지 최적화(WebP, lazy loading, 적절한 크기)
  • gzip/brotli 압축

6. 보안

Q. XSS와 방어?

악성 스크립트를 페이지에 주입하는 공격입니다. 방어: 사용자 입력 이스케이프/sanitize, React는 기본적으로 이스케이프하지만 dangerouslySetInnerHTML 주의, CSP(Content Security Policy) 헤더 적용.

Q. CSRF와 방어?

사용자가 인증된 상태를 악용해 의도치 않은 요청을 보내게 하는 공격입니다. 방어: CSRF 토큰, SameSite 쿠키 속성, Referer 검증.


7. TypeScript (간단)

Q. interface vs type?

대부분 호환되지만, interface는 선언 병합(declaration merging)이 가능하고 확장(extends)에 적합, type은 유니온·인터섹션·유틸리티 타입 등 더 유연한 표현이 가능합니다.

Q. 자주 쓰는 유틸리티 타입?

Partial<T>(모두 옵셔널), Required<T>, Pick<T, K>, Omit<T, K>, Record<K, V>, Readonly<T>.


면접 팁: 답을 외우기보다 "왜 그런가"를 설명할 수 있어야 합니다. 꼬리 질문(왜? 어떻게 동작? 트레이드오프는?)에 대비하세요.