What's new in ECMAScript 2020 (ES11)

ECMA-262(ECMAScript 표준 기술 규격) 명세를 관리하는 TC39 위원회는 2015년부터 매년 6월에 새로운 ECMAScript 버전을 발표하고 있습니다.

올해에는 11번째 ECMA-262명세인 ECMAScript 2020(ES11)가 발표될 예정인데요, 같이 다음 명세에 포함될 예정인 stage 4(Finished Proposals) 기능들을 알아보며 어떤 새로운 기능들이 ECMAScript 2020에 추가될 예정인지 알아보도록 하겠습니다.

Optional Chaining

Optional Chaining(?.) 연산자는 왼쪽 피연산자 값이 null이나 undefined일 경우 실행을 멈추고 undefined를 반환하는 연산자입니다.

Optional Chaining 연산자를 사용하면, 존재하지 않을 수도 있는 값에 대하여 예외처리를 해야 할 때 손쉽게 처리할 수 있습니다.

const data = {
  user: {
    name: 'foo',
    getName() {
      return this.name
    }
  }
}

const user1 = data?.user // {...}
// 위와 동일한 동작을 함
const user2 = data !== undefined && data !== null ? data.user : undefined // {...}

const userName = data?.user.getName?.() // foo
const firstFriend = data?.user.friends?.[0] // undefined

현재(2020-02-03)기준 Optional Chaining 연산자를 사용하기 위해선, @babel/plugin-proposal-optional-chaining을 적용하거나, typescript 3.7.2 버전 이상을 사용 해야 합니다.

Nullish coalescing Operator

Nullish coalescing Operator(??)는 왼쪽 피연산자 값이 null이나 undefined일 경우 오른쪽 피연산자를 반환하고 그렇지 않으면 왼쪽 피연산자를 반환하는 연산자입니다.

Nullish coalescing 연산자는 변수에 기본값을 할당할 때 유용해 보입니다. 주로 기본값을 할당할 때 || 연산자를 사용했는데, 만약 0, '', NaN같은 falsy값들을 유효한 값으로 생각한 경우 예기치 않은 결과가 발생할 수 있습니다. Nullish coalescing 연산자를 사용하면 값이 null이나 undefined인 경우에만 기본값을 할당해주기 때문에 좀 더 안전하게 코드를 작성할 수 있습니다.

const data = {
  title: 'foo',
  desc: ''
}

const description1 = data.desc ?? 'default value' // ''
// 위와 동일한 동작을 함
const description2 =
  data.desc !== undefined && data.desc !== null ? data.desc : 'default value' // ''

const description3 = data.desc || 'default value' // 'default value'

현재(2020-02-03)기준 Nullish coalescing Operator를 사용하기 위해선, @babel/plugin-proposal-nullish-coalescing-operator을 적용하거나, typescript 3.7.2 버전 이상을 사용 해야 합니다.

globalThis

globalThis은 어떠한 javaScript 실행 환경에서도 동일하게 전역 객체를 반환합니다.

기존에는 javaScript 실행환경에 따라 전역객체에 접근하는 방법이 달라서 브라우저 환경에서는 window, self, frames를 사용해서 접근하고, node.js 환경에서는 global, Web Worker에서는 self를 통해 접근해야 했습니다. 그래서 코드가 다양한 실행 환경에서 작동하려면 별도의 예외처리를 해줘야 했는데, 이제 globalThis를 이용하면 별도의 예외처리를 하지 않고도 손쉽게 전역 객체에 접근할 수 있습니다.

// 브라우저 실행 환경 기준

globalThis === window // true

현재(2020-02-03)기준 globalThisChrome 71 버전 이상, Firefox 65 버전 이상, Safari 12.1 버전 이상, node.js 12 버전 이상에서 globalThis를 사용할 수 있습니다.

Dynamic import

import()구문은 동적으로 모듈을 불러올 때 사용합니다.

import()구문은 Promise객체를 반환하기 때문에 async/await이나 then/catch를 사용해서 비동기처리를 할 수 있습니다.

import("./myModule.js")
    .then(module => {
      ...
    });
    .catch(error => {
      ...
    })

// async/await 사용
;(async () => {
    try {
      const module = await import("./myModule.js");
    } catch(error) {
      ...
    }
})()

현재(2020-02-03)기준 import()구문은 Chrome 63 버전 이상, Firefox 67 버전 이상, Safari 11.1 버전 이상, Edge 79 버전 이상에서 사용할 수 있습니다.

BigInt

BigIntNumber원시값이 표현할 수 있는 최대치인 2^53 - 1보다 큰 값을 표현하고 싶을 때 사용할 수 있습니다.

BigInt를 사용하려면 정수 리터럴 뒤에 n을 붙이거나, BigInt() 생성자 함수의 인자로 생성할 숫자를 전달해야 합니다.

주의해야 할 점은 BigIntMath객체의 메서드와 함께 사용할 수 없고, 연산에서 Number 타입의 원시값과 같이 연산할 수 없습니다.

// 정수 리터럴 방식
const bigInt1 = 9007199254740999n
// 생성자 함수 방식
const bigInt2 = BigInt(9007199254740998)

console.log(bigInt1 > bigInt2) // true
console.log(bigInt1 > bigInt2 + 2n) // false

현재(2020-02-03)기준 BigIntChrome 67 버전 이상, Firefox 68 버전 이상, Opera 54 버전 이상에서 사용할 수 있습니다.

String.prototype.matchAll

String.prototype.matchAll 메서드는 RegExp.prototype.exec 메서드와 유사하게 동작합니다.

String.prototype.matchAll 메서드는 lastIndex로부터 시작해서 정규표현식과 첫 번째로 일치하는 하위 문자열의 정보를 반환하는 RegExp.prototype.exec와 달리 일치하는 모든 하위 문자열의 정보를 포함하고 있는 iterator를 반환합니다.

const regexp = /t(e)(st(\d?))/g
const str = 'test1test2'
const array = [...str.matchAll(regexp)]

console.log(array[0]) // ["test1", "e", "st1", "1"]
console.log(array[1]) // ["test2", "e", "st2", "2"]

현재(2020-02-03)기준 String.prototype.matchAll 메서드는 Chrome 73 버전 이상, Firefox 67 버전 이상, Opera 60 버전 이상에서 사용할 수 있습니다.

Promise.allSettled

Promise.allSettled 메서드는 인자로 받은 배열이나 iterable 객체를 통해 열거된 Promise 객체들이 모두 실행됐을 때 resolve하는 Promise 객체를 반환합니다.

Promise.allSettled 메서드는 Promise.all 메서드와 유사하지만, Promise.all 메서드는 열거된 Promise 객체들 중 하나라도 reject되면 자신도 reject하지만 Promise.allSettled 메서드는 이행 여부와 상관없이 전부 다 실행되면 resolve합니다.

const promise1 = Promise.resolve(10)
const promise2 = new Promise((_, reject) => setTimeout(reject, 100, 'foo'))
const promises = [promise1, promise2]

Promise.allSettled(promises).then(
  results => results.forEach(result => console.log(result.status)) // "fulfilled", "rejected"
)

현재(2020-02-03)기준 Promise.allSettled 메서드는 Chrome 76 버전 이상, Firefox 71 버전 이상, Safari 13 버전 이상에서 사용할 수 있습니다.

Reference

comment

Comments