패스잇

프론트엔드 개발

JavaScript 면접 질문

클로저, 이벤트 루프, 프로토타입, this 바인딩, 비동기 처리 — JavaScript 면접의 단골 주제는 언어의 동작 방식을 정확히 이해하고 있는지를 봅니다. 헷갈리기 쉬운 개념을 예시와 모범답안으로 짚어 드립니다.

총 21문제 · 기초 7 · 중급 7 · 심화 7 · 모범답안 포함

JavaScript 면접 질문 — 기초

Q1 기초

JavaScript의 호이스팅(Hoisting)이란 무엇이며, var, let, const의 차이점은?

힌트 · TDZ(Temporal Dead Zone)와 스코프 차이를 생각해보세요.

"네, JavaScript에서 호이스팅은 선언된 변수나 함수가 코드 실행 전에 해당 스코프의 최상단으로 끌어올려지는 것처럼 보이는 현상을 말합니다. 실제로 변수가 물리적으로 이동하는 것은 아니고, JavaScript…

전체 모범답안 펼치기

"네, JavaScript에서 호이스팅은 선언된 변수나 함수가 코드 실행 전에 해당 스코프의 최상단으로 끌어올려지는 것처럼 보이는 현상을 말합니다. 실제로 변수가 물리적으로 이동하는 것은 아니고, JavaScript 엔진이 코드를 실행하기 전에 변수와 함수 선언을 먼저 처리하기 때문에 발생하는 개념입니다.

var, let, const는 변수를 선언하는 방식인데, 호이스팅 방식과 스코프에서 차이가 있습니다.

var는 함수 스코프를 가지고, 호이스팅 시 undefined로 초기화됩니다. 즉, 선언 전에 사용해도 에러가 발생하지 않고 undefined를 반환합니다.

letconst는 블록 스코프를 가지며, 호이스팅은 되지만 TDZ(Temporal Dead Zone)에 의해 선언 전에 접근하면 에러가 발생합니다. const는 선언 시 반드시 초기화해야 하고, 재할당이 불가능하다는 특징도 있습니다."

#호이스팅#선언#초기화#스코프#TDZ

이 질문 단독 페이지 →

Q2 기초

ES6에서 추가된 주요 기능들에 대해 설명해주세요.

힌트 · let/const, 화살표 함수, 템플릿 리터럴, 구조 분해 등을 설명해보세요.

ES6는 JavaScript에 많은 혁신적인 기능들을 도입했습니다. 가장 눈에 띄는 것은 let과 const를 사용한 변수 선언 방식의 변화입니다. var와 달리 블록 스코프를 가지기 때문에 예측 가능하고 안전한 코…

전체 모범답안 펼치기

ES6는 JavaScript에 많은 혁신적인 기능들을 도입했습니다. 가장 눈에 띄는 것은 letconst를 사용한 변수 선언 방식의 변화입니다. var와 달리 블록 스코프를 가지기 때문에 예측 가능하고 안전한 코드를 작성할 수 있게 되었습니다.

화살표 함수는 간결한 문법으로 함수를 표현할 수 있게 해주며, this 바인딩 방식에 있어서도 기존 함수와 차이를 보입니다.

템플릿 리터럴은 문자열 내에 변수를 쉽게 삽입할 수 있도록 해주고, 여러 줄 문자열을 표현하는 데도 용이합니다.

구조 분해 할당은 객체나 배열에서 값을 추출하여 변수에 할당하는 과정을 더욱 편리하게 만들어줍니다. 예를 들어 const { name, age } = person; 와 같이 사용할 수 있습니다.

이 외에도 클래스, 모듈, Promise 등 다양한 기능들이 추가되어 JavaScript 개발 경험을 크게 향상시켰습니다.

#화살표 함수#클래스#모듈#let/const#템플릿 리터럴

이 질문 단독 페이지 →

Q3 기초

JavaScript의 == 와 ===의 차이점은 무엇인가요?

힌트 · 타입 강제 변환(type coercion)의 동작을 생각해보세요.

"네, JavaScript에서 ==와 ===는 둘 다 동등성을 비교하는 연산자이지만, 중요한 차이점이 있습니다.

전체 모범답안 펼치기

"네, JavaScript에서 =====는 둘 다 동등성을 비교하는 연산자이지만, 중요한 차이점이 있습니다.

==는 '동등 연산자'라고 부르며, 비교하기 전에 필요하다면 타입 변환(type coercion)을 수행합니다. 즉, 두 값의 타입이 다를 경우 JavaScript 엔진이 자동으로 타입을 변환하여 비교합니다. 예를 들어, 1 == "1"true를 반환합니다.

반면에 ===는 '엄격한 동등 연산자'라고 부르며, 타입 변환 없이 값과 타입을 모두 비교합니다. 따라서 1 === "1"false를 반환합니다. 왜냐하면 숫자 1과 문자열 "1"은 타입이 다르기 때문입니다.

