ECMAScript 2020

ECMAScript 2020 (ES11)에 추가된 일부 기능 정리

Namespace re-exporting

기존에 존재하던 export-from과 유사하다.

export { x } from "foo";
export { x as y } from "foo";
export * from "foo";

// Namespace re-exporting
export * as ns from "foo";

하지만 특징은 export-from문에 상응하는 것이 없으며, ModuleNameSpace objectnamed export로써 export 된다.

Dynamic imports

기존에 모듈을 가져오는 유일한 방법은 import문을 통해서였다. 이것은 아래와 같은 문제가 있다.

  • 모듈의 최상위 레벨에서 사용해야 한다.

  • 모듈은 항상 고정되어 있어야 하며, 특정 조건에 따라 import하기가 어렵다.

하지만 이제는 import() 연산자를 통해 동적 import가 가능하며, 이 반환값은 프라미스(promise)이다.

// case 1
button.addEventListener('click', event => {
  import('./dialog.mjs')
    .then(dialog => {
      dialog.open();
    })
    .catch(error => {
      /* Error handling */
    })
});

// case 2
if(isLegacyBrowser()) {
  import('./my-polyfill.mjs')
    .then(() => {...});
}

// case 3
import(`messages_${getLocale()}.mjs`)
  .then(() => {...});

// case 4
const module = await import('/modules/my-module.js');

Optional chaining

이미 타입스크립트 덕분에 많이 사용하던 문법이다. 물음표(?) 앞의 값이 undefined 또는 null가 아니라면 물음표 뒤의 작업을 실행한다. undefined 또는 null이라면, undefined를 반환한다.

const temp = obj.first;
const nestedProp =
  temp === null || temp === undefined ? undefined : temp.second;

// -->
const nestedProp = obj.first?.second;

Nullish coalescing operator

이미 타입스크립트 덕분에 많이 사용하던 문법이다. ?? 왼쪽의 피연산자가 undefined 또는 null로 평가된다면, 오른쪽 피연산자가 반환된다.

const myText = ""; // An empty string (which is also a falsy value)

const notFalsyText = myText || "Hello world";
console.log(notFalsyText); // Hello world

const preservingFalsy = myText ?? "Hi neighborhood";
console.log(preservingFalsy); // '' (as myText is neither undefined nor null)

기존에 사용했던 ||(logical OR operator)의 경우 부울(bool) 논리 연산자이기 때문에 왼쪽의 피연산자를 부울로 강제로 변환되었으며, 이 과정에서 falsy한 값은 반환되지 않았다. (0, '', NaN, null, undefined). 이 때문에 의도치 않은 결과가 발생할 수 있다.

Promise.allSettled()

반복 가능한 객체(이터러블)을 매개변수로 받으며, 모든 프라미스가 완료되면, 반환 값은 각 프라미스의 결과를 포함하는 배열로 전달 받는다. 시그니처는 아래와 같다.

Promise.allSettled<T>(promises: Iterable<Promise<T>>)
  : Promise<Array<SettlementObject<T>>>

type SettlementObject<T> = FulfillmentObject<T> | RejectionObject;

interface FulfillmentObject<T> {
  status: 'fulfilled';
  value: T;
}

interface RejectionObject {
  status: 'rejected';
  reason: unknown;
}

시그니처와 예제를 보면 이해가 가장 빠르다.

// Promise.prototype.then()
Promise.allSettled([
  Promise.resolve(33),
  new Promise((resolve) => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error("an error")),
]).then((values) => console.log(values));

Promise.allSettled([
  Promise.resolve(33),
  new Promise((resolve) => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error("an error")),
]).then((values) => console.log(values));
// [
//   {status: "fulfilled", value: 33},
//   {status: "fulfilled", value: 66},
//   {status: "fulfilled", value: 99},
//   {status: "rejected",  reason: Error: an error}
// ]

// ------------------------------------------------------------
// await
const values = await Promise.allSettled([
  Promise.resolve(33),
  new Promise((resolve) => setTimeout(() => resolve(66), 0)),
  99,
  Promise.reject(new Error("an error")),
]);
console.log(values);

// [
//   {status: "fulfilled", value: 33},
//   {status: "fulfilled", value: 66},
//   {status: "fulfilled", value: 99},
//   {status: "rejected",  reason: Error: an error}
// ]

globalThis

globalThis는 전역 객체(global object)에 접근하는 새로운 표준 방법이다. 이름 그대로 전역 범위의 this와 동일한 값을 갖는다.

하지만 globalThis가 항상 전역 객체를 참조하는 건 아니다. (예외: iframe)

특징

  • globalThis모든 플랫폼에서 사용 가능하며, 전역 범위의 this와 동일한 값을 갖는다.

    • window를 참조하는건 고전적인 방법이며, 브라우저에서는 동작하지만 Node.js에서는 동작하지 않는다.

    • self는 모든 브라우저에서 동작하지만 Node.js에서는 동작하지 않는다.

    • globalNode.js에서만 사용 가능하다.

Last updated