스터디/프론트 cs 스터디(23.08-23.11)

# 자바스크립트 예상 질문 - 3

minseokiim 2023. 8. 15. 22:01

- ES6에서 새로 생긴 기능을 말씀해주세요. (26번)
1. let과 const
let: 블록 스코프 지역 변수를 선언합니다.
const: 재할당이 불가능한 변수(상수)를 선언합니다.
2.화살표 함수 
3. 클래스
4. 모듈 : import와 export 키워드를 사용하여 모듈을 가져오고 내보낼 수 있습니다.
5.프로미스 : 비동기 작업의 완료나 실패를 나타내는 객체입니다.
6. 템플릿 리터럴(백틱) : 문자열 내에서 변수와 표현식을 쉽게 포함시킬 수 있는 새로운 문자열 문법입니다.
7. 스프레드 연산자와 Rest 연산자: 배열이나 객체를 확장하거나, 나머지 매개변수를 사용하여 함수 내에서 배열로 받아올 수 있습니다.
8. Symbol 타입 : 완전히 새로운 유일하고 변경 불가능한 원시 타입입니다.
9. 제너레이터와 이터레이터 : 새로운 반복 메커니즘과 함께 제너레이터 함수를 제공합니다.


- undefined, null, undeclared를 비교해주세요. (27번)
1. undefined는 변수가 선언되었지만 아직 어떠한 값도 할당되지 않았을 때 그 변수의 기본 값입니다.
(ex. let x;
console.log(x); // undefined)
2. null은  명시적으로 할당된 "값이 없음"을 나타내는 값입니다.
(ex. let y = null;
console.log(y); // null)
3. undeclared는 변수 자체가 선언되지 않았을 때 그 변수의 상태를 설명하는 용어입니다.
undeclared 변수에 접근하려고 시도하면 자바스크립트는 ReferenceError를 발생시킵니다.
(ex. console.log(z); // ReferenceError: z is not defined)



- 자바스크립트를 멀티 스레드처럼 사용하는 방법이 뭔가요?
: 자바스크립트에서 멀티 스레드처럼 동작하는 비동기 프로그래밍 방법에는 setTimeout/setInterval, Promise, 및 async/await 등이 있습니다.
setTimeout/setInterval: 지정된 시간 후에 함수를 실행합니다.
Promise: 비동기 연산의 완료 시점과 결과를 나타냅니다.
async/await: 비동기 코드를 동기식으로 작성할 수 있게 해줍니다.
자바스크립트는 실제 비동기 처리를 위해 Web APIs에 일을 위임하며, 처리가 끝난 작업은 Callback Queue로 이동합니다. 이 큐는 Event Loop를 통해 메인 스레드로 반환되어 실행됩니다.




- requestAnimationFrame에 대해 설명해주세요. (28번)
:requestAnimationFrame은 브라우저에서 애니메이션을 구현하는 데 사용되는 API입니다.
requestAnimationFrame는 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 리페인트 바로 전에 브라우저가 애니메이션을 업데이트할 지정된 함수를 호출하도록 요청합니다. 이 메서드는 리페인트 이전에 호출할 인수로 콜백을 받습니다. (브라우저가 렌더링 할 수 있을 때, 다름 렌더링을 진행할 수 있도록 최적화 해주는 툴과 유사) 

브라우저의 화면 갱신 주기와 동기화되어 작동하므로, 불필요한 프레임 갱신을 줄이고 리소스 사용을 최적화하여  효율적인 애니메이션을 만들 수 있습니다.
또한, 웹 페이지가 백그라운드 탭에 있을 때는(현재 활성탭이 아닐때) requestAnimationFrame이 호출되지 않기 때문에 CPU 리소스와 배터리 수명을 낭비하지 않게 됩니다.
브라우저가 언제 업데이트를 할지 알게 해줌으로써 프레임 손실을 방지해줍니다.



- 비동기적으로 실행되는 것을 동기적으로 코딩하는 방법이 있나요? (29번)
: 콜백에 넣어주는 방법이 있긴 하지만, 중첩된 콜백 구조는 코드의 가독성을 저하시키고 오류를 디버깅하기 어렵게 만드므로 결국 콜백 지옥을 야기 시킨다.
조금 더 좋은 방법으로는, async/await 문법을 사용해 promise를 기반으로 동작 시키는 것이 있다.
async로 정의된 함수 내에서 await 키워드를 사용하여 Promise가 settle될 때까지 기다리게 하는 방법이다.
결과는 동기적이지만, 내부에서는 비동기적으로 코딩된다.




- ⭐map과 forEach, reduce에 대해 설명해주세요. (30번)
1. map: 배열의 모든 요소를 순회하면서 주어진 함수를 각 요소에 적용한 후, 새로운 배열을 생성 후 반환합니다. 원본배열은 훼손하지 않습니다.
2. forEach : 배열의 모든 요소를 순회하면서 주어진 함수를 각 요소에 적용합니다. 주로 배열을 순회하며 배열의 요소에 대한 작업의 결과를 확인하거나 다른 작업을 수행하는 데 사용됩니다.
3. reduce : 배열의 모든 요소를 순회하면서 주어진 리듀서 함수를 사용하여 배열의 요소를 단일 값으로 줄입니다.
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
이런식을 사용합니다.
accumulator는 중간 결과를 저장하는 변수이며, currentValue는 현재 배열의 요소를 나타냅니다.



- 자바스크립트의 메모리 관리에 대해 아는 대로 설명해주세요. (31번)
: JavaScript의 메모리 관리는 주로 가비지 컬렉션을 기반으로 동작합니다. 개발자는 직접 메모리를 할당하거나 해제할 필요 없이, 런타임이 알아서 메모리를 관리합니다.
따라서, JavaScript에서 메모리 누수는 주요 문제 중 하나입니다. 사용하지 않는데도 불구하고 어떠한 이유로 인해 메모리가 해제되지 않는 경우에 발생합니다.




- 자바스크립트의 클래스에 대해 설명해주세요.  (32번)
: 자바스크립트 객체를 만들어내기 위한 설계도 혹은 틀이며, 연관되어 있는 변수와 메서드의 집합이다. 클래스는 객체 정의를 위한 상태(멤버변수)와 메서드(함수)로 구성된다.
 Class를 사용하는 가장 큰 이유는 "재사용성"이다. 자바스크립트는 프로토타입 기반 객체지향 언어로서 클래스가 필요 없는 객체지향 언어라는 뜻이다. ES5 시절까지만 해도 생성자 함수와 프로토타입을 통해 상속을 구현했지만, ES6에서 도입된 “클래스” 개념 덕분에 객체지향 프로그래밍을 훨씬 간편하게 구현할 수 있다.


- 즉시 실행 함수 (IIFE)에 대해 설명해주세요. (33번)
:즉시 실행 함수는 함수를 선언과 동시에 즉시 실행합니다.
 IIFE는 한 번만 실행되며, 재실행될 수 없습니다.
IIFE 내부의 변수는 해당 함수 범위에서만 존재하기 때문에, 전역 스코프를 오염시키지 않습니다,데이터 은닉 또는 캡슐화를 수행하기 위한 방법 중 하나입니다. 


- 엄격 모드에 대해 설명해주세요. (34번)
: "엄격 모드"는 코드의 잠재적인 오류나 안정성 문제를 방지하고, 더 효율적이고 안정적인 코드를 작성할 수 있도록 도와주기 위해 도입된 모드입니다.
가동시키기 위해선 JS 소스코드 맨 위에 “use strict”라는 코드를 작성하면 됩니다.

주요 장점으로는 다섯가지가 있습니다.
1. 일반 모드에서는 무시되거나 조용히 실패하는 에러들에 대해서 명시적인 오류를 발생시킵니다.
2. 잠재적인 버그를 사전에 찾아내기 쉽게 합니다.
3. 일부 코드 패턴은 엄격 모드에서 최적화하기 쉬워져, 자바스크립트 엔진이 코드의 실행 성능을 높일 수 있습니다.
4. 보안에 문제가 될 수 있는 일부 기능들이 제한되므로, 보다 안전한 코드를 작성할 수 있습니다.
5. 엄격 모드는 미래의 ECMAScript 버전들에 대비하여 현재 문법에 맞지 않는 코드나 향후 문법에 충돌할 수 있는 요소들을 금지합니다.

(호이스팅은 자바스크립트의 핵심 동작 중 하나이므로 엄격 모드에서도 여전히 발생함)



- ⭐자바스크립트에서 콜 스택 (Call Stack)과 힙 (Heap)에 대해 설명해주세요. (35번)
:콜 스택은 함수의 실행 순서를 추적하는데 사용되는 자료 구조입니다. 함수가 호출될 때마다 해당 함수는 스택의 상단에 푸시되고, 함수의 실행이 완료되면 스택에서 팝됩니다.
콜 스택은 LIFO (Last In First Out) 원칙을 따릅니다.
콜 스택에 너무 많은 함수 호출이 있을 경우, 스택의 최대 크기를 초과하게 되어 스택 오버플로우 오류가 발생합니다.

힙은 주로 객체와 같은 복잡한 데이터 구조를 저장하는데 사용되는 메모리 영역입니다. 콜 스택과는 달리 구조화되어 있지 않으며, 할당과 해제가 동적으로 이루어집니다.
메모리는 필요에 따라 동적으로 할당되고, 사용이 끝난 메모리는 가비지 컬렉터에 의해 자동으로 해제될 수 있습니다.
메모리 관리가 자동적으로 이루어지는 언어에서, 가비지 컬렉션으로 인해 성능 저하가 발생할 수 있습니다.
프로그램이 더 이상 필요하지 않은 메모리를 계속 차지하게 되면 메모리 누수가 발생합니다. 가비지 컬렉터가 해당 메모리를 회수하지 못하게 되면, 프로그램의 사용 가능한 메모리가 점차 줄어들게 됩니다.

콜 스택은 프로그램의 실행 흐름을 추적하는데 사용되며, 힙은 복잡한 데이터 구조의 동적 메모리 할당을 관리하는데 사용됩니다.



- Rest 연산자와 Spread 연산자에 대해 설명해주세요. (36번)
:Rest 연산자와 Spread 연산자는 동일한 기호(...)를 사용하지만 용도가 다릅니다.

1. Rest 연산자 : 여러 개의 개별적인 요소나 속성들을 하나의 배열이나 객체로 모읍니다.
ex. function printArguments(firstArg, ...restArgs){}
printArguments(1, 2, 3, 4, 5);

2. Spread 연산자 :  배열이나 객체의 요소나 속성들을 개별적으로 펼쳐서 사용합니다.
ex. const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; 





- ⭐제너레이터에 대해 설명해주세요. (37번)
:JavaScript의 ES6에 도입된 특징 중 하나로, 함수의 실행을 중간에 일시적으로 중단하거나 다시 시작할 수 있는 기능을 가진 특별한 종류의 함수입니다.제너레이터를 사용하는 주요 이유는 세밀한 제어 기능을 통해 복잡한 실행 흐름을 다룰 수 있기 때문입니다. 

제너레이터 함수는 function* 키워드를 사용하여 선언합니다.
제너레이터 함수 내부에서 yield 키워드를 사용하여 함수의 실행을 일시적으로 중단하고 값을 반환할 수 있습니다.
제너레이터 함수를 호출하면 호출될 때 실행되지 않고, 제너레이터 객체가 반환됩니다. 이 객체는 next() 메소드를 가지고 있으며,  이 객체의 next() 메서드가 호출될 때만 실행됩니다. 이 메소드를 호출할 때마다 yield 키워드를 만날 때까지 함수가 실행되고 해당 yield의 값을 반환합니다.

next() 메소드가 반환하는 객체는 value와 done 두 개의 프로퍼티를 가집니다. done은 제너레이터 함수의 실행이 완료되었는지를 나타내며, 모든 yield를 실행한 후에는 true 값을 가집니다.


ex. function* numberGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

const generator = numberGenerator();

console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: false }
console.log(generator.next()); // { value: undefined, done: true }



제너레이터 객체는 return()과 throw() 메소드도 포함하고 있습니다. return()은 제너레이터의 실행을 종료하고 주어진 값을 반환합니다. throw()는 제너레이터 내에서 예외를 발생시킵니다.

ex. console.log(generator.next());  // { value: 1, done: false }
console.log(generator.return('end'));  // { value: 'end', done: true }
console.log(generator.next());  // { value: undefined, done: true }



ex. function* errorGenerator() {
    try {
        yield "Start";
        yield "Middle";
    } catch (error) {
        console.log('Error caught inside generator:', error);
    }
    yield "End";
}

const generator = errorGenerator();
console.log(generator.next());  // { value: 'Start', done: false }
console.log(generator.throw(new Error('Test Error')));  // Error caught inside generator: Error: Test Error
console.log(generator.next());  // { value: 'End', done: false }



- ⭐⭐이터러블과 이터레이터 프로토콜에 대해 설명해주세요. (38번)
: "이터러블"과 "이터레이터"는 컬렉션을 순회하는 메커니즘을 정의하는 중요한 개념입니다.

이터러블은 "반복 가능한 요소를 가진 객체"로서, Symbol.iterator 키를 속성으로 가진 메서드를 포함해야 합니다.이터러블 객체는 [Symbol.iterator] 메서드를 포함하며, 이 메서드를 호출하면 이터레이터 객체가 반환됩니다.
배열, 문자열, Map, Set 등의 기본 자료형이 내장 이터러블로 제공됩니다.
for...of 루프는 이터러블 객체를 자동으로 순회합니다.

ex. const array = [1, 2, 3];
const iterator = array[Symbol.iterator]();

console.log(iterator.next());  // { value: 1, done: false }
console.log(iterator.next());  // { value: 2, done: false }
console.log(iterator.next());  // { value: 3, done: false }
console.log(iterator.next());  // { value: undefined, done: true }



이터레이터는 next 메서드를 가진 객체로, 이 메서드를 호출할 때마다 { value, done } 형태의 객체를 반환합니다. 이터레이터는 수동적으로 동작하므로, 사용자가 next를 호출할 때마다 새로운 값을 생성하거나 반환합니다.



+ ⭐⭐이터레이터랑 제너레이터
: 제너레이터는 호출되면 이터레이터를 반환합니다. 그러나 제너레이터의 본문은 즉시 실행되지 않습니다. 대신 next 메서드 호출 때마다 실행이 진행됩니다.
제너레이터 함수를 호출하면, 반환된 객체는 이터레이터 프로토콜을 준수합니다. 즉, 제너레이터는 이터레이터를 생성하는 방법 중 하나입니다.