Node.js 주니어 코딩 기술면접
새 면접Q. JavaScript 배열에서 map(), filter(), reduce() 메서드의 차이점을 설명하고, 숫자 배열 [1, 2, 3, 4, 5]에서 짝수만 골라 각각 2배로 만든 후 합계를 구하는 로직을 어떤 메서드들을 조합하여 구현할지 설명해주세요.
map()은 배열의 각 요소를 변환하여 새 배열을 반환하고, filter()는 조건에 맞는 요소만 선택하여 새 배열을 반환하며, reduce()는 배열을 순회하며 하나의 값으로 축약합니다. 주어진 문제는 filter()로 짝수를 골라내고, map()으로 2배를 만든 후, reduce()로 합계를 구하면 됩니다. 예를 들어 [1,2,3,4,5].filter(n => n % 2 === 0).map(n => n * 2).reduce((sum, n) => sum + n, 0)와 같이 메서드 체이닝으로 구현할 수 있습니다.
- • map()은 변환, filter()는 선택, reduce()는 축약
- • 메서드 체이닝을 통한 순차적 처리
- • 각 메서드는 원본 배열을 변경하지 않고 새 배열/값을 반환
forEach()와 map()의 차이점은 무엇이며, 언제 forEach()를 사용하고 언제 map()을 사용해야 하나요?
Q. Node.js에서 setTimeout(() => console.log('A'), 0), Promise.resolve().then(() => console.log('B')), console.log('C')를 순서대로 실행하면 어떤 순서로 출력되는지 설명하고, 그 이유를 이벤트 루프와 태스크 큐의 관점에서 설명해주세요.
출력 순서는 C, B, A입니다. console.log('C')는 동기 코드로 즉시 실행되어 가장 먼저 출력됩니다. Promise는 마이크로태스크 큐에 들어가고, setTimeout은 매크로태스크 큐에 들어갑니다. 이벤트 루프는 콜스택이 비면 마이크로태스크 큐를 먼저 처리한 후 매크로태스크 큐를 처리하므로 B가 A보다 먼저 출력됩니다. setTimeout의 지연시간이 0이어도 태스크 큐에 들어가므로 마이크로태스크보다 늦게 실행됩니다.
- • 동기 코드가 가장 먼저 실행됨
- • 마이크로태스크(Promise)가 매크로태스크(setTimeout)보다 우선순위가 높음
- • 이벤트 루프는 콜스택 비움 → 마이크로태스크 → 매크로태스크 순으로 처리
process.nextTick()과 Promise.then()의 우선순위는 어떻게 되나요?
Q. URL 쿼리스트링 '?name=홍길동&age=25&city=서울'을 파싱하여 JavaScript 객체로 변환하는 함수를 구현할 때 어떤 문자열 메서드들을 사용해야 하는지 단계별로 설명해주세요.
먼저 substring() 또는 slice()를 사용해 맨 앞의 물음표를 제거합니다. 그 다음 split('&')로 각 파라미터를 배열로 분리합니다. 각 파라미터에 대해 다시 split('=')로 키와 값을 분리합니다. decodeURIComponent()를 사용해 URL 인코딩된 값을 디코딩하고, reduce() 또는 forEach()로 객체를 생성합니다. 최종적으로 {name: '홍길동', age: '25', city: '서울'} 형태의 객체가 반환됩니다.
- • split()을 사용한 문자열 분리
- • decodeURIComponent()로 URL 디코딩 처리
- • 배열을 객체로 변환하는 reduce 패턴
Node.js에서 제공하는 내장 모듈 중 URL 파싱을 도와주는 모듈은 무엇이며, 어떻게 사용하나요?
Q. Node.js에서 JSON.parse()와 JSON.stringify()를 사용할 때 발생할 수 있는 에러 상황과 이를 안전하게 처리하는 방법을 설명해주세요. 또한 순환 참조가 있는 객체를 JSON으로 변환할 때 어떤 문제가 발생하는지 설명해주세요.
JSON.parse()는 잘못된 형식의 JSON 문자열을 파싱할 때 SyntaxError를 발생시키므로 try-catch 블록으로 감싸서 처리해야 합니다. JSON.stringify()는 순환 참조가 있는 객체를 변환할 때 TypeError: Converting circular structure to JSON 에러를 발생시킵니다. 이를 해결하려면 stringify의 두 번째 인자로 replacer 함수를 전달하여 이미 방문한 객체를 추적하고 순환 참조를 제거하거나, WeakSet을 사용해 방문한 객체를 기록할 수 있습니다. undefined, 함수, Symbol은 JSON 변환 시 무시되므로 주의해야 합니다.
- • try-catch로 JSON 파싱 에러 처리
- • 순환 참조 시 TypeError 발생
- • replacer 함수를 통한 순환 참조 해결
JSON.stringify()의 세 번째 인자(space)의 역할은 무엇이며, 실무에서 어떻게 활용할 수 있나요?
Q. Node.js에서 대용량 CSV 파일을 읽어 각 행을 처리한 후 다른 파일로 저장할 때, fs.readFileSync()를 사용하는 것과 Stream을 사용하는 것의 차이점을 설명하고, Stream을 사용해야 하는 이유를 메모리 관점에서 설명해주세요.
fs.readFileSync()는 파일 전체를 메모리에 한 번에 로드하므로 대용량 파일의 경우 메모리 부족 에러가 발생할 수 있고, 파일을 모두 읽을 때까지 다른 작업을 차단합니다. Stream을 사용하면 파일을 청크 단위로 나누어 읽고 처리하므로 메모리 사용량이 일정하게 유지되며, 읽기와 쓰기를 동시에 진행할 수 있어 효율적입니다. createReadStream()과 createWriteStream()을 pipe()로 연결하면 백프레셔 처리도 자동으로 이루어져 안정적입니다. Stream 방식은 데이터를 버퍼 크기만큼만 메모리에 유지하므로 기가바이트 단위의 파일도 안전하게 처리할 수 있습니다.
- • readFileSync는 전체 파일을 메모리에 로드
- • Stream은 청크 단위로 처리하여 메모리 효율적
- • pipe()를 통한 백프레셔 자동 처리
Readable Stream, Writable Stream, Transform Stream의 차이점과 각각의 사용 사례를 설명해주세요.
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!