일반적으로는 예기치 않은 타입 변환으로 인한 오류를 방지하기 위해 ===를 사용하는 것이 더 안전하고 권장됩니다."

#동등 연산자#엄격한 동등 연산자#타입 변환#타입 비교#값 비교

이 질문 단독 페이지 →

Q4 기초

JavaScript의 Set과 Array의 차이점과 사용 사례를 설명해주세요.

힌트 · 중복 허용 여부, 주요 메서드, 성능을 비교해보세요.

네, JavaScript의 Set과 Array는 둘 다 여러 개의 값을 담을 수 있는 자료구조이지만, 몇 가지 중요한 차이점이 있습니다.

전체 모범답안 펼치기

네, JavaScript의 Set과 Array는 둘 다 여러 개의 값을 담을 수 있는 자료구조이지만, 몇 가지 중요한 차이점이 있습니다.

가장 큰 차이점은 Set은 중복된 값을 허용하지 않는다는 점입니다. Array는 같은 값을 여러 번 저장할 수 있지만, Set은 오직 유일한 값만 저장합니다. 따라서 중복된 데이터를 제거해야 할 때 Set을 유용하게 사용할 수 있습니다.

또 다른 차이점은 순서 보장 여부입니다. Array는 요소의 순서가 중요하고, index를 통해 요소에 접근할 수 있습니다. 반면 Set은 요소의 삽입 순서를 보장하지만, index를 통한 직접적인 접근은 제공하지 않습니다.

사용 사례를 예로 들자면, 사용자 ID 목록에서 중복된 ID를 제거해야 할 때 Set을 사용하면 간단하게 처리할 수 있습니다. Array는 순서가 중요한 데이터, 예를 들어 음악 재생 목록이나 할 일 목록 등을 관리할 때 적합합니다.

성능 면에서는 Set이 특정 값의 존재 여부를 확인하는 has() 메서드의 성능이 Array의 indexOf() 메서드보다 일반적으로 더 빠릅니다.

#유일성#중복 제거#순서 보장#집합 연산#indexOf

이 질문 단독 페이지 →

Q5 기초

JavaScript의 옵셔널 체이닝(?.)과 널 병합 연산자(??)에 대해 설명해주세요.

힌트 · null, undefined 처리와 이전 방식과의 차이를 설명해보세요.

JavaScript의 옵셔널 체이닝(?.)과 널 병합 연산자(??)는 nullish 값(null 또는 undefined)을 다루는 데 유용한 기능입니다.

전체 모범답안 펼치기

JavaScript의 옵셔널 체이닝(?.)과 널 병합 연산자(??)는 nullish 값(null 또는 undefined)을 다루는 데 유용한 기능입니다.

옵셔널 체이닝(?.)은 객체의 프로퍼티에 접근할 때 해당 프로퍼티가 nullish 값이면 에러를 발생시키는 대신 undefined를 반환합니다. 예를 들어 obj?.propobj가 null 또는 undefined이면 undefined를 반환하고, 그렇지 않으면 obj.prop의 값을 반환합니다. 이를 통해 중첩된 객체의 프로퍼티에 안전하게 접근할 수 있습니다.

널 병합 연산자(??)는 변수에 기본값을 할당할 때 사용됩니다. 변수가 nullish 값이면 지정된 기본값을 반환하고, 그렇지 않으면 변수의 값을 반환합니다. 예를 들어 value ?? 'default'value가 null 또는 undefined이면 'default'를 반환하고, 그렇지 않으면 value를 반환합니다. 이는 || 연산자와 비슷하지만, ||는 falsy 값(0, '', NaN 등)을 처리하는 반면 ??는 오직 nullish 값만 처리한다는 차이점이 있습니다.

이전에는 null 또는 undefined를 확인하기 위해 && 연산자를 사용하거나 삼항 연산자를 사용해야 했지만, 옵셔널 체이닝과 널 병합 연산자를 사용하면 코드를 더 간결하고 가독성 좋게 만들 수 있습니다.

#undefined#null#프로퍼티 접근#단축 평가#기본값 할당

이 질문 단독 페이지 →

Q6 기초

JavaScript의 엄격 모드(strict mode)란 무엇이며, 어떤 변화가 있나요?

힌트 · 묵시적 전역 변수, this 바인딩, 예약어 사용 등의 변화를 생각해보세요.

엄격 모드는 JavaScript 코드에 대한 일종의 "제한 모드"라고 생각하시면 됩니다. use strict라는 지시어를 사용해서 활성화할 수 있습니다.

전체 모범답안 펼치기

엄격 모드는 JavaScript 코드에 대한 일종의 "제한 모드"라고 생각하시면 됩니다. use strict라는 지시어를 사용해서 활성화할 수 있습니다.

