이번 포스팅에는 JavaScript와 TypeScript에 관한 프론트엔드 면접 질문과 답변을 정리하겠습니다.
추가적으로 내용에 대한 질문이나 수정사항이 있다면 댓글로 남겨주시면 감사하겠습니다.
자바스크립트는 웹 페이지에서 복잡한 기능을 구현할 수 있는 스크립팅 또는 프로그래밍 언어입니다.
자바스크립트는 고수준의 언어이고, 인터프리터 기반의 언어입니다. 또한, 프로토타입을 기반으로 한 객체지향 언어입니다.
하지만, 자바스크립트는 명령형, 함수형, 객체지향 프로그래밍이 모두 가능한 멀티 패러다임 언어입니다.
자바스크립트에서는 2가지의 방법으로 데이터 형변환이 일어납니다.
+, -, == 등의 기호를 통해 자동으로 타입을 변환합니다.자바스크립트는 변수를 선언할 때 타입을 지정하지 않으며, 실행 중에 값이 변경되면 그에 따라 타입도 변하는 동적타입입니다.
또한, 자바스크립트는 컴파일 타임이 아닌 런타임에 타입을 결정합니다.
객체도 속성을 동적으로 추가 및 삭제할 수 있으므로 자바스크립트는 동적언어입니다.
그것이 가능한 이유는 자바스크립트의 이벤트 루프때문입니다.
이벤트 루프는 호출 스택 내부에 수행해야 할 작업이 있는지 확인하고, 수행해야 할 코드가 있다면 자바스크립트 엔진을 이용해 실행하게 합니다.
또한, 태스크 큐에 대기 중인 함수가 있는지 반복해서 확인합니다.
여기서 중요한 것은 비동기작업을 누가 수행하느냐입니다. 이러한 작업은 메인스레드가 아니라 태스크 큐에 할당되는 별도의 스레드에서 수행됩니다. 이 별도의 스레드에서 태스크 큐에 작업을 할당해 처리하는 것은 브라우저나 Node.js의 역할입니다.
즉, 자바스크립트 코드 실행은 싱글 스레드에서 이루어지지만 이러한 외부 Web 등은 모두 자바스크립트 코드 외부에서 실행됩니다. 이를 통해 자바스크립트가 멀티 스레드를 사용하는 것 처럼보이고 비동기가 가능합니다.
이벤트 루프는 콜스택을 먼저 확인한 후에 마이크로 태스크 큐를 확인합니다. 만약 마이크로 태스크 큐에도 데이터가 없다면 태스크 큐를 마지막으로 확인합니다.
또한, 렌더링은 마이크로 태스크 큐가 실행되면 일어나게 됩니다.
따라서 마이크로 태스크 큐를 거치고 렌더링을 거쳐 태스크 큐를 확인합니다.
태스크 큐에는 setTimeout, setInterval, setImmediate와 같은 함수가 들어갑니다.
마이크로 태스크 큐에는 Promise와 같은 함수가 들어가게 됩니다.
자바스크립트는 자동 메모리관리를 사용합니다.
이를 설명하기 위해 메모리구조 먼저 설명하겠습니다.
자바스립트의 메모리 구조는 스택과 힙 두가지로 나누어져 있습니다.
스택에는 원시타입을 저장하고, 힙에는 객체타입을 저장합니다.
스택의 경우, 함수 내에서 선언된 변수들은 함수가 종료되면 자동으로 정리됩니다.
힙의 경우는, 가비지 컬렉터를 통해 더 이상 참조되지 않는 객체를 자동으로 제거합니다.
자바스크립트의 모든 객체들은 메서드와 속성들을 상속받기 위한 템플릿으로써 프로토타입을 갖습니다.
정확히 말하자면 상속되는 속성과 메서드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어있습니다.
프로토타입 체인은 객체에서 속성을 찾을 때 부모의 프로토타입을 따라 검색하는 구조입니다. 객체 인스턴스와 프로토타입간에 연결이 구성되며, 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메서드를 탐색하는 것이 프로토타입 체이닝입니다.
프로토타입기반 언어와 객체지향 언어는 다양한 부분에서 차이가 있습니다.
this 바인딩 : 프로토타입기반 언어는 this가 호출하는 문맥에 따라 동적으로 결정되지만 객체지향 언어는 고정적으로 인스턴스 자신을 가리킵니다.자바스크립트가 클래스를 도입한 여러 이유가 있습니다.
prototype을 직접 다루는 방식이 어렵고 복잡했기에 문법의 직관성을 올리고 상속을 간결화하기 위함입니다.
이를 통해 코드 가독성과 유지보수성이 향상되었습니다.
하지만 클래스를 도입했다 하더라도 내부 작동방식은 프로토타입을 사용합니다. 따라서, 사용자에게 편의성을 제공하기 위한 문법적 설탕입니다.
동기 방식은 순차적으로 코드가 실행되는 방식입니다.
즉, 이전 작업이 끝나야 다음 작업이 실행됩니다.
비동기 방식은 특정 작업이 끝날 때까지 기다리지 않고, 다음 작업을 먼저 실행하는 방식입니다.
즉, 작업이 끝날 때까지 블로킹(blocking)되지 않고, 다른 작업을 수행할 수 있습니다.
블로킹은 특정 작업이 끝날 때까지 기다려야 하는 방식입니다.
논블로킹 방식은 특정 작업이 끝날 때까지 기다리지 않고 다음 작업을 진행하는 방식입니다.
콜백 함수는 다른 함수의 인자로 넘겨지는 함수를 의미합니다.
즉, 어떤 함수가 실행된 후에 호출되는 함수라고 할 수 있습니다.
콜백 지옥은 콜백함수를 중첩해서 사용하는 경우입니다. 코드가 복잡해지고 가독성이 매우 떨어지게 됩니다.
이를 해결하기 위해 Promise나 async/await을 사용합니다.
Promise는 자바스크립트에서 비동기 작업을 처리하는 데 사용되는 객체입니다.
Promise 객체는 3가지의 상태를 갖습니다.
pending : 비동기 작업이 완료되지 않은 상태fulfilled : 비동기 작업이 성공적으로 완료된 상태, then()메서드에서 반환값을 처리할 수 있습니다.rejected : 비동기 작업이 실패한 상태, catch()메서드에서 반환값을 처리할 수 있습니다.Promise.all()은 여러 개의 Promise 객체를 병렬적으로 처리하고, 모든 Promise가 성공적으로 완료되었을 때 결과를 반환합니다. 하나라도 실패하면 전체가 실패로 간주됩니다.
Promise는 비동기 작업의 결과를 나타는 객체로 then(), catch(), finally()를 통해 후속 작업을 처리합니다.
Callback은 비동기 작업이 완료된 후 호출되는 함수입니다. 그래서, 작업이 끝나면 콜백함수가 호출되어 후속 작업을 처리합니다.
async와 await 전부 자바스크립트의 비동기를 처리하는 문법입니다.
async는 함수앞에 붙어 반환값을 Promise를 반환하도록 합니다. 즉, async가 붙으면 함수가 비동기 함수로 간주됩니다.
await은 async가 붙은 함수 내에서만 사용이 가능하고, await가 붙은 코드는 동기적으로 작동합니다.
Promise의 경우 then()이나 catch()를 통해 처리하지만 Async/Await의 경우는 async와 await자체를 사용하여 직관적입니다. 또한 에러처리는 try catch를 사용합니다.
Promise는 비동기 코드가 then()체인을 이룰 수 있어 가독성이 좋지 않지만 Async/Await의 경우 동기식으로 작성할 수 있습니다.
async/await을 사용하게 되면 비동기로 실행되는 작업을 동기적으로 작성할 수 있습니다.
AJAX는 JavaScript를 사용하여 비동기적으로 데이터를 요청하고 서버에서 받은 응답을 처리하는 방식입니다. 여기서 중요한 점은 페이지 전체를 새로고침 하지 않고, 필요한 데이터만을 업데이트한다는 것입니다.
fetch API를 통해 사용할 수 있습니다.
선언은 메모리 공간은 할당되지만 값이 저장되지 않은 상태입니다.
초기화는 변수가 선언되면 자동으로 undefined로 초기화되는 과정입니다.
할당은 변수에 값을 저장하는 과정입니다.
자바스크립트의 데이터 타입은 원시타입과 객체타입으로 나뉩니다.
원시타입은 값이 변경되지 않는 불변데이터입니다.
number, boolean, string, undefined, null, bigInt, symbol이 있습니다.
객체타입은 메모리에 주소를 저장하여 변수에 값을 복사하면 주소만 복사됩니다. 원본이 변경되면 참조하고 있던 모든 변수에 영항을 줍니다.
생성자(Constructor)는 객체를 생성할 때 호출하는 특별한 함수입니다.
class 내부에서 constructor를 정의할 수 있습니다.
this는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있는 키워드입니다.
this의 값은 호출되는 방식에 따라 달라집니다.
window, global을 가리킵니다.this를 상속받습니다.call메서드는 함수를 즉시 실행하여 this를 지정할 수 있는 메서드입니다.
apply메서드는 call과 동일하지만 매개변수를 배열로 전달합니다.
bind메서드는 this를 설정한 새로운 함수를 반환합니다. 즉, 즉시 실행되지 않고 이후 실행을 위해 저장할 수 있습니다.
var : var로 선언된 변수는 선언되기 전에 접근해도 undefined값을 반환합니다. 또한 함수 스코프를 갖기 때문에, 함수 내부에서 선언되었다면 함수 내부에서만 영향을 받고, 함수 외부에서 선언되었다면 전역 스코프에서 유효합니다. 또한, 중복선언과 재할당이 가능합니다.
let, const : let이나 const로 선언된 변수는 선언되기 전에 접근할 수 없고, 블록 스코프를 갖기때문에, 코드 블록 내에서 유효합니다. 두 경우 모두 중복선언이 불가능하지만, let의 경우는 재할당이 가능하고 const는 재할당이 불가능합니다.
호이스팅은 자바스크립트 엔진이 변수와 함수의 선언을 실행 전에 미리 메모리에 등록하는 과정입니다. 즉, 변수와 함수 선언이 메모리로 끌어올려지는 현상입니다.
자바스크립트는 컴파일 타임에 변수 선언과 함수 선언을 미리 메모리에 올려놓고, 이후 실행 시간에 이들을 사용합니다. 변수나 함수가 실행 전에 사용될 수 있도록 보장하기 위해 호이스팅을 발생시킵니다.
TDZ(Temporal Dead Zone)는 let 또는 const로 선언된 변수가 초기화되기 전에 접근할 수 없는 영역을 의미합니다.
let과 const는 호이스팅이 되지만 초기화되지는 않기때문에 TDZ에 들어갑니다.
함수 선언문과 함수 표현식은 호이스팅에서 차이가 난다.
함수 선언문의 경우 호이스팅이 발생하여 선언 전에 호출하여도 정상적인 값을 반환하는 반면, 함수 표현식의 경우는 선언 전에 호출하면 에러를 반환합니다.
화살표 함수는 일반 함수와 몇가지 다른 점이 있습니다.
첫 번째로 간결한 문법을 제공합니다.
두 번째로 화살표 함수는 인스턴스를 생성할 수 없습니다. prototype 프로퍼티도 없고 프로토타입도 생성하지 않습니다. 이를 통해 함수 자체의this, arguments, super, new.target 바인딩을 갖지 않습니다.
따라서, 함수 내부에서 위의 내용을 참조하면 상위 스코프의 내용을 참조합니다. 즉, 바인딩을 상위 스코프에 고정시킵니다.
이벤트 버블링은 이벤트가 하위 요소에서 발생한 후, 부모 요소로 전파되는 방식입니다.
이벤트 캡처링은 이벤트가 상위 요소에서부터 하위 요소로 전파되는 방식입니다.
이벤트는 캡처링 단계 -> 타겟 단계 -> 버블링 단계로 전파됩니다.
stopPropagation : 이벤트의 전파를 차단하여 버블링이나 캡처링을 막을 수 있습니다.
preventDefault : 이벤트의 기본 동작을 취소합니다. 버블링이나 캡처링은 막을 수 없습니다.
이벤트 위임(Event Delegation)은 부모 요소에 이벤트 리스너를 설정하여, 자식 요소에서 발생한 이벤트를 부모가 처리하는 기법입니다.
이벤트 위임은 이벤트 버블링을 활용합니다. 즉, 자식 요소에서 발생한 이벤트가 부모 요소로 전파되면서, 부모가 해당 이벤트를 처리하는 방식입니다.
event.target은 이벤트가 실제로 발생한 DOM 요소를 가리킵니다.
event.currentTarget은 이벤트 리스너가 실제로 등록된 DOM 요소를 가리킵니다.
스코프는 변수나 함수가 유효한 범위, 즉 해당 변수나 함수에 접근할 수 있는 코드의 영역을 의미합니다.
let이나 const로 선언된 변수는 블록 내에서만 유효합니다.스코프 체인은 자바스크립트에서 변수를 찾을 때, 각 스코프의 관계에 따라 변수를 차례로 검색하는 체인 구조입니다. 이 체인은 내부 함수가 외부 함수의 변수에 접근할 수 있게 합니다.
즉, 가장 안쪽부터 변수를 찾을 때까지 바깥쪽으로 스코프를 넓혀나갑니다.
실행 컨텍스트는 자바스크립트 코드가 실행되는 환경을 의미합니다.
즉, 변수, 함수, this 등이 어떻게 실행되고 관리되는지를 결정하는 개념입니다.
this, 전역 변수, 전역 함수 등이 등록됩니다.var변수, 함수 선언 등을 저장let, const 변수를 저장this바인딩 : 현재 실행 컨텍스트의 this값을 저장클로저는 외부 함수의 변수를 내부 함수에서 기억하고 접근할 수 있는 함수입니다.
즉, 외부 함수의 실행이 종료된 후에도 외부 함수의 변수를 계속 사용할 수 있는 함수입니다.
클로저는 함수가 선언될 때의 렉시컬 환경을 기억합니다.
이를 통해 전역 변수를 사용하지 않고도 함수 밖에서 해당 변수에 접근할 수 있는 방법을 만들어 주며, 이는 반환된 함수를 제외하면 외부에서 접근할 수 없으므로 마치 private 변수처럼 사용할 수 있습니다.
렉시컬 환경은 변수 및 함수 선언이 저장되는 공간이고, 실행 컨텍스트 내부에 저장됩니다.
자바스크립트는 렉시컬 스코프(정적 스코프)를 따르며,
변수의 유효 범위는 선언된 위치(즉, 렉시컬 환경)에서 결정됩니다.
콜 스택은 함수 실행 컨텍스트가 쌓이는 스택구조입니다.
함수를 호출하면 스택에 추가되고, 실행이 끝나면 제거됩니다.
자바스크립트는 단일 스레드 환경이므로 콜 스택이 하나뿐입니다.
힙은 동적 메모리 할당을 담당하는 영역입니다.
콜 스택처럼 정해진 구조가 없으며, 객체와 같은 참조형 데이터가 저장됩니다.
가비지 컬렉터에 의해 객체를 정리해 메모리를 관리됩니다.
불변성을 유지하기 위한 몇가지 방법이 있습니다.
첫 번째로, 자바스크립트에서 원시 타입의 경우 불변성을 갖고 있으므로 원시타입으로 값을 할당합니다.
두 번째로, Object.freeze()를 활용하여 객체를 불변하게 만들 수 있습니다.
얕은 비교는 두 객체나 배열의 참조만 비교합니다. 따라서 값이 같더라도 비교 결과가 false가 나올 수도 있습니다.
깊은 비교는 두 객체나 배열의 모든 속성이나 모든 원소를 재귀적으로 비교합니다. 즉, 객체가 중첩되어 있으면 그 내부의 속성까지 비교하여 두 객체나 배열이 동일한지 확인합니다.
얕은 복사는 객체나 배열의 1단계 속성만 복사하고, 중첩된 값은 참조를 복사합니다.
깊은 복사는 객체나 배열의 모든 속성이나 원소를 재귀적으로 복사하고, 중첩된 객체까지 복사합니다.
일급객체는 코드에서 다른 일반 데이터(숫자, 문자열 등)처럼 취급할 수 있는 대상입니다.
따라서, 자바스크립트의 합수는 일급객체입니다.
map()은 배열의 각 요소에 대해 주어진 함수를 호출하고, 그 결과로 새로운 배열을 반환하는 메서드입니다. 원본 배열은 변경되지 않습니다.
forEach()는 배열의 각 요소에 대해 주어진 함수를 한 번씩 실행하지만, 새로운 배열을 반환하지는 않습니다.
reduce()는 배열을 순회하며 각 요소를 누적값과 결합하여 단일 값을 반환하는 메서드입니다.
즉시 실행 함수는 말 그대로 함수를 정의하고 그 순간 즉시 실행되는 함수입니다. 단 한 번만 호출되고, 다시 호출할 수 없습니다.
즉시 실행 함수 내부에서 선언된 변수는 외부 스코프에 영향을 받지 않아 데이터를 보호하고 은닉이 가능합니다.
또한, 한 번 실행되면 메모리가 남지 않아 일시적인 데이터 처리에 적합합니다.
Rest 연산자는 여러 개의 인수를 하나로 받을 때 사용됩니다. 즉, 여러개의 값을 하나의 배열로 모아줍니다.
Spread 연산자는 배열이나 객체의 요소를 펼칠 때 사용됩니다.
제너레이터는 반복 가능한(Iterable) 함수로, 실행을 중간에 멈췄다가 다시 시작할 수 있는 함수입니다.
function* 키워드를 사용해 정의하며, yield 키워드를 사용하여 값을 반환할 수 있습니다.
또한, yield키워드를 만나면 실행이 멈추고 next() 메서드를 호출하면 다시 실행이 이어집니다.
제너레이터 객체도 이터레이터이자 이터러블입니다.
이를 통해 메모리 효율성이 올라갈 수 있습니다.
이터러블 프로토콜
Symbol.iterator를 프로퍼티 키로 사용한 메서드를 직접 구현하거나 프로토타입 체인을 통해 상속받은Symbol.iterator메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환합니다.
이터러블 프로토콜을 준수한 객체를 이터러블이라 합니다.
이터레이터 프로토콜
이터러블의
Symbol.iterator메서드를 호출하면 이터레이터 프로토콜을 준수한 이터레이터를 반환합니다. 이터레이터는next메서드를 소유하며next메서드를 호출하면 이터러블을 순회하며value와done프로퍼티를 갖는 이터레이터 리절트 객체를 반환합니다.
이터레이터 프로토콜을 준수한 객체를 이터레이터라 합니다.
등 다양한 기능이 추가되었습니다.
자바스크립트에서 애니메이션을 처리할 때 사용되며, 부드러운 애니메이션을 구현할 때 사용합니다.
브라우저의 디스플레이 리프레시 주기(1초에 60번, 60Hz)에 맞게 동기화되어 호출됩니다. 이는 매 프레임마다 한 번씩 실행하게 되어 매끄럽고 부드러운 애니메이션을 제공합니다.
또한, 브라우저는 화면이 리프레시될 때만 애니메이션을 실행합니다. 그래서 사용자가 다른 탭으로 전환하거나, 페이지가 백그라운드에 있을 경우 불필요한 애니메이션이 실행되지 않으며, 이로 인해 불필요한 CPU 리소스를 절약할 수 있습니다.
JS의 오류를 보다 엄격하게 검사하는 모드로 암묵적 변수 선언이 금지되고, this바인딩이 제한되는 등 여러가지가 제한됩니다.
타입스크립트는 Microsoft에서 개발한 오픈소스 프로그래밍 언어로, 자바스크립트의 상위 집합입니다.
타입스크립트를 사용하는 이유는 크게 2가지가 있습니다.
첫 번째로, 타입스크립트는 정적 타입 시스템을 사용합니다. 따라서, 런타임이 아닌 컴파일 타임에 타입 오류를 발견하여 안정성과 유지보수성에 뛰어납니다. 즉, 코드를 실행하기 전에 오류를 감지하여 예측하지 못한 동작을 줄여줍니다.
두번째로, 개발 생산성이 향상됩니다. 타입스크립트는 타입 추론, 코드 자동 완성, 디버깅 지원을 통해 개발 속도와 생산성이 크게 향상됩니다.
JavaScript와 TypeScript의 가장 큰 차이점은 2가지가 있습니다.
첫번째로, JavaScript의 경우 동적 타입으로 변수의 타입이 런타임에 결정되지만, TypeScript는 정적 타입으로 컴파일 단계에서 타입을 검사합니다.
두번째로, 컴파일 단계에서 JavaScript는 브라우저나 Node.js에서 바로 실행되지만 TypeScript는 JavaScript로 트랜스파일 된 후에 실행됩니다.
제네릭은 타입이 여러 종류의 값을 가질 수 있도록 일반화된 타입을 생성하는 방법입니다. 함수나 클래스, 인터페이스에서 타입을 변수처럼 다룰 수 있습니다. 또한, 타입 안전성을 제공하고 코드 재사용성을 높여줍니다.
객체 구조를 정의하고 확장하거나 병합이 필요할 때는 interface를 사용하고, 유연한 타입을 표현하거나 객체 외의 타입을 정의할 때는 type을 사용합니다.
Partial : 객체 타입의 모든 속성을 선택적으로 만드는 타입입니다.Pick : 객체 타입에서 특정 속성만 선택하여 새로운 타입을 만듭니다.Omit : 객체 타입에서 특정 속상만 제외하여 새로운 타입을 만듭니다.타입 단언은 as를 사용하여 타입을 강제로 지정하는 것이고, 타입 가드는 typeof, instanceof, 또는 사용자 정의 타입 가드를 통해 실제 타입을 체크하고 좁혀주는 방식입니다.
public의 경우 클래스의 모든 속성이나 메서드는 외부에서 접근이 가능합니다.
private의 경우 클래스 내에서만 접근할 수 있는 속성이나 메서드를 정의합니다. 따라서, 클래스 외부에서 접근할 수 없고, 상속된 클래스에서도 접근할 수 없습니다.
protected 의 경우 private과 비슷하지만, 자식 클래스에서는 접근할 수 있습니다.
TypeScript의 타입 시스템은 컴파일 타임에만 동작하며, 런타임에는 타입 정보가 제거됩니다. TypeScript는 코드가 실행되기 전에 타입 검사를 통해 오류를 검출합니다. 하지만 컴파일 후 생성되는 JavaScript 코드에는 트랜스파일링되어 타입 정보가 포함되지 않으므로, 실제 실행 시에는 타입 검사가 이루어지지 않습니다.
TypeScript로 작성된 코드의 성능은 JavaScript와 동일합니다. TypeScript는 컴파일 타임에 타입 검사를 통해 코드의 품질을 높이지만, 최종적으로 변환되는 코드는 JavaScript로 컴파일되기 때문에 실행 성능에는 차이가 없습니다.
다음 포스팅에는 React에 관하여 질문과 답변을 정리해보겠습니다.
이 집 정리 맛집이네요 :)