ES2024-2025 최신 JavaScript 문법 총정리

ES2024-2025 주요 변경사항

JavaScript는 매년 ECMAScript 명세를 통해 새로운 기능이 추가됩니다. ES2024와 ES2025에는 개발 생산성을 크게 높이는 기능들이 포함되었습니다. 이 글에서는 실무에서 바로 사용할 수 있는 주요 기능들을 예제와 함께 정리합니다.

Object.groupBy / Map.groupBy (ES2024)

배열의 요소를 특정 기준으로 그룹화하는 정적 메서드입니다. lodash의 groupBy를 네이티브로 사용할 수 있게 되었습니다.

const products = [
  { name: "맥북 프로", category: "노트북", price: 2500000 },
  { name: "아이패드", category: "태블릿", price: 1200000 },
  { name: "갤럭시북", category: "노트북", price: 1800000 },
  { name: "갤럭시탭", category: "태블릿", price: 800000 },
  { name: "LG 그램", category: "노트북", price: 1600000 },
];

// Object.groupBy — 일반 객체로 그룹화
const byCategory = Object.groupBy(products, (p) => p.category);
console.log(byCategory);
// {
//   "노트북": [
//     { name: "맥북 프로", category: "노트북", price: 2500000 },
//     { name: "갤럭시북", category: "노트북", price: 1800000 },
//     { name: "LG 그램", category: "노트북", price: 1600000 },
//   ],
//   "태블릿": [
//     { name: "아이패드", category: "태블릿", price: 1200000 },
//     { name: "갤럭시탭", category: "태블릿", price: 800000 },
//   ]
// }

// 가격대별 그룹화
const byPriceRange = Object.groupBy(products, (p) => {
  if (p.price >= 2000000) return "프리미엄";
  if (p.price >= 1000000) return "중급";
  return "보급형";
});
console.log(Object.keys(byPriceRange));
// ["프리미엄", "중급", "보급형"]

// Map.groupBy — Map 객체로 그룹화 (키에 객체 사용 가능)
const byMap = Map.groupBy(products, (p) => p.category);
console.log(byMap.get("노트북").length);  // 3
메서드반환 타입키 타입용도
Object.groupBy일반 객체문자열/심볼단순 그룹화
Map.groupByMap모든 타입객체를 키로 사용할 때

Promise.withResolvers (ES2024)

Promise 생성과 동시에 resolve, reject 함수를 외부로 꺼내는 유틸리티입니다. 콜백 패턴에서 Promise로 전환할 때 특히 유용합니다.

// 기존 방식: resolve/reject를 외부에서 사용하려면 변수 선언 필요
let externalResolve;
let externalReject;
const oldPromise = new Promise((resolve, reject) => {
  externalResolve = resolve;
  externalReject = reject;
});

// ES2024 방식: 한 줄로 해결
const { promise, resolve, reject } = Promise.withResolvers();

// 실전 예시: 이벤트 기반 코드를 Promise로 변환
function waitForEvent(element, eventName, timeoutMs = 5000) {
  const { promise, resolve, reject } = Promise.withResolvers();

  const timer = setTimeout(() => {
    reject(new Error(`${eventName} 이벤트 ${timeoutMs}ms 타임아웃`));
  }, timeoutMs);

  element.addEventListener(eventName, (event) => {
    clearTimeout(timer);
    resolve(event);
  }, { once: true });

  return promise;
}

// 사용 예시 (브라우저 환경)
// const event = await waitForEvent(button, "click", 3000);

// 실전 예시: 큐 기반 작업 처리
class TaskQueue {
  #queue = [];

  enqueue(task) {
    const { promise, resolve, reject } = Promise.withResolvers();
    this.#queue.push({ task, resolve, reject });
    this.#process();
    return promise;
  }

  async #process() {
    while (this.#queue.length > 0) {
      const { task, resolve, reject } = this.#queue.shift();
      try {
        const result = await task();
        resolve(result);
      } catch (error) {
        reject(error);
      }
    }
  }
}

Array.fromAsync (ES2024)

비동기 이터러블에서 배열을 생성합니다. Array.from의 비동기 버전입니다.

// 비동기 제너레이터
async function* fetchPages(totalPages) {
  for (let page = 1; page <= totalPages; page++) {
    // API 호출 시뮬레이션
    await new Promise((r) => setTimeout(r, 100));
    yield { page, items: [`항목_${page}_1`, `항목_${page}_2`] };
  }
}