엄격 모드를 사용하면 몇 가지 중요한 변화가 생깁니다. 가장 눈에 띄는 것은 선언되지 않은 변수를 사용하려고 하면 에러가 발생한다는 점입니다. 실수로 전역 변수를 만드는 것을 방지해줍니다.

또, this 바인딩 방식도 달라집니다. 일반 모드에서는 함수가 전역 객체에 바인딩될 수 있지만, 엄격 모드에서는 undefined가 됩니다.

arguments 객체에 대한 변경도 있고, 몇몇 예약어 사용에 제한이 생기는 등, 전반적으로 코드를 더 안전하고 예측 가능하게 만들어줍니다. 보안을 강화하고 잠재적인 오류를 줄이는 데 도움이 되죠.

#선언되지 않은 변수#전역 객체#this 바인딩#arguments 객체#보안 강화

이 질문 단독 페이지 →

Q7 기초

JavaScript의 Rest 파라미터와 Spread 연산자의 차이점과 사용법을 설명해주세요.

힌트 · 함수 파라미터에서의 사용과 배열/객체 조작에서의 사용을 구분해보세요.

Rest 파라미터와 Spread 연산자는 둘 다 ...을 사용하지만, 역할이 다릅니다.

전체 모범답안 펼치기

Rest 파라미터와 Spread 연산자는 둘 다 ...을 사용하지만, 역할이 다릅니다.

Rest 파라미터는 함수를 정의할 때 사용하며, 함수에 전달되는 여러 개의 인수를 하나의 배열로 묶어줍니다. 예를 들어 function sum(...numbers)처럼 사용하면, numbers는 함수에 전달된 모든 인수를 담은 배열이 됩니다. 가변 인자 함수를 만들 때 유용하죠.

반면 Spread 연산자는 배열이나 객체를 확장하는 데 사용됩니다. 배열을 다른 배열 안에 펼쳐 넣거나, 객체의 속성을 다른 객체에 복사할 때 활용할 수 있습니다. 예를 들어 [...arr1, ...arr2]arr1arr2의 모든 요소를 합쳐 새로운 배열을 만듭니다. 객체에서도 마찬가지로 ({...obj1, ...obj2})처럼 사용해서 속성을 합칠 수 있습니다.

요약하자면, Rest 파라미터는 함수 정의 시 인수를 묶는 역할, Spread 연산자는 배열이나 객체를 펼쳐서 확장하는 역할을 합니다.

#Rest 파라미터#Spread 연산자#함수 인자#배열 확장#가변 인자

이 질문 단독 페이지 →

읽기만으론 부족합니다 — 직접 말해보세요

패스잇 앱에서 JavaScript 질문에 직접 답하면 AI가 1:1로 답변을 코칭합니다.

JavaScript 면접 질문 — 중급

Q8 중급

JavaScript의 클로저(Closure)란 무엇이며, 실제 사용 예시를 들어주세요.

힌트 · 함수가 선언될 때의 렉시컬 환경을 기억하는 것을 설명해보세요.

클로저는 JavaScript에서 중요한 개념 중 하나입니다. 간단히 말하면, 함수가 자신이 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하는 현상을 말합니다. 렉시컬 환경은 함수가 속한 스코프…

전체 모범답안 펼치기

클로저는 JavaScript에서 중요한 개념 중 하나입니다. 간단히 말하면, 함수가 자신이 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하는 현상을 말합니다. 렉시컬 환경은 함수가 속한 스코프를 의미하며, 클로저를 통해 함수는 자신이 속한 스코프의 변수에 접근할 수 있습니다.

좀 더 자세히 설명하자면, 내부 함수가 외부 함수의 변수를 참조할 때 클로저가 생성됩니다. 이때 내부 함수는 외부 함수의 실행이 끝난 후에도 외부 함수의 변수(자유 변수)에 접근하고 사용할 수 있습니다.

실제 사용 예시로는, 카운터 함수를 만들 때 클로저를 활용할 수 있습니다. 외부 함수에서 카운트 변수를 선언하고, 내부 함수에서 이 변수를 증가시키는 방식으로 구현할 수 있습니다. 이렇게 하면 카운트 변수는 외부에서 직접 접근할 수 없도록 숨겨지고, 내부 함수를 통해서만 값을 변경할 수 있게 됩니다. 데이터 은닉과 캡슐화에 유용하게 사용될 수 있습니다. 콜백 함수 내부에서도 클로저를 활용하여 특정 상태를 유지하는 데 사용될 수 있습니다.

#렉시컬 스코프#함수 스코프#자유 변수#데이터 은닉#콜백 함수

이 질문 단독 페이지 →

Q9 중급

JavaScript의 이벤트 루프(Event Loop)와 비동기 처리 방식에 대해 설명해주세요.

