ECMAScript 2025/2026 주요 변경사항

TC39 위원회는 매년 JavaScript 명세를 발전시키고 있다. ES2025와 ES2026에는 개발자 생산성을 크게 향상시키는 중요한 기능들이 포함되었다. 이 글에서는 실무에서 바로 활용할 수 있는 핵심 기능들을 코드 예제와 함께 상세히 살펴본다.

Promise.try() — 동기/비동기 혼용 코드 통합

Promise.try()는 ES2025에 포함된 기능으로, 동기적으로 값을 반환하거나 Promise를 반환하는 함수를 일관된 방식으로 처리할 수 있게 해준다. 레거시 코드에서 자주 발생하는 동기/비동기 혼용 패턴을 깔끔하게 해결한다.

// 기존 방식 - 동기/비동기 혼용 처리의 어려움
function legacyFetch(id) {
  if (cache.has(id)) {
    return cache.get(id);  // 동기 반환
  }
  return fetch(`/api/data/${id}`).then(r => r.json());  // 비동기 반환
}

// 기존 처리 방식 - 지저분함
const result = legacyFetch(42);
if (result instanceof Promise) {
  result.then(data => process(data));
} else {
  process(result);
}

// Promise.try() 사용 - 깔끔하게 통합
Promise.try(() => legacyFetch(42))
  .then(data => process(data))
  .catch(err => handleError(err));

// async/await와 함께
const data = await Promise.try(() => legacyFetch(42));

Iterator Helpers — 이터레이터 체이닝

ES2025의 Iterator Helpers는 배열처럼 이터레이터에 map, filter, take, drop 등의 메서드를 직접 체이닝할 수 있게 해준다. 중간 배열 생성 없이 지연 평가(lazy evaluation)로 처리되어 메모리 효율적이다.

// 기존 방식 - 매번 배열로 변환 필요
const result = [...someIterator]
  .filter(x => x > 0)
  .map(x => x * 2)
  .slice(0, 5);

// Iterator Helpers 사용 - 지연 평가
const result = someIterator
  .filter(x => x > 0)
  .map(x => x * 2)
  .take(5)
  .toArray();

// 제너레이터와 함께 사용
function* range(start, end) {
  for (let i = start; i <= end; i++) yield i;
}

const squares = range(1, 1000)
  .filter(n => n % 2 === 0)   // 짝수만
  .map(n => n ** 2)            // 제곱
  .take(10)                    // 첫 10개만
  .toArray();

console.log(squares); // [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]

Set 메서드 — 집합 연산 표준화

ES2025에서 Set 객체에 교집합, 합집합, 차집합 등의 수학적 집합 연산 메서드가 추가되었다. 기존에는 직접 구현해야 했던 기능이 표준 API로 제공된다.

const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([3, 4, 5, 6, 7]);

// 교집합
console.log(setA.intersection(setB));    // Set {3, 4, 5}

// 합집합
console.log(setA.union(setB));           // Set {1, 2, 3, 4, 5, 6, 7}

// 차집합 (A - B)
console.log(setA.difference(setB));      // Set {1, 2}

// 대칭 차집합 (A XOR B)
console.log(setA.symmetricDifference(setB)); // Set {1, 2, 6, 7}

// 부분집합 여부
const setC = new Set([3, 4]);
console.log(setC.isSubsetOf(setA));      // true
console.log(setA.isSupersetOf(setC));    // true

RegExp.escape() — 정규식 특수문자 이스케이프

사용자 입력을 정규식 패턴에 포함할 때 특수문자를 이스케이프하는 유틸리티 함수가 ES2025에서 표준화되었다.

// 기존 방식 - 직접 구현
function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// ES2025 표준 방식
const userInput = "Hello (World) + [Test]";
const pattern = new RegExp(RegExp.escape(userInput), 'gi');

console.log("Hello (World) + [Test] - 검색됨".match(pattern));
// ['Hello (World) + [Test]']

Array.fromAsync() — 비동기 이터러블을 배열로

ES2026에 포함된 Array.fromAsync()는 비동기 이터러블, 유사 배열 객체, Promise를 배열로 변환하는 정적 메서드다. 비동기 데이터 소스 처리를 간소화한다.

