Front End Interview Handbook의 JS 파트를 번역 및 정리한 글입니다
Meta, Amazon., Google과 같은 미국 빅테크 프론트엔드 면접의 기출 문제라 합니다.
2019년 기준으로 작성된 것들이 꽤 있어서, 몇가지 경험 기반 답변들은 스스로 생각해 보시는 것도 좋은 듯 합니다.
1. 이벤트 위임(event delegation)을 설명해 주세요
- 하위 컴포넌트에 이벤트 핸들러를 연결하지 않고 상위 컴포넌트에 하나의 이벤트 핸들러만 사용하여 메모리를 절약할 수 있습니다.
- 하위 컴포넌트 제거/추가 시 이벤트 리스너를 해제 / 바인딩 할 필요가 없습니다.
참고
- https://davidwalsh.name/event-delegate
- https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation
2. this 키워드의 동작을 설명해 주세요
- 함수를 호출할 때 new 키워드를 사용하면 함수 내부의 this는 새로운 객체입니다.
- 함수를 호출/생성하기 위해 apply, call 또는 bind를 사용하는 경우, 함수 내부의 this는 인수로 전달되는 객체입니다.
- obj.method() 와 같이 함수가 메서드로 호출되는 경우, this는 함수를 속성으로 갖는 객체입니다.
- 함수가 자유 함수 호출(free function invocation)로 호출되는 경우(위에 제시된 조건 없이 호출됨을 의미) this는 전역 객체 입니다.
- 브라우저에서는 window 객체입니다. 엄격 모드('use strict')인 경우 전역 객체가 아닌 undefined 입니다.
- 위의 규칙 중 여러 개가 적용되는 경우 먼저 언급한 규칙이 우선합니다
- ES2015 화살표 함수인 경우 위의 모든 규칙을 무시하고 함수 선언 시 주변 scope의 this 값을 사용합니다.
참고
3. ES6 도입과 함께 변경된 작업 방식 중 하나의 예를 들어주실 수 있나요?
ES6에서는 주변 환경의 렉시컬 스코프(enclosing lexical scope)를 사용하는 화살표 함수(arrow functions)을 사용할 수 있습니다.
화살표 함수는 사용이 편리하지만, 호출자가 .call 또는 .apply를 통해 컨텍스트를 제어하는 것을 방지합니다.
그 결과 jQuery와 같은 라이브러리는 이벤트 핸들러 함수에 이를 적절하게 바인딩하지 않습니다.
대규모 레거시 애플리케이션을 리팩토링할 때 이를 염두에 두는 것이 중요합니다.
4. 프로토타입 상속의 동작을 설명해 주세요
참고 : 프로로타입의 예시
function Parent() {
this.name = 'Parent';
}
Parent.prototype.greet = function () {
console.log('Hello from ' + this.name);
};
const child = Object.create(Parent.prototype);
child.cry = function () {
console.log('waaaaaahhhh!');
};
child.cry();
// waaaaaahhhh!
child.greet();
// hello from Parent
child.constructor;
// ƒ Parent() {
// this.name = 'Parent';
// }
child.constructor.name;
// 'Parent'
- .greet은 child에 정의되어 있지 않으므로 엔진은 프로토타입 체인으로 올라가서 상위에서 상속된 .greet를 찾습니다.
- 프로토타입 메서드를 상속하려면 다음 방법 중 하나로 Object.create를 호출해야 합니다.
- Object.create(Parent.prototype);
- Object.create(new Parent(null));
- Object.create(objLiteral);
이렇게 하면, Childr의 생성자는 Parent를 가리키게 됩니다.
해당 문제를 고치는 방법은 다음과 같습니다. (혹은 ES6 Class 문법을 사용합니다.)
function Parent() {
this.name = 'Parent';
}
Parent.prototype.greet = function () {
console.log('Hello from ' + this.name);
};
function Child() {
Parent.call(this);
this.name = 'Child';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
const child = new Child();
child.greet();
// hello from Child
child.constructor.name;
// 'Child'
참조
- http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
- https://www.quora.com/What-is-prototypal-inheritance/answer/Kyle-Simpson
- https://davidwalsh.name/javascript-objects
- https://crockford.com/javascript/prototypal.html
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
5. AMD와 CommonJS에 대해 아시나요?
둘 다 ES2015가 등장하기 전까지 JavaScript에 기본적으로 존재하지 않았던 모듈 시스템을 구현하는 방법입니다.
- CommonJS는 동기식이며,
- CommonJS는 서버 측 개발을 염두에 두고 설계되었습니다.
- AMD(Asynchronous Module Definition)는 비동기식입니다.
- AMD는 모듈의 비동기 로드를 지원하므로 브라우저용으로 더 적합합니다.
- https://auth0.com/blog/javascript-module-systems-showdown/
- https://stackoverflow.com/questions/16521471/relation-between-commonjs-amd-and-requirejs
6. IIFE 함수 function foo(){}()가 왜 동작하지 않을까요?
function foo(){}()
- function foo(){ }를 함수 선언문으로 분석합니다.
- ()를 함수 호출로 분석합니다.
1. (function foo(){ })()로 앞에 괄호를 하나 더 추가합니다.
2. void 연산자를 사용합니다.
즉 void function foo(){ }()와 같이 사용할 수 있습니다.
이러한 접근 방식에는 한 가지 문제가 있습니다.
주어진 식의 평가는 항상 undefined 입니다.
const foo = void (function bar() {
return 'foo';
})();
console.log(foo); // undefined
참조
- http://lucybain.com/blog/2014/immediately-invoked-function-expression/
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
7. null, undefined, 선언되지 않은 변수(undeclared variables)의 차이를 설명해 주세요
- 선언되지 않은 변수는 현재 스코프 밖에 전역적으로(globally) 정의됩니다.
- 엄격 모드(strict mode)에서 선언되지 않은 변수에 할당하려고 하면 ReferenceError가 발생합니다.
linter를 사용하는 경우 일반적으로 선언되지 않은 변수를 참조하지 않는지 쉽게 확인할 수 있습니다.
function foo() {
x = 1; // Throws a ReferenceError in strict mode
}
foo();
console.log(x); // 1
var foo;
console.log(foo); // undefined
console.log(foo === undefined); // true
console.log(typeof foo === 'undefined'); // true
console.log(foo == null); // true. Wrong, don't use this to check!
function bar() {}
var baz = bar();
console.log(baz); // undefined
var foo = null;
console.log(foo === null); // true
console.log(typeof foo === 'object'); // true
console.log(foo == undefined); // true. Wrong, don't use this to check!
8. 클로저(closure)를 설명해 주세요
- 외부 함수 : 해당 함수의 선언을 둘러싸는 함수; enclosing function
"lexical"라는 단어는 어휘 범위 지정이 변수가 사용 가능한 위치를 결정하기 위해,
소스 코드 내에서 변수가 선언된 위치를 사용한다는 사실을 나타냅니다.
언제 사용할까요?
- 캡슐화를 위해 사용합니다.
- 클로저가 있는 프라이빗 메소드 에뮬레이션.
- module pattern에서 일반적으로 사용됩니다.
- 부분 적용과 커링에 사용합니다.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
- https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36
9. .forEach 반복문과 .map 반복문의 차이점과 사용방법에 대해 설명해 주세요
forEach
- 각 배열의 요소를 순회합니다.
- 각 요소에 대해 콜백을 실행합니다.
- 값을 반환하지 않습니다.
const a = [1, 2, 3];
const doubled = a.forEach((num, index) => {
// Do something with num and/or index.
});
// doubled = undefined
- 각 배열의 요소를 순회합니다.
- 각 요소에 대해 함수를 호출하여 각 요소를 새 요소에 "매핑"하고, 결과적으로 새 배열을 만듭니다.
10. 익명 함수의 사용사례를 설명해 주세요
1. 로컬 스코프 내 코드 캡슐화
IIFE 내에서 선언된 변수가 전역 범위로 누출되지 않도록 합니다.
(function () {
// Some code here.
})();
2. 함수형 프로그래밍 구조의 인수로 사용
setTimeout(function () {
console.log('Hello world!');
}, 1000);
3. 함수형 프로그래밍 구조의 인수로 사용할
const arr = [1, 2, 3];
const double = arr.map(function (el) {
return el * 2;
});
console.log(double); // [2, 4, 6]
References
- https://www.quora.com/What-is-a-typical-usecase-for-anonymous-functions
- https://stackoverflow.com/questions/10273185/what-are-the-benefits-to-using-anonymous-functions-instead-of-named-functions-fo
11. 코드를 구조화하는 방법을 설명해 주세요(모듈 패턴, 상속)
과거에는 더 많은 OOP 접근 방식을 권장하는 Backbone을 사용하여 모듈 패턴을 구현했습니다.
Backbone 모델을 생성하고 모델에 메소드를 추가했습니다.
모듈 패턴은 여전히 훌륭하지만,
요새는 Flux 아키텍처를 기반으로 단방향 데이터 흐름을 활용하는 React/Redux를 사용합니다.
일반적인 객체를 사용하여 내 앱의 모델을 나타내고, 이러한 객체를 조작하는 유틸리티 순수 함수를 작성합니다.
상태는 다른 Redux 애플리케이션과 마찬가지로 액션과 리듀서를 사용하여 조작합니다.
가능하면 고전적 상속을 사용하지 않습니다. 개인적으로 준수하는 원칙들은 다음과 같습니다,(these rules)
12. 호스트 객체와 네이티브 객체의 차이점은 뭔가요?
- 네이티브 객체는 String, Math, RegExp, Object, Function 등과 같이 ECMAScript 사양에 정의된 JavaScript 언어의 일부인 객체입니다.
- 호스트 객체는 window, XMLHTTPRequest 등과 같이 런타임 환경(브라우저 또는 노드)에서 제공하는 객체입니다.
References
13. function Person(){}, var person = Person(), var person = new Person()의 차이점은 뭘까요?
(해당 질문의 의도는 JS 생성자에 대한 이해를 파악하기 위함입니다.)
기술적으로 function Person(){}는 일반적인 함수 선언문 입니다.
관례로 함수명을 PascalCase로 선언하면, 해당 함수를 생성자로 사용하겠다는 뜻입니다.
function Person(name) {
this.name = name;
}
var person = Person('John');
console.log(person); // undefined
console.log(person.name); // Uncaught TypeError: Cannot read property 'name' of undefined
var person = new Person('John');
console.log(person); // Person { name: "John" }
console.log(person.name); // "john"
References
14. .call과 .apply의 차이점이 뭔가요?
function add(a, b) {
return a + b;
}
console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3
15. Function.prototype.bind에 대해 설명해 주세요
MDN에 의하면..
bind() 메서드는 호출될 때 this 키워드가 인수로 전달된 값으로 사용되며,
콤마로 구분된 일련의 값들을 순서대로 기억해두어, 나중에 필요한 값만 받아 호출하는 새 함수를 리턴합니다.
제 경험상 객체의 메서드를 다른 함수의 인수로 전달할 때, 부분 적용을 구현할 때 좋습니다.
References
16. document.write()는 언제 쓰나요?
- 자바스크립트가 사용 가능할 때에만 스타일을 포함하기 위해 사용합니다.
- 분석을 위한 코드에서 사용합니다.
- 스크립트를 병렬로 로드하고 실행 순서를 유지하기 위해 사용합니다.
하지만 모던 브라우저는 document.write 없애 해당 기능을 구현할 수 있으므로, 권장하지 않습니다.
References
- load scripts in parallel and preserve execution order
- when you want to include styles that should only work if JavaScript is enabled
- https://www.quirksmode.org/blog/archives/2005/06/three_javascrip_1.html
- https://github.com/h5bp/html5-boilerplate/wiki/Script-Loading-Techniques#documentwrite-script-tag
17. feature detection, feature inferenced, UA 문자열 활용은 무슨 차이가 있나요?
Feature Detection(기능 감지)
브라우저가 특정 코드 블록의 지원 여부에 따라 다른 코드를 실행하여
일부 브라우저에서 충돌/오류없는 환경을 제공하기 위한 기능입니다.
if ('geolocation' in navigator) {
// Can use navigator.geolocation
} else {
// Handle lack of feature
}
Feature inference(기능 추론)
기능 감지와 유사하지만, 특정 기능이 존재하면 같이 존재할 기능을 사용하는 것입니다.
if (document.getElementsByTagName) {
element = document.getElementById(id);
}
이것은 별로 권장되지 않습니다. 기능 감지가 더 확실합니다.
UA String
References
- https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection
- https://stackoverflow.com/questions/20104930/whats-the-difference-between-feature-detection-feature-inference-and-using-th
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
18. Ajax에 대해 설명해 주세요
Ajax는 프레젠테이션 계층에서 데이터 교환 계층을 분리
최신 구현에서는 일반적으로 XML 대신 JSON을 사용합니다. JSON이 JavaScript의 네이티브 객체라는 이점 때문입니다.
최근 비동기 통신에는 XMLHttpRequest API 또는 Fetch API를 자주 사용합니다.
References
19. Ajax 사용의 장단점은 무엇입니까?
장점
- 더 나은 상호 작용. 전체 페이지를 다시 로드할 필요 없이 서버의 새 콘텐츠를 동적으로 변경할 수 있습니다.
- 스크립트와 스타일시트는 한 번만 요청하면 되므로 서버 연결을 줄입니다.
- 페이지에서 상태를 유지할 수 있습니다.
- 기본 컨테이너 페이지가 다시 로드되지 않기 때문에 JavaScript 변수 및 DOM 상태가 유지됩니다.
- SPA의 대부분의 장점이 여기에서 나옵니다.
단점
- 동적 웹페이지는 북마크하기가 더 어렵습니다.
- 브라우저에서 JavaScript가 비활성화된 경우 동작하지 않습니다.
- 일부 웹 크롤러는 JavaScript를 실행하지 않으며 JavaScript에 의해 로드된 콘텐츠를 볼 수 없습니다.
- SPA의 대부분의 단점이 여기에서 나옵니다.
- DOM을 업데이트하기 위해 가져온 원격 데이터를 클라이언트측 템플릿과 결합해야 할 가능성이 높습니다.
- 이를 위해서는 JavaScript가 브라우저에서 구문 분석되고 실행되어야 합니다.
- 저사양 모바일 장치에서는 성능 문제가 발생할 수 있습니다.
20 . JSONP에 대해 설명해 주세요
JSONP(JSON with Padding)는 현재 페이지에서 교차 출처 도메인으로의 Ajax 요청이 허용되지 않기 때문에
웹 브라우저에서 교차 도메인 정책을 우회하기 위해 일반적으로 사용되는 방법입니다.
JSONP는 일반적으로 <script>태그를 사용해 교차 출처 요청합니다.
서버에 콜백 쿼리 매개변수(예: https://example.com?callback=printData)를 사용합니다.
서버는 printData라는 함수 내에서 데이터를 래핑하고 클라이언트에 반환합니다.
<!-- https://mydomain.com -->
<script>
function printData(data) {
console.log(`My name is ${data.name}!`);
}
</script>
<script src="https://example.com?callback=printData"></script>
서버는 qs로 전달된 전역 범위에 존재하는 함수를 호출합니다.
// File loaded from https://example.com?callback=printData
printData({name: 'Yang Shun'});
JSONP는 보안 관련 문제가 있습니다.
JSONP는 실제로 JavaScript이므로 JavaScript가 수행할 수 있는 다른 모든 작업을 수행할 수 있으므로 JSONP 데이터 공급자를 신뢰해야 합니다.
References
21. JS 탬플릿 엔진에 대해 설명해 주세요
const template = `<div>My name is: ${name}</div>`;
22. hoisting에 대해 설명해 주세요
console.log(foo); // undefined
var foo = 1;
console.log(foo); // 1
함수 선언문은 함수 본문(body)가 호이스팅 됩니다.
함수 표현식(변수 선언 형식으로 작성됨)은 변수 선언만 호이스팅 됩니다.
// Function Declaration
console.log(foo); // [Function: foo]
foo(); // 'FOOOOO'
function foo() {
console.log('FOOOOO');
}
console.log(foo); // [Function: foo]
// Function Expression
console.log(bar); // undefined
bar(); // Uncaught TypeError: bar is not a function
var bar = function () {
console.log('BARRRR');
};
console.log(bar); // [Function: bar]
x; // undefined
y; // Reference error: y is not defined
var x = 'local';
let y = 'local';
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_Types#Variable_hoisting
- https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6/31222689#31222689
23. 이벤트 버블링에 대해 설명해 주세요
이벤트 버블링은 이벤트 위임 메커니즘입니다.
이벤트가 DOM 요소에서 트리거될 때 연결된 리스너가 있는 경우 해당 리스너는 해당 이벤트를 처리하려 시도합니다.
이후 이벤트가 부모에게 버블링되고 해당 부모에게서 동일한 일이 발생합니다.
이 버블링은 document에 이르기까지 요소의 조상에서 순서대로 발생합니다.
24. attribute와 property의 차이는 무엇인가요?
attributesms HTML 마크업에서 정의되지만 property은 DOM에서 정의됩니다.
HTML에 <input type="text" value="Hello"> 텍스트 필드가 있다고 가정합니다.
getAttribute는 마크업에 존재하는 바로 그 값을 리턴합니다.
const input = document.querySelector('input');
console.log(input.getAttribute('value')); // Hello
console.log(input.value); // Hello
console.log(input.getAttribute('value')); // Hello
console.log(input.value); // Hello World!
References
25. JS의 빌트인 객체를 확장하는 것이 왜 좋지 않나요?
폴리필 ;
JavaScript 사양의 일부이지만 이전 브라우저이기 때문에 사용자의 브라우저에 존재하지 않을 수 있는 메서드에 대한
유일한 구현을 제공합니다.
26. document의 load 이벤트와 DOMContentLoaded 이벤트의 차이점은 뭘까요?
DOMContentLoaded 이벤트는 스타일시트, 이미지 및 서브 프레임의 로딩 완료를 기다리지 않습니다.
초기 HTML 문서가 완전히 로드되고 구문 분석되면 시작됩니다.
27. === 과 == 의 차이는 뭔가요?
1 == '1'; // true
1 == [1]; // true
1 == true; // true
0 == ''; // true
0 == '0'; // true
0 == false; // true
== 연산자를 사용하지 않는 것이 좋습니다.
단, null 또는 undefined와 비교할 때 a == null은 a가 null이거나 정의되지 않은 경우 true를 반환합니다.
이 경우는 == 도 괜찮습니다.
var a = null;
console.log(a == null); // true
console.log(a == undefined); // true
References
28. 동일 출처 정책(same-origin policy)와 JS의 관계를 설명해 주세요
29. 배열 복사 구현
duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5]
function duplicate(arr) {
return arr.concat(arr);
}
// Or with ES6:
const duplicate = (arr) => [...arr, ...arr];
30. 삼항 연산자의 삼항(Ternary)는 무슨 의미일까요?
"Ternary"는 3을 나타내며 3항 식은 세 개의 피연산자(테스트 조건, "then" 식 및 "else" 식)를 허용합니다.
삼항 표현식은 JavaScript에만 국한되지 않습니다.
References
31. "use strict"의 장단점에 대해 설명해 주세요
'use strict'는 전체 스크립트 또는 개별 함수에 대해 엄격 모드를 활성화하는 데 사용되는 문입니다.
Strict 모드는 JavaScript의 제한된 변형을 선택하는 방법입니다.
장점
- 실수로 전역 변수를 생성하는 것을 불가능하게 합니다.
- 조용히 실패하는 할당을 오류가 발생하도록 합니다.
- 삭제할 수 없는 속성을 삭제하려고 시도하면 예외가 발생합니다. (이전에는 시도가 효과가 없었음).
- 함수 매개변수 이름이 고유해야 합니다.
- 전역 컨텍스트의 this는 undefined 입니다.
- 몇 가지 일반적인 코딩 오류를 포착하여 예외를 발생시킵니다.
- 혼란스럽고 오해하기 쉬운 기능들을 비활성화 합니다.
단점
- 일부 개발자들이 자연스럽게 사용하는 기능을 못쓰게 됩니다.
- 더 이상 function.caller 및 function.arguments에 액세스할 수 없습니다.
- 비엄격 모드로 작성된 스크립트를 연결하면 문제가 발생할 수 있습니다.
전반적으로 단점보다 장점이 더 많다고 생각하며 엄격 모드가 차단하는 기능에 의존할 필요가 없습니다.
엄격 모드를 사용하는 것이 좋습니다.
References
32. fizzbuzz 구현
3의 배수에서 "fizz", 5의 배수에서 "buzz", 3과 5의 배수에서 "fizzbuzz"를 출력하면서 최대 100까지 반복되는 for 루프를 만듭니다.
for (let i = 1; i <= 100; i++) {
let f = i % 3 == 0,
b = i % 5 == 0;
console.log(f ? (b ? 'FizzBuzz' : 'Fizz') : b ? 'Buzz' : i);
}
33. 글로벌 스코프를 사용하면 좋지 않는 이유를 설명해 주세요
모든 스크립트가 전역 범위에 액세스할 수 있고, 모든 사람이 전역 네임스페이스를 사용하여 변수를 정의하면 충돌이 발생할 수 있습니다.
모듈 패턴(IIFE)을 사용하여 로컬 네임스페이스 내에서 변수를 캡슐화합니다.
34. load Event와 대안에 대해 설명해 주세요.
load 이벤트는 문서 로드 프로세스가 끝날 때 발생합니다.
이 시점에서 문서의 모든 객체는 DOM에 있고 모든 이미지, 스크립트, 링크 및 하위 프레임의 로드가 완료된 상태입니다.
References
35. SPA 앱에 대해 설명해 주세요
SPA의 장점
- 앱의 반응 속도가 빨라지고 전체 페이지 새로 고침으로 인한 플래시가 없어집니다.
- 페이지 로드 시 마다 동일한 자산을 다시 다운로드할 필요가 없으므로 서버에 대한 HTTP 요청이 줄어듭니다.
- 클라이언트와 서버 간의 문제를 명확하게 분리합니다.
- 서버 코드를 수정하지 않고도 다양한 플랫폼(예: 모바일, 챗봇, 스마트 워치)을 위한 새 클라이언트를 쉽게 구축할 수 있습니다.
- API 계약이 깨지지 않는 한 클라이언트와 서버의 기술 스택을 독립적으로 수정할 수도 있습니다.
SPA의 단점
- 여러 페이지에 필요한 프레임워크, 앱 코드 및 에셋의 로드로 인해 초기 페이지 로드가 더 많습니다.
- 서버에서 모든 요청을 단일 진입점으로 라우팅하고 거기에서 클라이언트 측 라우팅을 허용하도록 설정이 필요합니다. (rewrite)
- SPA는 콘텐츠를 렌더링하기 위해 JavaScript에 의존하지만 모든 검색 엔진이 크롤링 중에 JavaScript를 실행하는 것은 아니며 페이지에 빈 콘텐츠가 표시될 수 있습니다.
- 이로 인해 앱의 검색 엔진 최적화(SEO)가 손상됩니다.
- 그러나 대부분의 경우 앱을 구축할 때 모든 콘텐츠가 검색 엔진에 의해 인덱싱될 필요가 없기 때문에 SEO가 가장 중요한 요소는 아닙니다.
- 이를 극복하기 위해 서버 측에서 앱을 렌더링합니다.
- Prerender와 같은 서비스를 사용하여 "브라우저에서 자바스크립트를 렌더링하고 정적 HTML을 저장한 다음 크롤러에 반환"할 수 있습니다.
References
- https://github.com/grab/front-end-guide#single-page-apps-spas
- http://stackoverflow.com/questions/21862054/single-page-app-advantages-and-disadvantages
- http://blog.isquaredsoftware.com/presentations/2016-10-revolution-of-web-dev/
- https://medium.freecodecamp.com/heres-why-client-side-rendering-won-46a349fadb52
36. Promise 및/또는 polyfill에 대한 경험이 있나요?
- 이행(resolved)된 값
- 이행되지 않은;거부된(rejected) 이유(예: 네트워크 오류 발생)입니다.
- 아직 처리되지 않은;보류 중인 약속(Promise)
37. Promise와 callback의 장단점을 비교해 주세요
Promise의 장점
- 가독성을 낮추는 콜백 지옥을 피할 수 있습니다.
- .then()으로 순차적 비동기 코드를 쉽고 가독성 높게 작성할 수 있습니다.
- Promise.all()을 사용하여 병렬 비동기 코드를 쉽게 작성할 수 있습니다.
- Promise를 사용하면 다음 시나리오가 발생하지 않습니다.
- 콜백을 너무 일찍 호출
- 콜백을 너무 늦게 호출하거나 호출하지 않음
- 콜백을 너무 적게 또는 너무 많이 호출합니다.
- 필요한 환경/매개변수 전달 실패
- 발생할 수 있는 모든 오류/예외 무시
- 오류 / 예외가 발생하지 않은 것처럼, 코드 실행을 무효화하고 넘어가기
Promise의 단점
- 약간 더 복잡한 코드(논쟁의 여지가 있음).
- ES2015가 지원되지 않는 이전 브라우저에서 사용하려면 polyfill을 로드해야 합니다.
References
38. JavaScript로 컴파일되는 언어로 JavaScript 코드를 작성하는 것의 장점/단점은 무엇입니까?
장점
- JavaScript의 오랜 문제 중 일부를 수정하고 JavaScript 안티 패턴을 권장하지 않습니다.
- 구문 설탕을 제공하여 더 짧은 코드를 작성할 수 있습니다.
- ES5는 구문 설탕이 부족하다고 생각하지만 ES2015는 이미 훌륭합니다.
- 정적 타입은 오래 유지 보수해야 하는 대규모 프로젝트에 적합합니다(TypeScript의 경우).
단점
- 브라우저는 JavaScript만 실행하므로 빌드/컴파일 프로세스가 필요하며 브라우저에 제공하기 전에 코드를 JavaScript로 컴파일해야 합니다.
- 소스 맵이 미리 컴파일된 소스에 제대로 매핑되지 않으면 디버깅이 어려울 수 있습니다.
- 커뮤니티가 소규모인 기술은 리소스, 자습서, 라이브러리 및 도구를 찾기 어렵습니다.
- IDE/에디터 지원이 부족할 수 있습니다.
- 이러한 언어는 항상 최신 JavaScript 표준에 뒤쳐지곤 합니다.
- 개발자는 자신의 코드가 어떻게 컴파일 되는지 알아야 합니다.
ES2015는 JavaScript를 크게 개선하고 작성하기 훨씬 더 좋게 만들었습니다.
저는 요즘 CoffeeScript의 필요성을 별로 느끼지 못합니다.
References
39. JavaScript를 디버강 하는 도구 및 기술을 설명해 주세요
- React and Redux
- Vue
- JavaScript
- Chrome Devtools
- debugger statement
- Good old console.log debugging
References
- https://hackernoon.com/twelve-fancy-chrome-devtools-tips-dc1e39d10d9d
- https://raygun.com/blog/javascript-debugging/
40. JS에서 객체 속성과 배열 항목을 어떻게 순회하나요?
객체 :
- for-in loop - for (var property in obj) { console.log(property); }
- 그러나 이 방법은 상속된 속성도 순회합니다.
- 이를 막으러면 obj.hasOwnProperty(property) 검사를 추가합니다.
- 그러나 이 방법은 상속된 속성도 순회합니다.
- Object.keys() - Object.keys(obj).forEach(function (property) { ... })
- Object.keys()는 객체의 모든 열거 가능한 속성을 나열하는 정적 메서드입니다.
- Object.getOwnPropertyNames() - Object.getOwnPropertyNames(obj).forEach(function (property) { ... })
- Object.getOwnPropertyNames()는 객체의 모든 열거 가능 속성과 열거 불가능 속성을 나열하는 정적 메서드입니다.
배열 :
- for loop - for (var i = 0; i < arr.length; i++)
- 일반적인 함정은 var가 블록 범위가 아닌 함수 범위에 있고 대부분의 경우 블록 범위 반복자 변수를 원한다는 것입니다.
- ES2015는 블록 스코프가 있는 let을 도입했으며 이를 대신 사용할 것을 권장합니다.
- 따라서 이것은 for (let i = 0; i < arr.length; i++)가 됩니다.
- forEach - arr.forEach(function (el, index) { ... })
- 항목만 필요한 경우 인덱스를 사용할 필요가 없기 때문에 이 구성은 때때로 더 편리할 수 있습니다.
- 반복을 조기에 종료할 수 있는 every 및 some 메서드도 있습니다.
- for-of loops - for (let elem of arr) { ... }
- ES6는 String, Array, Map, Set 등과 같은 iterable protocol을 준수하는 객체를 반복할 수 있는 새로운 루프인 for-of 루프를 도입했습니다.
- for loop와 forEach()의 장점을 결합합니다.
- for loop의 장점은 중단할 수 있다는 것입니다.
- forEach()의 장점은 카운터 변수가 필요하지 않기 때문에 for 루프보다 간결하다는 것입니다.
- for-of 루프를 사용하면 루프에서 중단하는 기능과 보다 간결한 구문을 모두 얻을 수 있습니다.
또한 for-of 루프를 사용할 때 각 배열 요소의 인덱스와 값에 모두 액세스해야 하는 경우,
ES6 Array entries() 메서드와 구조 분해를 사용할 수 있습니다.
const arr = ['a', 'b', 'c'];
for (let [index, elem] of arr.entries()) {
console.log(index, ': ', elem);
}
References
- http://2ality.com/2015/08/getting-started-es6.html#from-for-to-foreach-to-for-of
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries
41. 불변 객체와 가변 객체에 대해 설명해 주세요.
- 가변 객체는 생성 후 상태를 수정할 수 있는 객체입니다.
- 불변 객체는 생성된 후에 상태를 수정할 수 없는 객체입니다.
JS의 불변 객체의 예시는 뭔가요?
JavaScript에서 일부 내장 타입(number,string)은 변경할 수 없지만 커스텀 객체는 일반적으로 변경할 수 있습니다.
일부 빌트인 불변 JavaScript 객체는 Math, Date입니다.
다음은 일반 JavaScript 객체에 불변성을 추가/시뮬레이트하는 몇 가지 방법입니다.
객체 상수 속성 (Object Constant Properties)
writable: false 및 configurable: false를 결합하면
다음과 같이 객체 속성으로 상수(변경, 재정의 또는 삭제할 수 없음)를 만들 수 있습니다.
let myObject = {};
Object.defineProperty(myObject, 'number', {
value: 42,
writable: false,
configurable: false,
});
console.log(myObject.number); // 42
myObject.number = 43;
console.log(myObject.number); // 42
확장 방지 (Prevent Extension)
객체에 새 속성이 추가되지 않도록 하고 나머지 객체 속성은 그대로 두려면 Object.preventExtensions(...)를 호출합니다.
var myObject = {
a: 2,
};
Object.preventExtensions(myObject);
myObject.b = 3;
myObject.b; // undefined
비엄격 모드에서는 b 속성 생성이 조용히(silently) 실패합니다.
엄격 모드에서는 TypeError가 발생합니다.
봉인 (Seal)
- 값의 수정은 가능합니다. (writable : true 면)
- 다른 디스크립터의 속성은 수정 불가능 합니다.
- 해당 값을 객체에서 삭제할 수 없습니다.
- 해당 값의 타입을 데이터 속성과 접근자 속성에서 변경할 수 없습니다.
Freeze
Object.freeze()는 고정된 객체를 만듭니다.
객체를 대상으로 Object.seal()을 호출하지만 모든 "데이터 접근자" 속성을 writable : false로 만든 것과 유사합니다.
해당 값을 변경할 수 없도록 합니다.
객체 또는 객체의 직접적인 속성에 대한 변경을 방지하므로
객체 자체에 대해 달성할 수 있는 가장 높은 수준의 불변성입니다.
(참조 대상 객체는 해당 영향을 받지 않음)
var immutable = Object.freeze({});
불변성의 장점과 단점
장점
- 더 쉬운 변경 감지
- 객체 동등성은 참조 동등성을 통해 쉽게 확인할 수 있습니다.
- 이는 React와 Redux의 객체 차이점을 비교하는 데 유용합니다.
- 시간에 따른 객체 변경을 생각할 필요가 없습니다.
- 겍체 변경을 누적할 필요 없음
- 방어적 복사본이 필요없습니다
- 기존 객체가 수정될 가능성이 없기 떄문입니다.
- 참조를 통한 손쉬운 공유
- 변경되지 않으면 항상 동일한 참조임이 보장되기에 쉽게 객체를 여러번 재사용할 수 있습니다.
- thread safe
- 불변 개체는 동시에 실행 중인 다른 스레드에서 수정될 위험이 없기 때문에 다중 스레드 환경에서 안전하게 사용할 수 있습니다.
- ImmutableJS와 같은 라이브러리를 사용하면 구조적 공유를 사용해 객체가 수정되어 유사한 구조를 가진 여러 객체를 보유하는 데 필요한 메모리가 더 적습니다.
단점
- 변경할 수 없는 데이터 구조와 해당 작업을 순진하게 구현하면 매번 새 객체가 생성되기 때문에 성능이 극도로 저하될 수 있습니다. 구조적 공유를 활용하는 효율적인 불변 데이터 구조 및 작업을 위해 라이브러리를 사용하는 것이 좋습니다.
- 그래프와 같은 순환 데이터 구조의 구현이 어렵습니다.
- 초기화 후에 수정할 수 없는 두 개의 객체가 서로를 가리키도록 하려면 어떻게 해야 하나요?
References
42. 불변성을 구현하는 방법을 설명해 주세요
- immutable.js, mori or immer.와 같은 라이브러리를 사용하는 것입니다.
- 객체를 "변경"하는 경우 확산 연산자 Object.assign, Array.concat() 등을 사용하여 원래 객체를 변경하는 대신 새 객체를 만듭니다.
// Array Example
const arr = [1, 2, 3];
const newArr = [...arr, 4]; // [1, 2, 3, 4]
// Object Example
const human = Object.freeze({race: 'human'});
const john = {...human, name: 'John'}; // {race: "human", name: "John"}
const alienJohn = {...john, race: 'alien'}; // {race: "alien", name: "John"}
43. 동기 함수와 비동기 함수의 차이점을 설명하십시오.
44. 이벤트 루프가 뭔가요? 콜스택과 태스크 큐는 어떤 차이가 있죠?
References
45. function foo() {}와 var foo = function() {} 의 foo 사용의 차이점을 설명하세요.
전자는 함수 선언(문)이고 후자는 함수 표현식입니다.
주요 차이점은 다음과 같습니다.
- 함수 선언문은 본문이 호이스팅됩니다.
- 함수 표현식의 본문은 호이스팅 되지 않습니다.
- (변수와 동일한 호이스팅 동작이 있음).
Function Declaration
foo(); // 'FOOOOO'
function foo() {
console.log('FOOOOO');
}
Function Expression
foo(); // Uncaught TypeError: foo is not a function
var foo = function () {
console.log('FOOOOO');
};
46. 변수 정의 시 var, let, const의 차이점을 설명해 주세요
function foo() {
// All variables are accessible within functions.
var bar = 'bar';
let baz = 'baz';
const qux = 'qux';
console.log(bar); // bar
console.log(baz); // baz
console.log(qux); // qux
}
console.log(bar); // ReferenceError: bar is not defined
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
if (true) {
var bar = 'bar';
let baz = 'baz';
const qux = 'qux';
}
// var declared variables are accessible anywhere in the function scope.
console.log(bar); // bar
// let and const defined variables are not accessible outside of the block they were defined in.
console.log(baz); // ReferenceError: baz is not defined
console.log(qux); // ReferenceError: qux is not defined
var를 사용하면 변수를 호이스팅할 수 있습니다.
즉, 변수를 선언하기 전에 코드에서 참조할 수 있습니다.
let 및 const는 이를 허용하지 않고 대신 오류를 발생시킵니다.
console.log(foo); // undefined
var foo = 'foo';
console.log(baz); // ReferenceError: can't access lexical declaration 'baz' before initialization
let baz = 'baz';
console.log(bar); // ReferenceError: can't access lexical declaration 'bar' before initialization
const bar = 'bar';
var foo = 'foo';
var foo = 'bar';
console.log(foo); // "bar"
let baz = 'baz';
let baz = 'qux'; // Uncaught SyntaxError: Identifier 'baz' has already been declared
// This is fine.
let foo = 'foo';
foo = 'bar';
// This causes an exception.
const baz = 'baz';
baz = 'qux';
References
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
47. es6 클래스와 es6 생성자 함수의 차이점은 뭔가요?
// ES5 Function Constructor
function Person(name) {
this.name = name;
}
// ES6 Class
class Person {
constructor(name) {
this.name = name;
}
}
생성자의 주요 차이점은 상속을 사용할 때 발생합니다.
Person의 하위 클래스인 Student 클래스를 만들고 studentId 필드를 추가하기 위한 작업입니다.
// ES5 Function Constructor
function Student(name, studentId) {
// Call constructor of superclass to initialize superclass-derived members.
Person.call(this, name);
// Initialize subclass's own members.
this.studentId = studentId;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
// ES6 Class
class Student extends Person {
constructor(name, studentId) {
super(name);
this.studentId = studentId;
}
}
References
- https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
- https://eli.thegreenplace.net/2013/10/22/classical-inheritance-in-javascript-es5
48. 화살표 함수의 이점과 사용 사례에 대해 설명해 주세요.
49. 메서드의 생성자에 화살표 함수를 사용하면 어떤 이점이 있나요?
const Person = function (firstName) {
this.firstName = firstName;
this.sayName1 = function () {
console.log(this.firstName);
};
this.sayName2 = () => {
console.log(this.firstName);
};
};
const john = new Person('John');
const dave = new Person('Dave');
john.sayName1(); // John
john.sayName2(); // John
// The regular function can have its 'this' value changed, but the arrow function cannot
john.sayName1.call(dave); // Dave (because "this" is now the dave object)
john.sayName2.call(dave); // John
john.sayName1.apply(dave); // Dave (because 'this' is now the dave object)
john.sayName2.apply(dave); // John
john.sayName1.bind(dave)(); // Dave (because 'this' is now the dave object)
john.sayName2.bind(dave)(); // John
var sayNameFromWindow1 = john.sayName1;
sayNameFromWindow1(); // undefined (because 'this' is now the window object)
var sayNameFromWindow2 = john.sayName2;
sayNameFromWindow2(); // John
50. 고차 함수가 뭔가요?
map
const names = ['irish', 'daisy', 'anna'];
명령형 방법은 다음과 같습니다.
const transformNamesToUppercase = function (names) {
const results = [];
for (let i = 0; i < names.length; i++) {
results.push(names[i].toUpperCase());
}
return results;
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
const transformNamesToUppercase = function (names) {
return names.map((name) => name.toUpperCase());
};
transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA']
References
- https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99
- https://hackernoon.com/effective-functional-javascript-first-class-and-higher-order-functions-713fde8df50a
- https://eloquentjavascript.net/05_higher_order.html
51. 객체나 배열을 분해하는 예를 들어주세요
Destructuring(구조분해)는 ES6에서 사용할 수 있는 표현식으로
객체 또는 배열의 값을 추출하여 개별 변수에 배치하는 간결하고 편리한 방법을 제공합니다.
배열 구조분해
// Variable assignment.
const foo = ['one', 'two', 'three'];
const [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
// Swapping variables
let a = 1;
let b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
객체 구조분해
// Variable assignment.
const o = {p: 42, q: true};
const {p, q} = o;
console.log(p); // 42
console.log(q); // true
References
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
- https://ponyfoo.com/articles/es6-destructuring-in-depth
52. ES6 템플릿 리터럴은 문자열 생성에 많은 유연성을 제공합니다. 예를 들어주실 수 있나요?
템플릿 리터럴은 문자열 보간을 간단하게 수행하거나 문자열에 변수를 포함하는 데 도움이 됩니다.
ES2015 이전에는 다음과 같은 작업을 수행하는 것이 일반적이었습니다.
var person = {name: 'Tyler', age: 28};
console.log(
'Hi, my name is ' + person.name + ' and I am ' + person.age + ' years old!',
);
// 'Hi, my name is Tyler and I am 28 years old!'
const person = {name: 'Tyler', age: 28};
console.log(`Hi, my name is ${person.name} and I am ${person.age} years old!`);
// 'Hi, my name is Tyler and I am 28 years old!'
console.log('This is line one.\nThis is line two.');
// This is line one.
// This is line two.
console.log('This is line one.\n' + 'This is line two.');
// This is line one.
// This is line two.
console.log(`This is line one.
This is line two.`);
// This is line one.
// This is line two.
const person = {name: 'Tyler', age: 28};
document.body.innerHTML = `
<div>
<p>Name: ${person.name}</p>
<p>Age: ${person.age}</p>
</div>
`;
References
53. 커링 함수 구문의 예시와 이점을 설명해 주세요
function curry(fn) {
if (fn.length === 0) {
return fn;
}
function _curried(depth, args) {
return function (newArgument) {
if (depth - 1 === 0) {
return fn(...args, newArgument);
}
return _curried(depth - 1, [...args, newArgument]);
};
}
return _curried(fn.length, []);
}
function add(a, b) {
return a + b;
}
var curriedAdd = curry(add);
var addFive = curriedAdd(5);
var result = [0, 1, 2, 3, 4, 5].map(addFive); // [5, 6, 7, 8, 9, 10]
References
54. 스프레드 구문은 rest 구문과 무엇이 다르죠?
function putDookieInAnyArray(arr) {
return [...arr, 'dookie'];
}
const result = putDookieInAnyArray(['I', 'really', "don't", 'like']); // ["I", "really", "don't", "like", "dookie"]
const person = {
name: 'Todd',
age: 29,
};
const copyOfTodd = {...person};
function addFiveToABunchOfNumbers(...numbers) {
return numbers.map((x) => x + 5);
}
const result = addFiveToABunchOfNumbers(4, 5, 6, 7, 8, 9, 10); // [9, 10, 11, 12, 13, 14, 15]
const [a, b, ...rest] = [1, 2, 3, 4]; // a: 1, b: 2, rest: [3, 4]
const {e, f, ...others} = {
e: 1,
f: 2,
g: 3,
h: 4,
}; // e: 1, f: 2, others: { g: 3, h: 4 }
References
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
55. 파일 간에 코드를 어떻게 공유할 수 있나요?
References
- http://requirejs.org/docs/whyamd.html
- https://nodejs.org/docs/latest/api/modules.html
- http://2ality.com/2014/09/es6-modules-final.html
56. 정적 클래스 멤버를 사용하는 이유는 뭔가요?
References
Other Answers
'FrontEnd' 카테고리의 다른 글
styled-components best practices(모범 사례) (0) | 2023.02.17 |
---|---|
styled-components의 동작 원리와 주의사항 (0) | 2023.02.17 |
React의 cloneElement API, 기존 엘리먼트를 기반으로 새로운 엘리먼트 생성하는 방법 알아보기 (0) | 2023.02.16 |
리액트 디자인 패턴(React design pattern) : Compound Component Pattern(컴파운드 컴포넌트패턴)과 Uncontrolled Component Pattern(유상태 컴포넌트 패턴) (0) | 2023.02.15 |
[React] 리액트 Children, React Children API의 모든 것 (0) | 2023.02.15 |