힌트 · Call Stack, Task Queue, Microtask Queue의 관계를 설명해보세요.

JavaScript는 싱글 스레드 기반이지만, 이벤트 루프를 통해 비동기적인 작업을 효율적으로 처리합니다.

전체 모범답안 펼치기

JavaScript는 싱글 스레드 기반이지만, 이벤트 루프를 통해 비동기적인 작업을 효율적으로 처리합니다.

JavaScript 엔진은 콜 스택을 사용하여 동기적인 코드를 순차적으로 실행합니다. 비동기적인 작업(예: setTimeout, 네트워크 요청)은 브라우저나 Node.js 환경에 위임되고, 완료되면 태스크 큐(Task Queue)에 콜백 함수가 추가됩니다.

이벤트 루프는 콜 스택이 비어있는지 지속적으로 확인하고, 비어있다면 태스크 큐에서 콜백 함수를 꺼내 콜 스택에 넣어 실행합니다. Microtask Queue는 Promise나 MutationObserver와 관련된 콜백을 저장하며, 태스크 큐보다 우선순위가 높아 이벤트 루프가 다음 태스크를 처리하기 전에 먼저 실행됩니다.

이러한 방식으로 JavaScript는 싱글 스레드 환경에서도 blocking 없이 여러 작업을 동시에 처리하는 것처럼 보이게 합니다. 이것이 JavaScript의 동시성(concurrency) 모델의 핵심입니다.

#콜 스택#태스크 큐#비동기 API#이벤트 루프#동시성

이 질문 단독 페이지 →

Q10 중급

Promise와 async/await의 차이점과 에러 처리 방법에 대해 설명해주세요.

힌트 · 가독성, 에러 처리, 동시 실행 관점에서 비교해보세요.

Promise와 async/await는 둘 다 JavaScript에서 비동기 코드를 처리하는 데 사용됩니다. Promise는 비동기 작업의 최종 완료(성공 또는 실패)를 나타내는 객체이고, async/await는 P…

전체 모범답안 펼치기

Promise와 async/await는 둘 다 JavaScript에서 비동기 코드를 처리하는 데 사용됩니다. Promise는 비동기 작업의 최종 완료(성공 또는 실패)를 나타내는 객체이고, async/await는 Promise를 더 쉽게 사용할 수 있도록 해주는 문법적 설탕(Syntactic Sugar)입니다.

가장 큰 차이점은 가독성입니다. async/await를 사용하면 코드가 동기 코드처럼 보여서 이해하기 쉽습니다.

에러 처리 방식도 차이가 있습니다. Promise는 .catch() 메서드를 사용하여 에러를 처리하지만, async/await는 try...catch 구문을 사용하여 동기 코드처럼 에러를 처리할 수 있습니다.

// Promise
fetchData()
  .then(data => processData(data))
  .catch(error => console.error(error));

// async/await
async function fetchDataAndProcess() {
  try {
    const data = await fetchData();
    processData(data);
  } catch (error) {
    console.error(error);
  }
}

동시 실행 측면에서는 Promise.all() 등을 사용하여 여러 Promise를 병렬로 실행할 수 있고, async/await에서도 Promise를 활용하여 병렬 처리를 구현할 수 있습니다. async/await는 기본적으로 순차적으로 실행되지만, Promise와 함께 사용하면 동시성을 확보할 수 있습니다.

#Promise#async/await#Syntactic Sugar#try...catch#.catch()

이 질문 단독 페이지 →

Q11 중급

JavaScript의 this 바인딩 규칙에 대해 설명해주세요.

힌트 · 일반 함수, 메서드, 생성자, 화살표 함수에서의 this를 비교해보세요.

JavaScript에서 this는 함수가 호출될 때 결정되는 실행 컨텍스트를 나타냅니다. this 바인딩은 크게 네 가지 규칙에 따라 결정됩니다.

전체 모범답안 펼치기

JavaScript에서 this는 함수가 호출될 때 결정되는 실행 컨텍스트를 나타냅니다. this 바인딩은 크게 네 가지 규칙에 따라 결정됩니다.

첫째, 일반 함수 호출의 경우 this는 전역 객체(브라우저에서는 window, Node.js에서는 global)를 가리킵니다. strict mode에서는 undefined가 됩니다.

둘째, 메서드 호출의 경우 this는 메서드를 호출한 객체를 가리킵니다. 예를 들어 obj.method()에서 thisobj가 됩니다.

셋째, 생성자 함수 호출의 경우 this는 새로 생성된 객체를 가리킵니다. new MyClass()를 통해 생성된 객체 내부에서 this는 해당 객체를 참조합니다.

넷째, 화살표 함수의 경우 this는 함수가 정의될 때의 주변 컨텍스트의 this 값을 상속받습니다. 즉, 화살표 함수 내부의 this는 상위 스코프의 this와 같습니다.