// 비동기 제너레이터를 배열로 변환
async function* asyncRange(start, end) {
  for (let i = start; i <= end; i++) {
    await new Promise(resolve => setTimeout(resolve, 10)); // 비동기 작업 시뮬레이션
    yield i;
  }
}

const numbers = await Array.fromAsync(asyncRange(1, 5));
console.log(numbers); // [1, 2, 3, 4, 5]

// ReadableStream 처리 예제
const stream = response.body.pipeThrough(new TextDecoderStream());
const chunks = await Array.fromAsync(stream);
const fullText = chunks.join('');

// 매핑 함수 지원
const doubled = await Array.fromAsync(asyncRange(1, 5), x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

using / await using — 자원 자동 관리

ES2026에서 가장 주목받는 기능 중 하나인 using 키워드는 명시적 자원 관리(Explicit Resource Management)를 위한 문법이다. C#의 using, Python의 with 문과 유사하며, Symbol.dispose 프로토콜을 활용한다.

// Symbol.dispose를 구현하는 클래스
class DatabaseConnection {
  constructor(url) {
    this.connection = openConnection(url);
    console.log('DB 연결 열림');
  }
  
  query(sql) {
    return this.connection.execute(sql);
  }
  
  [Symbol.dispose]() {
    this.connection.close();
    console.log('DB 연결 닫힘');
  }
}

// using 키워드로 자동 정리
function processData() {
  using conn = new DatabaseConnection('postgresql://localhost/mydb');
  // 함수가 끝나거나 예외 발생 시 자동으로 conn[Symbol.dispose]() 호출
  const result = conn.query('SELECT * FROM users');
  return result;
} // 여기서 자동으로 DB 연결 닫힘

// 비동기 버전
async function processDataAsync() {
  await using conn = new AsyncDatabaseConnection('postgresql://localhost/mydb');
  // Symbol.asyncDispose 호출됨
  const result = await conn.query('SELECT * FROM users');
  return result;
}

Temporal API — 날짜/시간 처리의 혁신

기존 Date 객체의 수많은 문제점을 해결하는 Temporal API가 ES2026에서 표준화되었다. 불변(immutable) 객체, 타임존 처리, 캘린더 시스템을 올바르게 지원한다.

// 기존 Date의 문제점들
const date = new Date(2026, 3, 12); // 월이 0 기반 → 4월임!
const date2 = new Date('2026-04-12'); // 타임존에 따라 날짜가 달라질 수 있음

// Temporal API 사용
import { Temporal } from '@js-temporal/polyfill'; // 폴리필 (표준화 전)

// 명확한 날짜 생성
const today = Temporal.PlainDate.from('2026-04-12');
console.log(today.year);  // 2026
console.log(today.month); // 4 (1 기반!)
console.log(today.day);   // 12

// 날짜 계산 - 불변 객체 반환
const nextMonth = today.add({ months: 1 });
console.log(nextMonth.toString()); // 2026-05-12

// 타임존 처리
const seoul = Temporal.ZonedDateTime.from({
  year: 2026, month: 4, day: 12,
  hour: 9, minute: 0,
  timeZone: 'Asia/Seoul'
});

const newYork = seoul.withTimeZone('America/New_York');
console.log(newYork.toString()); // 서울 9시 = 뉴욕 전날 20시

// 두 날짜 사이 계산
const start = Temporal.PlainDate.from('2026-01-01');
const end = Temporal.PlainDate.from('2026-04-12');
const duration = start.until(end);
console.log(duration.toString()); // P101D (101일)

브라우저 및 Node.js 호환성

ES2025 기능(Promise.try, Iterator Helpers, Set 메서드, RegExp.escape)은 Chrome 131+, Firefox 133+, Safari 18.2+, Node.js 22+ 에서 지원된다. ES2026 기능(Array.fromAsync, using/await using, Temporal)은 최신 브라우저와 Node.js 22 LTS에서 순차적으로 지원되고 있으며, 폴리필을 통해 구형 환경에서도 활용 가능하다.