70 자바스크립트 인터뷰 질문 - 3부(번역)
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 🎆🎆🎆!
이 글은 긴 내용이므로 한두 시간 동안 나와 함께하시길 바랍니다. 모든 질문에 대한 답변에는 질문 목록으로 돌아가는 화살표 ↑ 링크가 있어서 스크롤 하는 시간을 낭비하지 않아도 됩니다.
질문
- 37. arguments 객체란 무엇인가?
- 38. prototype없이 객체를 만드는 방법은 무엇인가?
- 39. 이 함수를 호출할 때 b가 글로벌 변수로 되는 이유는 무엇인가?
- 40. ECMAScript이란 무엇인가?
- 41. ES6 또는 ECMAScript 2015의 새로운 기능은 무엇인가?
- 42. var, let 및 const 키워드의 차이점은 무엇인가?
- 43. Arrow functions이란 무엇인가?
- 44. Classes란 무엇인가?
- 45. Template Literals이란 무엇인가?
- 46. Object Destructuring이란 무엇인가?
- 47. ES6 Modules이란 무엇인가?
- 48. Set 객체는 무엇이며 어떻게 작동하는가?
- 49. 콜백 함수란 무엇인가?
- 50. Promises란 무엇인가?
- 51. async/await란 무엇이며 어떻게 작동하는가?
- 52. Spread operator와 Rest operator의 차이점은 무엇인가?
- 53. Default Parameters란 무엇인가?
- 54. Wrapper Objects란 무엇인가?
37. arguments 객체란 무엇인가?
↑
arguments 객체는 함수에 전달된 매개 변수 값의 집합입니다.
length 속성을 가지고 있고 배열 인덱싱 arguments[1]
표기법을 사용하여 각각의 값에 액세스 할 수 있기 때문에 배열과 같은 객체입니다.
그러나 forEach
, reduce
, filter
및 map
배열에는 내장 메서드가 없습니다.
이것은 함수에 전달되는 인수의 수를 알 수 있습니다.
우리는 Array.prototype.slice
를 사용하여 arguments
객체를 배열로 변환 할 수 있습니다.
function one() {
return Array.prototype.slice.call(arguments);
}
Note: arguments
객체는 ES6 화살표 함수에서 작동하지 않습니다.
function one() {
return arguments;
}
const two = function () {
return arguments;
}
const three = function three() {
return arguments;
}
const four = () => arguments;
four(); // 에러를 던집니다 - arguments가 정의되지 않았습니다
함수 four
를 호출하면 ReferenceError: arguments is not defined
오류가 발생합니다.
환경이 rest 구문(rest syntax) 을 지원하는 경우에 이 문제를 해결할 수 있습니다.
const four = (...args) => args;
그러면 모든 매개 변수 값이 배열에 자동으로 넣어집니다.
38. prototype없이 객체를 만드는 방법은 무엇인가?
↑
Object.create
메서드를 사용하여 프로토 타입없이 객체를 만들 수 있습니다.
const o1 = {};
console.log(o1.toString());
// 로그로 [object Object]가 기록됩니다. 이 메서드를 Object.prototype에서 가져옵니다.
const o2 = Object.create(null);
// 첫 번째 매개 변수는 "o2" 객체의 프로토 타입입니다.이 경우 프로토 타입을 원하지 않기에 null이 됩니다.
console.log(o2.toString());
// 오류를 던집니다. o2.toString is not a function
39. 이 함수를 호출할 때 b
가 글로벌 변수로 되는 이유는 무엇인가?
function myFunc() {
let a = b = 0;
}
myFunc();
그 이유는 할당 연산자(assignment operator) 또는 =
에 오른쪽에서 왼쪽으로 결합 방향(associativity) 또는 평가(evaluation) 가 있기 때문입니다.
이것은 여러 할당 연산자가 단일 표현식으로 나타날 때 오른쪽에서 왼쪽으로 평가한다는 뜻입니다. 그래서 우리 코드는 이렇게 됩니다.
function myFunc() {
let a = (b = 0);
}
myFunc();
먼저, 표현식 b = 0
이 평가되고 예제에서 b
는 선언되지 않습니다.
따라서 JS 엔진은 표현식 b = 0
의 리턴 값이 0이 되고 let
키워드를 사용하여 새로운 로컬 변수 a
에 할당된 후 이 함수 외부에서 글로벌 변수 b를 만듭니다.
변수를 할당하기 전에 이 변수를 선언하여 문제를 해결할 수 있습니다.
function myFunc() {
let a,b;
a = b = 0;
}
myFunc();
40. ECMAScript이란 무엇인가?
↑ ECMAScript는 스크립팅 언어를 만들기 위한 표준입니다. 이 말인즉, JavaScript의 청사진이기 때문에 JavaScript는 ECMAScript 표준의 사양 변경을 따릅니다.
41. ES6 또는 ECMAScript 2015의 새로운 기능은 무엇인가?
- Arrow Functions
- Classes
- Template Strings
- Enhanced Object literals
- Object Destructuring
- Promises
- Generators
- Modules
- Symbol
- Proxies
- Sets
- Default Function parameters
- Rest and Spread
- Block Scoping with let and const
42. var
, let
및 const
키워드의 차이점은 무엇인가?
↑
var
키워드로 선언된 변수는 함수 스코프입니다.
이것은 블록 안에서 변수를 선언하더라도 해당 함수에서 변수에 액세스 할 수 있음을 뜻합니다.
function giveMeX(showX) {
if (showX) {
var x = 5;
}
return x;
}
console.log(giveMeX(false));
console.log(giveMeX(true));
첫 번째 console.log
문은 undefined
, 두 번째는 5
를 기록합니다.
함수 스코프의 맨 위로 호이스팅하기 때문에 x
변수에 액세스 할 수 있습니다.
따라서 함수 코드는 다음과 같이 해석됩니다.
function giveMeX(showX) {
var x; // 기본값은 undefined
if (showX) {
x = 5;
}
return x;
}
첫 번째 console.log
문에 undefined
를 기록하는지 궁금하다면 초깃값 없이 선언된 변수의 기본값은 undefined
임을 기억해야 합니다.
let
및 const
키워드로 선언된 변수는 블록 스코프입니다. 이것은 변수가 선언된 {}
블록에서만 변수에 액세스 할 수 있음을 뜻합니다.
function giveMeX(showX) {
if (showX) {
let x = 5;
}
return x;
}
function giveMeY(showY) {
if (showY) {
let y = 5;
}
return y;
}
이 함수들을 false
인수로 호출하면 Reference Error
가 발생합니다.
블록 외부의 x
와 y
변수에 액세스 할 수 없는데 해당 변수가 호이스팅되지 않았기 때문입니다.
let
과 const
사이에도 차이가 있습니다.
let
을 사용하여 새로운 값을 할당 할 수 있지만 const
는 할 수 없습니다.
하지만 const
는 변경 가능한(mutable) 의미입니다.
이것은 만약 const
에 할당한 값이 객체라면 우리는 그 속성들의 값을 바꿀 수는 있어도 새로운 값을 재할당할 수는 없다는 것을 의미합니다.
43. Arrow functions 이란 무엇인가?
↑
화살표 함수(Arrow Functions) 는 JavaScript에서 함수를 만드는 새로운 방법입니다.
화살표 함수는 함수를 만드는 데 시간이 적게 걸립니다. 그리고 function
키워드를 만들 때 생략하기 때문에 함수 표현식(function expression) 보다 구문이 깔끔합니다.
// ES5 Version
var getCurrentDate = function () {
return new Date();
}
// ES6 Version
const getCurrentDate = () => new Date();
이 예제에서, ES5 버전은 함수를 만들고 값을 각각 리턴하는데 필요한 function () {}
선언 및 return
키워드가 있습니다.
화살표 함수 버전에는 ()
괄호만 필요합니다. 그리고 return
구문이 필요하지 않습니다. 왜냐하면 리턴하는 표현식이나 값을 하나만 가지고 있다면 화살표 함수는 암시적으로 리턴합니다.
// ES5 Version
function greet(name) {
return 'Hello ' + name + '!';
}
// ES6 Version
const greet = (name) => `Hello ${name}`;
const greet2 = name => `Hello ${name}`;
또한 화살표 함수의 매개 변수는 함수 표현식 및 함수 선언과 같게 사용할 수 있습니다. 화살표 함수에 하나의 매개 변수가 있을 시 괄호를 생략해도 유효합니다.
const getArgs = () => arguments
const getArgs2 = (...rest) => rest
화살표 함수는 arguments
객체에 액세스 할 수 없습니다.
따라서 첫 번째 getArgs
함수를 호출하면 오류가 발생합니다.
대신에 rest 매개 변수를 사용해서 화살표 함수에 전달된 모든 인수를 가져올 수 있습니다.
const data = {
result: 0,
nums: [1, 2, 3, 4, 5],
computeResult() {
// 여기서 "this"는 "data"객체를 말합니다.
const addAll = () => {
// arrow functions "copies" the "this" value of the lexical enclosing function
// 화살표 함수는 렉시컬을 포함한 함수(lexical enclosing function)의 "this"값을 "복사"합니다.
return this.nums.reduce((total, cur) => total + cur, 0)
};
this.result = addAll();
}
};
data.computeResult();
console.log(data.result) // 15
화살표 함수에는 자신의 this
값이 없습니다.
렉시컬을 포함한 함수(lexically enclosing function)의 this
값을 포착하거나 얻거나 또는 이 예제에서 addAll
함수는 computeResult
메서드의 this
값을 복사합니다.
그리고 글로벌 스코프에서 화살표 함수를 선언하면 this
의 값이 window
객체가 됩니다.
44. 클래스(Classes)란 무엇인가?
↑ 클래스는 JavaScript에서 constructor 함수를 작성하는 새로운 방법입니다. constructor 함수를 사용하는 문법적 설탕(syntactic sugar)이지만 여전히 프로토 타입과 프로토 타입 기반 상속을 사용합니다.
// ES5 Version
function Person(firstName, lastName, age, address) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
}
Person.self = function() {
return this;
}
Person.prototype.toString = function() {
return "[object Person]";
}
Person.prototype.getFullName = function () {
return this.firstName + " " + this.lastName;
}
// ES6 Version
class Person {
constructor(firstName, lastName, age, address) {
this.lastName = lastName;
this.firstName = firstName;
this.age = age;
this.address = address;
}
static self() {
return this;
}
toString() {
return "[object Person]";
}
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
메서드를 재정의하고 다른 클래스에서 상속
// ES5 Version
Employee.prototype = Object.create(Person.prototype);
function Employee(firstName, lastName, age, address, jobTitle, yearStarted) {
Person.call(this, firstName, lastName, age, address);
this.jobTitle = jobTitle;
this.yearStarted = yearStarted;
}
Employee.prototype.describe = function () {
return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
}
Employee.prototype.toString = function () {
return "[object Employee]";
}
// ES6 Version
class Employee extends Person { //Inherits from "Person" class
constructor(firstName, lastName, age, address, jobTitle, yearStarted) {
super(firstName, lastName, age, address);
this.jobTitle = jobTitle;
this.yearStarted = yearStarted;
}
describe() {
return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
}
toString() { // Overriding the "toString" method of "Person"
return "[object Employee]";
}
}
그렇다면 그것이 프로토 타입을 사용한다는 것을 어떻게 알 수 있습니까?
class Something {
}
function AnotherSomething(){
}
const s = new Something();
const as = new AnotherSomething();
console.log(typeof Something); // logs "function"
console.log(typeof AnotherSomething); // logs "function"
console.log(as.toString()); // logs "[object Object]"
console.log(as.toString()); // logs "[object Object]"
console.log(as.toString === Object.prototype.toString);
console.log(s.toString === Object.prototype.toString);
// 두 로그 모두 true를 반환합니다.
// prototypes을 사용한다는 것을 나타내는 이유는 Object.prototype이 프로토 타입 체인의 마지막 부분이고
// "Something"과 "AnotherSomething" 둘다 Object.prototype에서 상속되기 때문입니다.
45. 템플릿 리터럴(Template Literals) 이란 무엇인가?
↑ 템플릿 리터럴은 JavaScript에서 문자열(strings) 을 만드는 새로운 방법입니다. 억음 부호(backtick) 또는 백 따옴표 기호를 사용하여 템플릿 리터럴을 만들 수 있습니다.
// ES5 Version
var greet = 'Hi I\'m Mark';
// ES6 Version
let greet = `Hi I'm Mark`;
ES5 버전에서는 문자열로 끝내야하는 이 경우에는 심볼의 정상적인 기능을 피하기 위해 \
를 사용하여 `를 이스케이프 해야 합니다.
템플릿 리터럴에서는 그렇게 할 필요가 없습니다.
// ES5 Version
var lastWords = '\n'
+ ' I \n'
+ ' Am \n'
+ 'Iron Man \n';
// ES6 Version
let lastWords = `
I
Am
Iron Man
`;
ES5 버전에서는 문자열에 줄을 넣을려면 \n
을 추가해야합니다.
템플릿 리터럴에서는 그렇게 할 필요가 없습니다.
// ES5 Version
function greet(name) {
return 'Hello ' + name + '!';
}
// ES6 Version
function greet(name) {
return `Hello ${name} !`;
}
ES5 버전에서는 문자열에 표현식이나 값을 추가해야하는 경우에 +
또는 문자열 연결 연산자(string concatenation operator)를 사용해야합니다.
템플릿 리터럴에서는 ${expr}
을 사용하여 ES5 버전보다 깔끔한 표현식으로 나타낼 수 있습니다.
46. 객체 구조 분해(Object Destructuring)란 무엇인가?
↑ 객체 구조 분해는 객체 또는 배열에서 가져오거나 추출하는 새롭고 깔끔한 방법입니다.
아래와 같은 객체가 있다고 가정해봅시다.
const employee = {
firstName: "Marko",
lastName: "Polo",
position: "Software Developer",
yearHired: 2017
};
객체로부터 속성들을 가져오는 오래된 방법은 그 객체 속성과 같은 이름의 변수를 만드는 것 입니다. 이 방법은 모든 속성에 대해 새로운 변수로 만들어야 하므로 번거롭습니다. 속성을 추출하는데, 이 방법을 사용하여 많은 속성과 메서드가 있는 큰 객체가 있다고 상상하면 짜증 날 것입니다.
var firstName = employee.firstName;
var lastName = employee.lastName;
var position = employee.position;
var yearHired = employee.yearHired;
객체 구조 분해를 사용하면 깔끔해보이고 예전보다 시간이 덜 걸립니다.
객체 구조 분해 구문은 객체에서 속성을 얻을 시 {}
를 사용하고 그 안에 추출할 속성을 명시한다는 것입니다. 그리고 배열에서 데이터를 얻는다면 []
를 사용합니다.
let { firstName, lastName, position, yearHired } = employee;
구조 분해를 할 경우에 기본값도 가질 수 있습니다.
이 예제에서, 객체의 firstName
속성이 undefined
값을 가진다면 firstName
변수는 기본값 "Mark"
를 가지게 될 것입니다.
let { firstName = "Mark", lastName: lName, position, yearHired } = employee;
47. ES6 Modules
이란 무엇인가?
↑ 모듈은 코드베이스를 여러 파일로 분할해서 유지 관리 효율성을 높이고 코드 전부를 하나의 큰 파일(yucksss)에 넣는 것을 피하게 해줍니다. ES6가 모듈을 지원하기 전에 JavaScript에서 코드 유지 관리에 사용되는 두 가지 유명한 모듈 시스템이 있었습니다.
- CommonJS - Nodejs
- AMD (Asynchronous Module Definition) - Browsers
기본적으로 모듈을 사용하는 구문은 간단합니다.
import
는 다른 파일이나 여러 기능 또는 값에서 getting 기능으로 사용됩니다.
반면에 export
는 파일이나 여러 기능 또는 값에서 exposing 기능으로 사용됩니다.
파일 또는 명명된 내보내기(Named Exports)에서 기능 내보내기
ES5 (CommonJS) 사용
// Using ES5 CommonJS - helpers.js
exports.isNull = function (val) {
return val === null;
}
exports.isUndefined = function (val) {
return val === undefined;
}
exports.isNullOrUndefined = function (val) {
return exports.isNull(val) || exports.isUndefined(val);
}
ES6 모듈 사용
// Using ES6 Modules - helpers.js
export function isNull(val){
return val === null;
}
export function isUndefined(val) {
return val === undefined;
}
export function isNullOrUndefined(val) {
return isNull(val) || isUndefined(val);
}
다른 파일에서 기능 가져오기
// Using ES5 (CommonJS) - index.js
const helpers = require('./helpers.js'); // helpers is an object
const isNull = helpers.isNull;
const isUndefined = helpers.isUndefined;
const isNullOrUndefined = helpers.isNullOrUndefined;
// 또는 환경에서 Destructuring을 지원하면
const { isNull, isUndefined, isNullOrUndefined } = require('./helpers.js');
// ES6 Modules - index.js
import * as helpers from './helpers.js'; // helpers is an object
// or
import { isNull, isUndefined, isNullOrUndefined as isValid } from './helpers.js';
// Named Exports의 이름을 바꿀 때 "as" 사용
파일 또는 기본 내보내기(Default Exports)에서 단일 기능 내보내기
ES5 (CommonJS) 사용
// Using ES5 (CommonJS) - index.js
class Helpers {
static isNull(val) {
return val === null;
}
static isUndefined(val) {
return val === undefined;
}
static isNullOrUndefined(val) {
return this.isNull(val) || this.isUndefined(val);
}
}
module.exports = Helpers;
ES6 모듈 사용
// Using ES6 Modules - helpers.js
class Helpers {
static isNull(val) {
return val === null;
}
static isUndefined(val) {
return val === undefined;
}
static isNullOrUndefined(val) {
return this.isNull(val) || this.isUndefined(val);
}
}
export default Helpers
다른 파일에서 단일 기능 가져오기
ES5 (CommonJS) 사용
// Using ES5 (CommonJS) - index.js
const Helpers = require('./helpers.js');
console.log(Helpers.isNull(null));
ES6 모듈 사용
import Helpers from './helpers.js'
console.log(Helpers.isNull(null));
이것이 ES6 모듈 사용의 기본입니다. 모듈은 광범위한 주제에 제 포스트는 정말 긴 관계로 모든 것을 다 설명하지 않겠습니다.
48. Set
객체는 무엇이며 어떻게 작동하는가?
↑ Set 객체는 고유값(unique values), 원시값 또는 객체 참조를 저장할 수 있는 ES6 기능입니다. Set의 값은 한 번만 발생할 수 있습니다. SameValueZero 알고리즘을 사용하여 set 객체에 값이 있는지 확인합니다.
Set
생성자를 사용하여 Set
인스턴스를 만들 수 있습니다.
그리고 선택적으로 Iterable
을 초기 값으로 전달할 수 있습니다.
const set1 = new Set();
const set2 = new Set(["a","b","c","d","d","e"]);
add
메서드를 사용해서 Set
인스턴스에 새로운 값을 추가할 수 있습니다.
add
는 Set 객체를 리턴하기 때문에 add
호출을 이을 수 있습니다.
Set
개체에 값이 이미 존재한다면 다시 추가되지 않습니다.
set2.add("f");
set2.add("g").add("h").add("i").add("j").add("k").add("k");
// 마지막 "k"는 이미 존재하기 때문에 Set 객체에 추가되지 않습니다.
delete
메서드를 사용해서 Set
인스턴스에 값을 삭제할 수 있습니다.
이 메서드는 Set
객체에 같은 값이 존재하면 true
를, 값이 존재하지 않으면 false
를 리턴합니다.
set2.delete("k") // returns true, "k" 존재함
set2.delete("z") // returns false, "z" 존재하지 않음
size
속성을 사용하여 Set
인스턴스의 길이를 구할 수 있습니다.
set2.size // returns 10
clear
를 사용하여 Set
인스턴스의 모든 요소를 삭제하거나 제거할 수 있습니다.
set2.clear();
// clears the set data
Set
객체를 사용하여 배열에서 중복 요소를 제거할 수 있습니다.
const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5];
const uniqueNums = [...new Set(numbers)]; // has a value of [1,2,3,4,5,6,7,8]
49. 콜백 함수란 무엇인가?
↑ 콜백 함수는 나중에 호출될 함수입니다.
const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener('click', function clickCallback(e) {
// do something useless
});
이 예제에서, id가 btnAdd인 엘리먼트의 click event
를 기다립니다. clicked
이면 clickCallback
함수가 실행됩니다.
콜백 함수는 일부 데이터 또는 이벤트에 몇가지 기능을 추가합니다.
배열의 reduce
, filter
및 map
메서드는 콜백을 매개 변수로 사용합니다.
콜백에 대한 좋은 비유는 누군가에게 전화를 걸 때 응답하지 않으면 메시지를 남기고 콜백을 기대합니다.
누군가에게 전화하거나 메시지를 남기는 행위는 이벤트 또는 데이터입니다. 그리고 콜백은 나중에 발생할 것으로 예상되는 작업입니다.
50. 프로미스(Promises) 란 무엇인가?
↑ Promises는 JavaScript에서 비동기 작업을 처리하는 한 가지 방법입니다. 이것은 비동기 작업의 값을 나타냅니다. Promises는 콜백을 사용하기 전에 비동기 코드를 동작하고 처리하는 문제를 해결하기 위해 만들어졌습니다.
fs.readFile('somefile.txt', function (e, data) {
if (e) {
console.log(e);
}
console.log(data);
});
이 접근 방법의 문제는 콜백 안에 다른 비동기 작업이 있고 또 더 있을 경우입니다. 콜백 내부에 다른 비동기 작업이 있고 다른 작업이 있는 경우 이 방법의 문제입니다. 이렇게 되면 엉망이고 읽을 수 없는 코드가 되어버립니다. 이 코드를 콜백 지옥이라고 합니다.
//Callback Hell yucksss
fs.readFile('somefile.txt', function (e, data) {
//your code here
fs.readdir('directory', function (e, files) {
//your code here
fs.mkdir('directory', function (e) {
//your code here
})
})
})
이 코드에서 promises를 사용하면 더 읽기, 이해하기 및 유지관리도 쉽습니다.
promReadFile('file/path')
.then(data => {
return promReaddir('directory');
})
.then(data => {
return promMkdir('directory');
})
.catch(e => {
console.log(e);
})
Promises에는 3 가지 상태가 있습니다.
Pending - promise의 초기 상태. 작업이 아직 완료되지 않아서 promise의 결과는 아직 알려지지 않았습니다.
Fulfilled - 비동기 작업이 완료되고 성공한 결과값이 생깁니다.
Rejected - 비동기 작업이 실패했으며 실패한 이유가 생깁니다.
Settled - promise가 Fulfilled 또는 Rejected인 경우.
Promise 생성자에는 각각 함수 resolve
및 resolve
인 두 개의 매개 변수가 있습니다.
비동기 작업이 에러없이 완료되면 resolve
함수를 호출해 promise
을 처리하거나 에러가 발생하면 reject
함수를 호출해서 에러 난 이유를 전달합니다.
그리고 .then
메서드를 사용해서 성공한 promise의 결과에 액세스 할 수 있으며 .catch
메서드를 사용해서는 에러를 포착합니다.
.then
메서드는 위의 예제와 같이 Promise를 리턴하기 때문에 여러 개의 비동기 promise 작업을 .then
메서드에 연결할 수도 있습니다.
const myPromiseAsync = (...args) => {
return new Promise((resolve, reject) => {
doSomeAsync(...args, (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
})
})
}
myPromiseAsync()
.then(result => {
console.log(result);
})
.catch(reason => {
console.log(reason);
})
콜백으로 비동기 작업을 promise로 변환하는 헬퍼 함수를 만들 수 있습니다.
이것은 노드 코어 모듈 util
과 같은 작동을 하는 promise 유틸리티 함수입니다.
const toPromise = (asyncFuncWithCallback) => {
return (...args) => {
return new Promise((res, rej) => {
asyncFuncWithCallback(...args, (e, result) => {
return e ? rej(e) : res(result);
});
});
}
}
const promReadFile = toPromise(fs.readFile);
promReadFile('file/path')
.then((data) => {
console.log(data);
})
.catch(e => console.log(e));
51. async/await란 무엇이며 어떻게 작동하는가?
↑ async/await는 JavaScript에서 비동기 또는 비 차단(non-blocking) 코드를 작성하는 새로운 방법입니다. Promises 위에 만들어졌습니다. 이것은 Promises 와 Callbacks보다 비동기 코드 작성을 더 읽기 쉽고 깔끔하게 만듭니다. 그러나 이 기능을 사용하기 전에 Promises의 기본을 배워야합니다. 앞서 이야기한 바대로, 이것은 Promises 위에 만들어졌기 때문에 여전히 Promises 속에서 사용합니다.
Promises 사용.
function callApi() {
return fetch("url/to/api/endpoint")
.then(resp => resp.json())
.then(data => {
//do something with "data"
}).catch(err => {
//do something with "err"
});
}
Async/Await 사용.
Note: 이전 try/catch 문을 사용하여 try 문 내부의 비동기 작업에서 발생한 에러를 포착합니다.
async function callApi() {
try {
const resp = await fetch("url/to/api/endpoint");
const data = await resp.json();
//do something with "data"
} catch (e) {
//do something with "err"
}
}
Note: 함수 선언 이전의 async 키워드는 함수가 암시적으로 Promise를 리턴하도록 만듭니다.
const giveMeOne = async () => 1;
giveMeOne()
.then((num) => {
console.log(num); // logs 1
});
Note: await 키워드는 비동기 함수 내에서만 사용할 수 있습니다. 비동기 함수가 아닌 다른 함수에서 await 키워드를 사용하면 에러를 던집니다. await 키워드는 다음 코드 줄을 실행하기 전에 오른쪽 표현식 (아마도 Promise)이 리턴되기를 기다립니다.
const giveMeOne = async () => 1;
function getOne() {
try {
const num = await giveMeOne();
console.log(num);
} catch (e) {
console.log(e);
}
}
// Compile-Time Error = Uncaught SyntaxError 발생: await는 비동기 함수에서만 유효합니다.
async function getTwo() {
try {
const num1 = await giveMeOne(); // 이 비동기 작업을 먼저 마치고
const num2 = await giveMeOne(); // 이 라인이 작동
return num1 + num2;
} catch (e) {
console.log(e);
}
}
await getTwo(); // returns 2
52. 스프레드 연산자(Spread operator) 와 나머지 연산자(Rest operator) 의 차이점은 무엇인가?
↑
스프레드 연산자와 나머지 매개 변수는 동일한 연산자 ...
를 가집니다.
차이점은 배열의 개별 데이터를 다른 데이터에 건네주거나 분산시키는 것이 스프레드 연산자이고 반면에 나머지 매개 변수는 함수 또는 배열에서 모든 인수나 값을 가져와서 배열에 넣거나 일부를 빼내는데 사용됩니다.
function add(a, b) {
return a + b;
};
const nums = [5, 6];
const sum = add(...nums);
console.log(sum);
이 예제에서는 nums 배열을 분산시키는 add
함수를 호출 할 때 스프레드 연산자를 사용합니다.
따라서 매개 변수 a
의 값은 5, b
의 값은 6이 됩니다. 그리고 결과는 11이 됩니다.
function add(...rest) {
return rest.reduce((total,current) => total + current);
};
console.log(add(1, 2)); // logs 3
console.log(add(1, 2, 3, 4, 5)); // logs 15
이 예제에서는 많은 인수를 받는 add
함수가 있고 그 모두를 추가하며 total을 리턴합니다.
const [first, ...others] = [1, 2, 3, 4, 5];
console.log(first); // logs 1
console.log(others); // logs [2,3,4,5]
여기에 있는 또다른 예제에서는 나머지 연산자를 사용하여 나머지 배열 값들을 추출하고 그것들 중 first
아이템만 제외해서 배열 others
에 넣습니다.
53. 기본 매개 변수(Default Parameters) 란 무엇인가?
↑ 기본 매개 변수는 JavaScript에서 기본 변수를 정의하는 새로운 방법으로 ES6 또는 ECMAScript 2015 버전에서 사용할 수 있습니다.
// ES5 Version
function add(a,b) {
a = a || 0;
b = b || 0;
return a + b;
}
// ES6 Version
function add(a = 0, b = 0) {
return a + b;
}
// 'a'나 'b'에 어떤 인자도 넘기지 않으면 0인 "default parameter"를 사용할 것입니다
add(1); // returns 1
기본 매개 변수에서 구조 분해(Destructuring) 를 사용할 수도 있습니다.
function getFirst([first, ...rest] = [0, 1]) {
return first;
}
getFirst(); // returns 0
getFirst([10,20,30]); // returns 10
function getArr({ nums } = { nums: [1, 2, 3, 4] }){
return nums;
}
getArr(); // returns [1, 2, 3, 4]
getArr({nums:[5,4,3,2,1]}); // returns [5,4,3,2,1]
또한 먼저 정의된 매개 변수를 그 뒤에 정의된 매개 변수에 사용할 수도 있습니다.
function doSomethingWithValue(value = "Hello World", callback = () => { console.log(value) }) {
callback();
}
doSomethingWithValue(); //logs "Hello World"
54. 래퍼 객체(Wrapper Objects) 란 무엇인가?
↑
null
과 undefined
를 제외하고 string
, number
및 boolean
과 같은 **원시값(Primitive Values)**에는 객체가 아니더라도 속성 및 메서드가 있습니다.
let name = "marko";
console.log(typeof name); // logs "string"
console.log(name.toUpperCase()); // logs "MARKO"
name
is a primitive string
value that has no properties and methods
name
은 속성과 메서드가 없는 primitive string
값입니다.
하지만 이 예제에서는 에러를 던지진 않지만 MARKO
를 반환하는 toUpperCase ()
메서드를 호출합니다.
그 이유는 primitive
값이 일시적으로 변환되거나 객체로 강제하기 때문입니다. 그래서 name
변수는 객체처럼 동작합니다.
null
과 undefined
를 제외한 모든 primitive
에는 Wrapper Object가 있습니다.
래퍼 객체는 String
, Number
, Boolean
, Symbol
및 BigInt
입니다.
여기서는 name.toUpperCase()
호출 장면 뒷모습이 다음과 같이 보입니다.
console.log(new String(name).toUpperCase()); // logs "MARKO"
새로 만든 객체는 속성에 액세스하거나 메서드 호출을 끝나면 즉시 삭제됩니다.