apply, call, bind 메서드를 사용하면 this 값을 명시적으로 지정할 수 있습니다. applycall은 함수를 즉시 호출하며, bind는 새로운 함수를 반환합니다.

#전역#함수 호출#apply#call#bind

이 질문 단독 페이지 →

Q12 중급

JavaScript의 프로토타입(Prototype)과 프로토타입 체인에 대해 설명해주세요.

힌트 · __proto__와 prototype 속성의 차이를 설명해보세요.

JavaScript에서 프로토타입은 객체 지향 프로그래밍의 핵심 개념 중 하나입니다. 모든 객체는 자신의 프로토타입 객체를 가리키는 숨겨진 링크인 proto 속성을 가지고 있습니다. 이 proto는 객체를 생성한 함…

전체 모범답안 펼치기

JavaScript에서 프로토타입은 객체 지향 프로그래밍의 핵심 개념 중 하나입니다. 모든 객체는 자신의 프로토타입 객체를 가리키는 숨겨진 링크인 __proto__ 속성을 가지고 있습니다. 이 __proto__는 객체를 생성한 함수의 prototype 속성을 참조합니다.

프로토타입 체인은 객체의 속성이나 메서드를 찾을 때, 해당 객체에서 찾지 못하면 프로토타입 객체로 이동하여 찾고, 거기서도 없으면 그 프로토타입의 프로토타입으로 이동하는 과정을 반복하는 것을 말합니다. 이 과정을 통해 객체는 자신의 프로토타입 객체의 속성과 메서드를 상속받아 사용할 수 있습니다.

예를 들어, const obj = {};로 생성된 객체 objObject.prototype을 프로토타입으로 가지며, Object.prototype은 최상위 프로토타입이므로 null을 가리킵니다.

prototype 속성은 함수 객체만이 가지는 속성으로, 해당 함수를 생성자 함수로 사용하여 객체를 생성했을 때, 생성된 객체의 __proto__가 참조하게 될 객체를 가리킵니다. Object.getPrototypeOf(obj)를 사용하면 obj의 프로토타입 객체를 명시적으로 확인할 수 있습니다.

#프로토타입#프로토타입 체인#상속#__proto__#Object.getPrototypeOf

이 질문 단독 페이지 →

Q13 중급

JavaScript의 가비지 컬렉션(Garbage Collection) 동작 방식에 대해 설명해주세요.

힌트 · Mark and Sweep 알고리즘과 메모리 누수 방지를 생각해보세요.

JavaScript의 가비지 컬렉션은 더 이상 사용하지 않는 메모리를 자동으로 회수하는 기능입니다. JavaScript 엔진은 주로 "Mark and Sweep" 알고리즘을 사용합니다.

전체 모범답안 펼치기

JavaScript의 가비지 컬렉션은 더 이상 사용하지 않는 메모리를 자동으로 회수하는 기능입니다. JavaScript 엔진은 주로 "Mark and Sweep" 알고리즘을 사용합니다.

Mark and Sweep은 먼저 루트(root) 객체, 즉 전역 객체와 같은 도달 가능한 객체부터 시작하여 연결된 모든 객체를 "표시(Mark)"합니다. 그 후, 표시되지 않은 객체는 더 이상 사용되지 않는다고 판단하고 메모리에서 "제거(Sweep)"합니다.

초기에는 "참조 카운트" 방식도 사용되었지만, 순환 참조 문제 때문에 Mark and Sweep이 더 널리 사용됩니다. 순환 참조는 객체들이 서로를 참조하여 도달 가능하게 유지되지만, 실제로는 더 이상 필요하지 않은 경우를 말합니다.

가비지 컬렉션은 자동으로 이루어지지만, 개발자는 메모리 누수를 방지하기 위해 불필요한 전역 변수 사용을 줄이고, 이벤트 리스너를 적절히 제거하는 등의 노력을 기울여야 합니다.

#참조 카운트#Mark and Sweep#메모리 누수#도달 가능성#순환 참조

이 질문 단독 페이지 →

Q14 중급

JavaScript의 debounce와 throttle의 차이점과 사용 사례를 설명해주세요.

힌트 · 이벤트 처리 최적화와 각각의 동작 타이밍을 비교해보세요.

면접관님, debounce와 throttle은 JavaScript에서 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화하는 데 사용되는 기술입니다.

전체 모범답안 펼치기

면접관님, debounce와 throttle은 JavaScript에서 이벤트 핸들러의 호출 빈도를 제어하여 성능을 최적화하는 데 사용되는 기술입니다.