// 비동기 이터러블을 배열로 변환
const pages = await Array.fromAsync(fetchPages(3));
console.log(pages);
// [
//   { page: 1, items: ["항목_1_1", "항목_1_2"] },
//   { page: 2, items: ["항목_2_1", "항목_2_2"] },
//   { page: 3, items: ["항목_3_1", "항목_3_2"] },
// ]

// 매핑 함수와 함께 사용
const pageNumbers = await Array.fromAsync(
  fetchPages(3),
  (data) => data.page
);
console.log(pageNumbers);  // [1, 2, 3]

Set 메서드 (ES2025)

집합 연산 메서드가 추가되어 교집합, 합집합, 차집합 등을 간편하게 수행할 수 있습니다.

const frontendSkills = new Set(["JavaScript", "React", "CSS", "TypeScript"]);
const backendSkills = new Set(["Node.js", "Python", "TypeScript", "SQL"]);

// 교집합 — 두 집합에 모두 포함된 요소
const common = frontendSkills.intersection(backendSkills);
console.log([...common]);  // ["TypeScript"]

// 합집합 — 두 집합의 모든 요소
const allSkills = frontendSkills.union(backendSkills);
console.log([...allSkills]);
// ["JavaScript", "React", "CSS", "TypeScript", "Node.js", "Python", "SQL"]

// 차집합 — 첫 번째 집합에만 있는 요소
const onlyFrontend = frontendSkills.difference(backendSkills);
console.log([...onlyFrontend]);  // ["JavaScript", "React", "CSS"]

// 대칭 차집합 — 한쪽에만 있는 요소
const exclusive = frontendSkills.symmetricDifference(backendSkills);
console.log([...exclusive]);
// ["JavaScript", "React", "CSS", "Node.js", "Python", "SQL"]

// 부분집합 검사
const coreSkills = new Set(["JavaScript", "TypeScript"]);
console.log(coreSkills.isSubsetOf(frontendSkills));    // true
console.log(frontendSkills.isSupersetOf(coreSkills));  // true
console.log(frontendSkills.isDisjointFrom(backendSkills));  // false
메서드설명수학 기호
intersection교집합A ∩ B
union합집합A ∪ B
difference차집합A - B
symmetricDifference대칭 차집합A △ B
isSubsetOf부분집합 여부A ⊆ B
isSupersetOf상위집합 여부A ⊇ B
isDisjointFrom서로소 여부A ∩ B = ∅

Iterator.prototype 헬퍼 (ES2025)

이터레이터에 map, filter, take 등의 지연(lazy) 메서드가 추가되었습니다. 배열 메서드와 달리 중간 배열을 생성하지 않아 대용량 데이터 처리에 효율적입니다.

// 대용량 데이터에서 조건에 맞는 처음 5개만 추출
function* naturalNumbers() {
  let n = 1;
  while (true) {
    yield n++;
  }
}

// 무한 이터레이터에서 짝수만 골라 처음 5개 추출
const firstFiveEvens = naturalNumbers()
  .filter((n) => n % 2 === 0)  // 지연 필터링
  .map((n) => n * n)            // 지연 매핑
  .take(5)                      // 처음 5개
  .toArray();                   // 배열로 변환

console.log(firstFiveEvens);  // [4, 16, 36, 64, 100]

// .drop()으로 앞부분 건너뛰기
const result = naturalNumbers()
  .filter((n) => n % 3 === 0)
  .drop(2)    // 처음 2개 건너뛰기 (3, 6 건너뜀)
  .take(3)    // 그 다음 3개 (9, 12, 15)
  .toArray();
console.log(result);  // [9, 12, 15]

배열의 map/filter는 즉시 실행되어 중간 배열을 생성하지만, Iterator 헬퍼는 지연 평가되어 toArray() 호출 시점에 실제 연산이 수행됩니다. 무한 시퀀스도 안전하게 처리할 수 있습니다.

정리

ES2024-2025에 추가된 주요 기능들은 실무에서 자주 사용되는 패턴을 네이티브로 지원합니다.

  • Object.groupBy: 배열 요소를 기준별로 그룹화 (lodash 불필요)
  • Promise.withResolvers: Promise의 resolve/reject를 외부로 분리
  • Array.fromAsync: 비동기 이터러블을 배열로 변환
  • Set 메서드: 교집합, 합집합, 차집합 등 집합 연산
  • Iterator 헬퍼: map, filter, take 등 지연 평가 메서드
  • 브라우저 호환성: 주요 브라우저는 대부분 지원하지만, Iterator 헬퍼는 폴리필이 필요할 수 있습니다

이 글이 도움이 되었나요?