본문 바로가기

Backend/Javascript

ES2022

다소 (많이) 늦었지만, ES2022 에서 새로 나온 기능들 중 일부에 대해 얘기를 해보려 합니다.

 

- ES2022 ?

 

ES2022, ES6, ES5, ES2015 등의 용어는 자바스크립트 개발자라면 꽤 자주 봤을 것 입니다.

여기서 ES 는 ECMAScript 의 줄임말로, 국제적 표준화 기구인 Ecma International 이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어를 뜻한다고 합니다. 알아둬야 할 건 자바스크립트 표준화를 위해 만들어졌다는 것 입니다.

ECMAScript 에 대해선 다른 포스팅에서 좀 더 적어보도록 하겠습니다.

 

무튼 이 버전은 publish 되는 해에 맞춰서 네이밍 되는 것 같습니다. ES2020, ES2021, ES2022 이런 순서로 나오고 있죠.

 

ES2022

 

위의 캡쳐는 ES2022 에서 새로 나온 기능들이고, 이 링크에서 직접 확인하실 수 있습니다.

이 중에서 눈에 띄는 몇 가지 기능들을 살펴보려 합니다.

 

- Class Fields ?

 

Class Fields 에서 눈여겨 볼 내용은 private 와 static 이 정식으로 도입된 스펙입니다.

 

class Cafe {
  id = 1;
  #name = 'unknown';
  static type = 'cafe';
  static #type2 = 'shop';

  getName1() {
    return this.#name;
  }

  #getName2() {
    return this.#name;
  }

  static print() {
    console.info(3);
  }
}

const cafe = new Cafe();