debounce는 특정 시간 동안 이벤트가 발생하지 않을 때, 마지막 이벤트 발생 시점의 함수를 딱 한 번만 호출합니다. 예를 들어, 검색어 자동 완성 기능에서 사용자가 입력을 멈춘 후에 검색 결과를 보여주는 데 유용합니다.

반면, throttle은 설정된 시간 간격 동안 함수가 최대 한 번만 호출되도록 합니다. 스크롤 이벤트 처리처럼 짧은 시간 간격으로 이벤트가 계속 발생하는 경우, throttle을 사용하면 함수 호출 빈도를 줄여 성능 저하를 방지할 수 있습니다.

핵심적인 차이는 debounce는 "마지막" 이벤트에 반응하고, throttle은 "일정 간격"으로 반응한다는 점입니다.

#debounce#throttle#호출 빈도 제한#setTimeout#성능 최적화

이 질문 단독 페이지 →

JavaScript 면접 질문 — 심화

Q15 심화

JavaScript의 실행 컨텍스트(Execution Context)와 스코프 체인에 대해 설명해주세요.

힌트 · Variable Object, Scope Chain, this의 결정 과정을 설명해보세요.

면접관님, JavaScript의 실행 컨텍스트와 스코프 체인에 대해 설명드리겠습니다.

전체 모범답안 펼치기

면접관님, JavaScript의 실행 컨텍스트와 스코프 체인에 대해 설명드리겠습니다.

실행 컨텍스트는 JavaScript 코드가 실행되는 환경을 의미하며, 코드가 실행될 때마다 생성됩니다. 각 실행 컨텍스트는 변수 객체(Variable Object), 스코프 체인, 그리고 this 값을 가집니다.

변수 객체는 해당 컨텍스트 내에서 선언된 변수와 함수를 저장하는 공간입니다. 스코프 체인은 현재 실행 컨텍스트와 그 상위 컨텍스트들의 변수 객체를 연결한 리스트입니다. JavaScript 엔진은 변수를 찾을 때 스코프 체인을 따라 올라가면서 탐색합니다.

스코프 체인은 렉시컬 환경(Lexical Environment)을 기반으로 구성됩니다. 렉시컬 환경은 코드가 작성된 물리적인 구조를 반영하며, 클로저가 가능한 이유이기도 합니다.

this는 함수가 호출될 때 결정되며, 호출 방식에 따라 다른 값을 가질 수 있습니다. 예를 들어, 전역 스코프에서는 window 객체를, 메서드 호출 시에는 해당 객체를 가리킵니다.

이러한 실행 컨텍스트와 스코프 체인을 이해하는 것은 JavaScript 코드를 디버깅하고 최적화하는 데 매우 중요합니다.

#실행 컨텍스트#렉시컬 환경#변수 환경#스코프 체인#클로저

이 질문 단독 페이지 →

Q16 심화

JavaScript의 WeakMap과 WeakSet의 특징과 사용 사례를 설명해주세요.

힌트 · 약한 참조와 가비지 컬렉션의 관계를 설명해보세요.

WeakMap과 WeakSet은 JavaScript에서 객체를 약하게 참조하는 컬렉션입니다. "약한 참조"라는 것은, WeakMap이나 WeakSet에 저장된 객체가 가비지 컬렉션 대상이 되는 것을 막지 않는다는 의…

전체 모범답안 펼치기

WeakMap과 WeakSet은 JavaScript에서 객체를 약하게 참조하는 컬렉션입니다. "약한 참조"라는 것은, WeakMap이나 WeakSet에 저장된 객체가 가비지 컬렉션 대상이 되는 것을 막지 않는다는 의미입니다.

일반적인 Map이나 Set은 객체를 강하게 참조하기 때문에, 해당 객체를 더 이상 사용하지 않더라도 메모리에 남아있게 됩니다. 반면 WeakMap과 WeakSet은 객체가 다른 곳에서 참조되지 않으면 가비지 컬렉터에 의해 회수될 수 있습니다.

주요 사용 사례는 다음과 같습니다. 첫째, 메모리 누수 방지입니다. DOM 요소와 관련된 데이터를 저장할 때, 요소가 제거되면 WeakMap에 저장된 데이터도 자동으로 제거되어 메모리 누수를 막을 수 있습니다. 둘째, 데이터 은닉화입니다. 객체에 대한 비공개 데이터를 연결할 때, 외부에서 직접 접근할 수 없도록 WeakMap을 사용할 수 있습니다.

예를 들어, 특정 DOM 요소에 이벤트 리스너를 연결하고, 해당 요소에 대한 추가 정보를 WeakMap에 저장할 수 있습니다. 요소가 제거되면 WeakMap의 해당 데이터도 함께 제거되므로 메모리 관리에 유용합니다.

#가비지 컬렉션#약한 참조#메모리 누수 방지#은닉화#데이터 연결

이 질문 단독 페이지 →

Q17 심화

