logo

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 객체란 무엇인가?

arguments 객체는 함수에 전달된 매개 변수 값의 집합입니다. length 속성을 가지고 있고 배열 인덱싱 arguments[1] 표기법을 사용하여 각각의 값에 액세스 할 수 있기 때문에 배열과 같은 객체입니다. 그러나 forEach, reduce, filtermap 배열에는 내장 메서드가 없습니다. 이것은 함수에 전달되는 인수의 수를 알 수 있습니다.

우리는 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의 새로운 기능은 무엇인가?

42. var, letconst 키워드의 차이점은 무엇인가?

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임을 기억해야 합니다.

letconst 키워드로 선언된 변수는 블록 스코프입니다. 이것은 변수가 선언된 {}블록에서만 변수에 액세스 할 수 있음을 뜻합니다.

function giveMeX(showX) {
  if (showX) {
    let x = 5;
  }
  return x;
}


function giveMeY(showY) {
  if (showY) {
    let y = 5;
  }
  return y;
}

이 함수들을 false 인수로 호출하면 Reference Error가 발생합니다. 블록 외부의 xy 변수에 액세스 할 수 없는데 해당 변수가 호이스팅되지 않았기 때문입니다.

letconst 사이에도 차이가 있습니다. 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, filtermap 메서드는 콜백을 매개 변수로 사용합니다. 콜백에 대한 좋은 비유는 누군가에게 전화를 걸 때 응답하지 않으면 메시지를 남기고 콜백을 기대합니다. 누군가에게 전화하거나 메시지를 남기는 행위는 이벤트 또는 데이터입니다. 그리고 콜백은 나중에 발생할 것으로 예상되는 작업입니다.

50. 프로미스(Promises) 란 무엇인가?

PromisesJavaScript에서 비동기 작업을 처리하는 한 가지 방법입니다. 이것은 비동기 작업의 값을 나타냅니다. 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 생성자에는 각각 함수 resolveresolve 인 두 개의 매개 변수가 있습니다. 비동기 작업이 에러없이 완료되면 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 위에 만들어졌습니다. 이것은 PromisesCallbacks보다 비동기 코드 작성을 더 읽기 쉽고 깔끔하게 만듭니다. 그러나 이 기능을 사용하기 전에 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) 란 무엇인가?

nullundefined를 제외하고 string, numberboolean과 같은 **원시값(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 변수는 객체처럼 동작합니다. nullundefined를 제외한 모든 primitive에는 Wrapper Object가 있습니다. 래퍼 객체는 String, Number, Boolean, SymbolBigInt입니다. 여기서는 name.toUpperCase() 호출 장면 뒷모습이 다음과 같이 보입니다.

console.log(new String(name).toUpperCase()); // logs  "MARKO"

새로 만든 객체는 속성에 액세스하거나 메서드 호출을 끝나면 즉시 삭제됩니다.