console.info(cafe.id); // 1
console.info(cafe.getName1()); // 'unknown'
console.info(Cafe.type); // 'cafe'
console.info(cafe.#getName2()); // throw error
console.info(Cafe.print()); // 3

 

추가된 스펙이 거의 포함된 예시 코드입니다.

우선 멤버 변수 id 부터 보면, constructor 의 외부에서도 선언이 가능하도록 개선이 되었습니다.

 

# 키워드를 멤버 변수 혹은 메서드 앞에 붙임으로써 private 를 나타낼 수 있게 되었습니다.

현재 팀에선 거의 TS 를 사용하므로 JS 에서 이런 키워드의 필요성을 느꼈던건 너무 옛날이지만, 그간 어쩔 수 없이 앞에 _ 를 사용하거나

다른 우회 방법들을 사용했던 때와 비교하면 이 스펙의 추가는 꽤 놀라운 점이었습니다.

예시에서 보이듯 private method 로 선언한 getName2 를 외부에서 호출 시 에러가 발생하는 걸 확인할 수 있습니다.

 

static 도 이제 정식 스펙이 되었습니다. 또한 위의 # 와 조합해 private static 도 생성이 가능해졌습니다.

 

저는 위의 코드를 Node.js 환경 위에서 실행했는데 node10 버전에선 # 키워드를 사용할 수 없고 node12 에선 멤버변수엔 사용가능하지만 메서드 앞에 붙이면 인식을 못하며 node14 에선 사용에 문제가 없네요.

node12 와 node14 동일하게 SyntaxError 를 뱉지만 node12 에선 #getName2 를 선언한 부분에서, node14 에선 이후 getName2 를 호출했을 때 Private field '#getName2' must be declared in an enclosing class 와 같은 에러가 발생하는걸 확인할 수 있습니다.

 

- Top-level await ?

 

지금까지 보통 비동기 로직을 작성할 때 ES2017 때부터 async - await 의 도움을 충분히 받을 수 있었습니다.

axios 를 사용해 request 에 대한 응답을 받고자 할 땐, 아래와 같이 코드를 작성해야 했습니다.

 

const axios = require('axios');

(async () => {
  const { data } = await axios('http://localhost...');
  
  console.info(data); // ...
})();

 

이렇게 코드를 작성하는 이유는 await 키워드를 사용할 땐 async 를 반드시 같이 사용해야하기 때문입니다.

하지만 최상단에서 async 를 사용하지 않아도 await 키워드를 사용할 수 있게 되었습니다.

 

import axios from 'axios';

const { data } = await axios('http://localhost...');

console.info(data); // ...

 

하지만 조금 설정이 필요한데, 코드에서 뜬금없이 import 구문이 사용된 이유이기도 합니다.

동일하게 일반 Node.js 환경에서 CommonJS 방식으로 모듈을 사용하게 되면, node14 까진 SyntaxError 가 발생하고

node16 에선 SyntaxError: await is only valid in async functions and the top level bodies of modules 와 같은 에러가 발생합니다.

 

이는 Node.js 에서 CommonJS 방식이 아닌 ES 방식으로 모듈을 사용하도록 변경하면 해결이 가능합니다.

package.json 에서 아래와 같이 "type": "module" 을 추가합니다. (파일 단위로 확장자를 mjs 로 변경하는 방법도 있지만, 그냥 심플하게 전체 적용으로 갑니다)

 

package.json

 

이러면 ES 방식으로 모듈 사용이 가능하지만 require 구문을 import 로 변경해야 합니다. 따라서 위 코드처럼 작성하고, 실행해보면 async 키워드 없이 await 사용이 가능한걸 확인할 수 있습니다. 이렇게하면 node12 는 에러가 발생하고 node14 부턴 문제가 없네요.

 

왜 이름에 top-level 이 붙은지는 아직 제 이해로는 명확하지가 않고, CommonJS 방식의 node16 버전에서 top level bodies of modules 와 같은 에러가 따로 붙는거보면 ES 방식으로 변경하지 않아도 사용 가능한 스펙이 원래 있었던 것 같네요.

이건 따로 확인을 좀 해봐야겠습니다..

 

- .at() ?

 

이 메서드는 배열의 인덱스에 해당하는 요소를 선택해 반환해주는 Array.prototype 의 메서드입니다.

기존에 arr[1] 이런식으로 대괄호를 써오곤 했지만, arr.at(1) 로 사용이 가능해졌습니다. 여기에 추가 기능이 생겼습니다.

 

const list = [1, 2, 3, 4, 5];

console.info(list.at(1)); // 2
console.info(list.at(3)); // 4
console.info(list.at(-1)); // 5
console.info(list.at(-3)); // 3
console.info(list.at(-10)); // undefined

 

at 메서드를 통해 마이너스 인덱싱이 가능해졌다는 점 입니다.

자연스럽게 가장 마지막 요소부터 동작하고, range 를 넘어갈 경우 undefined 를 반환합니다.

다른 일부 언어들에서 볼때마다 부러웠던 기능인데.. 좋아진 포인트인 것 같습니다. 일반 Node.js 환경에선 node16 부터 사용 가능하네요.

 

- Error Cause ?

 

개발을 하면서 에러 핸들링은 너무도 자주 하게 되는데, 그때 사용할 수 있는 프로퍼티가 에러 객체에 추가되었습니다.

 

try {
  throw new Error('Bad Request', { cause: 'id' });
} catch (e) {
  console.error(e); // Error: Bad Request
  console.error(e.cause); // 'id'
}

 

에러 객체를 생성할 때 두번째 인자에 cause 프로퍼티를 같이 넘기면, 이 프로퍼티를 이후 확인할 수 있게 된 내용입니다.

이 스펙은 딱히 좋은 점을 아직은 못 느끼고 있지만, 앞으로 필요할 때 사용하면서 체감을 해봐야 할 것 같습니다.

위 스펙과 마찬가지로 node16 부터 사용이 가능하네요.

 

어떤 스펙은 기존 TS 를 사용하다보니 별 이점을 모르겠고, 또 어떤 스펙은 꽤나 유용하다고 느껴지는 내용이었습니다.

전반적으로 느껴지는건 아직 멀긴 했으나 OOP 에 가까워지려는 듯한 느낌입니다.

아마 TS 에서도 컴파일러 옵션을 통해 ES2022 를 사용할 수 있으리라 봅니다. 이 부분은 나중에 따로 포스팅해봐야겠네요.

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

ECMAScript  (0) 2022.02.12
TC39 Process  (0) 2022.02.07
Javascript 내장 클래스 확장  (0) 2021.12.25
Javascript - Closure (클로저) 에 대해  (1) 2021.07.17
Javascript - 실행 컨텍스트란  (0) 2021.07.10