JavaScript의 이터레이터(Iterator)와 제너레이터(Generator)에 대해 설명해주세요.

힌트 · Symbol.iterator, next(), yield 키워드를 설명해보세요.

면접관님, JavaScript의 이터레이터와 제너레이터에 대해 설명드리겠습니다.

전체 모범답안 펼치기

면접관님, JavaScript의 이터레이터와 제너레이터에 대해 설명드리겠습니다.

이터레이터는 이터레이션 프로토콜을 따르는 객체입니다. 이터레이션 프로토콜은 next() 메서드를 통해 순차적으로 값에 접근하는 방식을 정의합니다. next() 메서드는 { value: 값, done: 완료여부 } 형태의 객체를 반환합니다. donetrue가 되면 순회가 종료됩니다.

제너레이터는 이터레이터를 생성하는 함수입니다. 함수 내부에 yield 키워드를 사용하여 값들을 순차적으로 반환할 수 있습니다. 제너레이터 함수를 호출하면 이터레이터 객체가 반환되고, next() 메서드를 호출할 때마다 yield 키워드에서 값을 반환하며 함수 실행이 일시 중단됩니다. 제너레이터는 내부 상태를 유지하기 때문에 복잡한 이터레이션 로직을 간결하게 구현할 수 있다는 장점이 있습니다.

예를 들어, 다음과 같은 제너레이터 함수를 만들 수 있습니다.

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const iterator = numberGenerator();
console.log(iterator.next()); // { value: 1, done: false }

이처럼 제너레이터는 이터레이터를 쉽게 생성하고 관리할 수 있도록 도와주는 강력한 기능입니다.

#이터레이션 프로토콜#next()#done#yield#상태 관리

이 질문 단독 페이지 →

Q18 심화

JavaScript의 Proxy와 Reflect의 용도와 사용법에 대해 설명해주세요.

힌트 · 객체 동작 가로채기와 Vue.js의 반응성 시스템을 생각해보세요.

Proxy와 Reflect는 JavaScript에서 메타 프로그래밍을 가능하게 해주는 도구입니다.

전체 모범답안 펼치기

Proxy와 Reflect는 JavaScript에서 메타 프로그래밍을 가능하게 해주는 도구입니다.

Proxy는 객체의 기본적인 동작(속성 접근, 할당, 삭제 등)을 가로채고 제어할 수 있게 해줍니다. 마치 객체에 대한 '대리인' 역할을 하는 것이죠. Proxy를 사용하면 객체에 접근하거나 수정할 때 특정 로직을 실행할 수 있습니다. 예를 들어, 속성 접근 시 로그를 남기거나, 특정 속성에 대한 접근을 막는 등의 작업을 할 수 있습니다.

Reflect는 객체의 기본적인 동작을 수행하는 메서드들을 제공합니다. Proxy의 트랩(Trap) 내에서 원래 객체의 동작을 수행해야 할 때 Reflect API를 사용합니다. Reflect를 사용하면 객체의 기본 동작을 보다 안전하고 명확하게 제어할 수 있습니다.

Vue.js의 반응성 시스템도 Proxy를 활용하여 데이터 변경을 감지하고 UI를 업데이트합니다.

#메타 프로그래밍#객체 프록시#트랩(Trap)#기본 동작 제어#Reflect API

이 질문 단독 페이지 →

Q19 심화

for 루프 안에서 setTimeout 콜백이 모두 같은 값을 출력하는 고전적인 문제를 var로 작성했을 때 왜 발생하는지, 그리고 let으로 바꾸면 왜 의도대로 동작하는지를 블록 스코프와 클로저 캡처 관점에서 설명해주세요.

힌트 · 변수 환경(environment record)이 반복마다 새로 생성되는지 하나만 공유되는지의 차이로 접근하세요.

var를 사용하면 for 루프가 끝난 후에 setTimeout 콜백들이 실행되는데, 이때 var 변수는 함수 스코프를 가지므로 루프 전체에서 하나의 변수 환경을 공유합니다. 따라서 콜백이 실행될 시점에는 이미 루프가…

전체 모범답안 펼치기

var를 사용하면 for 루프가 끝난 후에 setTimeout 콜백들이 실행되는데, 이때 var 변수는 함수 스코프를 가지므로 루프 전체에서 하나의 변수 환경을 공유합니다. 따라서 콜백이 실행될 시점에는 이미 루프가 완료되어 변수 값이 마지막 값으로 고정되어 있기 때문에 모두 같은 값을 출력하게 됩니다.

let을 사용하면 for 루프의 각 반복마다 새로운 블록 스코프와 함께 새로운 변수 환경이 생성됩니다. setTimeout 콜백은 자신이 생성된 스코프의 변수를 클로저로 캡처하는데, 각 콜백은 자신만의 고유한 변수 값을 가지게 되므로 의도대로 각기 다른 값을 출력하게 됩니다.

