ECMAScript 최신 명세 흐름

JavaScript는 TC39 위원회가 매년 6월 새 버전을 발표하는 방식으로 발전해왔습니다. ES2025(ES16)는 2025년 6월 공식 릴리즈되었고, ES2026은 현재 Stage 3~4 제안들이 최종 확정을 앞두고 있습니다. 이 글에서는 실무에서 즉시 활용 가능한 핵심 신기능들을 코드 예제와 함께 상세히 정리합니다.

ES2025 핵심 기능

1. Iterator Helpers

기존에는 배열에서만 .map(), .filter() 같은 메서드를 체이닝할 수 있었습니다. ES2025의 Iterator Helpers는 전역 Iterator 객체를 통해 모든 이터러블에서 지연 평가(lazy evaluation) 방식으로 체이닝이 가능해집니다.

// 기존 방식 (배열 변환 필요)
const result = Array.from(someSet)
  .filter(x => x > 10)
  .map(x => x * 2)
  .slice(0, 5);

// ES2025 Iterator Helpers (지연 평가, 메모리 효율적)
const result = someSet.values()
  .filter(x => x > 10)
  .map(x => x * 2)
  .take(5)
  .toArray();

// 제너레이터와의 조합
function* naturals() {
  let n = 0;
  while (true) yield n++;
}

// 무한 시퀀스에서 짝수만 10개 추출
const first10Evens = naturals()
  .filter(n => n % 2 === 0)
  .take(10)
  .toArray();
// [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

// 지원 메서드 목록
// .map(), .filter(), .take(), .drop(), .flatMap()
// .every(), .some(), .find(), .reduce()
// .toArray(), .forEach(), .toAsync()

2. Set 메서드 추가

ES2025에서 Set에 집합 연산 메서드들이 공식 추가되었습니다. 기존에는 직접 구현하거나 라이브러리를 써야 했던 교집합, 합집합, 차집합 등을 네이티브로 지원합니다.

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

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

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

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

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

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

// 상위집합 여부
console.log(setA.isSupersetOf(new Set([1, 2]))); // true

// 분리 여부 (교집합 없음)
console.log(new Set([6, 7]).isDisjointFrom(setA)); // true

3. Promise.try()

동기 함수와 비동기 함수를 일관되게 Promise로 감싸주는 정적 메서드입니다. 기존에 try/catch와 Promise를 혼합할 때 발생하는 패턴 불일치 문제를 해결합니다.

// 기존: 동기 오류를 Promise 체인으로 처리하기 위한 번거로운 패턴
function fetchData(userId) {
  return Promise.resolve().then(() => {
    if (!userId) throw new Error("userId required"); // 동기 throw
    return fetch(`/api/users/${userId}`);
  });
}

// ES2025: Promise.try()로 깔끔하게
function fetchData(userId) {
  return Promise.try(() => {
    if (!userId) throw new Error("userId required"); // 동기 throw도 .catch()에서 처리
    return fetch(`/api/users/${userId}`);
  });
}

fetchData(null)
  .then(data => console.log(data))
  .catch(err => console.error(err.message)); // "userId required"

4. RegExp.escape()

사용자 입력을 정규식에 안전하게 사용할 수 있도록 특수문자를 이스케이프하는 정적 메서드입니다.

// 기존: 직접 escape 함수 구현 필요
function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

// ES2025: 네이티브 지원
const userInput = "hello.world (test)";
const safe = RegExp.escape(userInput);
console.log(safe); // "hello\.world \(test\)"

const regex = new RegExp(safe, "g");
"hello.world (test) hello.world".match(regex);
// ["hello.world (test)", "hello.world"]

ES2026 주요 제안 (Stage 4 진입 예정)

1. Temporal API — Date 객체의 완전한 대체

25년 이상 개발자들을 괴롭혀 온 JavaScript의 Date 객체를 완전히 대체하는 Temporal API가 ES2026에 공식 포함됩니다. 불변(immutable) 객체, 타임존 완전 지원, 명확한 API 설계가 핵심입니다.

// 기존 Date의 문제점들
const d = new Date(2026, 0, 1); // 월이 0부터 시작 (혼란)
d.setDate(d.getDate() + 30); // 가변(mutable) — 원본 수정됨
// 타임존 처리가 복잡하고 불일치 많음

// Temporal API: 직관적이고 안전한 날짜/시간 처리
const today = Temporal.Now.plainDateISO(); // 2026-04-14
const tomorrow = today.add({ days: 1 }); // 불변 — 새 객체 반환
console.log(today.toString()); // "2026-04-14"
console.log(tomorrow.toString()); // "2026-04-15"

// 타임존 완전 지원
const seoulNow = Temporal.Now.zonedDateTimeISO("Asia/Seoul");
const nyNow = seoulNow.withTimeZone("America/New_York");
console.log(seoulNow.hour); // 서울 현재 시각
console.log(nyNow.hour); // 뉴욕 현재 시각

// 날짜 차이 계산
const start = Temporal.PlainDate.from("2026-01-01");
const end = Temporal.PlainDate.from("2026-12-31");
const diff = start.until(end);
console.log(diff.days); // 364

// 자연스러운 날짜 파싱
const meeting = Temporal.ZonedDateTime.from(
  "2026-04-15T09:00:00+09:00[Asia/Seoul]"
);

2. using 키워드 — 명시적 리소스 관리

C#의 using, Python의 with 문과 유사한 개념으로, 리소스의 생명주기를 선언적으로 관리할 수 있게 됩니다. DB 연결, 파일 핸들, 잠금(lock) 등의 자동 해제에 매우 유용합니다.

// Symbol.dispose를 구현한 리소스 클래스
class DatabaseConnection {
  constructor(url) {
    this.conn = openConnection(url);
    console.log("DB 연결 열림");
  }

  query(sql) {
    return this.conn.execute(sql);
  }

  [Symbol.dispose]() {
    this.conn.close();
    console.log("DB 연결 자동 닫힘");
  }
}

// using 키워드로 자동 해제
function processData() {
  using db = new DatabaseConnection("postgresql://localhost/mydb");
  // ... 블록 내에서 db 사용
  const users = db.query("SELECT * FROM users");
  return users;
} // 블록 종료 시 db[Symbol.dispose]() 자동 호출

// await using: 비동기 리소스
async function processAsync() {
  await using conn = await AsyncConnection.open(url);
  const data = await conn.fetch("/api/data");
  return data;
} // 블록 종료 시 await conn[Symbol.asyncDispose]() 자동 호출

3. Error.isError()

// 기존: instanceof가 iframe이나 다른 realm에서 실패하는 문제
function handleError(val) {
  if (val instanceof Error) { // realm 문제로 신뢰 불가
    console.error(val.message);
  }
}

// ES2026: 신뢰할 수 있는 Error 확인
function handleError(val) {
  if (Error.isError(val)) { // 모든 realm에서 정확하게 작동
    console.error(val.message);
  }
}

실무 적용 가이드

ES2025 기능들은 Node.js 22+ 및 최신 브라우저에서 네이티브로 지원됩니다. Temporal API는 현재 폴리필(@js-temporal/polyfill)을 통해 미리 적용할 수 있으며, using 키워드는 TypeScript 5.2+에서 이미 지원하고 있어 실무에서 즉시 활용 가능합니다. 특히 Iterator Helpers와 Set 메서드는 기존 lodash 의존성을 줄이고 코드를 단순화하는 데 즉각적인 효과가 있습니다.