ES2021에서 추가된 신기능 5가지
서론
JavaScript는 지속적으로 발전하는 언어로, 새로운 기능이 정기적으로 추가된다. ES2021에서는 보다 직관적이고 효율적인 코드를 작성할 수 있도록 다섯 가지 주요 기능이 도입되었다. 이번 글에서는 ES2021에서 추가된 기능들을 하나씩 살펴보고, 어떻게 활용할 수 있는지 알아본다.
추가된 기능
1. 논리 할당 연산자 (&&=, ||=, ??=)
기존에는 변수를 조건에 따라 할당할 때 if 문이나 삼항 연산자를 사용해야 했다. ES2021에서는 논리 연산자와 할당 연산자를 결합한 &&=, ||=, ??=가 추가되어, 보다 간결한 코드를 작성할 수 있다.
- &&= : 기존 값이 true일 때만 새로운 값을 할당한다.
- ||= : 기존 값이 false일 때만 새로운 값을 할당한다.
- ??= : 기존 값이 null 또는 undefined일 때만 새로운 값을 할당한다.
let username = "Alice";
username &&= "Bob";
console.log(username); // "Bob" (기존 값이 truthy이므로 할당됨)
let theme = "";
theme ||= "dark";
console.log(theme); // "dark" (기존 값이 falsy이므로 새 값 할당)
let maxUsers;
maxUsers ??= 100;
console.log(maxUsers); // 100 (기존 값이 undefined이므로 새 값 할당)
2. 숫자 구분자 (Numeric Separators)
긴 숫자를 읽을 때 자릿수를 세는 것은 번거로운 일이다. ES2021에서는 _(언더스코어)를 사용해 숫자를 가독성 좋게 표현할 수 있도록 개선되었다.
const population = 51_000_000; // 한국 인구 약 5천만
const fileSize = 4_294_967_296; // 4GB (바이트 단위)
const pi = 3.141_592_653; // 소수점 이하도 가능
console.log(population); // 51000000
console.log(fileSize); // 4294967296
console.log(pi); // 3.141592653
이렇게 숫자를 표현하면 코드 가독성이 높아지고, 숫자의 구조를 한눈에 파악할 수 있다.
3. 문자열에서 모든 일치 항목 대체 (String.prototype.replaceAll)
기존 replace() 메서드는 문자열 내 첫 번째 일치 항목만 변경할 수 있었다. ES2021에서 추가된 replaceAll()을 사용하면 모든 일치 항목을 한 번에 변경할 수 있다.
const text = "나는 고양이를 좋아해. 고양이는 귀엽다.";
console.log(text.replaceAll("고양이", "강아지"));
// "나는 강아지를 좋아해. 강아지는 귀엽다."
이제 정규식을 사용하지 않아도 전체 문자열을 간편하게 변경할 수 있다.
4. Promise.any()
비동기 작업을 여러 개 실행할 때, 가장 먼저 완료된 작업의 결과만 사용하고 싶다면 Promise.any()를 사용할 수 있다. 이는 Promise.race()와 유사하지만, race()는 실패한 프로미스가 가장 먼저 반환되면 즉시 에러를 발생시키는 반면, any()는 하나라도 성공하면 그 값을 반환하고, 모두 실패했을 때만 에러를 반환한다.
const fetchData = (url, delay) =>
new Promise((resolve, reject) =>
setTimeout(() =>
Math.random() > 0.3 ? resolve(`${url} 응답 완료`) : reject(`${url} 실패`), delay
)
);
Promise.any([
fetchData("server1.com", 1000),
fetchData("server2.com", 2000),
fetchData("server3.com", 3000),
])
.then(response => console.log("가장 빨리 성공한 요청:", response))
.catch(error => console.log("모든 요청이 실패:", error));
5. WeakRef와 FinalizationRegistry
JavaScript의 가비지 컬렉터(GC)는 더 이상 사용되지 않는 객체를 자동으로 정리하지만, 특정 객체를 보다 유연하게 관리하고 싶을 때 WeakRef와 FinalizationRegistry를 사용할 수 있다.
let cache = new WeakRef({ data: "중요한 데이터" });
console.log(cache.deref()?.data); // "중요한 데이터"
setTimeout(() => {
console.log(cache.deref()?.data); // 가비지 컬렉터가 실행되면 undefined가 될 수도 있음
}, 5000);
객체를 WeakRef로 감싸면 가비지 컬렉터가 필요할 때 해당 객체를 자동으로 제거할 수 있어 메모리 관리를 효율적으로 할 수 있다.
또한 FinalizationRegistry를 활용하면 객체가 삭제될 때 실행할 콜백을 등록할 수 있다.
const registry = new FinalizationRegistry(value => {
console.log(`${value}가 가비지 컬렉션됨`);
});
let user = { name: "Alice" };
registry.register(user, "사용자 객체");
user = null; // 더 이상 참조하지 않으므로 가비지 컬렉션 대상이 됨