JavaScript Quiz - 비동기, 메모리 관리, 클래스, Call Stack/Heap, 이터러블/이터레이터
1. 비동기적으로 실행되는 것을 동기적으로 코딩하는 방법이 있나요?
- 네, async, await 키워드를 사용해서 비동기적으로 실행되는 것을 동기적으로 코딩할 수 있습니다.
1.1 배열을 순회하면서 비동기 처리를 동기적으로 처리하는 방법에 대해 설명해주세요.
- 비동기 처리 결과가 필요하지 않다면, forEach 메서드와 async/await을 함께 사용합니다.
- 각 요소의 비동기 처리 결과를 기다려야 한다면, for 문과 async/await을 함께 사용합니다.
- 요청이 끝나는 순서는 상관 없이 모든 비동기 처리 결과를 받고 싶다면, map 메서드와 async/await를 같이 사용합니다.
2. map, forEach, reduce에 대해 설명해주세요.
- map 메서드는 배열의 각 요소에 콜백 함수를 실행한 결과값으로 구성된 새 배열을 반환하는 메서드입니다.
- forEach 메서드는 배열의 각 요소에 콜백함수를 실행시키는 메서드입니다.
- reduce 메서드는 배열의 각 요소에 주어진 reducer 함수를 실행하여 이전 요소에 대한 결과값을 전달합니다. 그래서 배열의 모든 요소에 대해 reducer를 실행한 최종 결과값은 단일 값을 반환하는 메서드입니다.
3. JavaScript의 메모리 관리에 대해 설명해주세요.
- JavaScript는 객체가 생성되었을 때 자동으로 메모리를 할당하고, 더 이상 필요하지 않을 때 자동으로 해제합니다.
- JavaScript는 가비지 콜렉션이라는 자동 메모리 관리 방법을 사용합니다.
- 가비지 콜렉터의 목적은 메모리 할당을 추적하고 할당된 메모리 블록이 더 이상 필요하지 않게 되었는지를 판단하여 회수하는 것입니다.
- 가비지 콜렉션 알고리즘은 참조-세기(reference-counting) 알고리즘과 표시하고-쓸기(mark-and-sweep) 알고리즘이 있습니다.
- 참조-세기 알고리즘은 어떤 다른 객체도 참조하지 않는 객체를 더 이상 필요하지 않은 객체로 판단하여 수집합니다.
- 순환 참조는 두 객체가 서로 참조하고 있을 때 둘 다 가비지 컬렉션의 대상이 되지 않아서 메모리 누수의 흔한 원인이 됩니다.
- 더 이상 최신 브라우저에서 가비지 콜렉션 알고리즘으로 참조-세기 알고리즘을 사용하지 않습니다.
- 표시하고-쓸기 알고리즘은 root부터 시작하여 닿을 수 없는 객체를 더 이상 필요하지 않은 객체로 판단하여 수집합니다.
4. 클래스에 대해 설명주세요.
- 클래스는 특정 객체를 생성하기 위해 변수와 메서드를 정의하는 템플릿을 말합니다.
- 클래스는 new 연산자와 함께 호출되어 인스턴스를 생성합니다.
- 클래스는 표현식으로 정의할 수 있기 때문에 값으로 사용할 수 있는 일급 객체입니다.
- 클래스의 내부에서 정의할 수 있는 메서드는 생성자 함수 constructor, 프로토타임 메서드, 정적 메서드가 있습니다.
- 클래스 내부에서 정의한 메서드는 기본적으로 프로토타입 메서드가 됩니다.
- 클래스 내부에서 정의한 메서드에 static 키워드를 붙이면 정적 메서드가 됩니다.
- 정적 메서드는 클래스에 바인딩된 메서드로 인스턴스를 생성하지 않아도 호출할 수 있습니니다.
- 정적 메서드는 인스턴스의 프로토타입 체인 상에 존재하지 않으므로 인스턴스로 호출할 수 없습니다.
- 클래스 선언문은 호이스팅이 발생합니다. 단, 클래스는 let, const 키워드로 선언한 변수처럼 선언 단계와 초기화 단계가 분리되어 있으므로, 선언문 이전에 일시적 사각지대 TDZ가 있습니다.
4.1 클래스의 정적 메서드와 프로토타입 메서드의 차이에 대해 설명해주세요.
- 정적 메서드는 클래스의 프로토타입 체인상에 존재하는 반면에, 프로토타입 메서드는 인스턴스의 프로토타입 체인상에 존재합니다.
- 정적 메서드는 인스턴스 프로퍼티를 참조할 수 없지만, 프로토타입 메서드는 인스턴스 프로퍼티를 참조할 수 있습니다.
- 정적 메서드는 클래스로 호출하고, 프로토타입 메서드는 인스턴스로 호출합니다.
- 정적 메서드 내부의 this는 클래스를 가리키고, 프로토타입 메서드 내부의 this는 인스턴스를 가리킵니다.
5. 즉시 실행 함수(IIFE)에 대해 설명해주세요.
- 즉시 실행 함수는 함수가 정의와 동시에 즉시 호출되는 함수를 말합니다.
- 즉시 실행 함수는 단 한번만 호출되며 다시 호출할 수 없습니다.
- 즉시 실행 함수는 익명 함수와 기명 함수 둘 다 사용할 수 있습니다.
- 즉시 실행 함수는 반드시 그룹 연산자 (...)로 감싸야 합니다.
- 그룹 연산자 (...) 내 기명 함수는 함수 리터럴로 평가되며 함수 내부에서만 참조할 수 있는 식별자로 즉시 실행 함수를 다시 호출할 수는 없습니다.
5.1 즉시 실행 함수의 장점에 대해 설명해주세요.
- 즉시 실행 함수 내에 코드를 모아 두면 혹시 있을 변수나 함수 이름의 충돌을 방지할 수 있습니다.
6. Strict mode에 대해 설명해주세요.
- stict mode는 JavaScript 언어의 문법을 좀 더 엄격히 적용하여 오류를 발생시킬 가능성이 높거나 JavaScript 엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 대해 명시적인 에러를 발생시킵니다.
6.1 strict mode가 발생시키는 에러에 대해 아는대로 설명해주세요.
- 선언하지 않은 변수를 참조하면 ReferenceError를 발생시킵니다.
- delete 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError를 발생시킵니다.
- 중복된 매개변수 이름을 사용하면 SyntaxError를 발생시킵니다.
- with 문을 사용하면 SyntaxError를 발생시킵니다.
- with 문은 동일한 객체의 프로퍼티를 반복해서 사용할 때 객체의 이름을 생략할 수 있어서 코드가 간단해지는 효과가 있지만, 성능과 가독성이 나빠지는 문제가 있습니다. 따라서 with 문은 사용하지 않는 것이 좋습니다.
6.2 strict mode를 적용했을 때의 변화에 대해 설명해주세요.
- strict mode에서 함수를 일반 함수로 호출하면 this에 undefined가 바인딩됩니다.
- strict mode에서는 매개변수에 전달된 인수를 재할당하여 변경해도 arguments 객체에 반영되지 않습니다.
7. 콜 스택(Call Stack)과 힙(Heap)에 대해 설명해주세요.
- 콜 스택은 소스코드 평가 과정에서 생성된 실행 컨텍스트가 추가되고 제거되는 스택 자료 구조입니다.
- 힙은 객체가 저장되는 메모리 공간입니다.
- 실행 컨텍스트는 힙에 저장된 객체를 참조합니다.
- 객체는 런타임에 메모리를 동적으로 할당되기 때문에, 힙은 구조화되어 있지 않습니다.
8. Rest parameter와 Spread 연산자에 대해 설명해주세요.
- rest parameter는 함수에 전달된 인수 목록을 배열로 전달받기 위해 매개변수 이름 앞에 ...을 붙이는 것입니다.
- spread syntax는 여러 개의 값이 하나로 뭉쳐 있는 배열과 같은 이터러블을 펼쳐서 개별적인 값들의 목록을 만드는 것입니다.
9. 제네레이터에 대해 설명해주세요.
- 제네레이터는 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수입니다.
9.1 제네레이터와 일반 함수의 차이에 대해 설명해주세요.
- 함수의 제어권
- 일반 함수는 호출하면 제어권이 함수에게 넘어가고 함수 코드가 일괄 실행됩니다.
- 제네레이터 함수는 함수 호출자에게 함수 실행권을 양도할 수 있습니다.
- 따라서 함수 호출자가 함수 실행을 일시 중단시키나 재개시킬 수 있습니다.
- 함수 호출자와 함수의 상태 전달
- 일반 함수는 함수가 실행되는 동안 함수 외부에서 함수 내부로 값을 전달하여 함수의 상태를 변경할 수 없습니다.
- 제네레이터 함수는 함수 호출자와 함수의 상태를 주고 받을 수 있습니다.
- 반환값
- 일반 함수를 호출하면 함수 코드를 일괄 실행하고 값을 반환합니다.
- 제네레이터 함수를 호출하면 이터러블이면서 이터레이터인 제네레이터 객체를 반환합니다.
9.2 제네레이터 객체에 대해 설명해주세요.
- 제네레이터 객체는 Symbol.iterator 메서드를 상속받는 이터러블이면서 next 메서드를 소유하는 이터레이터입니다. 그리고 제네레이터 객체는 이터레이터에 없는 return, throw 메서드를 갖고 있습니다.
9.3 제네레이터 객체의 메서드를 각각 호출했을 때 어떤 일이 발생하나요?
- next 메서드를 호출하면, 제네레이터 함수의 yield 표현식까지 코드 블록을 실행하고 yield된 값을 value 프로퍼티 값으로, false를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환합니다.
- return 메서드를 호출하면, 인수로 전달받은 값을 value 프로퍼티 값으로, true를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환합니다.
- throw 메서드를 호출하면, 인수로 전달받은 에러를 발생시키고 undefined를 value 프로퍼티 값으로, true를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환합니다.
10. 이터러블와 이터레이터 프로토콜에 대해 설명해주세요.
- 이터러블 프로토콜은 직접 구현하거나 프로토타입 체인을 통해 상속받은 Symbol.iterator 메서드를 호출하면 이터레이터를 반환한다는 규약입니다.
- 이터레이터 프로토콜은 이터레이터가 next 메서드를 소유하며, next 메서드를 호출하면 이터러블을 순회하며 value와 done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환한다는 규약입니다.
10.1 빌트인 이터러블에 대해 아는대로 얘기해주세요.
- 빌트인 이터러블에는 Array, String, Map, Set, TypedArray, arguments, NodeList, HTMLCollection이 있습니다.
10.2 for ... in 문과 for ... of 문의 동작과정에 대해 설명해주세요.
- for ... in 문은 객체의 프토토타입 체인 상에 존재하는 모든 프로토타입의 프로퍼티 중 프로퍼티 어트리뷰트 [[Enumerable]]이 true인 프로퍼티를 순회하며 열거합니다.
- for ... of 문은 내부적으로 이터레이터의 next 메서드를 호출하여 이터러블을 순회하며 next 메서드가 반환한 이터레이터 리절트 객체의 value 프로퍼티 값을 for ... of 문의 변수에 할당합니다. 그리고 이터레이터 리절트 객체의 done 프로퍼티 값이 false이면 이터러블의 순회를 계속하고 true이면 이터러블의 순회를 중단합니다.
10.3 이터레이션 프로토콜이 나오게 된 배경에 대해 설명해주세요.
- ES6 이전의 순회 가능한 데이터 컬렉션은 통일된 규약없이 각자 나름의 구조를 가지고 for 문, for ... in 문, forEach 메서드 등 다양한 방법으로 순회할 수 있었습니다.
- 다양한 데이터 공급자가 각자의 순회 방식을 갖는다면 데이터 소비자는 데이터 공급자의 모든 순회 방식을 지원해야 합니다. 이는 효율적이지 않습니다.
- 그래서 ES6에서는 순회 가능한 데이터 컬렉션을 이터레이션 프로토콜을 준수하는 이터러블로 통일하여 for ... of 문, 스프레드 문법, 배열 구조 분해 할당의 대상으로 사용할 수 있도록 일원화했습니다.
11. Service Worker에 대해 설명해주세요.
- 서비스 워커는 웹 애플리케이션과 브라우저, 그리고 네트워크 사이에서 proxy 서버처럼 동작합니다.
- 서비스 워커의 목적은 효과적인 오프라인 경험을 생성하고, 네트워크 요청을 가로채 네트워크가 사용 가능 여부에 따라 적절한 조치를 취하며 서버에 있는 자원을 갱신하는 것입니다.
- 서비스 워커는 푸시 알림이나 백그라운드 동기화 API에 대한 접근도 허용합니다.
- 서비스 워커는 워커 컨텍스트에서 실행되므로 DOM 접근을 할 수 없고, 앱을 구동하는 메인 JavaScript 스레드와 다른 스레드에서 실행되므로 non-blocking입니다.
- 서비스 워커는 완전히 비동기로 설계되어서 동기적인 XHR, Web Storage는 서비스 워커 내부에서 사용할 수 없습니다.
- 서비스 워커는 JavaScript 모듈을 동적으로 가져올 수 없습니다. 서비스 워커의 전역 스코프에서 import()를 실행하면 에러가 발생합니다.
- import 문을 사용한 정적인 가져오기는 허용됩니다.
- 서비스 워커는 보안상의 이유로 HTTPS에서만 실행됩니다.
- HTTP 연결은 중간자 공격에 의한 악성 코드 삽입에 취약하며, 이러한 강력한 API에 접근이 허용되면 공격이 심해질 수 있습니다.
11.1 service worker의 사용 예에 대해 설명해주세요.
- 백그라운드 데이터 동기화
- 다른 출처로부터의 자원 요청에 응답할 때
- 백그라운드 서비스에 대한 훅
- 사용자가 사용할 것 같은 리소스를 미리 받아옴을 통한 성능 향상
- API mocking
참고