#var#let#클로저#블록 스코프#호이스팅

이 질문 단독 페이지 →

Q20 심화

메모이제이션 캐시나 카운터를 클로저로 구현할 때, 시간이 지나면서 의도치 않게 메모리가 계속 점유되는 상황이 생길 수 있습니다. 클로저가 참조를 붙잡는 방식이 GC와 어떻게 상호작용하는지, 그리고 이를 어떻게 완화할 수 있을지 설명해주세요.

힌트 · 어떤 변수가 클로저 스코프에 살아남는지와, 더 이상 필요 없을 때 참조를 끊는 전략 관점에서 접근하세요.

클로저가 외부 스코프의 변수를 참조할 때, 해당 변수는 클로저가 살아있는 동안 계속 메모리에 유지됩니다. 메모이제이션 캐시나 카운터처럼 클로저가 오래 유지되는 경우, 이 참조 때문에 불필요한 메모리가 점유될 수 있습…

전체 모범답안 펼치기

클로저가 외부 스코프의 변수를 참조할 때, 해당 변수는 클로저가 살아있는 동안 계속 메모리에 유지됩니다. 메모이제이션 캐시나 카운터처럼 클로저가 오래 유지되는 경우, 이 참조 때문에 불필요한 메모리가 점유될 수 있습니다.

가비지 컬렉터(GC)는 더 이상 접근할 수 없는 객체를 제거하지만, 클로저가 참조하는 변수는 접근 가능하다고 판단하여 GC 대상에서 제외됩니다.

이를 완화하려면, 더 이상 필요 없는 변수에 대한 참조를 명시적으로 끊어주는 것이 중요합니다. 예를 들어, 캐시의 경우 일정 시간이 지나거나 특정 조건이 되면 해당 항목을 제거하는 로직을 추가할 수 있습니다. 또한, WeakMap이나 WeakSet 같은 약한 참조를 활용하면 객체가 GC 대상이 될 때 자동으로 참조가 해제되도록 하여 메모리 누수를 방지하는 데 도움이 됩니다.

#클로저#참조#가비지 컬렉션#메모리 누수#약한 참조

이 질문 단독 페이지 →

Q21 심화

화살표 함수의 this와 일반 함수의 this는 결정 시점과 규칙이 다릅니다. 객체 메서드를 화살표 함수로 정의했을 때 흔히 발생하는 버그와, 반대로 콜백에서 화살표 함수가 유리한 경우를 각각 예를 들어 설명해주세요.

힌트 · this가 호출 시점에 동적으로 묶이는지 정의 시점에 정적으로 묶이는지의 차이로 접근하세요.

네, 화살표 함수와 일반 함수의 this 차이에 대해 설명드리겠습니다.

전체 모범답안 펼치기

네, 화살표 함수와 일반 함수의 this 차이에 대해 설명드리겠습니다.

일반 함수는 this가 호출되는 시점에 동적으로 결정됩니다. 반면 화살표 함수는 this가 자신이 선언된 시점의 상위 스코프(lexical scope)를 그대로 따라갑니다.

객체 메서드를 화살표 함수로 정의하면 this가 예상과 다르게 동작하는 버그가 발생할 수 있습니다. 예를 들어, 객체의 프로퍼티를 변경하는 메서드를 화살표 함수로 만들면, 메서드 내부의 this는 객체 자체가 아닌 전역 객체나 undefined를 가리키게 되어 의도대로 동작하지 않습니다.

const obj = {
  value: 10,
  updateValue: () => {
    this.value = 20; // 여기서 this는 obj가 아닙니다.
  }
};
obj.updateValue();
console.log(obj.value); // 10 (변경되지 않음)

반대로, 콜백 함수에서 화살표 함수는 매우 유용합니다. setTimeout이나 이벤트 핸들러와 같이 콜백 함수 내부에서 상위 스코프의 this를 그대로 사용해야 할 때, 화살표 함수를 사용하면 bindthat = this와 같은 번거로운 작업 없이 간결하게 코드를 작성할 수 있습니다.

const counter = {
  count: 0,
  start: function() {
    setTimeout(() => {
      this.count++; // 여기서 this는 counter 객체를 올바르게 가리킵니다.
      console.log(this.count);
    }, 1000);
  }
};
counter.start(); // 1
#lexical scope#dynamic scope#context#binding#prototype

이 질문 단독 페이지 →

함께 보면 좋은 프론트엔드 개발 면접 질문

← 전체 면접 질문 카테고리 보기

보유한 JavaScript 질문은 이게 전부가 아닙니다

패스잇 앱에는 직무별 면접 질문 수천 개와 모범답안이 담겨 있습니다. AI 모의면접으로 직접 답하고, 약점을 분석받아 보세요.