-
[면접 스터디] 프론트엔드 JavaScript 기술 면접 질문Front-end 개발/FE 용어 2024. 7. 15. 06:05
이번에 준비할 기술면접 질문은 웹 프론트엔드 개발자라면 숙지하고 있어야 할 JavaScript와 관련된 질문이다. 스터디원 중에 기술면접을 받고 와서 JavaScript 쪽에서 나오는 질문에 답변 준비가 미흡했다는 후기를 바탕으로 주제와 키워드를 선정하게 되었다. 이번 주에 다룰 키워드는 아래와 같다.
기술면접 키워드
- 호이스팅이란?
- var, let, const의 차이
- 프로토타입
- this 스코프, 스코프체인
- ES6+ 새로 생긴 기능들
- 클로저
- Event Loop
- JavaScript 원시타입과 참조타입
- 동기 비동기의 차이점
- forEach 루프를 멈추는 방법1. 기술 면접 질문
1-1. var, let, const의 차이 (p. 109)
각 키워드가 변수로 선언됐을 때, var 키워드는 함수 스코프를 가지고 있습니다. var 변수는 함수 내에서만 유효하며 함수 외부에서 선언된 var 변수는 전역 변수가 됩니다. 또한 중복 선언이 가능합니다.
let과 const 변수는 블록 스코프를 가지고 있으며 블록 내에서만 유효하며 중복 선언이 불가합니다. 반면 const 변수는 let 변수와는 다르게 재할당이 불가능하며, 초기값을 꼭 할당해야 합니다.
const 키워드로 선언된 객체 타입인 경우에 참조된 값을 바꿀 수 있습니다. 객체의 경우 속성의 키는 변경할 수 없지만 속성은 추가, 삭제할 수 있으며 소성의 값은 변경할 수 있습니다.
1-2. ES6+ 새로 생긴 기능들
JavaScript에 ES6 이전과 뚜렷하게 다른 추가 기능으로는 let, const, arrow function, classes, module, destructuring, map/set, promise, awiat/async, rest/spread properties, class fileds 등이 있습니다. 말씀드린 추가 기능을 통해서 JavaScript는 좀 더 객체 지향 프로그래밍 언어가 되었으며, 의도치 않은 오류가 줄어들고, 데이터를 가공 및 접근이 보다 용이해질 수 있게 됐습니다. 2015년 승인된 ECMAScript 제 6판을 기준으로 매년 새로운 판이 출판되고 있습니다.
* ECMAScript의 변경 기록 및 앞으로 추가될 내용은 ECMA-262 GitHub 저장소에서 확인 가능
* ECMAScript(ES)란 European Computer Manufactures Association(ECMA) International이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어를 말한다. JavaScript를 표준화하기 위해 만들어졌다. (ES6 === ECMAScript 2015)
1-3. forEach 루프를 멈추는 방법
배열의 forEach 메서드는 배열을 순회하는 데 사용되지만, 중간에 멈추는 기능은 내장되어 있지 않습니다. 만약 배열의 순회을 중단하고 싶다면 forEach 대신 for...of나 while 반복문을 사용해야 합니다.
1-4. JavaScritp 원시타입과 참조타입
원시타입(Primitive Type)은 고정된 크기를 가지며, 변수에 실제 값이 저장됩니다. 그 종류로는 string, number, bigint, boolean, null, undefined, symbol이 있습니다. 참조타입(Reference Type)은 객체의 번지를 참조하는 타입으로 변수에 메모리 주소가 저장됩니다. 참조타입 종류로는 배열, 객체, 함수 등이 있습니다. 참조타입은 동적으로 크기가 변하며 메모리 관리자가 heap 영역을 관리합니다.
두 가지 타입은 변수 할당과 복사에서 확연한 차이가 발생합니다. 원시타입 데이터는 변수에 할당하면 (Call Stack)변수에 실제 값이 저장되는 반면, 참조타입 데이터는 (Call Stack)변수에 해당 데이터의 (Heap memory)주소가 저장됩니다. 이렇게 할당된 변수를 복사할 때 원시타입의 변수들은 (Call Stack)메모리 공간을 새롭게 확보하여 독립적인 값을 저장하여 문제가 없습니다. 하지만 참조 타입은 메모리에 직접 접근이 아닌 메모리 주소를 통한 간접적인 접근(참조)을 하기 때문에 힙 영역을 참조할 원본 데이터의 메모리 주소를 저장합니다. 그 결과 원본 데이터가 바뀌더라도 원시타입은 복사본이 영향을 받지 않지만, 참조타입은 원본의 영향을 받아 참조 값이 바뀌게 됩니다.
1-5. 클로저 (p. 112)
함수 선언 당시의 환경을 기억하며 생성 이후 상위 함수의 변수 및 기타 리소스에 계속 접근이 가능한 것을 말합니다. JavaScript가 렉시컬 스코프를 따르기 때문에 외부 함수에 내부 함수를 정의하고 호출하면 내부 렉시컬 환경에서 외부 렉시컬 환경을 참조할 수 있습니다. 즉, 클로저를 이용하여 내부 함수가 외부 함수에 접근할 수 있으며, 외부 함수의 실행이 끝난 이후에 외부 함수는 실행 컨텍스트 스택에서 제거되지만 외부 함수의 렉시컬 환경은 유지되어, 내부 함수를 이용하여 외부 함수의 변수에 계속해서 접근이 가능한 특징을 가집니다. 클로저의 주요 사용 목적은 데이터 은닉과 보호입니다. 클로저는 함수 내부에 변수를 숨기고 외부에서 접근할 수 없게 하므로 변수의 값과 상태를 보호할 수 있습니다.
1-6. 호이스팅이란? (p. 110)
호이스팅(Hoisting)은 JavaScript에서 인터프리터가 코드를 실행하기 전에 변수와 함수 선언이 해당 스코프의 최상단으로 끌어올려진 것처럼 동작하는 것입니다. 이로인해 변수나 함수가 선언되기 전에도 접근할 수 있습니다. 변수의 경우 var 키워드는 호이스팅 되면서 선언과 초기화가 동시에 일어나기 때문에 undefined가 되지만, let과 const는 선언과 초기화가 분리되어 발생하기 때문에 초기화 이전의 변수는 참조할 수 없습니다.
함수의 경우 함수 선언문에서는 함수의 이름이 호이스팅 되지만, 함수 표현식에서는 할당된 변수 이름이 호이스팅 됩니다. 따라서 함수 선언문으로 선언된 함수는 해당 함수를 선언하기 전에도 호출할 수 있습니다.
* 렉시컬 환경(Lexical Environment)은 식별자와 식별자에 바인딩된 값, 그리고 상위 스코프에 대한 참조를 기록하는 자료구조로 실행 컨텍스트를 구성하는 컴포넌트다.
1-7. 프로토타입 (p. 114)
JavaScprit에서 Prototype은 모든 객체가 상속할 수 있는 기본적인 Object입니다. Prototype은 상속을 가능하게 하며, 모든 객체는 하나 이상의 Prototype을 가질 수 있습니다. Prototype은 객체의 속성 및 메서드를 정의하며, 해당 객체의 모든 인스턴스에서 공유됩니다. 프로토타입을 기반으로 상속을 구현하여 코드의 재사용성을 높일 수 있습니다.
대표적으로 .toString(), hasOwnProperty() 등의 메서드를 제공하는 Object.prototype이 있으며, 해당 객체는 JavaScript에서 모든 객체가 상속하는 가장 기본적인 Prototype 입니다.
1-8. this 스코프, 스코프체인 (p. 115)
[this 동작]
this란 자신이 속한 객체를 가리키는 자기 참조 변수입니다. this는 함수가 호출되는 위치에 따라 값이 다르게 출력됩니다. 예를 들어 함수의 경우 전역, 객체의 메서드, 화살표, 생성자 함수에 따라 달라집니다. 전역 스코프에서 호출되는 함수의 this는 전역 객체인 window 객체를 가리킵니다. 객체 안에 메서드로 정의되어 있는 함수를 호출한 경우에는 인스턴스를 가리킵니다. 추가적으로 이벤트 리스너에서의 this는 이벤트가 발생한 target을 가리킵니다. 클래스에서 this는 주로 해당 클래스의 인스턴스를 가리킵니다. 클래스 내부의 메서드에서 this를 사용하면 그 메서드가 호출된 객체 또는 인스턴스를 참조합니다.
호출하는 위치에 따라 값이 달라지는 this의 단점을 보완하기 위해서 화살표 함수를 사용하거나 call, apply, bind 함수를 사용할 수 있습니다. call과 apply는 함수를 호출할 때 첫 번째 인수로 this를 지정하고 두 번째 인수로 함수에 전달될 값을 지정합니다. 이때 call과 다르게 apply는 인수 값을 배열로 전달합니다. bind 함수는 this 값을 고정하여 해당 함수를 반환합니다. 이렇게 만든 함수를 호출하면 항상 고정된 this 값을 가진 함수가 실행됩니다.
[스코프 체이닝]
스코프 체인이란 식별자를 찾아서 참조로 연결된 렉시컬 환경를 따라 상위 스코프로 가는 과정을 스코프 체이닝이라고 합니다. 활성화된 실행 컨텍스트의 환경 레코드를 봤을 때 찾으려는 값이 없는 경우, JavaScript 엔진은 그 다음 스택인 외부 렉시컬 환경에서 해당 값을 찾게 됩니다. 이 과정에서 값을 찾게 되면 JavaScript는 더 외부 렉시컬 환경을 확인하지 않지만, 찾지 못한다면 전역 실행 컨텍스트까지 확인하게 됩니다. 그럼에도 값을 찾지 못하면 값이 없다는 결론을 내리고 Reference Error를 발생합니다.
* 환경 레코드(Environment Record): 스코프에 포함된 식별자를 등록하고, 등록된 식별자에 바인딩된 값을 관리.
* 렉시컬 환경(Lexical Environment): 렉시컬 환경은 스코프 체인을 형성하고 관리하며 변수 및 함수 식별자와 그 값들을 관리.
1-9. 동기 비동기의 차이점 (p. 116)
동기 코드는 위에서 아래로 순차적으로 실행되어 한 작업이 완료될 때까지 다음 작업을 시작하지 않으며, 파일을 읽는 작업이 끝날 때까지 웹 페이지의 렌더링이 차단될 수 있습니다. 비동기 코드는 작업을 순서대로 기다려 처리하지 않고 병렬로 처리할 수 있습니다. 이벤트 핸들러, 타이머, AJAX 요청과 같은 비동기 작업은 비동기 코드에서 파일을 읽는 작업을 시작하고 중간에 다른 작업을 수행할 수 있으며, 해당 작업이 완료될 때 콜백 함수를 호출하여 결과를 처리합니다. 비동기 코드는 네트워크 요청, 파일 I/O, 사용자 입력처럼 시간이 걸리는 작업을 효과적으로 다룰 수 있기 때문에 웹 애플리케이션은 사용자와 상호작용하면서도 백그라운드에서 다른 작업을 처리할 수 있습니다.
1-10. Event Loop
이벤트 루프는 태스크가 들어오길 기다렸다가 태스크가 들어오면 이를 순차적으로 처리하고, 처리할 태스크가 없는 경우엔 새로운 태스크가 추가될 때까지 기다리며, 끊임없이 돌아가는 JavaScript 엔진 내 루프입니다.
JavaScript 엔진을 활성화하는 대표적인 태스크에는 외부 스크립트 <script src="...">가 로드되어 실행하는 것, 사용자가 마우스를 움직일 때 mousemove 이벤트와 이벤트 헨들러를 실행하는 것, setTimeout에서 설정한 시간이 다 되어 콜백 함수를 실행하는 것 등등이 있습니다. 태스크는 하나의 집합을 이루며, 태스크가 추가되는 큐는 V8 용어로 '매크로태스 큐(macrotask queue)'라고 부른다.
태스크는 매크로태스크(macrotask)와 마이크로태스크(microtask)로 나뉩니다. 마이크로태스크는 코드를 사용해서만 만들 수 있는데, 주로 프라미스(promise)를 사용해 만듭니다. 프라미스와 함께 쓰이는 .then/catch/finally 핸들러가 마이크로태스크가 됩니다. 여기에 더하여 마이크로태스크는 프라미스를 핸들링하는 또 다른 문법인 await를 사용해 만들기도 합니다. 이 외에도 표준 API인 queueMicrotask(func)를 사용하면 함수 func를 마이크로태스크 큐에 넣어 처리할 수 있습니다.
JavaScript 엔진은 매크로태스크 하나를 처리할 때마다 또 다른 매크로태스크나 렌더링 작업을 하기 전에 마이크로태스크 큐에 쌓인 마이크로태스크 전부를 처리합니다. 그림을 보면 매크로태스크(script, mousemove, setTimeout 등) 하나가 처리되고 난 후 마이크로태스크 전부(microtasks)가 처리되고 그 이후 렌더링이 진행됩니다. 다시말해, 마이크로태스크는 다른 이벤트 핸들러나 렌더링 작업, 혹은 다른 매크로태스크가 실행되기 전에 처리됩니다.
이런 처리순서가 아주 중요한 이유는 (마우스 좌표 변경이나 네트워크 통신에 의한 데이터 변경 같이 애플리케이션 환경에 변화를 주는 작업에 영향을 받지 않고) 모든 마이크로태스크를 동일한 환경에서 처리할 수 있기 때문입니다.
개발을 하다 보면 직접 만든 함수를 현재 코드 실행이 끝난 후, 새로운 이벤트 핸들러가 처리되기 전이면서 렌더링이 실행되기 전에 비동기적으로 실행해야 하는 경우가 생기곤 합니다. 이럴 때 queueMicrotask를 사용해 커스텀 함수를 스케줄링하면 됩니다.
2. 인적성 면접 질문
2-1. 프론트엔드 직무을 선택한 이유와 선택 직무에 본인이 적합하다고 판단될 수 있는 이유와 근거를 제시해 주세요.
[헤드라인]
(이런이런 역할을 수행하는) 웹 프론트엔드 개발자는 (이런이런) 역량이 필요하다고 생각합니다. 그래서 전문 교육을 통해 프론트엔드 개발자로써 갖춰야 할 HTML/CSS, JS, TS, React, Next 등의 지식과 기술을 배웠고, UI 개발과 사용자 인터렉션 개발의 숙련도를 쌓기 위해 직무와 관련된 팀 프로젝트를 수행했습니다. 이러한 학습과 활동으로 프론트엔드 개발자에 필요한 지식과 역량을 보유하게 되었고, 앞서 말씀드린 지원동기를 고려해 봤을 때 지원한 직무가 가장 적합하다고 판단하게 되었습니다.2-2. 본인의 의견이 팀원과 다를 때 어떻게 대화하고 타협하나요?
상대방의 감정이 격해지지 않은 상태라면 대면해서 대화하는 방식을 선호합니다. 또한 기본적으로 Notion이나 Figma/FigJam 등의 도구를 사용해 시각적인 자료나 하이퍼링크를 포함한 근거자료를 기반으로 대화합니다.
타협의 경우, 개인 보다는 팀에 도움이 되는 방향을 기준으로 하며, 프로젝트의 기한 더 효과적이 실현가능한 방향으로 의견을 조율하고 서로 타협하려고 의식적으로 노력하고 있습니다.
출처 1. 눈떠보니 기술 면접 전날 with JS, Python - Ridi Books
출처 2. JavaScript 원시타입 vs 참조타입 - devfrank Velog
출처 3. 이벤트루프와 매크로태스크, 마이크로태스크 - JAVASCRIPT.INFO
출처4. JavaScript 이벤트 루프란?
'Front-end 개발 > FE 용어' 카테고리의 다른 글
[면접 스터디] 프론트엔드 브라우저와 네트워크 그리고 렌더링 질문 (2) 2024.07.02 [책집필] 기술면접 질문 ChatGPT 로 빠르게 답변 찾아보기 (0) 2023.09.06 [용어] 웹 접근성 - A11y (0) 2023.07.11 [용어] 프론트엔드 관련 용어 해설, '프론트엔드 도대체 뭐야' 시리즈의 목차 (0) 2023.06.27 [용어] 스프린트(Sprint) - 단기 기획 및 실행 프로세스 (0) 2023.05.18