70 자바스크립트 인터뷰 질문 - 1부(번역)
70 JavaScript Interview Questions
javascript, interview, translation
출처
70 JavaScript Interview Questions
시작하며
글이 긴 관계로 4부로 나눠서 진행하며 1부는 1-17번 질문, 2부는 18-36번, 3부는 37-54번, 4부는 55-70번 질문으로 구성되어 있다.
Hi Guys Good Day and a Happy New Year 🎆🎆🎆!
이 글은 긴 내용이므로 한두 시간 동안 나와 함께하시길 바랍니다. 모든 질문에 대한 답변에는 질문 목록으로 돌아가는 화살표 ↑ 링크가 있어서 스크롤 하는 시간을 낭비하지 않아도 됩니다.
질문
- 1. undefined 와 null 은 무엇이 다른가?
- 2. && 연산자는 무엇을 하는가?
- 3. || 연산자는 무엇을 하는가?
- 4. string을 number로 변환하는 가장 빠른 방법은 + 또는 단항 더하기 연산자를 사용하는 것인가?
- 5. DOM 이란 무엇인가?
- 6. Event Propagation란 무엇인가?
- 7. Event Bubbling이란 무엇인가?
- 8. Event Capturing이란 무엇인가?
- 9. event.preventDefault()와 event.stopPropagation() 메서드의 차이점은 무엇인가?
- 10. event.preventDefault() 메서드가 element에 사용되었는지 어떻게 확인하는가?
- 11. 이 코드에서 obj.someprop.x가 에러 발생하는 이유는 무엇인가?
- 12. event.target 이란 무엇인가?
- 13. event.currentTarget 이란 무엇인가?
- 14. == 와 === 의 차이는 무엇인가?
- 15. 자바스크립트에서 비슷한 두 객체를 비교할때 false를 리턴하는 이유는 무엇인가?
- 16. !! 연산자는 무엇을 하는가?
- 17. 한 줄에 여러 표현식을 평가하는 방법은 무엇인가?
1. undefined
와 null
은 무엇이 다른가?
↑
undefined
와 null
의 차이점을 이해하기 전에 이들의 유사점을 이해해야 합니다.
- 이들은 JavaScript의 7가지 원시 타입에 속합니다.
let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
- 이것은 falsy 값입니다.
Boolean(value)
또는!!value
를 사용해서 boolean로 변환할 때 false로 평가된 값입니다.
console.log(!!null); //logs false
console.log(!!undefined); //logs false
console.log(Boolean(null)); //logs false
console.log(Boolean(undefined)); //logs false
Ok, 차이점에 관해 얘기해봅시다.
undefined
는 특정 값이 할당되지 않은 변수의 기본값입니다. 또는 명시적인 리턴 값이 없는 함수 예를들어console.log(1)
. 또는 객체에 존재하지 않는 속성. 자바스크립트 엔진은 이를 위해undefined
값을 할당합니다.
let _thisIsUndefined;
const doNothing = () => {};
const someObj = {
a : "ay",
b : "bee",
c : "si"
};
console.log(_thisIsUndefined); //logs undefined
console.log(doNothing()); //logs undefined
console.log(someObj["d"]); //logs undefined
null
은 **“값을 나타내지 않는 값”**입니다.null
은 변수에 명시적으로 정의된 값입니다. 이 예제에서는fs.readFile
메서드가 에러를 던지지 않으면null
값을 얻습니다.
fs.readFile('path/to/file', (e,data) => {
console.log(e); // 에러가 없을 때 로그 null
if (e) {
console.log(e);
}
console.log(data);
});
null
과 undefined
를 비교할 때 ==
를 사용하면 true
를, ===
을 사용하면 false
를 얻습니다. 여기서 확인 할 수 있습니다.
console.log(null == undefined); // logs true
console.log(null === undefined); // logs false
2. &&
연산자는 무엇을 하는가?
↑
&&
또는 논리 AND 연산자는 피연산자에서 첫 번째 falsy 표현식을 찾아서 리턴하며, falsy 표현식을 찾지 못하면 마지막 표현식을 리턴합니다.
불필요한 작업을 방지하기 위해 단락(short-circuiting)을 사용합니다. 저는 저의 프로젝트 중 하나에서 데이터베이스 연결을 닫을 때 이것을 catch
블록에서 사용했습니다.
console.log(false && 1 && []); //logs false
console.log(" " && true && 5); //logs 5
if 문 사용.
const router: Router = Router();
router.get('/endpoint', (req: Request, res: Response) => {
let conMobile: PoolConnection;
try {
//do some db operations
} catch (e) {
if (conMobile) {
conMobile.release();
}
}
});
&& 연산자 사용.
const router: Router = Router();
router.get('/endpoint', (req: Request, res: Response) => {
let conMobile: PoolConnection;
try {
//do some db operations
} catch (e) {
conMobile && conMobile.release()
}
});
3. ||
연산자는 무엇을 하는가?
↑
||
또는 논리 OR
연산자는 피연산자에서 첫 번째 truthy 표현식을 찾아 리턴합니다. 이것 또한 불필요한 작업을 방지하기 위해 단락(short-circuiting)을 사용합니다.
ES6 Default function parameters가 지원되기 전에 함수 안에서 기본 매개 변수 값 초기화를 위해 사용되었습니다.
console.log(null || 1 || undefined); //logs 1
function logName(name) {
var n = name || "Mark";
console.log(n);
}
logName(); //logs "Mark"
4. string을 number로 변환하는 가장 빠른 방법은 + 또는 단항 더하기 연산자를 사용하는 것인가?
↑
MDN 문서에 따르면 +
는 이미 number일 경우 값에 대한 작업을 수행하지 않기 때문에 string을 number로 변환하는 가장 빠른 방법입니다.
5. DOM 이란 무엇인가?
↑ DOM은 Document Object Model의 약자로 HTML 및 XML 문서를 위한 인터페이스 (API)입니다. 브라우저가 HTML 문서를 처음 읽을 때 (구문 분석할 때) HTML 문서를 기반으로 하는 큰 오브젝트를 만드는데 이것이 DOM입니다. HTML 문서에서 모델링 된 트리와 유사한 구조입니다. DOM은 DOM 구조 또는 특정 Elements 또는 Nodes를 상호 작용하고 수정하는 데 사용됩니다.
이와 같은 HTML 구조로 되어 있다고 상상해보십시오.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document Object Model</title>
</head>
<body>
<div>
<p>
<span></span>
</p>
<label></label>
<input>
</div>
</body>
</html>
DOM은 다음과 같을 것입니다.
JavaScript의 document
객체는 DOM을 나타냅니다.
이것은 element 내용을 업데이트하기 위해 elements를 선택하는 데 사용할 수 있는 많은 방법을 제공합니다.
6. 이벤트 전파(Event Propagation) 란 무엇인가?
↑
이벤트가 DOM element에서 발생하면 그 이벤트는 하나의 element에서만 발생하지 않습니다.
버블링 단계에서는 이벤트가 버블링되거나 부모, 조부모, 조부모의 부모에게, window
에 도달할 때까지 진행되며 반면에 캡처링 단계에서는 이벤트가 window
부터 이벤트를 트리거 한 element 또는 event.target
까지 아래로 시작됩니다.
이벤트 전파는 3단계를 가집니다.
- Capturing Phase – 이벤트는
window
에서 시작하여 대상 element에 도달할 때까지 모든 element를 내려갑니다. - Target Phase – 이벤트가 대상 element에 도달합니다.
- Bubbling Phase – 대상 element에서 이벤트가 발생하고
window
에 도달할 때까지 모든 element를 올라갑니다.
7. 이벤트 버블링(Event Bubbling) 이란 무엇인가?
↑
이벤트가 DOM element에서 발생하면 그 이벤트는 하나의 element에서만 발생하지 않습니다.
버블링 단계에서는 이벤트가 버블링되거나 부모, 조부모, 조부모의 부모에게, window
에 도달할 때까지 진행됩니다.
이와 같은 마크업 예제가 있다면.
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
그리고 JS 코드.
function addEvent(el, event, callback, isCapture = false) {
if (!el || !event || !callback || typeof callback !== 'function') return;
if (typeof el === 'string') {
el = document.querySelector(el);
};
el.addEventListener(event, callback, isCapture);
}
addEvent(document, 'DOMContentLoaded', () => {
const child = document.querySelector('.child');
const parent = document.querySelector('.parent');
const grandparent = document.querySelector('.grandparent');
addEvent(child, 'click', function (e) {
console.log('child');
});
addEvent(parent, 'click', function (e) {
console.log('parent');
});
addEvent(grandparent, 'click', function (e) {
console.log('grandparent');
});
addEvent(document, 'click', function (e) {
console.log('document');
});
addEvent('html', 'click', function (e) {
console.log('html');
});
addEvent(window, 'click', function (e) {
console.log('window');
});
});
addEventListener
메서드에는 기본값이 false
인 세 번째 옵션 매개 변수 useCapture가 있으며, 이 이벤트는 버블링 단계에서 발생하고 만약 true
인 경우에는 캡쳐링 단계에서 발생합니다.
child
element를 클릭하면 콘솔에 child
, parent
, grandparent
, html
, document
및 window
가 각각 로그로 기록됩니다.
이것이 이벤트 버블링입니다.
8. 이벤트 캡쳐링(Event Capturing) 이란 무엇인가?
↑
이벤트가 DOM element에서 발생하면 그 이벤트는 하나의 element에서만 발생하지 않습니다.
캡처링 단계에서 이벤트는 window
에서 이벤트를 트리거 한 element로 시작합니다.
이와 같은 마크업 예제가 있다면.
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
그리고 JS 코드.
function addEvent(el, event, callback, isCapture = false) {
if (!el || !event || !callback || typeof callback !== 'function') return;
if (typeof el === 'string') {
el = document.querySelector(el);
};
el.addEventListener(event, callback, isCapture);
}
addEvent(document, 'DOMContentLoaded', () => {
const child = document.querySelector('.child');
const parent = document.querySelector('.parent');
const grandparent = document.querySelector('.grandparent');
addEvent(child, 'click', function (e) {
console.log('child');
}, true);
addEvent(parent, 'click', function (e) {
console.log('parent');
}, true);
addEvent(grandparent, 'click', function (e) {
console.log('grandparent');
}, true);
addEvent(document, 'click', function (e) {
console.log('document');
}, true);
addEvent('html', 'click', function (e) {
console.log('html');
}, true);
addEvent(window, 'click', function (e) {
console.log('window');
}, true);
});
addEventListener
메서드에는 기본값이 false
인 세 번째 옵션 매개 변수 useCapture가 있으며, 이 이벤트는 버블링 단계에서 발생하고 만약 true
인 경우에는 캡쳐링 단계에서 발생합니다.
child
element를 클릭하면 콘솔에 window
, document
, html
, grandparent
, parent
및 child
가 각각 로그로 기록됩니다.
이것이 이벤트 캡쳐링입니다.
9. event.preventDefault()
와 event.stopPropagation()
메서드의 차이점은 무엇인가?
↑
event.preventDefault()
메서드는 element의 기본 동작을 방지합니다.
form
element에 사용하면 submitting 할 수 없습니다.
anchor
element에 사용하면 navigating 할 수 없습니다.
contextmenu
에서 사용하면 보여지거나 표시되지 않습니다.
반면에 event.stopPropagation()
메서드는 이벤트 전파를 중지하거나 버블링 또는 캡처링 단계에서 이벤트 발생을 중지합니다.
10. event.preventDefault()
메서드가 element에 사용되었는지 어떻게 확인하는가?
↑
이벤트 객체에서 event.defaultPrevented
속성을 사용할 수 있습니다.
이것은 event.preventDefault()
가 특정 element에서 호출되었는지 여부를 나타내는 boolean
을 리턴합니다.
11. 이 코드에서 obj.someprop.x
가 에러 발생하는 이유는 무엇인가?
const obj = {};
console.log(obj.someprop.x);
↑
분명하게도, 이 에러는 undefined
값을 가진 someprop
속성에서 x
속성에 접근하려는 이유 때문에 발생합니다.
그 자체로 존재하지 않는 객체의 속성을 명심해야 되고 그리고 그것의 프로토 타입은 undefined
를 기본값으로 가지며 undefined
는 x
의 속성이 없습니다.
12. event.target 이란 무엇인가?
↑ 간단히 말해서 event.target은 이벤트가 발생한 element 또는 이벤트를 트리거 한 element입니다.
샘플 HTML 마크업.
<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
<div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
<div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
<button style="margin:10px">
Button
</button>
</div>
</div>
</div>
샘플 JavaScript.
function clickFunc(event) {
console.log(event.target);
}
버튼을 클릭하면 버튼 마크업이 로그로 기록됩니다. 이벤트를 가장 바깥쪽 div
에 연결해도 버튼은 항상 기록됩니다.
그래서 event.target이 이벤트를 트리거 한 element라는 결론을 내릴 수 있습니다.
13. event.currentTarget 이란 무엇인가?
↑ event.currentTarget은 이벤트 핸들러를 명시적으로 붙이는 element입니다.
질문 12의 마크업 복사. 샘플 HTML 마크업.
<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
<div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
<div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
<button style="margin:10px">
Button
</button>
</div>
</div>
</div>
그리고 JS를 약간 변경.
function clickFunc(event) {
console.log(event.currentTarget);
}
버튼을 클릭하더라도 가장 바깥 쪽 div
마크업이 로그로 기록됩니다.
이 예제에서 event.currentTarget
이 이벤트 핸들러를 붙이는 element라고 결론을 내릴 수 있습니다.
14. ==
와 ===
의 차이는 무엇인가?
↑
==
**(추상적 같음)**와 ===
**(엄격한 같음)**의 차이점은 ==
는 강제변환(coercion) 후 값으로 비교하고 ===
는 강제변환 없이 값 및 타입으로 비교한다는 것입니다.
==
에 대해 더 깊이 파봅시다. 그럼 먼저 강제변환에 대해 이야기합시다.
강제변환은 값을 다른 타입으로 변환하는 프로세스입니다.
이 경우와 같이 ==
는 암묵적인 강제변환을 수행합니다.
==
는 두 값을 비교하기 전에 수행해야 할 몇가지 조건이 있습니다.
x == y
값을 비교해야 한다고 가정해봅시다.
x
와y
가 같은 타입일 경우===
연산자와 비교.x
가null
이고y
가undefined
이면true
를 리턴.x
가undefined
이고y
가null
이면true
를 리턴.x
타입이number
이고y
타입이string
이면x == toNumber(y)
를 리턴.x
타입이string
이고y
타입이number
이면toNumber(x) == y
를 리턴.x
타입이boolean
이면toNumber(x) == y
를 리턴.y
타입이boolean
이면x == toNumber(y)
를 리턴.x
가string
,symbol
또는number
중 하나이고y
타입이object
이면x == toPrimitive(y)
를 리턴.x
가object
이고y
가string
,symbol
중 하나이면toPrimitive(x) == y
를 리턴.false
를 리턴.
Note: toPrimitive
는 먼저 valueOf
메서드를 사용한 다음 객체의 toString
메서드를 사용하여 해당 객체의 원시값을 가져옵니다.
예를 들어 봅시다.
x | y | x == y |
---|---|---|
5 |
5 |
true |
1 |
'1' |
true |
null |
undefined |
true |
0 |
false |
true |
'1, 2' |
[1, 2] |
true |
'[object Object]' |
{} |
true |
이 예제들은 모두 true
를 리턴합니다.
첫 번째 예는 x
와 y
의 타입과 값이 같으므로 조건 1에 해당합니다.
두 번째 예는 y
는 비교하기 전에 number
로 변환됨으로 조건 4에 해당합니다.
세 번째 예는 조건 2에 해당합니다.
네 번째 예는 y
가 boolean
이므로 조건 7로 해당합니다.
다섯 번째 예는 조건 8에 해당합니다.
배열은 1,2
를 리턴하는 toString()
메서드를 사용하여 string
으로 변환됩니다.
마지막 예는 조건 10에 해당합니다.
객체는 [object Object]
를 리턴하는 toString()
메서드를 사용하여 string
으로 변환됩니다.
x | y | x === y |
---|---|---|
5 |
5 |
true |
1 |
'1' |
false |
null |
undefined |
false |
0 |
false |
false |
'1,2' |
[1,2] |
false |
'[object Object]' |
{} |
false |
===
연산자를 사용하면 첫 번째 예제를 제외한 모든 비교는 같은 타입이 아니기 때문에 false
를 리턴합니다. 반면에 첫 번째 예제는 동일한 타입과 값을 가지기 때문에 true
를 리턴합니다.
15. 자바스크립트에서 비슷한 두 객체를 비교할때 false를 리턴하는 이유는 무엇인가?
↑ 아래의 예가 있다고 가정해봅시다.
let a = { a: 1 };
let b = { a: 1 };
let c = a;
console.log(a === b); // 속성이 같더라도 로그는 false를 기록합니다.
console.log(a === c); // 로그 true hmm
JavaScript는 *객체(objects)*와 *원시값(primitives)*을 다르게 비교합니다.
원시값에서는 **값(value)**별로 비교하지만 객체에서는 참조 또는 변수가 저장된 메모리의 주소로 비교합니다.
그렇기에 첫 번째 console.log
문은false
를, 두 번째console.log
문은true
를 라턴한 이유입니다.
a
와c
는 같은 참조를 가지고 있으며 a
와b
는 동일하지 않습니다.
16. !!
연산자는 무엇을 하는가?
↑
이중 NOT 연산자 또는 !!는 오른쪽의 값을 boolean
로 강제합니다. 기본적으로 값을 boolean
로 변환하는 멋진 방법입니다.
console.log(!!null); //logs false
console.log(!!undefined); //logs false
console.log(!!''); //logs false
console.log(!!0); //logs false
console.log(!!NaN); //logs false
console.log(!!' '); //logs true
console.log(!!{}); //logs true
console.log(!![]); //logs true
console.log(!!1); //logs true
console.log(!![].length); //logs false
17. 한 줄에 여러 표현식을 평가하는 방법은 무엇인가?
↑
,
또는 쉼표 연산자를 사용하여 한 줄에서 여러 표현식을 평가할 수 있습니다.
왼쪽에서 오른쪽으로 평가하여 오른쪽 또는 마지막 피연산자의 마지막 항목 값을 리턴합니다.
let x = 5;
x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);
function addFive(num) {
return num + 5;
}
console.log(x) // 27
x
의 값을 로그로 기록하면 27이 됩니다.
먼저 x
의 값을 6으로 증가시킨 다음 addFive(6)
함수를 호출합니다.
6을 매개 변수로 전달하고 그 결과를 x
에 할당하면 x
의 새로운 값은 11
됩니다.
그런 다음 x
의 현재 값을 2
로 곱하면 x
에 업데이트 된 x
의 값은 22
가 됩니다.
그 뒤 x
의 현재 값에 5
를 뺍니다.
그럼 그 결과를 x
에 할당하면 업데이트 된 값은 17
이 됩니다.
마지막으로 x
의 값을 10
증가시킵니다.
그리고 x
에 업데이트 된 값을 할당하면 x
의 값은 27
이 됩니다.