일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- media query
- Servlet
- @media
- node.js
- 반응형 페이지
- 자바문제풀이
- TypeScript
- github
- HTML
- max-width
- 코딩테스트
- JS
- 코드업
- coding
- 그럼에도 불구하고
- redux
- 프론트엔드
- 그럼에도불구하고
- react
- JavaScript
- webpack
- frontend
- 자바
- react-router-dom
- CSS
- 변수
- java
- cleancode
- git
- node
- Today
- Total
그럼에도 불구하고
[면접 준비] JavaScript / TypeScript 본문
지속적으로 업데이트됩니다! 🧐
Start!
🧑🏻💻 자바스크립트 엔진
자바스크립트가 동작되게 하려면 브라우저 자체에서 내장되어 있는 JS 엔진이 필요하다. 이것이 동작하는 시간을 런타임이라고 하는데 런타임 하는 과정에서 코드를 한 줄씩 읽고 번역해서 실행을 해주는 것을 인터프리터 라고 한다.
런타임 : JS 엔진이 동작하는 시간
인터프리터 : 런타임 하는 과정에서 코드를 한 줄 한 줄 읽고 번역해서 실행해 주는 것
🧑🏻💻 자바스크립트란?
- 자바스크립트는 가볍고 인터프리터를 이용해서 런타임 시 한 줄씩 번역해 준다.
- 일급 함수를 가진 언어이며, 자바스크립트 엔진이 있는 어떤 곳이든 사용할 수 있다.
- 자바스크립트는 프로토타입을 베이스로 다양한 스타일로 구현이 가능하고 멀티 패러다임이다. ( 절차지향으로도 가능하고 객체지향으로도 가능하다. )
- 싱글 스레드이다.
- 자바스크립트는 언어 자체만으로는 할 수 있는 것이 그리 많지 않다. 브라우저에서 무언가를 출력하고 싶다면 외부 환경에 출력을 도와줄만한 라이브러리를 사용해야 한다.
- 네트워크 통신을 하려면 통신을 할 라이브러리를 사용해야 한다.
📌 자바스크립트가 동적 언어인 이유는 무엇인가요?
자바스크립트는 런타임 시 변수의 타입이 결정됩니다.
즉, 소스가 빌드될 때 자료형이 결정되는 것이 아닌 실행 시 결정됩니다. 이를 통해 런타임까지 타입에 대한 결정을 끌고 갈 수 있지만, 실행 도중 변수에 예상치 못한 타입이 들어와 TypeError가 발생할 수 있습니다.
🧑🏻💻 스코프에 대해 설명해 주세요.
스코프는 식별자의 유효범위입니다.
식별자는 자신이 어디에서 선언됐는지에 의해 다른 코드가 자신을 참조할 수 있는 범위를 갖습니다.
var는 가장 가까운 함수를 스코프로 갖는 반면, let과 const는 가장 가까운 블록을 유효 범위로 갖습니다.
- 변수를 참조(=접근)할 수 있는 유효한 범위, 영역을 지정하는 것을 말한다.
- 선언된 위치에 따라 유효 범위가 결정된다.
- 범위는 코드 블록 {} 안에서만 유효한다.
- 블록 밖에서는 참조할 수 없다.
👉 장점
1. 이름 충돌이 방지된다.
2. 메모리를 절약할 수 있다.
👉 결론
변수는 최대한 필요한 곳에서 정의하자!!
👉 코드 블록이 쓰이는 곳들
{ }
if() {
}
for() {
}
function() {
}
📌 스코프 체인에 대해 설명해 주세요.
자바스크립트 엔진은 식별자를 찾을 때, 자신이 속한 스코프에서 찾고, 그 스코프에 식별자가 없으면 상위 스코프에서 다시 찾아나갑니다.
이러한 현상을 스코프 체인이라고 하며, 스코프가 중첩되어 있는 모든 상황에서 발생합니다.
또한, 함수가 어디서 호출되었는지가 아닌, 어디서 선언되었는지에 따라서 상위 스코프를 결정합니다.
🧑🏻💻 지역변수
function sum (a, b) {
console.log(a,b)
} // 이런 매개변수들도 블록안에서만 접근이 가능하다.
- 블록 외부에서는 블록 내부 변수를 참조할 수 없다.
- 함수 외부에서는 함수 내부의 변수를 참조할 수 없다.
- 함수 외부에서는 함수 매개변수를 참조할 수 없다.
{
const x = 1;
{
const y = 2;
console.log(x); // 1
}
console.log(x); // 1
console.log(y); // 블록 외부에서는 내부를 참조할 수 없다.
}
const x = 1 은 전체적인 코드 블록 내부에서 유효하다. 그래서 안에서 외부를 접근할 수 없다.
🧑🏻💻 글로벌 스코프
// 📍 전역 변수, 전역 스코프, 글로벌 변수, 글로벌 스코프 라고한다.
const text ='global';
{
// 📍 지역 변수, 로컬 변수, 지역 스코프, 로컬 스코프
const text = 'inside block';
{
console.log(text)
}
}
console.log로 인해 나오는 결과는 'inside block'이 됩니다. 내부에 있는 것은 외부에 있는 것에 접근이 안되기 때문에, 만약 inside block 값이 없다면 한 단계 위로 상위 변수에 접근할 수 있습니다.
쉽게 말해 가장 가까운 변수에 접근하는 것입니다.
🧑🏻💻 자바스크립트의 메모리 관리에 대해 설명해 주세요. 👉 가비지 컬렉터 (= 쓰레기 수집)
프로그래밍을 할 때 자동으로 메모리 청소를 해주는 기능이 있습니다.
⭐️ 메모리 구조
let apple = {
name : 'apple',
}
let orange = apple;
orange = null;
apple = null;
오브젝트를 변수에 할당하면 오브젝트는 메모리 어딘가에 heap이라는 곳에 만들어집니다. 변수는 메모리가 만들어진 주소를 가리키게 되는데, 메모리 안에 아무것도 없을 경우에 (Null) 참조하는 것이 없다면, 쓰레기로 간주하고 메모리에서 깔끔하게 청소를 해줍니다.
자바스크립트에서 가비지 컬렉션이 발생하는 원리는 가비지 컬렉터라는 기능이 있는데, 이는 자바스크립트 엔진 자체에서 제공해 주고 백그라운드 프로세스에서 동작해 줍니다. 대신 이런 점에서 CPU가 발생합니다. ( 즉, 그에 따른 비용이 발생합니다. )
const global = 1;
{
const local = 1;
}
이처럼 글로벌 변수는 앱이 종료될 때까지 계속 메모리에 유지됩니다.
블록 스코프는 블록 스코프의 역할이 끝나면 자동으로 소멸됩니다. -> 가비지 컬렉터가 메모리를 처리해 줍니다.
그래서 가급적이면 글로벌하게 전역 변수를 쓰지 않는 것이 좋습니다.
메모리 측면에서 좋지 않기 때문에 가급적이면 필요한 곳에서만 사용하는 것이 좋습니다.
🧑🏻💻 변수 선언, 초기화, 할당의 차이점에 대해 설명해 주세요.
- 변수 선언은 변수를 생성하는 것을 의미합니다. 해당 식별자를 등록하여 스코프가 참조할 대상을 만듭니다.
- 초기화는 메모리에 변수 저장을 위한 공간을 확보하는 단계입니다. 기본값으로 undefined가 할당됩니다.
- 할당은 = 연산자를 사용하여 값을 할당하는 단계로, undefined로 초기화된 변수에 실제 값을 할당해 주는 단계입니다.
🧑🏻💻 데이터 타입에 대해 설명해 주세요.
JavaScript의 데이터 타입은 원시값과 객체로 나뉩니다.
원시 값은 불변 값을 의미하며, Number, String, Boolean, null, undefined, Symbol, BigInt 타입이 있습니다.
객체는 여러 다른 값과 메서드를 포함할 수 있는 복합 데이터 타입이며, 객체 리터럴, 배열, 함수, Date 등이 있습니다.
🧑🏻💻 생성자에 대해 설명해 주세요
생성자 함수란 new 연산자와 함께 호출하여 객체를 생성하는 함수를 의미합니다.
생성자 함수에 의해 생성된 객체를 인스턴스라 하며, 자바스크립트는 Object 외에도 다양한 타입의 빌트인 생성자 함수를 제공합니다.
🧑🏻💻 렉시컬 환경
렉시컬 환경은 두 부분으로 구성됩니다.
- 환경 레코드: 모든 지역 변수를 프로퍼티로 저장하고 있는 객체입니다. this 값과 같은 기타 정보도 여기에 저장됩니다.
- 외부 렉시컬 환경에 대한 참조
환경 레코드는 변수나 함수에 대한 정보를 갖고 있으며, 변수가 변경되면 환경 레코드의 프로퍼티가 변경됩니다.
외부 렉시컬 환경에 대한 참조는 스코프 체인에 활용됩니다.
내부 렉시컬 환경에서 원하는 변수를 찾지 못하면 내부 렉시컬 환경이 참조하는 외부 렉시컬 환경으로 검색 범위를 확장하며, 이를 전역 렉시컬 환경까지 반복합니다.
📌 ⭐️ 실행 컨텍스트에 대해 설명해 주세요.
실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체입니다.
자바스크립트는 이러한 환경 정보들을 모은 실행 컨텍스트를 콜 스택에 쌓아 올린 후 실행하여 코드의 환경과 순서를 보장합니다.
- 코드의 실행 순서와 스코프를 기억하고 있기 때문에 콜 스택과 밀접하게 관련이 있습니다.
- 내부에서 외부로 접근이 가능합니다. 전역에서 선언된 것을 전역 스코프라 하고 내부에 있는 것을 블록 스코프라고 합니다. 블록 안에는 또 다른 스코프가 존재할 수도 있습니다.
const a = 1;
{
const a = 2;
{
const a = 3;
}
}
이런 코드가 있다고 가정할 때, 각각의 블록에서는 렉시컬 환경이라는 내부 오브젝트를 가지고 있습니다. 그래서 각 블록마다 "어떤 변수가 들어있는지, 부모는 누구인지?" 이런 것을 추적하는 것을 렉시컬 환경이라고 합니다.
자바스크립트 엔진은 이런 실행 순서와 각각의 블록의 정보들을 한 오브젝트에 데이터를 담아두고 있습니다.
⭐️ 실행 컨텍스트 스택
const a = 1; // 전역 스코프
{
const a = 2; // 블록 스코프 1
{
const a = 3; // 블록 스코프 2
}
}
이와 같이 전역 스코프 렉시컬 환경이 만들어져 있다고 가정하면, 블록 스코프 1의 렉시컬 환경이 있고 블록 스코프 2가 있습니다.
이렇게 이어지는 것을 스코프 체인이라고 합니다.
⭐️ 렉시컬 환경과 스코프 체인을 통해 배운 점
1. 메모리 절약뿐만 아니라 성능을 위해서, 변수는 최대한 필요한 곳에 정의해야 합니다.
2. 중첩된 스코프나 중첩된 함수가 있다면 모든 체인을 검사하며 돌아다니기 때문에 성능에 좋지 않을 수 있습니다.
⭐️ 스코프 개념 정리
스코프는 식별자가 유효한 범위를 나타내는데, 스코프 밖에서는 스코프 내부에 있는 것을 접근할 수 없지만 스코프 내부에서는 스코프 외부에 있는 어떤 부모의 데이터라도 접근할 수 있습니다.
접근할 수 있는 이유 : 렉시컬 환경 참조와 스코프 체인을 통해 부모에 접근할 수 있기 때문
⭐️ 🧑🏻💻 변수 호이스팅과 발생하는 이유에 대해 설명해 주세요.
자바스크립트 엔진(인터프리터)이 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미합니다.
또한, 변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는 작업입니다.
⭐️ 변수
- 값을 저장할 수 있는 공간
- 자료를 저장할 수 있는 이름이 주어진 기억 장소
보통 let과 const를 많이 사용합니다.
- let : 재할당이 필수로 필요한 경우에 사용합니다.
- const : 재할당이 필요 없는 경우에 사용합니다.
let과 const가 없을 때는 var를 사용했는데 var은 문제점이 많습니다.
⭐️ var의 문제점
기본적으로 함수의 호이스팅은 함수의 선언문 전에 호출이 가능하게 해 줍니다.
즉, 함수의 선언문은 선언 이전에도 호출이 가능합니다.
print();
function print() {
console.log('hello');
}
하지만 변수는 변수 선언하기 이전에 호출하면 오류가 발생합니다.
console.log(hi); // ☠️
let hi = 'hi';
함수 선언만 호이스팅이 가능해서 호출이 가능하고, 변수( let, const )와 클래스는 선언된 이름만 호이스팅이 가능하고 값 자체는 (위에서 아래로) 순서대로 처리하기 때문입니다.
하지만 var는 let과 const와는 다르게 선언 이전에 호출이 가능하다는 문제가 있습니다.
📌 var 특징
- 코드의 가독성과 유지보수성이 좋지 않습니다.
- 변수를 선언하는 키워드 없이 선언과 할당이 가능합니다.
- 선언인지 재할당인지 구분하기가 어렵습니다.
- 중복 선언이 가능합니다. ( a라는 변수를 선언하고, 그 이후로 같은 이름의 a로 재선언이 가능합니다.)
⭐️ 🧑🏻💻 var, let, const 차이에 대해 설명해 주세요.
var는 let, const와 달리 함수 레벨 스코프입니다. 따라서 함수가 아닌 블록 안에서 var 변수를 정의하면 해당 블록 밖에서도 이 변수에 접근할 수 있습니다. 또한 var는 중복 선언이 가능합니다. 그러나 두 번째 선언은 무시되며, 에러는 발생하지 않습니다.
반대로 let, const는 중복 선언이 불가능하며 에러가 발생합니다.
let과 const는 불변성의 차이를 갖는데, const는 변수가 아닌 상수를 정의하며, 상수를 변경하려고 하면 에러가 발생합니다.
📌 TDZ에 대해 설명해 주세요.
ES6의 let과 const는 변수를 블록의 상단으로 호이스팅 하지만 초기화하지는 않습니다.
변수가 선언되기 전에 블록 안에서 사용할 수 없는데, 이 위치를 시간상 사각지대 (Temporal Dead Zone, TDZ)라고 표현합니다.
즉, 변수 스코프의 맨 위에서 변수 초기화 전까지의 영역을 의미합니다.
🧑🏻💻 함수 선언문과 함수 표현식의 차이에 대해 설명해 주세요
- 함수 선언문은 function add(x, y) {}의 형태로 쓰이며, 완료 시 undefined가 출력됩니다. 이때 함수의 이름을 생략할 수 없습니다.
- 함수 표현식은 const add = function(x, y) {}의 형태로 쓸 수 있으며, 함수 리터럴의 함수 이름을 생략할 수 있습니다.
📌 주요 차이점
- 호이스팅: 함수 선언문은 호이스팅에 의해 코드 블록 내 어디에서든 호출할 수 있지만, 함수 표현식은 변수 할당이 실행되기 전에 함수를 사용할 수 없습니다.
- 이름의 필수성: 함수 선언문은 함수 이름이 필수적이며, 함수 표현식은 이름을 생략할 수 있습니다.
- 스코프: 함수 선언문은 함수의 스코프를 무시하고 항상 상위 스코프에 바인딩되지만, 함수 표현식은 변수의 스코프에 따라 함수의 가시성이 결정됩니다.
- 익명 함수: 함수 표현식을 사용하면 익명 함수를 생성할 수 있으며, 이러한 함수는 필요한 곳에서 직접 호출하거나 변수에 할당하여 사용할 수 있습니다.
⭐️ 🧑🏻💻 클로저에 대해 설명해 주세요
자바스크립트에서 클로저는 함수와 그 외부를 둘러싸고 있는 렉시컬 환경의 조합이라고 보면 되는데, 쉽게 말해 내부 함수와 그 외부에 있는 함수의 스코프에 접근할 수 있는 것을 클로저라고 합니다.
클로저는 반환된 내부 함수가 자신이 선언되었을 때의 환경(렉시컬 환경)인 스코프를 기억하여, 그 밖에서 호출되어도 해당 환경에 접근할 수 있는 함수를 의미합니다.
이를 통해 전역 변수를 사용하지 않고도 함수 밖에서 해당 변수에 접근할 수 있는 방법을 만들어 주며, 이는 반환된 함수를 제외하면 외부에서 접근할 수 없으므로 마치 private 한 변수처럼 사용할 수 있습니다.
function outer() {
const x = 0;
function inner() {
x; // 감싸고있는 함수의 변수에 접근이 가능하다. 이유는 클로저 버프 때문
}
inner();
}
outer();
실행 컨텍스트 스택에 전역 스코프 렉시컬 환경이 먼저 들어오고 그다음에 outer라는 스코프 렉시컬 환경이 들어옵니다.
후에 outer 렉시컬 환경에 inner 스코프가 들어오게 됩니다.
⭐️ 클로저를 사용하는 이유
- 클로저는 내부 정보를 은닉하고, 공개 함수(public, 외부)를 통한 데이터 조작을 위해 쓰입니다.
- 클로저는 캡슐화와 정보은닉을 위해 쓰입니다.
- 클로저는 클래스 private 필드 또는 메서드를 사용하는 효과와 동일합니다.
🧑🏻💻 프로토타입에 대해 설명해 주세요.
자바스크립트의 모든 객체들은 메서드와 속성들을 상속받기 위한 템플릿으로써 프로토타입 객체를 갖습니다.
정확히 말하자면 상속되는 속성과 메서드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있습니다.
자바스크립트에서는 객체 인스턴스와 프로토타입 간의 연결이 구성되며, 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메서드를 탐색합니다.
🧑🏻💻 깊은 복사와 얕은 복사에 대해 설명해 주세요.
얕은 복사는 객체의 참조값(주소 값)을 복사하고, 깊은 복사는 객체의 실체 값을 복사합니다.
A라는 객체를 B로 복사했다고 할 경우, 얕은 복사를 했다면 B를 변경할 시, A도 함께 변경됩니다.
반면 깊은 복사를 했다면 A와 B가 완전히 분리되어 A가 변경되지 않게 됩니다.
📌 불변성을 유지하려면 어떻게 해야 하나요?
대표적으로 세 가지 방법이 있습니다.
Object.preventExtensions 메서드는 객체의 확장 즉, 프로퍼티의 추가를 금지합니다.
Object.seal 메서드는 객체를 밀봉합니다. 객체 밀봉이란 프로퍼티 추가와 삭제, 프로퍼티 어트리뷰트 재정의 금지를 의미합니다.
즉, 읽기와 쓰기만 가능합니다.
Object.freeze 메서드는 객체를 동결합니다. 객체 동결이란 프로퍼티의 추가와 삭제, 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지를 의미합니다. 즉, 읽기만 가능합니다.
하지만 이 방법들 모두 직속 프로퍼티만 변경을 방지하므로 중첩 객체까지 동결하기 위해서는 재귀적으로 메서드를 호출하거나 immer와 같은 불변성 라이브러리를 사용해야 합니다.
🧑🏻💻 클래스에 대해 설명해 주세요.
자바스크립트에서 클래스는 함수의 한 종류입니다.
혹자는 자바스크립트의 클래스를 문법적 설탕에 불과하다고 말하지만 함수와는 중요한 차이가 몇 가지 있습니다.
class로 만든 함수에는 특수 내부 프로퍼티인 [[IsClassConstructor]]: true가 붙습니다.
따라서 new와 함께 호출하지 않으면 에러가 발생합니다.
또한 클래스에 정의된 메서드는 열거할 수 없으며, 항상 strict mode로 실행됩니다.
🧑🏻💻 Strict mode (엄격 모드)에 대해 설명해 주세요.
엄격 모드는 "use strict"; 를 스크립트 최상단에 작성하여 사용합니다.
이는 ES5에서 기존 스펙을 변경하며 하위 호환성 문제가 발생했기 때문에 도입된 문법으로, 엄격 모드를 활성화했을 때에만 변경사항이 활성화되도록 해두었습니다.
또한 코드를 클래스와 모듈을 사용해 구성한다면 use strict를 사용하지 않아도 자동으로 엄격모드가 활성화됩니다.
🧑🏻💻 즉시 실행 함수 (IIFE)에 대해 설명해 주세요.
즉시 실행 함수는 정의되자마자 즉시 실행되는 함수를 말하며, 소괄호로 함수를 감싸서 실행하는 문법을 사용합니다.
이를 통해 필요 없는 전역 변수의 생성을 줄일 수 있고, 자체적인 스코프를 가지게 되기 때문에 private 한 변수를 만들 수 있습니다.
🧑🏻💻 Blocking과 Non-Blocking에 대해 설명해 주세요.
Blocking은 직접 제어할 수 없는 작업이 끝날 때까지 기다려야 하는 경우를 의미합니다. 호출된 함수에서 I/O 작업 등을 요청했을 경우 I/O 작업이 처리되기 전까지 아무 일도 하지 못합니다.
Non-Blocking은 직접 제어할 수 없는 작업이 완료되기 전에 제어권을 넘겨주는 경우를 말합니다. 호출된 함수에서 I/O 작업 등을 요청했을 경우 I/O 작업의 처리 여부와 관계없이 바로 다음 작업을 할 수 있습니다.
⭐️ 🧑🏻💻 동기와 비동기에 대해 설명해 주세요.
동기는 순차적으로 태스크를 수행하며, 요청을 보냈다면 응답을 받아야 다음 동작이 이루어집니다.
순차적으로 실행되므로, 어떤 작업이 수행 중이라면 뒤의 작업은 대기하게 됩니다.
반면 비동기는 병렬적으로 태스크를 수행합니다. 현재 작업의 종료여부와는 무관하게 다음 작업을 실행하므로 동기 방식과 달리 완료 순서가 보장되지 않습니다.
자바스크립트는 기본적으로, 싱글 스레드 기반으로 동기적으로 작동합니다.
🧑🏻💻 ES6에서 새로 생긴 기능을 아는 대로 말씀해 주세요.
- 블록 스코프, let, const
- 클래스
- 모듈
- 화살표 함수
- 매개변수 기본값
- 템플릿 리터럴
- 디스트럭쳐링
- 스프레드 연산자
- 프로미스
📌 Rest 연산자와 Spread 연산자에 대해 설명해 주세요.
Rest 연산자는 객체, 배열, 그리고 함수의 파라미터에서 사용이 가능합니다.
객체나 배열에서 Rest 연산자를 사용하면 디스트럭처링된 값들을 다시 객체나 배열로 묶을 수 있습니다.
함수의 파라미터에서는 파라미터가 몇 개가 될지 모르는 상황에서 이 파라미터들을 배열로 묶어주는 역할을 수행합니다.
새로 만들어줄 객체나 이름 앞에 ...를 붙여 사용합니다.
Spread 연산자를 사용하면 객체 혹은 배열을 펼칠 수 있습니다. 이를 사용해 객체의 프로퍼티들을 기존 객체를 건드리지 않으면서 다른 객체에 모두 집어넣을 수 있습니다.
객체나 배열의 이름 앞에 ...를 붙여서 사용합니다.
🧑🏻💻 제너레이터에 대해 설명해 주세요.
제너레이터는 function* 로 만들어지는 제너레이터 함수를 통해 만들 수 있으며, 해당 함수는 본문을 실행하지 않고 제너레이터 객체를 반환합니다.
그 후, next()를 수행할 때마다, 함수에서 yield 한 값들을 하나씩 반환합니다.
next()를 사용할 수 있는 것으로 짐작할 수 있듯, 제너레이터 객체는 이터레이터이자 이터러블입니다.
따라서 제너레이터에서도 for ... of나 Spread 문법, 배열 디스트럭처링과 같은 기능을 사용할 수 있습니다.
🧑🏻💻 이터러블과 이터레이터 프로토콜에 대해 설명해 주세요.
이터러블(Iterable)과 이터레이터 프로토콜(Iterator Protocol)은 자바스크립트에서 반복 가능한 데이터 구조를 정의하고 조작하는 데 사용되는 중요한 개념입니다.
이터레이션 프로토콜은 순회 가능한 데이터 컬렉션을 만들기 위해 ES6에서 도입된 규칙입니다.
이터레이션 프로토콜에는 이터러블 프로토콜과 이터레이터 프로토콜이 있습니다.
Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은 Symbol.iterator 메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환합니다.
이러한 규약을 이터러블 프로토콜이라고 하며, 이터러블 프로토콜을 준수한 객체를 이터러블이라고 합니다.
이터러블의 Symbol.iterator 메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환합니다. 이터레이터는 next 메서드를 소유하며 next 메서드를 호출하면 이터러블을 순회하며 value와 done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환합니다.
이러한 규약을 이터레이터 프로토콜이라고 하며, 이터레이터 프로토콜을 준수한 객체를 이터레이터라고 합니다.
🧑🏻💻 undefined, null, undeclared를 비교해 주세요.
undefined는 값이 할당되지 않았음을 의미합니다. 변수가 초기화 관계를 거치면 undefined로 남아있게 됩니다.
null은 의도적으로 null이라는 빈 값을 할당한 경우를 의미합니다.
undeclared는 변수 선언조차 되어있지 않은 상태를 의미합니다.
⭐️ 🧑🏻💻 this에 대해 설명해 주세요.
this 키워드는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있는 키워드입니다.
this는 함수가 호출되는 방식에 따라 달라집니다.
- 일반 함수 호출을 사용할 경우 기본적으로 전역 객체가 바인딩됩니다.
- 메서드 호출을 할 경우, 마침표 연산자 앞에 기술한 객체가 바인딩됩니다.
- 생성자 함수 호출을 할 경우, 미래에 생성할 인스턴스가 바인딩됩니다.
- 화살표 함수의 경우 this가 없기 때문에 선언될 시점에서의 상위 스코프가 바인딩됩니다.
이보다 더 this에 대해 잘 설명할 수 없다! (아님 말고)
📌 call, apply, bind에 대해 설명해 주세요.
1. call 메서드
- call 메서드는 함수를 호출할 때 특정 컨텍스트(값으로 주어진 'this' 객체)와 함께 호출하는 데 사용됩니다.
- 함수를 호출하면서 순서대로 인수를 전달합니다.
- 사용법:
function sayHello() {
console.log(`Hello, ${this.name}`);
}
const person = { name: "John" };
sayHello.call(person); // Hello, John
2. apply 메서드
- apply 메서드는 함수를 호출할 때 특정 컨텍스트와 함께 호출하며, 인수를 배열 형태로 전달합니다.
- 함수를 호출하면서 배열로 된 인수를 전달합니다.
- 주로 함수에 동적으로 많은 인수를 전달해야 할 때 유용합니다.
- 사용법:
function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}
const person = { name: "Alice" };
greet.apply(person, ["Hello"]); // Hello, Alice
3. bind 메서드
- bind 메서드는 함수의 컨텍스트를 영구적으로 바인딩(bind)하고, 새로운 함수를 반환합니다.
- 원본 함수는 변경되지 않고, 바인딩된 새 함수를 생성합니다.
- 주로 이벤트 핸들러나 콜백함수를 정의할 때 사용합니다.
- 사용법:
function sayHi() {
console.log(`Hi, ${this.name}`);
}
const person = { name: "Emily" };
const greetPerson = sayHi.bind(person);
greetPerson(); // Hi, Emily
이 세 가지 메서드는 강제로 this를 바꿉니다.
- call과 apply는 함수를 호출하는 함수입니다. 그러나 첫 번째 인자에 this로 만들고 싶은 객체를 넘겨주어, this를 바꾸고 나서 실행합니다.
- bind는 함수를 실행하지 않고, this를 바꾸고 난 뒤에 함수인 bound 함수를 리턴합니다.
⭐️ 🧑🏻💻 콜백 함수에 대해 설명해 주세요.
콜백 함수는 다른 함수의 인자로 넘겨지는 함수를 의미합니다.
콜백 함수는 비동기 프로그래밍에 자주 사용되며, 자바스크립트에서 이벤트 정의를 위해 사용되기도 합니다.
📌 ⭐️ 콜백 지옥을 해결하는 방법을 설명해 주세요.
콜백 지옥은 비동기 처리 로직을 위해 콜백 함수를 연속으로 중첩하여 사용할 때 발생하는 문제입니다.
일반적으로 콜백 지옥을 해결하는 방법에는 Promise나 Async가 있습니다.
Promise는 비동기 연산이 종료된 이후에 결과를 알기 위해 사용하는 객체입니다.
Promise의. then을 사용하여 함수 실행 순서를 정할 수 있습니다.
ES8에 도입된 async, await를 사용하면 비동기 함수를 마치 동기적 코드인 것처럼 동작하도록 구현할 수 있습니다.
- async 함수는 항상 promise를 반환합니다.
- await는 async 함수 안에서만 작동하며, await 키워드를 쓰게 되면 해당 값이 반환되기 전까지 기다리는 동안 async 내부 함수는 일시 중단됩니다.
⭐️ 🧑🏻💻 Promise에 대해 설명해 주세요.
Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.
Promise는 비동기 연산이 종료된 이후에 결과 값과 실패 사유를 처리하기 위한 처리기를 연결할 수 있습니다.
다만, 최종 결과를 반환하는 것이 아니고, 미래에 어떤 시점에 결과를 제공하겠다는 약속(Promise)을 반환합니다.
📌 ⭐️ Promise와 Callback을 비교 설명해 주세요.
- Callback을 사용하면 비동기 로직의 결괏값을 처리하기 위해 Callback 안에서만 처리할 수 있고, 밖에서는 결괏값을 알 수 없습니다.
- 하지만 Promise를 사용하면 비동기 로직의 결괏값이 Promise 객체에 저장되기 때문에 코드 작성이 용이합니다.
📌 ⭐️ Promise와 Async, Await의 차이를 설명해 주세요.
- Promise는. catch()를 통해 에러 핸들링이 가능하지만, async/await은 try-catch() 문을 사용해야 합니다.
- 또한 Promise도. then() 지옥이 발생할 수 있기 때문에 코드가 길어질수록 async/await을 활용한 코드가 코드 흐름을 이해하기 쉽습니다.
⭐️ 🧑🏻💻 이벤트 캡쳐링과 버블링에 대해 설명해 주세요.
이벤트 흐름은 캡쳐링 단계, 타깃 단계, 버블링 단계로 나누어집니다.
⭐️ 이벤트 캡쳐링
이벤트 캡쳐링은 최상위 조상(window)에서 시작해 해당 요소까지 이벤트가 전파되는 과정을 의미합니다. ( 부모 컴포넌트에서 시작돼서 자식까지 이벤트에 영향을 끼칩니다. )
이 단계에서 이벤트를 잡아내려면 addEventListener의 capture 옵션을 true로 설정해야 합니다.
캡쳐링 단계 이후, 버블링이 발생합니다.
⭐️ 이벤트 버블링 (⭐️x2)
이벤트 버블링은 가장 최상단의 조상 요소를 만날 때까지 이어서 부모 요소에게 이벤트가 전파되는 과정을 의미합니다.
- 상위에 있는 부모에게 이벤트를 호출하게 합니다.
- event.stopPropagation()는 부모에 세 전달하는 것을 중지시킵니다.
🏷️ 버블링이 되지 않는 이벤트
포커스 이벤트: focus / blur
리소스 이벤트: load / unload / abort / error
마우스 이벤트: mouseenter / mouseleave
📌 ⭐️ 이벤트 위임에 대해 설명해 주세요.
이벤트 위임이란 비슷한 방식으로 여러 요소를 다뤄야 할 때 사용합니다. 이벤트 위임을 사용하면 요소마다 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다를 수 있습니다.
이벤트 위임을 사용하려면 이벤트가 반드시 버블링 되어야 하며, 이벤트가 발생한 요소를 특정하기 위해 event.target을 사용할 수 있습니다.
이 패턴을 통해 얻을 수 있는 이점은 다음과 같습니다.
1. 동적으로 요소 추가 시 핸들러를 고려할 필요가 없습니다.
2. 상위 요소에 하나의 이벤트 핸들러만 추가하면 되기 때문에 코드가 훨씬 깔끔해집니다.
3. 메모리에 있게 되는 이벤트 핸들러가 적어지기 때문에 퍼포먼스 측면에서 이점이 있습니다.
📌 ⭐️ 이벤트 위임 동작 방식에 대해 설명해 주세요.
우선 컨테이너에 하나의 이벤트 핸들러를 추가합니다.
그 후 컨테이너 내의 요소에서 이벤트가 발생하면 해당 이벤트는 이벤트 버블링 단계를 통해 부모요소로 전파됩니다.
만약 이벤트 핸들러가 추가된 컨테이너까지 이벤트가 전파되면 event.target을 사용해 이벤트가 발생한 요소가 어디인지 알아내고, 원하는 요소에서 이벤트가 발생했다면 이벤트를 핸들링합니다.
⭐️ 🧑🏻💻 자바스크립트에서 비동기 로직이 어떻게 동작하는지 설명해 주세요. (이벤트 루프)
자바스크립트의 특징 중 하나는 싱글 스레드로 동작한다는 것입니다. (싱글 스레드 방식은 한 번에 하나의 태스크만 처리할 수 있다는 것을 의미합니다.) 하지만 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 느껴집니다.
예를 들어, HTML 요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하기도 하고, HTTP 요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링 하기도 합니다. 이처럼 자바스크립트의 동시성(concurrency)을 지원하는 것이 이벤트 루프입니다.
자바스크립트 엔진은 크게 2개의 영역으로 구분할 수 있습니다.
📌 콜 스택과 힙에 대해 설명해 주세요.
콜 스택은 코드가 실행되면서 생성되는 실행 컨텍스트를 저장하는 자료구조입니다. 이를 통해 변수 식별자, 스코프 체인 및 this 관리, 코드 실행 순서 관리등을 수행하게 되며, 원시 타입의 값과 참조 타입의 메모리 힙 주소값이 저장되는 공간입니다.
메모리 힙은 원시 타입이 아닌 타입의 데이터가 저장되는 공간으로, 메모리 할당이 일어나게 됩니다.
👉 콜스택 (Call Stack)
소스코드(전역 코드나 함수 코드 등) 평과 가정에서 생성된 실행 컨텍스트가 추가되거 제거되는 스택 자료구조인 실행 컨텍스트 스택이 바로 콜스택입니다.
함수를 호출하면 함수 실행 컨텍스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행됩니다. 자바스크립트 엔진은 단 하나의 콜 스택을 사용하기 때문에 최상위 실행 컨텍스트(실행 중인 실행 컨텍스트)가 종료되어 콜 스택에서 제거되기 전까지는 다른 어떤 태스크도 실행되지 않습니다.
👉 힙 (Heap)
힙은 객체가 저장되는 메모리 공간입니다. 콜 스택의 요소인 실행 컨텍스트는 힙에 저장된 객체를 참조합니다.
메모리에 값을 저장하려면 먼저 값을 저장할 메모리 공간의 크기를 결정해야 합니다. 객체는 원시 값과는 달리 크기가 정해져 있지 않으므로 할당해야 할 메모리 공간의 크기를 런타임에 결정해야 합니다. 따라서 객체가 저장되는 메모리 공간인 힙은 구조화되어 있지 않다는 특징이 있습니다.
이처럼 콜 스택과 힙으로 구성되어 있는 자바스크립트 엔진은 단순히 태스크가 요청되면 콜 스택을 통해 요청된 작업을 순차적으로 실행할 뿐입니다. 비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 Node.js가 담당하게 됩니다.
👉 이벤트 루프 (Event Loop)
이벤트 루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 그리고 태스크 큐에 대기 중인 함수(콜백 함수, 이벤트 핸들러 등)가 있는지 반복해서 확인합니다. 만약 콜 스택이 비어 있고 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프는 순차적(FIFO)으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시킵니다. 이때 콜 스택으로 이동한 함수는 실행됩니다. 즉, 태스크 큐에 일시 보관된 함수들은 비동기 처리 방식으로 동작합니다.
이벤트 루프는 2개의 큐를 감시하고 있다가 콜 스택이 비게 되면, 콜백함수를 꺼내와서 실행합니다. 이때 마이크로테스트 큐의 콜백함수가 우선순위를 가지기 때문에 마이크로테스트 큐의 콜백 함수를 전부 실행하고 나서 매크로테스트 큐의 콜백 함수들을 실행합니다. (단, UI 렌더링이 매크로테스트 큐에 속하기 때문에 마이크로태스크 큐의 태스크가 많다면 렌더링이 지연될 수 있습니다.)
📌 예시
1. setTimeout이라는 Web API가 A라는 함수에 있다고 가정합니다. 그리고 setTimeout은 B라는 콜백을 전달받았습니다.
2. A 함수를 호출하면 콜 스택에 함수가 추가됩니다. 그리고 A 내부의 setTimeout 함수도 콜스택에 추가됩니다.
3. setTimeout 안에 있는 B 콜백은 Web API로 넘어가고, 그동안 setTimeout 함수는 콜 스택에서 제거됩니다. 그 후 A 함수도 콜 스택에서 제거됩니다.
4. Web API에서 정해진 시간 동안 타이머가 돌고, B 함수는 콜 스택으로 들어가는 것이 아닌 태스크 큐라는 곳으로 전달됩니다.
5. 이벤트 루프는 콜 스택과 태스크 큐를 계속 확인합니다. tick 단위로 둘을 계속 순회하며 지켜보다가 콜 스택이 비게 된다면 태스크 큐에서 해당 콜백을 빼서 콜 스택으로 넣어줍니다.
만약 Promise를 사용한다면, 마이크로 태스크 큐를 사용합니다. 마이크로 태스크 큐는 태스크 큐보다 우선순위가 높은 큐로, 태스크 큐에 대기 중인 함수가 있더라도, 마이크로 태스크 큐가 비어있지 않다면, 마이크로 태스크 큐에 대기 중인 함수부터 콜스택으로 전달합니다.
⭐️ 태스크 큐
setTimeout(), setInterval(), UI rendering, requestAnimationFrame(), script, mousemove 등
일반적인 이벤트 핸들러, 콜백함수를 의미합니다.
⭐️ 마이크로태스크 큐
Promise (. then/catch/finally), MutationObserver, async/await
📌 예시
console.log('안녕');
setTimeout(() => console.log('큐!'),0);
Promise.resolve().then(() => console.log('마이크로 큐!'));
위와 같은 코드가 있을 때, 결과는 다음과 같습니다.
안녕
마이크로 큐!
큐!
처음 스크립트가 로드될 때, 스크립트 실행이라는 태스크가 먼저 태스크 큐에 들어갑니다. 그러고 나서 이벤트 루프가 태스크 큐에서 해당 태스크를 가져와 콜 스택을 실행하는 것입니다.
🧑🏻💻 requestAnimationFrame에 대해 설명해 주세요.
requestAnimationFrame()은 자바스크립트가 프레임 시작 시 실행되도록 보장해 주기 때문에, 밀림 현상이 발생하지 않아 부드러운 애니메이션을 제공하는 함수입니다.
이는 일반적인 비동기 task로 분류되지만, Animation frames라는 별개의 큐에서 처리하게 됩니다.
따라서 별도의 큐에 적재된 뒤, 이벤트 루프에 의해 꺼내지기 때문에 실행이 뒤쳐지는 현상을 감소시킬 수 있습니다.
🧑🏻💻 map과 forEach, reduce에 대해 설명해 주세요.
Array.prototype.map()은 배열 내의 모든 요소 각각에 대하여 주어진 콜백을 실행한 뒤, 그 결괏값들을 모아 새로운 배열을 만들어냅니다.
Array.prototype.forEach()는 주어진 콜백을 각각의 array 요소들에게 실행합니다.
Array.prototype.reduce()는 배열의 각 요소에 대해 주어진 함수를 실행하고 하나의 결괏값을 반환합니다. 초기 값을 설정하여 특정 인덱스부터 실행할 수도 있습니다.
성능은 대략 reduce > forEach > map 순입니다.
📌 map과 forEach의 차이에 대해 설명해 주세요.
map()의 경우 return 값이 있지만 forEach의 경우 return 값이 따로 없습니다.
🧑🏻💻 타입스크립트는 왜 사용하나요?
타입스크립트는 자바스크립트를 기반으로 정적 타입 문법을 추가한 프로그래밍 언어입니다.
1. 타입을 직접 지정해 주고 컴파일 시점에 에러를 잡아낼 수 있습니다.
2. 변수에 지정된 타입이 아닌 다른 타입을 지정해 주면 에러가 발생합니다.
3. 제네릭, 인터페이스, 접근 제어자등을 통해, 기존 객체지향 언어를 사용하던 개발자의 진입 장벽을 낮춰줍니다.
이런 이유들로 인해 코드의 안정성과 더 나은 개발 디버깅이 가능하며, 데이터가 어떤 타입인지 직관적으로 알 수 있습니다.
※ 자바스크립트는 동적 타입의 인터프리터 언어로 런타임에서 오류를 발견할 수 있고,
타입스크립트는 정적 타입의 컴파일 언어이며 타입스크립트 컴파일러 또는 바벨(Babel)을 통해 자바스크립트 코드로 변환됩니다.
🧑🏻💻 Type과 Interface의 차이점에 대해 설명해 주세요.
1. 선언적 확장
interface는 같은 이름으로 중복 선언을 함으로써 확장이 가능하지만, type의 경우 에러가 발생합니다.
2. extends, &, |
interface는 extends 키워드를 통해 확장할 수 있습니다. 비슷한 기능을 type에서 구현하려면 intersection 타입인 &를 통해 사용할 수 있습니다.
🧑🏻💻 제네릭에 대해 설명해 주세요.
제네릭은 타입을 파라미터처럼 사용하는 것을 의미합니다.
<>안에 대표적으로 T를 써서 사용합니다.
제네릭은 함수 뿐만 아니라 인터페이스에서도 사용할 수 있으며, extends와 함께 사용하면, 특정 타입에 대해서만 작동하도록 제약조건을 만들수도 있습니다.
📌 제네릭 유틸리티 타입에 대해 설명해 주세요.
유틸리티 타입이란, 이미 정의한 타입을 변환할 때 사용할 수 있는 타입 문법으로, 대표적으로 Partical<T>, Readonly<T>, Record<K,T>, Pick<T>, Omit<T>가 있습니다.
🧑🏻💻 참고:
'이모저모 > 면접 준비' 카테고리의 다른 글
[면접 준비] React (0) | 2023.09.27 |
---|---|
[면접 준비] 프론트엔드 전반적인 질문 및 CS (0) | 2023.09.27 |
[면접 준비] HTML / CSS (0) | 2023.09.27 |