본문 바로가기

Backend/Javascript

ES11 (ES2020)

이번 포스팅에선 ES11 의 기능들에 대해 알아보겠습니다.

 

- matchAll

 

정규표현식에 사용할 수 있는 새로운 메서드가 추가되었습니다.

기존에는 match 메서드를 사용해왔었는데, 어떤 차이점이 있는지 아래 코드 예제로 보도록 하겠습니다.

 

const regex1 = /https?:\/\/www.npmjs.com\/package\/(\w*)/g;
const regex2 = /https?:\/\/www.npmjs.com\/package\/(\w*)/;

const domain = 'https://www.npmjs.com/package/axios';

const test1 = domain.match(regex1);
const test2 = domain.match(regex2);

console.info(test1); // [ 'https://www.npmjs.com/package/axios' ]
console.info(test2);
/*
[
  'https://www.npmjs.com/package/axios',
  'axios',
  index: 0,
  input: 'https://www.npmjs.com/package/axios',
  groups: undefined
]
*/

 

기존 match 메서드에선 정규표현식에 g flag 를 같이 사용한다면 일치하는 요소만 Array 형으로 반환하지만, g flag 를 사용하지 않으면 캡쳐 그룹까지 반환하는 것을 볼 수 있습니다.

 

const regex = /https?:\/\/www.npmjs.com\/package\/(\w*)/g;
const domain = 'https://www.npmjs.com/package/axios';

const test1 = domain.matchAll(regex);
const test2 = [...test1];

console.info(test1); // Object [RegExp String Iterator] {}
console.info(test2);
/*
[
  [
    'https://www.npmjs.com/package/axios',
    'axios',
    index: 0,
    input: 'https://www.npmjs.com/package/axios',
    groups: undefined
  ]
]
*/

 

새로 추가된 matchAll 메서드에선 g flag 를 사용해 동일하게 테스트했을 때, 일치하는 결과에대한 iterator object 가 반환됩니다.

이를 전개연산자를 사용해 풀어보면 index, input, groups 프로퍼티까지 전부 반환하는 것을 볼 수 있습니다.

개인적으론 정규표현식을 자주 사용할 일은 없어서 이 차이점에 대해 크게 체감이 되진 않습니다..

 

- BigInt

 

내장 객체 Number 의 안전한 수 최대치는 2^53 - 1 입니다. 이 수를 넘어가면 연산이 제대로 되지 않는 문제가 있는데, 이보다 더 큰 정수를 표현할 수 있는 내장 객체인 BigInt 가 나왔습니다.

 

const number = Number.MAX_SAFE_INTEGER;
const bigNumber = BigInt(number);

console.info(number); // 9007199254740991
console.info(number * 10); // 90071992547409900
console.info(bigNumber * 10n); // 90071992547409910n

 

Number.MAX_SAFE_INTEGER 에 *10 연산을 했을 때 기존 Number 로는 정확한 값을 얻을 수 없지만, BigInt 에선 정확한 값을 구할 수 있습니다. 다만 정수 리터럴뒤에 n 표기가 추가되었고, 연산에 사용되는 숫자 뒤에도 n 을 붙여야 합니다.

 

const number = Number.MAX_SAFE_INTEGER;
const bigNumber = BigInt(number);

console.info(typeof number); // number
console.info(typeof bigNumber); // bigint

console.info(0n === 0); // false
console.info(0n == 0); // true

 

자료형은 bigint 입니다. 또한 bigint 는 number 와 일치하진 않으나, 동등합니다.

BigInt 를 Number 로 변환하는 것은 과정에서 정확도를 유실할 수 있으므로 권장되지 않습니다.

기존엔 연산의 정확도를 높이거나 더 큰 수에 대한 연산을 할 필요가 있을 경우 BigNumber.js 와 같은 라이브러리의 도움을 받았었는데,

활용하기에 따라 BigInt 로 대체할 수도 있을 것 같습니다.

 

- Promise.allSettled

 

Promise.allSettled 메서드는 주어진 모든 프로미스에 대해 fulfilled 되거나 rejected 된 결과를 배열로 반환합니다.

 

const promise1 = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(1);
    }, 500);
  });
};

const promise2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(3);
    }, 100);
  });
};

(async () => {
  try {
    const promises = [promise1(), promise2()];
    const test1 = await Promise.all(promises);
    console.info(test1);
  } catch (e) {
    console.error(e); // 3
  }
})();

 

Promise.all 의 경우 주어진 프로미스가 하나라도 거부되면 다른 프로미스의 이행 여부에 상관 없이 거부됩니다.

 

const promise1 = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(1);
    }, 500);
  });
};

const promise2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(3);
    }, 100);
  });
};

(async () => {
  const promises = [promise1(), promise2()];
  const test1 = await Promise.allSettled(promises);

  console.info(test1); // [{ status: 'fulfilled', value: 1 }, { status: 'rejected', reason: 3 }]
})();

 

Promise.allSettled 의 경우엔 위와 같이 반환하므로 서로 성공 여부에 상관없는 비동기 작업들을 모아서 처리하거나

프로미스가 fulfilled 혹은 rejected 되었는지에 대한 결과만 궁금하다면 사용하기 좋을 것 같습니다.

 

- asynchronously import Modules

 

자바스크립트에선 commonJS 스타일로 모듈을 사용할 경우 import 구문을 사용할 수도 없고, 사용한다해도 제약이 꽤 있어 함수안에서 사용도 불가했습니다.

 

// test-module.js
export function test1() {
  console.info('test1');
}

export function test2() {
  console.info('test2');
}

// test.js
const tmp = async () => {
  const { test1, test2 } = await import('./test-module.js');

  test1(); // 'test1'
  test2(); // 'test2'
};

tmp();

 

이제 import 표현식을 위와 같이 코드 내 어디서든 동적으로 사용할 수 있게 되었습니다.

import 앞에 await 때문에 무조건 async 와 같이 사용해야하는가? 라고 생각이 들 수 있지만 그냥 사용도 가능합니다.

워낙에 async - await 는 세트로 다뤘다보니 어색하게 느껴지긴 합니다.

 

- globalThis

 

console.info(globalThis);
/*
Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  }
}
*/
console.info(globalThis === global); // true

 

일단 환경은 Node.JS 입니다. 전역객체에 접근할 수 있는 통일된 방법이 globalThis 로 나왔습니다.

브라우저 환경이라면, globalThis 는 window 객체와 동일합니다.

 

정확히 말하자면 globalThis 자체가 전역객체는 아니고, 전역 스코프의 this 를 반환하는 형태입니다.

사실 전역 스코프의 this 에 접근해서 뭘 하는 일은 지금까지 저한텐 거의 없었고, 앞으로도 없지 않을까 싶습니다만 프론트 개발자면 다소 있을 것 같기도 합니다. 또한 환경에 따라 global 을 쓰거나 window 를 써야하는 통일성이 없던 것에 비하면 좋은 변화인 것 같습니다.

 

그 외엔 import.meta / for-in / nullish 등에 변화가 있지만 마이너한 부분으로 보여 이정도에서 넘어가도록 하겠습니다.

'Backend > Javascript' 카테고리의 다른 글

ES7 (ES2016)  (0) 2022.03.19
ES12 (ES2021)  (0) 2022.03.13
ES10 (ES2019)  (0) 2022.02.27
ES9 (ES2018)  (0) 2022.02.19
ECMAScript  (0) 2022.02.12