REF
아래 블로그를 참조하여, 고쳐야 할 부분을 수정해보았다.
https://velog.io/@dnr6054/fe-interview-JavaScript
Q. 자바스크립트는 무슨 언어인가요?
웹 개발을 위한 대표적인 인터프리터 언어로,
동적 프로토타입 기반의 객체지향 언어입니다.
주로 클라이언트 측에서 사용되지만,
Node.js 등의 런타임 환경에서는 서버 측에서도 사용할 수 있습니다.
또한 자바스크립트는 명령형, 함수형, 객체 지향 프로그래밍이 모두 가능한 멀티 패러다임 언어 입니다.
+
인터프리터 언어: 코드를 컴파일 없이 실행환경에서 바로 해석하고 실행합니다.
동적 타이핑: 변수의 데이터 타입을 명시하지 않아도 되고, 런타임 시에 자동으로 타입이 결정됩니다.
이벤트 기반 비동기 프로그래밍에 적합하며,
콜백과 프로미스(Promise), async/await 으로 비동기 작업을 효율적으로 처리할 수 있습니다.
크로스 플랫폼 언어로, 다양한 브라우저와 운영체제에서 작동하여 웹 애플리케이션을 구축하는 데 가장 많이 사용됩니다.
최근에는 ES6를 통해 모듈화, 클래스, 화살표 함수 등의 새로운 기능이 도입되었습니다.
+
: 자바스크립트는 본래 브라우저를 제어하는 언어였으나, Node.js라는 새로운 실행환경과 구글 V8 엔진의 등장으로 자체 어플리케이션을 만들 수 있게 된 언어입니다. 또한 자바스크립트는 명령형, 함수형, 객체지향 프로그래밍이 모두 가능한 멀티 패러다임 언어입니다.
설명)
- 브라우저 제어 언어: 자바스크립트는 원래 웹 브라우저에서 동작하는 스크립트 언어로 개발되었으며,
주로 웹 페이지를 동적으로 만들기 위해 사용되었습니다.
- Node.js와 구글 V8 엔진: 이후 Node.js라는 실행 환경과 구글 V8 엔진이라는 자바스크립트 엔진이 등장하면서,
자바스크립트는 브라우저를 넘어 서버 측 애플리케이션까지 개발할 수 있는 언어가 되었습니다.
즉, 자바스크립트는 처음에는 웹 브라우저에서만 사용되었지만,
이제는 웹 서버나 다양한 환경에서 사용할 수 있는 범용적인 언어로 발전했다는 의미입니다
+
스크립트 언어란? : 프로그램을 작성할 때 컴파일 없이 실행할 수 있는 프로그래밍 언어를 의미한다.
주로 인터프리터를 통해 한 줄씩 코드를 읽고 바로 실행한다.
이로 인해 개발 속도가 빠르고, 코드 수정 후 즉시 실행결과를 확인할 수 있다.
- 스크립트 언어 주요 특징
1) 컴파일 과정이 필요 없음
2) 동적 타이핑 : 변수를 선언할 때 타입 명시 X, 시리행 중에 데이터 타입 결정
3) 해석 실행 : 코드가 한 줄씩 해석되면서 실행되기 때문에 컴파일된 언어(C,C++, Java)보다 느릴 수 있지만, 개발 편의성이 높다.
- 대표적인 스크립트 언어 : js,python, ruby, php
- 멀티 패러다임 언어란? :
다양한 프로그래밍 스타일을 지원한다는 뜻
1) 명령형 프로그래밍: for문 , if 문과 같은 명령을 통해 프로그램의 흐름을 제어할 수 있다.
2) 함수형 프로그래밍: 함수를 일급 시민(first-class citizen)으로 취급하며, 데이터를 함수로 처리하는 방식이다. 자바스크립트는 map, filter, reduce와 같은 함수형 메서드를 지원한다.
3) 객체지향 프로그래밍: 객체라는 개념을 중심으로 프로그램을 설계하는 방식이다. 자바스크립트는 클래스를 정의하고 객체를 생성하여 프로그래밍할 수 있다.
Q. 변수 선언, 초기화, 할당의 차이점에 대해 설명해주세요.
변수 선언:
변수를 생성하는 것을 의미합니다.
식별자(변수 이름)를 등록하여 스코프가 참조할 대상을 만듭니다.
초기화:
메모리에 변수 저장을 위한 공간을 확보하는 것입니다. 기본값으로 undefined를 할당됩니다.
할당:
선언된 변수에 구체적인 값을 넣는 과정입니다.
할당 연산자(=)를 사용하며 변수에 값을 저장합니다.
Q. 데이터 타입에 대해 설명해주세요.
자바스크립트 타입은 원시 타입과 참조 타입으로 구분됩니다.
원시 타입은 값 자체를 저장하는 타입으로, 불변합니다.
Number, String, boolean, undefined, null, symbol , bigint 타입이 있습니다.
참조 타입은 객체, 배열, 함수 등과 같이 메모리 참조를 통해 관리되는 데이터 타입입니다.
객체는 다양한 프로퍼티를 가질 수 있는 복합 데이터 구조입니다.
+ 객체는 키와 값 사이의 매핑이며,
키는 문자열 또는 심볼입니다. 값은 어떤 것이든 가능합니다.
또한 함수는 호출이 가능하다는 점을 제외하면 일반적인 객체입니다.
- 원시 타입 설명
1) Number: 정수 및 부동 소수점 숫자를 저장한다.
2) String: 텍스트 데이터를 저장한다. 작은따옴표나 큰따옴표로 감싼다.
3) Boolean: true, false 값을 가진다.
4) undefined: 변수가 선언되었지만, 아직 값이 할당되지 않은 상태다.
5) null: 값이 없음을 의도적으로 표현한 데이터 타입이다.
6) Symbol: 고유하고 변하지 않는 값을 생성할 때 사용된다. 주로 객체의 키로 사용된다.
let uniqueId = Symbol('id');
7) Bigint: 매우 큰 정수를 표현할 때 사용하는 데이터 타입이다.
let bigNumber = 123456789012345678901234567890n;
- 참조 타입 설명
1) 객체(Object) : 모든 참조 타입의 기본이 되는 타입으로, 키-값 쌍으로 이루어진 복합 데이터 타입이다.
2) 배열(Array): 순서가 있는 값들의 집합이며, 객체의 한 종류이다.
3) 함수(Function): 객체의 일종이며, 실행 가능한 코드 블록이다.
Q. 생성자에 대해 설명해주세요.
자바스크립트의 생성자(Constructor)는 객체를 생성하고 초기화하는 함수입니다
new 키워드와 함께 사용하여 새 객체를 만들며, 이를 인스턴스라고 합니다.
인스턴스는 해당 생성자의 프로토타입을 상속받습니다.
따라서 생성자의 프로토타입을 통해 공통 메서드에 접근할 수 있습니다.
이를 통해 자바스크립트에서 객체 지향 프로그래밍을 구현할 수 있습니다.
+
- 생성자의 주요 특징
1) 함수로 정의됨:
생성자는 보통 함수로 정의되며, 이름은 대분자로 시작하는 것이 관례이다.
함수 안에서 this 키워드를 사용하여 생성될 객체의 속성과 메서드를 정의할 수 있다.
function Person(name, age) {
this.name = name;
this.age = age;
}
2) new 키워드와 함께 사용:
new 키워드를 사용하면, 빈 객체가 생성되고, 그 객체의 this가 생성자 함수의 this로 설정된다.
생성자 함수 내에서 this를 통해 속성을 설정한 후, 새롭게 생성된 객체가 반환된다.
let john = new Person('John', 30);
console.log(john.name); // John
console.log(john.age); // 30
3) 자동 반환:
생성자 함수는 명시적으로 return문을 작성하지 않아도 된다.
new 키워드가 객체를 자동으로 반환합니다.
만약 return 문을 작성하더라도, 반환값이 객체가 아닌 경우 무시되고, 자동으로 새롭게 생성된 객체가 반환됩니다.
4) 프로토타입과 함께 사용:
생성자를 사용하면 해당 객체는 생성자 함수의 프로토타입을 상속 받습니다.
이를 통해 생성된 모든 객체가 동일한 메서드를 공유할 수 있습니다.
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
let alice = new Person('Alice', 25);
alice.greet(); // Hello, my name is Alice
- 생성자 함수에 의해 생성된 객체를 인스턴스라 한다.
인스턴스는 특정 생성자 함수로부터 만들어진 특정한 객체를 의미한다.
let john = new Person('John', 30); // john은 Person의 인스턴스
let alice = new Person('Alice', 25); // alice도 Person의 인스턴스
여기서 john과 alice는 각각 Person 생성자 함수의 인스턴스입니다.
이 인스턴스들은 Person의 구조와 메서드를 상속받습니다.
정리하자면, 생성자 함수로 만든 객체는 그 생성자 함수의 인스턴스라고 부릅니다.
- 자바스크립트는 Object외에도 배열, 문자열, 숫자, 함수, 정규 표현식, 날짜등 다양한 타입의 빌트인(built-in) 생성자 함수를 제공합니다.
이러한 생성자 함수들은 자바스크립트에서 미리 정의된 함수로, 특정 타입의 객체를 생성할 때 사용됩니다.
생성자 함수는 일반 함수와 동일한 방법으로 정의하지만,
이름을 지을 때 파스칼 케이스(PascalCase)를 사용하는 관례를 따릅니다
Q. this에 대해 설명해주세요.
this 키워드는 자신이 속한 객체를 가리키는 식별자를 참조할 수 있는 키워드입니다.
this는 함수가 호출되는 방식에 따라 달라집니다.
- 일반 함수 호출을 사용할 경우 기본적으로 전역 객체가 바인딩 됩니다.
- 메서드 호출을 할 경우, 마침표 연산자 앞에 기술한 객체가 바인딩 됩니다.
- 생성자 함수 호출을 할 경우, 새로 생성되는 인스턴스가 바인딩 됩니다.
- 화살표 함수는 this가 없기 때문에, 선언될 시점에서의 상위 스코프가 바인딩됩니다.
+ this는 JavaScript에서 매우 중요한 키워드로, 특정 맥락(context)에서 객체를 참조하는 역할을 합니다.
this의 값은 함수가 호출되는 방식에 따라 달라지며,
상황에 따라 동적으로 할당됩니다.
이를 통해 객체 지향 프로그래밍 패러다임에서 자주 사용되는 패턴을 구현할 수 있습니다.
q. call, apply, bind에 대해 설명해주세요.
call: this 값을 설정하고, 개별 인자를 전달하면서 함수를 즉시 호출.
apply: this 값을 설정하고, 인자를 배열로 전달하면서 함수를 즉시 호출.
bind: this 값을 설정한 새로운 함수를 반환(즉시 호출되지 않음).
이 세 가지는 주로 this를 명시적으로 설정하거나 함수의 실행 맥락을 제어할 때 유용하게 사용됩니다.
+
1. call 메서드
call 메서드는 함수를 호출하면서, this 값을 설정하고, 개별적인 인자를 전달합니다.
functionName.call(thisArg, arg1, arg2, ...)
- thisArg: 함수 내에서 사용할 this 값을 설정합니다.
- arg1, arg2, ...: 호출할 때 전달할 인자들을 개별적으로 넘깁니다.
2. apply 메서드
apply는 call과 비슷하지만, 인자를 배열ㄹ 전달한다는 차이점이 있습니다.
functionName.apply(thisArg, [argsArray])
- thisArg: 함수 내에서 사용할 this 값을 설정합니다.
- argsArray: 함수에 전달할 인자를 배열로 넘깁니다.
예시)
function greet(greeting, name) {
console.log(`${greeting}, ${name}! My name is ${this.name}.`);
}
const person = { name: 'Alice' };
greet.apply(person, ['Hi', 'Bob']); // Output: Hi, Bob! My name is Alice.
3. bind 메서드
bind는 this 값을 설정한 새로운 함수를 반환합니다.
즉, 함수를 실행하지 않고,
나중에 실행할 수 있는 함수를 반환합니다.
이때, 인자를 미리 설정할 수도 있습니다.
const boundFunction = functionName.bind(thisArg, arg1, arg2, ...)
예시)
function greet(greeting, name) {
console.log(`${greeting}, ${name}! My name is ${this.name}.`);
}
const person = { name: 'Alice' };
const boundGreet = greet.bind(person, 'Hey');
boundGreet('Charlie'); // Output: Hey, Charlie! My name is Alice.
Q. 콜백 함수에 대해 설명해주세요.
콜백 함수는 다른 함수에 인자로 전달되어,
그 함수의 실행이 끝난 후 호출되는 함수입니다.
비동기 처리나 이벤트 핸들링에 자주 사용됩니다.
자바스크립트에서는 함수도 일급 객체이기 때문에,
다른 함수에 전달하거나 반환할 수 있습니다.
예시)
function fetchData(callback) {
setTimeout(() => {
const data = { name: 'Alice', age: 25 }; // 2초 후에 데이터가 준비됨
callback(data); // 작업 완료 후 콜백 호출
}, 2000); // 2초 후에 실행되는 비동기 작업
}
fetchData(function(data) {
console.log(data); // 데이터가 준비된 후 출력됨
});
q. 콜백 지옥을 해결하는 방법을 설명해주세요.
콜백 지옥은 비동기 처리 로직에서 콜백 함수가 연속적으로 중첩되어 코드의 가독성이 떨어지고,
유지보수가 어려워지는 문제입니다.
이를 해결하는 방법은,
Promise와 async/await가 있습니다.
Promise는 비동기 연산이 완료된 후의 결과를 처리하기 위해 사용하는 객체입니다.
.then() 메서드를 사용하여 함수 실행 순서를 관리할 수 있습니다.
async/await는 ES8에서 도입되었으며,
비동기 코드를 동기 코드처럼 작성할 수 있게 해줍니다.
async 함수는 항상 Promise를 반환하며,
await는 Promise가 처리될 때까지 코드 실행을 잠시 중단합니다.
await는 async 함수 내부에서만 사용할 수 있으며,
이를 통해 비동기 함수의 결과가 반환될 때까지 기다릴 수 있습니다.
Q. Promise에 대해 설명해주세요.
Promise 객체는 비동기 작업의 결과를 나타내는 객체입니다.
즉, 작업의 완료 또는 실패를 나타내며, 그 결과 값을 처리할 수 있도록 합니다.
Promise는 즉시 결과를 반환하는 것이 아니라,
비동기 작업이 완료된 이후에 처리할 수 있는 약속을 반환합니다.
이로 인해 비동기 작업의 결과를 나중에 처리할 수 있도록 도와줍니다
이처럼 Promise는 콜백 패턴보다 가독성이 뛰어나고,
여러 비동기 작업을 순차적으로 처리하거나 동시에 처리할 수 있는 유연성을 제공합니다.
+
+
Promise는 세가지 상태를 가진다.
- Pending: 비동기 작업이 아직 완료되지 않은 상태
- Fulfilled: 비동기 작업이 성공적으로 완료된 상태로, 결과 값을 반환
- Rejected: 비동기 작업이 실패한 상태로, 실패 이유를 반환
Promise 객체는 다음과 같은 방식으로 결과를 처리할 수 있다.
- .then() 메서드를 사용하여 작업이 성공했을 때의 결과 값을 처리할 수 있다.
- .catch() 메서드를 사용하여 작업이 실패했을 때의 오류를 처리할 수 있다.
- .finally() 메서드는 성공 여부와 관계없이 작업이 완료된 후에 실해오딜 코드를 작성할 수 있다.
q. Promise.all() 에 대해 설명해주세요.
Promise.all() 은 여러 프로미스의 결과를 집계할 때 사용합니다.
일반적으로 서로 연관된 비동기 작업 여러 개가 모두 이행되어야 하는 경우에 사용됩니다.
또한 입력값으로 들어온 프로미스 중 하나라도 거부당하면 Promise.all() 은 즉시 거부합니다.
+
Promise.all()는 여러 개의 프로미스를 동시에 처리할 때 사용되는 메서드이다.
주어진 Promise 객체들의 배열을 받아,
모든 프로미스가 이행 (Fulfilled) 되었을 때 하나의 프로미스를 반환한다.
반면에, 배열 내 프로미스 중 하나라도 거부(rejected) 되면 즉시 거부된 상태로 반환된다.
동작 방식
- Promise.all()에 전달된 모든 프로미스가 성공(Fulfilled)해야만 then() 블록이 실행되며,
결과값은 각 프로미스가 이행된 값들의 배열로 반환된다.
- 배열 내 하나라도 거부(rejected)될 경우, 즉시 거부된 프로미스를 반환하며, 이때 catch() 블록이 실행된다.
이 방법은 여러 비동기 작업을 동시에 실행하고, 그 작업들이 모두 완료된 후에 어떤 작업을 수행해야 할 때 유용하다.
주의점
1. 실패 처리: 입력된 프로미스 중 하나라도 거부되면, 나머지 프로미스의 결과가 이행되더라도 전체가 거부된 것으로 처리 된다.
2. 순서 보장: 각 프로미스가 완료되는 시간에 상관없이 Promise.all()은 입려된 순서대로 결과값을 배열로 반환한다.
3. 병렬 실행: Promise.all()은 여러 비동기 작업을 병렬로 실행하고 결과를 집계하기 때문에, 성능 최적화 측면에서 유리할 수 있다.
Q. Promise와 Callback을 비교 설명해주세요.
Callback과 Promise의 차이점:
1. 가독성: Callback은 중첩되기 쉬워 코드가 복잡해질 수 있는 반면,
Promise는 체이닝 방식으로 코드의 흐름이 더 명확합니다.
2. 에러 처리: Callback 방식에서는 각 콜백마다 에러 처리가 필요하지만,
Promise는 catch()를 통해 한번에 에러를 처리할 수 있습니다.
3. 코드 작성 방식: Callback은 함수 내부에서만 결과를 처리할 수 있어 박에서는 그 결과값을 알 수 없습니다.
Promise는 비동기 로직의 결과값이 Promise 객체에 저장되기 때문에 코드 작성이 용이합니다.
+
Callback과 Promise는 모두 js에서 비동기 작업을 처리하는 방법이다.
그러나 두 방식에는 중요한 차이점과 각기 다른 장단점이 있다.
Callback
: Callback 함수는 비동기 작업이 완료된 후 실행할 코드를 인수로 전달하는 방식이다. 특정 작업이 끝난 후에 실행될 함수를 미리 정의해 비동기 결과를 처리할 수 있다.
장점
- 단순한 비동기 작업에서는 코드가 직관적일 수 있다.
단점
- Callback hell: 중첩된 비동기 작업이 많아지면,
콜백 함수들이 계속 중첩되어 코드가 복잡하고 가독성이 떨어지는 콜백 지옥이 발생할 수 있다.
- 에러 처리: 여러 단계의 콜백이 있을 경우 에러를 처리하기가 복잡해진다.
function fetchData(callback) {
setTimeout(() => {
callback("data fetched");
}, 1000);
}
fetchData((result) => {
console.log(result); // 'data fetched'
});
Promise
: Promise는 비동기 작업의 결과를 처리할 수 있는 객체로,
비동기 작업의 성공 또는 실패 상태와 그 결과 값을 처리할 수 있다.
Promise는 콜백보다 가독성이 뛰어나고, 여러 비동기 작업을 처리하는 구조를 쉽게 만들 수 있다.
장점
- 가독성: then(), catch()와 같은 체이닝을 통해 비동기 작업을 순차적으로 처리할 수 있어, 코드가 직관적이고 가독성이 좋다.
- 에러 처리: Promise 체이닝에서 발생한 모든 에러를 catch() 로 한번에 처리할 수 있어, 에러 처리 구조가 단순해진다.
- 병렬 작업: Promise.all() 과 같은 기능을 통해 여러 비동기 작업을 병렬로 처리할 수 있다.
단점
- 이전의 콜백 기반 방식에 비해 학습 곡선이 있을 수 있다.
const fetchDataPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("data fetched");
}, 1000);
});
fetchDataPromise
.then(result => console.log(result)) // 'data fetched'
.catch(error => console.error(error));
Q. Promise와 Async/Await 의 차이를 설명해주세요.
Promise는 .then()과 .catch()를 사용해 비동기 작업의 결과를 처리하고,
에러는 .catch()에서 처리합니다.
하지만 .then() 체이닝이 많아지면 코드가 복잡해질 수 있습니다.
async/await은 Promise 기반이지만,
동기식 코드처럼 비동기 작업을 처리할 수 있습니다.
await을 사용해 비동기 작업이 완료될 때까지 기다리고, 에러는 try-catch 블록으로 처리합니다.
코드의 가독성이 높아지고 흐름을 쉽게 이해할 수 있다는 장점이 있습니다.
결론적으로, async/await은 Promise보다 가독성이 높고 더 직관적이며, 복잡한 비동기 로직을 처리하는 데 유리합니다
// Promise
fetchData()
.then(result => processData(result))
.then(finalResult => console.log(finalResult))
.catch(error => console.error(error));
// async/await
try {
const result = await fetchData();
const finalResult = await processData(result);
console.log(finalResult);
} catch (error) {
console.error(error);
}
Q. TDZ에 대해 설명해주세요.
let이나 const로 선언된 변수가 선언된 위치부터 초기화되기 전까지의 구간을 의미합니다.
이 구간에서는 변수가 참조되지 않으며, 참조하려고 하면 ReferenceError가 발생합니다.
발생하는 이유는,
JavaScript는 변수가 선언된 스코프에서 위로 끌어올리는 호이스팅이 일어납니다. 하지만 var와 달리, let과 const는 호이스팅되더라도 초기화되기 전까지는 사용할 수 없는 상태로 남아있습니다. 이 기간이 바로 TDZ입니다.
(var는 호이스팅과 동시에 undefined로 초기화된다.)
TDZ에 영향을 받는 구문으로는 let, const 외에도 클래스와 contructor() 내부의 super() 호출도 포함됩니다.
예를 들어, constructor() 내부에서 super()를 호출하기 전까지는 this를 사용할 수 없습니다.
+ let과 const는 선언이 완료된 후에만 접근할 수 있습니다. 선언 후에도 아직 초기화가 되지 않았다면, 이때는 여전히 TDZ에 있으며 참조할 수 없습니다.
Q. 함수 선언문과 함수 표현식의 차이에 대해 설명해주세요.
함수 선언문은 function add(x, y) {}처럼 함수 이름을 명시하는 형태로 작성되며, 함수 선언이 호이스팅됩니다.
즉, 함수 선언문은 호이스팅되기 때문에 코드에서 함수 선언 이전에 호출해도 정상적으로 실행됩니다.
함수 표현식은 const add = function(x, y) {}처럼 변수에 익명 함수(혹은 기명 함수)를 할당하는 형태입니다.
이때 함수 이름을 생략할 수 있습니다.
함수 표현식은 변수에 할당되는 방식이므로, 변수 호이스팅은 발생하지만 실제 함수 정의는 변수 할당 이후에 이루어지기 때문에 함수 표현식으로 정의된 함수는 정의되기 전에는 호출할 수 없습니다.
Q. 이벤트 버블링과 캡처링에 대해 설명해주세요.
이벤트 흐름은 캡처링 단계, 타깃 단계, 버블링 단계로 나뉩니다.
이벤트 캡처링은 이벤트가 최상위 조상 요소(예: window나 document)에서 시작하여 타깃 요소에 도달할 때까지 내려가는 과정을 말합니다.
이 과정에서 이벤트를 포착하려면, addEventListener의 세 번째 인자인 capture 옵션을 true로 설정해야 합니다.
타깃 단계는 이벤트가 실제 이벤트가 발생한 타깃 요소에서 처리되는 단계입니다.
캡처링과 버블링 사이에 위치합니다.
이벤트 버블링은 타깃 요소에서 발생한 이벤트가 다시 상위 조상 요소들로 전파되는 과정을 의미합니다.
기본적으로 거의 모든 이벤트가 버블링되지만, focus와 같은 특정 이벤트는 버블링되지 않습니다.
q. 이벤트 위임에 대해서 설명해주세요.
이벤트 위임은 여러 하위 요소에서 발생하는 이벤트를 하나의 상위 요소에 핸들러를 등록해 처리하는 기법입니다.
이 방법은 특히 동적으로 생성되는 요소들이 많을 때 유용합니다.
이벤트 위임을 사용하려면 이벤트가 반드시 버블링되어야 합니다.
이벤트가 하위 요소에서 발생한 후 상위 요소로 전파되면서 상위 요소에서 해당 이벤트를 처리할 수 있게 됩니다.
이벤트가 발생한 구체적인 하위 요소를 식별하기 위해 event.target을 사용하여 실제로 이벤트가 발생한 요소를 확인할 수 있습니다.
q. 이벤트 위임의 동작 방식에 대해서 설명해주세요.
1. 먼저, 상위 컨테이너(부모 요소)에 하나의 이벤트 핸들러를 추가합니다.
2. 컨테이너 내의 하위 요소에서 이벤트가 발생하면, 그 이벤트는 이벤트 버블링을 통해 상위 요소로 전파됩니다.
3. 이벤트가 핸들러가 등록된 컨테이너(상위 요소)까지 전파되면,
해당 핸들러는 **event.target**을 통해 실제로 이벤트가 발생한 하위 요소를 식별할 수 있습니다.
4. 이벤트가 발생한 요소가 원하는 대상인지 확인한 후, 조건에 맞는다면 이벤트를 처리합니다.
즉, 특정 조건에 따라 필요한 하위 요소에서만 이벤트를 핸들링할 수 있습니다.
Q. 호이스팅과 발생하는 이유에 대해 설명해주세요.
호이스팅이란, JavaScript 인터프리터가 코드를 실행하기 전에 변수 선언과 함수 선언을 메모리에 미리 할당하는 동작을 의미합니다.
이는 코드 작성 순서와 상관없이 선언된 변수나 함수가 코드의 최상단으로 "끌어올려지는" 것처럼 동작합니다.
- var로 선언된 변수는 호이스팅 시 **undefined**로 초기화됩니다.
따라서 변수 선언 전에 해당 변수를 참조하면 undefined가 출력됩니다.
- 반면, let과 const로 선언된 변수는 호이스팅되지만 초기화되지 않으며,
선언 전에 접근하면 **ReferenceError**가 발생합니다.
이는 let과 const 변수가 **TDZ(Temporal Dead Zone)**에 있기 때문입니다.
함수의 경우:
- 함수 선언문은 호이스팅되며,
선언된 함수는 스코프의 최상단으로 끌어올려져 코드 어디에서든 호출할 수 있습니다.
- 함수 표현식은 변수에 할당되므로, 변수 자체는 호이스팅되지만,
함수 표현식이 할당된 함수는 해당 선언 이후에만 사용할 수 있습니다.
선언 전에 호출하면 **ReferenceError**가 발생합니다.
Q. 스코프 (Scope)에 대해 설명해주세요.
스코프란 식별자(변수, 함수, 또는 클래스 등)가 코드 내에서 유효한 범위를 의미합니다.
식별자가 어디에서 선언되었는지에 따라, 해당 식별자를 참조할 수 있는 범위가 결정됩니다.
- var는 함수 스코프를 따릅니다.
이는 var로 선언된 변수는 가장 가까운 함수를 기준으로 스코프가 결정되며,
블록({}) 내부에서 선언된 경우에도 함수 전체에서 접근할 수 있습니다.
- 반면, let과 const는 블록 스코프를 따릅니다.
이는 중괄호 {}로 둘러싸인 코드 블록을 기준으로 스코프가 설정되며,
블록 내부에서만 유효하고, 블록 밖에서는 참조할 수 없습니다.
q. 스코프 체인에 대해 설명해주세요.
스코프 체인이란,
자바스크립트 엔진이 식별자를 찾을 때 현재 스코프에서 찾지 못하면 상위 스코프로 올라가며 식별자를 검색하는 과정을 말합니다. 스코프가 중첩된 상황에서 이러한 탐색이 발생합니다.
이 과정을 통해 식별자를 검색할 수 있는 모든 스코프가 연결된 구조를 스코프 체인이라고 합니다.
함수의 상위 스코프는 호출된 위치가 아닌, 함수가 선언된 위치에 따라 결정됩니다. (렉시컬 스코프(정적 스코프))
Q. 클로저(Closure)에 대해 설명해주세요.
클로저는 함수와 그 함수가 선언된 렉시컬 환경의 조합입니다. 쉽게 말해, 클로저는 함수가 생성될 때 그 함수가 선언된 스코프 밖에서 호출되더라도 그 외부 스코프에 접근할 수 있게 해줍니다.
이를 통해 전역 변수를 사용하지 않고도 함수 밖에서 해당 변수에 접근할 수 있는 방법을 만들어주며
이는 반환된 함수를 제외하면 외부에서 접근할 수 없으므로 마치 private 변수처럼 사용할 수 있습니다.
+
렉시컬 스코프:
js 함수는 자신이 정의된 위치에 따라 스코프가 결정됩니다.
이는 함수 내부에서 변수에 접근할 때 해당 함수가 어디에서 호출되었는지가 아니라, 어디에서 선언되었는지에 따라 변수를 찾는 방식을 의미합니다.
+
함수가 다른 함수 내부에 정의될 경우, 그 내부 함수는 외부 함수의 변수에 접근할 수 있습니다.
외부함수가 실행이 끝난 뒤에도 내부 함수가 그 변수를 참조할 수 있습니다.
+
실행 컨텍스트와 가비지 컬렉션:
일반적으로 함수가 실행되면 그 실행 컨텍스트가 종료되면서 변수들이 메모리에서 제거되지만,
클로저를 사용하는 경우에는 함수가 참조하고 있는 외부 변수들이 계속해서 메모리에 유지됩니다.
+ 예시
function outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 2
counter(); // 3
Q. 실행 컨텍스트에 대해 설명해주세요.
실행 컨텍스트는
실행할 코드에 제공할 환경 정보들을 모아놓은 객체입니다.
자바스크립트는 이러한 환경 정보들을 모은 실행 컨텍스트를 call stack에 쌓아올린 후 실행하여
코드의 환경과 순서를 보장합니다.
+
실행 컨텍스트는 자바스크립트 코드가 실행되는 환경을 정의하는 개념입니다.
자바스크립트는 싱글 스레드 기반의 언어로,
코드를 실행할 때 특정한 규칙을 따르는데,
이 규칙을 관리하는 것이 바로 실행 컨텍스트입니다.
실행 컨텍스트는 코드의 실행 순서와 변수, 함수 등의 스코프를 관리합니다.
핵심 개념
1. 전역 실행 컨텍스트
- 자바스크립트 프로그램이 시작되면 가장 먼저 생성되는 컨텍스트로, 전역 코드를 실행합니다.
- 전역 변수와 함수는 전역 실행 컨텍스트에 의해 관리됩니다.
2. 함수 실행 컨텍스트
- 함수가 호출될 때마다 새로운 실행 컨텍스트가 생성됩니다.
- 각각의 함수 호출은 고유한 실행 컨텍스트를 가지며, 함수 실행이 완료되면 해당 컨텍스트는 제거됩니다.
3. 실행 컨텍스트의 구성 요소
- 변수 객체 : 함수 내에서 선언된 변수, 함수 선언문, 매개변수 등을 저장합니다.
- 스코프 체인 : 현재 컨텍스트와 상위 컨텍스트를 참조하여 변수에 접근할 수 있게 합니다.
- this 바인딩 : 실행되는 문맥에 따라 this가 참조하는 객체를 결정합니다.
4. 실행 컨텍스트 스택
- 자바스크립트는 실행 컨텍스트 스택을 통해 코드의 실행 흐름을 관립합니다.
- 스택 구조로 쌓이면서 현재 실행 중인 코드의 컨텍스트를 추적하며, 함수가 호출될 때마다 새로운 실행 컨테그스트가 스택에 추가되고, 함수가 종료되면 스택에서 제거됩니다.
Q. 렉시컬 환경에 대해 설명해주세요.
렉시컬 환경은 자바스크립트의 내부 메커니즘으로, 코드가 어디에서 어떻게 작성되었는지를 기반으로
변수와 함수가 어떻게 접근되고 실행되는지를 정의하는 환경입니다.
렉시컬 환경 구성
1. 환경 레코드
: 현재 실행 컨텍스트에서 사용할 변수, 함수 선언, 매개변수 등이 저장되는 객체입니다.
2. 외부 렉시컬 환경에 대한 참조
: 현재 렉시컬 환경의 부모 환경을 참조하는 링크로, 스코프 체인을 형성합니다.
렉시컬 환경의 종류
1. 전역 렉시컬 환경
: 코드의 최상위, 즉 전역에서 정의된 변수를 저장하는 환경입니다.
전역 스코프에 속하는 모든 변수와 함수는 여기서 관리됩니다.
2. 함수 렉시컬 환경
: 함수가 호출될 때마다 생성되는 환경으로,
함수 내부에서 선언된 변수와 함수가 여기에 저장됩니다.
렉시컬 환경은 스코프 체인을 구성합니다. 각 실행 컨텍스트는 자신이 속한 렉시컬 환경과 상위 렉시컬 환경에 대한 참조를 유지합니다. 이를 통해, 함수나 블록 내부에서 선언된 변수가 상위 스코프의 변수를 참조할 수 있습니다.
내부 렉시컬 환경에서 원하는 변수를 찾지 못하면 내부 렉시컬 환경에 참조하는 외부 렉시컬 환경으로 검색 범위를 확장하며, 이는 전역 렉시컬 환경까지 반복됩니다.
Q. 자바스크립트에서 일어나는 데이터 형변환에 대해 설명해주세요.
js에서 형변환은 암묵적과 명시적으로 나뉩니다.
1. 암묵적 형변환
: js가 자동으로 타입을 변환하는 것으로, 주로 연산이나 비교에서 발생합니다.
예를 들어 '5' + 1은 문자열 결합으로 51이 되고, 0,null, undefined 같은 값은 조건문에서 false로 평가됩니다.
2. 명시적 형변환
: 개발자가 직접 String(), Number(), Boolean()을 사용하여 타입을 변환하는 것입니다.
예를 들어, Number('123')은 숫자 123으로 변환됩니다.
3. 객체의 형변환
: 객체는 Symbol.toPrimitive를 사용해 특정 타입으로 변환할 수 있습니다.
또한 toString()이나 valueOf() 메서드를 통해 문자열이나 숫자로 변환이 가능합니다.
Symbol.toPrimitive는 객체가 특정 연산에 대해 어떤 타입으로 변환될지를 제어할 수 있는 방법입니다.
Q. 자바스크립트가 동적 언어인 이유는 무엇인가요?
자바스크립트는 런타임 시 변수의 타입이 결정되는 동적 언어입니다.
즉, 코드를 빌드할 때가 아닌 실행 중에 변수의 타입이 결정되며,
동일한 변수에 다양한 타입의 값을 자유롭게 할당할 수 있습니다.
이러한 유연성 덕분에 런타임까지 타입 결정을 미룰 수 있지만,
예상치 못한 타입이 변수에 할당되면 TypeError 같은 오류가 발생할 수 있어 주의가 필요합니다.
Q. 프로토타입에 대해 설명해주세요.
자바스크립트에서 모든 객체는 메서드와 속성을 상속받기 위해 프로토타입 객체를 참조합니다.
프로토타입은 객체의 일종의 템플릿으로,
객체들이 상속할 수 있는 속성과 메서드들이 정의된 곳입니다.
자세히 말하자면, 각 객체의 개별 인스턴스가 직접 속성과 메서드를 갖는 것이 아니라,
생성자의 prototype 속성에 정의된 속성과 메서드를 공유하여 사용합니다.
js는 프로토타입 체인을 통해 객체와 생성자의 프로토타입 간에 연결을 구성하고,
객체의 속성이나 메서드를 호출할 때 해당 객체에 없는 경우
이 체인을 따라 상위 프로토타입으로 올라가며 탐색합니다.
이러한 구조 덕분에 메모리를 절약할 수 있고,
동일한 기능을 여러 객체가 공유하여 효율적으로 사용할 수 있습니다.
Q. 깊은 복사와 얕은 복사에 대해 설명해주세요.
얕은 복사는 참조값만을 복사하는 방식입니다.
즉, 복사된 객체는 원본 객체의 같은 메모리 주소를 가리키기 때문에,
한 객체의 속성을 변경하면 다른 객체에도 영향을 미치게 됩니다.
깊은 복사는 객체의 실제 값을 복사하여 완전히 새로운 객체를 생성하는 방식입니다.
원본 객체와 복사된 객체가 독립적으로 존재하기 때문에,
복사된 객체의 속성을 변경해도 원본 객체에는 영향을 미치지 않습니다.
Q. 불변성을 유지하려면 어떻게 해야하나요?
대표적으로 세가지 방법이 있습니다.
1. Object.preventExtensions
: 이 메서드는 객체의 확장을 방지하여 새로운 프로퍼티를 추가할 수 없게 합니다.
그러나 기존 프로퍼티의 수정과 삭제는 가능합니다.
2. Object.seal
: 이 메서드는 객체를 밀봉합니다.
밀봉된 객체는 프로퍼티의 추가와 삭제가 금지되며,
프로퍼티 어트리뷰트 재정의도 할 수 없습니다.
다만, 기존 프로퍼티의 값을 읽고 쓰는 것은 가능합니다.
3. Object.freeze
: 이 메서드는 객체를 동결합니다.
동결된 객체는 프로퍼티 추가, 삭제, 어트리뷰트 재정의, 값 갱신이 모두 금지되며
읽기만 가능하게 합니다.
Q. Blocking과 Non-Blocking 에 대해 설명해주세요.
Blocking은 호출된 함수가 제어할 수 없는 작업이 완료될 때까지 기다리는 방식을 의미합니다.
예를 들어, 함수가 I/O 작업을 요청했을 때,
해당 작업이 끝날 때까지 프로그램의 실행이 멈춰 다른 작업을 수행하지 못합니다.
이로 인해 응답 속도가 느려질 수 있습니다.
Non-Blocking은 호출된 함수가 제어할 수 없는 작업이 완료되기 전에도 제어권을 즉시 넘겨주는 방식을 의미합니다.
I/O 작업을 요청한 경우,
해당 작업의 완료 여부와 관계없이 바로 다음 작업으로 넘어가며,
요청된 작업이 완료되면 나중에 그 결과를 처리합니다.
Non-Blocking 방식은 프로그램의 응답성을 높이고 동시에 여러 작업을 수행하는 데 유리합니다.
Q. 동기와 비동기에 대해 설명해주세요.
동기는 순차적으로 태스크를 수행하며,
요청을 보내고 응답을 받아야 다음 동작이 이루어집니다.
순차적으로 실행되므로,
어떤 작업이 수행중이라면
뒤의 작업은 대기합니다.
비동기는 병렬적으로 태스크를 수행합니다.
현재 작업의 종료여부와는 무관하게 다음작업을 실행하므로
완료 순서가 보장되지 않습니다.
자원을 효율적으로 사용할 수 있게 해주며,
특히 네트워크 요청이나 파일 읽기처럼 시간이 걸리는 작업을 수행할 때
시스템의 응답성을 높이는데 유리합니다.
자바스크립트는 기본적으로 싱글 스레드 기반 동기적으로 동작합니다.
이벤트 루프와 콜백 큐를 통해
비동기 작업을 처리합니다.
이를 통해 동기 코드와 비동기 코드가 조화를 이룹니다.
Q. ES6에서 새로 생긴 기능을 아는대로 말씀해주세요.
- 블록 스코프, let, const
let과 const 키워드를 통해 변수를 선언하며,
함수 스코프가 아닌 블록 스코프를 가지게 됩니다.
let은 재할당이 가능하지만 const는 선언 이후 재할당이 불가능합니다.
- 클래스
객체 지향 프로그래밍을 위한 클래스 문법이 추가되어,
기존의 프로토타입 기반 상속 대신 직관적으로 클래스를 정의하고 상속을 구현할 수 있습니다.
- 모듈
export와 import 키워드를 사용하여 모듈화를 지원합니다.
이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.
- 화살표 함수
간결한 문법으로 함수를 정의할 수 있으며,
this 바인딩이 기존 함수와 다릅니다.
화살표 함수는 자신의 this를 가지지 않고, 외부 스코프의 this를 유지합니다.
- 매개변수 기본값
함수의 매개변수에 기본값을 설정할 수 있어,
호출 시 인자를 전달하지 않을 경우 기본값이 사용됩니다.
- 템플릿 리터럴
백틱(`)을 이용한 문자열 선언으로,
문자열 내에서 ${변수} 형태로 표현식을 쉽게 포함할 수 있습니다.
이를 통해 문자열 연결이 더욱 간편해졌습니다.
- 디스트럭처링
배열이나 객체의 구조를 분해하여 손쉽게 변수에 할당할 수 있습니다.
이를 통해 데이터를 직관적으로 추출할 수 있습니다.
- 스프레드 연산자
배열이나 객체를 펼치거나 병합할 때 사용합니다.
배열이나 객체의 복사, 합치기, 함수 호출 시 인자로 펼치기 등에 유용합니다.
- 프로미스 (Promise)
비동기 작업을 관리하기 위한 객체로,
비동기 작업의 성공 또는 실패를 다루며 콜백 헬을 방지합니다.
ES6 이후 비동기 코드를 작성할 때 주로 사용됩니다.
'취준 > 기술면접' 카테고리의 다른 글
[OS 면접 총정리] 핵심 & 요약 (진행중) (4) | 2024.10.31 |
---|