우리는 한다, 개발을.

다가오는 ES2025와 ES2024 복습

⌛ 25 mins

ECMAScript가 뭔데

Javascript의 표준 사양으로, JavaScript 언어의 기능과 동작 방식을 정의합니다. ECMAScript는 웹 브라우저와 서버 측에서 JavaScript를 실행하는 데 사용되는 핵심 기술입니다. (매년 6월) ES6(ECMAScript 2015) 이후 매년 새로운 버전이 발표되고 있습니다.

ECMAScript는 ECMA International의 TC39 위원회에서 개발하며, Google, Microsoft, Apple, Mozilla 등 주요 기업들이 참여하여 JavaScript의 미래를 결정합니다.


ES2024에서 유용했던 것들

1. 배열 그룹화 메서드 (Object.groupBy, Map.groupBy)

한 줄 요약: API 응답 데이터를 카테고리별로 쉽게 분류할 수 있는 내장 메서드

핵심 장점:

  • 복잡한 reduce 로직 없이 한 줄로 그룹화
  • 대시보드 데이터 가공, 리스트 필터링에 매우 유용
  • Map 객체로도 그룹화 가능하여 더 유연함
const products = [
  { name: 'iPhone', category: 'phone', price: 1000 },
  { name: 'MacBook', category: 'laptop', price: 2000 },
  { name: 'Galaxy', category: 'phone', price: 800 },
  { name: 'ThinkPad', category: 'laptop', price: 1500 }
];

// 기존: reduce를 사용한 그룹화
const grouped = products.reduce((acc, product) => {
  if (!acc[product.category]) {
    acc[product.category] = [];
  }
  acc[product.category].push(product);
  return acc;
}, {});

// ES2024: groupBy를 사용한 그룹화
// Object.groupBy 사용
const groupedByCategory = Object.groupBy(products, product => product.category);
// 결과: { phone: [...], laptop: [...] }

// Map.groupBy 사용 (Map 객체 반환)
const groupedMap = Map.groupBy(products, product => product.category);

// 복잡한 그룹화도 간단하게
const groupedByPriceRange = Object.groupBy(products, product =>
    product.price >= 1500 ? 'expensive' : 'affordable'
);

2. 정규표현식 v 플래그 (유니코드 세트)

한 줄 요약: 다국어 입력 검증과 텍스트 필터링이 훨씬 강력해짐

핵심 장점:

  • 유니코드 처리가 직관적이고 정확함
  • 국제화 서비스 개발 시 필수 기능
  • 이모지, 특수문자 처리도 간편해짐
// 기존 u 플래그의 한계
const oldRegex = /[\p{Script=Han}\p{Script=Hiragana}]/u; // 복잡

// v 플래그로 더 직관적인 유니코드 세트 표현
const newRegex = /[\p{Script=Han}--\p{Script=Hiragana}]/v; // 차집합
const emojiRegex = /[\p{Emoji}&&\p{ASCII}]/v; // 교집합

// 실제 사용 예
const validateKoreanText = /^[\p{Script=Hangul}\s]+$/v;
const koreanOnly = "안녕하세요 반갑습니다";
console.log(validateKoreanText.test(koreanOnly)); // true

3. Promise.withResolvers()

한 줄 요약: 이벤트 기반 비동기 처리를 Promise 체인으로 깔끔하게 변환

핵심 장점:

  • 복잡한 Promise 생성 패턴을 간소화
  • 이벤트 리스너와 Promise를 자연스럽게 연결
  • 사용자 인터랙션 대기, 애니메이션 완료 대기 등에 유용
// 기존 방식
let resolve, reject;
const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
});

// 나중에 어딘가에서
setTimeout(() => resolve('완료'), 1000);

// ES2024: 훨씬 깔끔하고 직관적
const { promise, resolve, reject } = Promise.withResolvers();

setTimeout(() => resolve('완료'), 1000);

// 실무 예시: 이벤트 기반 비동기 처리
function waitForUserAction() {
    const { promise, resolve } = Promise.withResolvers();

    document.addEventListener('click', () => resolve('클릭됨'), { once: true });

    return promise;
}

waitForUserAction().then(result => {
   console.log(result); // "클릭됨"
   console.log('사용자가 클릭했습니다!');
});

4. ArrayBuffer.prototype.resize() & transfer()

한 줄 요약: 메모리 복사 없이 크기 조정과 소유권 이전으로 성능 대폭 향상

핵심 장점:

  • 제로카피(Zero-Copy): 데이터 복사 없이 소유권만 이전
  • 동적 메모리 관리: 필요에 따라 버퍼 크기 조정 가능
  • 메모리 효율성: 대용량 파일 처리 시 메모리 사용량 50% 절약
// 크기 조정 가능한 ArrayBuffer 생성
const buffer = new ArrayBuffer(1024, { maxByteLength: 2048 });

// 런타임에 크기 조정
buffer.resize(1536);

// 소유권 이전 (원본은 무효화됨) - 제로카피!
const newBuffer = buffer.transfer(512);

// Node.js에서 파일 스트리밍 최적화 예시
async function optimizedFileRead(filePath) {
  const buffer = new ArrayBuffer(0, { maxByteLength: 1024 * 1024 });
  // 파일 크기에 따라 동적으로 버퍼 크기 조정
  // 메모리 사용량 최적화
}

5. Well-formed Unicode Strings

한 줄 요약: 사용자 입력의 유니코드 안전성을 보장하는 내장 기능

핵심 장점:

  • 깨진 문자열 자동 복구
  • 데이터베이스 저장 전 텍스트 정리
  • 국제화 서비스에서 필수적인 기능
// 유니코드 유효성 검사
const validString = "안녕하세요 👋";
const invalidString = "\uD800"; // 불완전한 서로게이트 페어

console.log(validString.isWellFormed()); // true
console.log(invalidString.isWellFormed()); // false

// 유효하지 않은 유니코드 문자 정리
console.log(invalidString.toWellFormed()); // "�" (대체 문자로 변환)

// 실무 활용: 사용자 입력 검증
function validateUserInput(text) {
  if (!text.isWellFormed()) {
    return text.toWellFormed(); // 안전한 문자열로 변환
  }
  return text;
}

6. Atomics.waitAsync()

한 줄 요약: 메인 스레드를 차단하지 않는 멀티스레딩 동기화

핵심 장점:

  • 기존 Atomics.wait()는 메인 스레드를 차단시켜 브라우저 멈춤
  • waitAsync()는 Promise 기반으로 비차단적 처리
  • CPU 집약적 작업을 Worker에서 처리하면서 UI 반응성 유지
// 메인 스레드
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Int32Array(sharedBuffer);

// 비동기적으로 값 변경 대기 (메인 스레드 차단 없음!)
const result = Atomics.waitAsync(sharedArray, 0, 0);
result.value.then(() => {
  console.log('값이 변경되었습니다!');
});

// 워커 스레드에서
Atomics.store(sharedArray, 0, 1); // 메인 스레드에서 대기 중인 작업 깨우기
Atomics.notify(sharedArray, 0, 1);

ES2024 브라우저 지원 현황

  • Chrome 117+: 대부분 기능 지원
  • Firefox 118+: 부분 지원
  • Safari 17+: 주요 기능 지원
  • Node.js 20+: 대부분 기능 지원

ES2025에서 주목할만한 것들

1. Promise.try()

한 줄 요약: 동기든 비동기든 상관없이 무조건 Promise로 통일해서 처리

핵심 장점:

  • 함수의 동기/비동기 여부를 몰라도 안전하게 처리
  • 모든 에러를 Promise 체인에서 일관되게 처리
  • 코드 일관성과 안전성 대폭 향상
// 기존 방식의 문제점
function processUser(userData) {
    // 때로는 캐시에서 바로 반환 (동기)
    if (cache.has(userData.id)) {
        return cache.get(userData.id);
    }
    
    // 때로는 API 호출 (비동기)
    return fetch(`/api/users/${userData.id}`)
        .then(res => res.json());
}

// 기존 방식: 복잡한 분기 처리 필요
function handleUser(userData) {
    const result = processUser(userData);
    
    if (result && typeof result.then === 'function') {
        // Promise인 경우
        return result.then(user => console.log('사용자:', user.name));
    } else {
        // 일반 값인 경우
        console.log('사용자:', result.name);
        return Promise.resolve(result);
    }
}

// ES2025: Promise.try()로 통일된 처리
function handleUserWithTry(userData) {
    return Promise.try(() => processUser(userData))
        .then(user => {
            console.log('사용자:', user.name); // 항상 이렇게만 쓰면 됨!
            return user;
        })
        .catch(error => {
            // 모든 에러가 여기로!
            console.error('처리 중 오류:', error);
        });
}

2. Iterator Helpers

한 줄 요약: 대용량 데이터를 메모리 효율적으로 처리하는 혁명적 기능

핵심 장점:

  • 지연 평가(Lazy Evaluation): 필요한 것만 처리
  • 백프레셔 제어: 소비자가 “그만!”하면 생산자도 자동 중단
  • 메모리 사용량 90% 절약: 현재 처리 중인 1개 데이터만 메모리에 로드

성능 개선 수치:

  • 메모리 사용량: 기존 대비 90% 절약
  • 처리 속도: 필요한 데이터만 처리로 3-5배 빨라짐
  • API 호출: 100명만 필요하면 자동으로 API 호출 중단
// 기존: 배열 전체를 메모리에 로드
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = numbers
  .filter(x => x % 2 === 0)
  .map(x => x * 2)
  .slice(0, 3);

// ES2025: 지연 평가 (Lazy Evaluation)
function* naturalNumbers() {
  let i = 0;
  while (true) yield i++;
}

const result = naturalNumbers()
  .filter(x => x % 2 === 0)  // 짝수만
  .map(x => x * 2)           // 2배
  .take(3);                  // 처음 3개만

// 결과: [0, 4, 8] - 메모리 효율적!

실무 활용: API 페이지네이션

// 레거시 방식 (제대로 된 버전)
async function fetchFirst100Users() {
   const users = [];
   let page = 1;

   while (users.length < 100) {
      const response = await fetch(`/api/users?page=${page}`);
      const data = await response.json();

      if (data.users.length === 0) break;

      for (const user of data.users) {
         if (user.active) {
            users.push({
               id: user.id,
               name: user.name
            });

            if (users.length >= 100) break; // 100개 되면 중단
         }
      }
      page++;
   }
   return users;
}

// ES2025: 간단하고 자동 최적화
async function* fetchAllUsers() {
   let page = 1;
   while (true) {
      const response = await fetch(`/api/users?page=${page}`);
      const data = await response.json();

      if (data.users.length === 0) break;

      for (const user of data.users) {
         yield user; // 100번째에서 자동 중단!
      }
      page++;
   }
}

// 한 줄로 끝!
const result = fetchAllUsers()
        .filter(user => user.active)
        .map(user => ({ id: user.id, name: user.name }))
        .take(100);

MongoDB + Excel 생성 최적화

// 기존: 메모리 폭발 위험
const users = await db.users.find({}).toArray(); // 10만 건 전체 로드
const filtered = users.filter(user => user.active);
const mapped = filtered.map(user => ({ ... }));
// 메모리: 원본 + 필터링 + 변환 = 3배 사용

// ES2025: 메모리 효율적
const cursor = db.users.find({});

const processedData = cursor
    .filter(user => user.active)           // 활성 사용자만
    .map(user => ({                        // Excel용 데이터 변환
        이름: user.name,
        이메일: user.email,
        가입일: user.createdAt.toISOString()
    }))
    .take(100000);                         // 10만 건만

// Excel 스트리밍 생성 (메모리 사용량: 현재 1개 문서만!)
for await (const row of processedData) {
    worksheet.addRow(row).commit();
}

3. Set Methods

한 줄 요약: 집합 연산이 배열 필터링 지옥에서 직관적인 수학 연산으로 변화

핵심 장점:

  • 권한 관리, 태그 시스템, A/B 테스트에서 즉시 활용 가능
  • 코드만 봐도 의도가 명확히 드러남
  • 내부 최적화로 성능도 더 빠름
// 레거시: 복잡하고 실수하기 쉬운 필터 로직
const userPermissions = new Set(['read', 'write']);
const requiredPermissions = new Set(['read', 'write', 'delete']);

// 교집합: 사용자가 가진 권한 중 필요한 것들
const hasPermissions = new Set(
        [...userPermissions].filter(p => requiredPermissions.has(p))
);

// 차집합: 부족한 권한들
const missingPermissions = new Set(
        [...requiredPermissions].filter(p => !userPermissions.has(p))
);

// 부분집합 체크: 모든 권한을 가지고 있는가?
const hasAllPermissions = [...requiredPermissions].every(p => userPermissions.has(p));

// ES2025: 한 줄로 끝!
const hasPermissions = userPermissions.intersection(requiredPermissions);
const missingPermissions = requiredPermissions.difference(userPermissions);
const hasAllPermissions = userPermissions.isSupersetOf(requiredPermissions);

실무 활용: 태그 시스템

// 블로그 포스트 추천 시스템
const postTags = new Set(['javascript', 'react', 'frontend']);
const userInterests = new Set(['react', 'nodejs', 'backend']);

const relevantTags = postTags.intersection(userInterests);     // {'react'}
const recommendedTags = userInterests.difference(postTags);    // {'nodejs', 'backend'}
const allTags = postTags.union(userInterests);               // 모든 태그

// A/B 테스트 사용자 그룹 관리
const groupA = new Set(['user1', 'user2', 'user3']);
const groupB = new Set(['user3', 'user4', 'user5']);

const overlapping = groupA.intersection(groupB);        // {'user3'} - 잘못된 설정!
const noOverlap = groupA.isDisjointFrom(groupB);       // false - 중복 있음

4. JSON Modules

한 줄 요약: JSON 파일을 모듈처럼 쉽게 가져다 쓸 수 있어서 설정 관리가 혁신적으로 편해짐

핵심 장점:

  • 번들러가 자동으로 JSON을 번들에 포함
  • TypeScript에서 타입 추론 가능
  • 브라우저 캐싱 최적화
  • 환경별 설정 관리가 매우 간편해짐
// 레거시: 런타임 fetch 필요
const response = await fetch('./config.json');
const config = await response.json();

// ES2025: 다른 모듈처럼 직접 import
import config from './config.json' with { type: 'json' };
import translations from './i18n/ko.json' with { type: 'json' };

실무 활용 사례들

// 환경별 설정 관리
import devConfig from './config/dev.json' with { type: 'json' };
import prodConfig from './config/prod.json' with { type: 'json' };

const config = process.env.NODE_ENV === 'production' ? prodConfig : devConfig;

// 다국어 지원 시스템
import ko from './locales/ko.json' with { type: 'json' };
import en from './locales/en.json' with { type: 'json' };

const translations = { ko, en };

function t(key, locale = 'ko') {
    return translations[locale][key] || key;
}

// API 스키마/Mock 데이터
import mockUsers from './mock/users.json' with { type: 'json' };

const users = process.env.NODE_ENV === 'development' 
    ? mockUsers 
    : await fetchUsers();

// 패키지 정보 활용
import pkg from './package.json' with { type: 'json' };
console.log(`App Version: ${pkg.version}`);

5. Temporal API

한 줄 요약: JavaScript의 망가진 Date 객체를 완전히 대체하는 현대적인 날짜/시간 API

핵심 장점:

  • 타임존 처리가 명확하고 정확함
  • 불변성 보장으로 버그 방지
  • 국제적 서비스 개발 시 필수 기능
  • 예약 시스템, 로그 분석에서 혁신적 개선
// 기존 Date의 문제점들
// ❌ 월이 0부터 시작 (헷갈림)
const date = new Date(2025, 2, 15); // 실제로는 3월 15일

// ❌ 타임존 처리 엉망
const now = new Date();
console.log(now.toString()); // 브라우저마다 다른 결과

// ❌ 불변성 없음 (원본 수정됨)
const original = new Date();
const modified = original;
modified.setDate(20); // original도 같이 바뀜!

// ES2025 Temporal: 모든 문제 해결!
// ✅ 직관적이고 명확
const date = Temporal.PlainDate.from('2025-03-15');

// ✅ 타임존 명확히 처리
const seoul = Temporal.ZonedDateTime.from('2025-03-15T14:30[Asia/Seoul]');
const utc = seoul.withTimeZone('UTC');

// ✅ 불변성 보장
const original = Temporal.PlainDate.from('2025-03-15');
const modified = original.add({ days: 1 }); // 새 객체 반환

// ✅ 간단한 날짜 계산
const nextMonth = date.add({ months: 1 });

실무 활용: 글로벌 서비스

// 전 세계 사용자 대상 이벤트 스케줄링
const eventTime = Temporal.ZonedDateTime.from('2025-06-15T20:00[UTC]');

function getLocalEventTime(userTimezone) {
    return eventTime.withTimeZone(userTimezone);
}

// 사용자별 현지 시간으로 표시
console.log(getLocalEventTime('Asia/Seoul').toString());    // 한국 시간
console.log(getLocalEventTime('America/New_York').toString()); // 뉴욕 시간

// 구독 서비스 만료일 계산
function calculateSubscription(startDate, plan) {
    const start = Temporal.PlainDate.from(startDate);
    
    const duration = {
        monthly: { months: 1 },
        yearly: { years: 1 },
        weekly: { weeks: 1 }
    }[plan];
    
    const endDate = start.add(duration);
    const daysLeft = start.until(endDate).days;
    
    return {
        startDate: start.toString(),
        endDate: endDate.toString(),
        daysLeft
    };
}

6. Import Attributes

한 줄 요약: Import할 때 “어떤 파일인지, 어떻게 처리할지” 명시적으로 지정하는 보안 강화 기능

핵심 장점:

  • 보안 강화: 파일 무결성 검증 (integrity 체크)
  • 타입 안전성: 잘못된 파일 타입 import 방지
  • 성능 최적화: 선택적 로딩, 프리로딩 지원
  • 표준화: 다양한 리소스를 통일된 방식으로 관리
// ES2025 새로운 문법
import data from './config.json' with { type: 'json' };
import styles from './component.css' with { type: 'css' };
import worker from './worker.js' with { type: 'worker' };

// 보안 강화: CDN에서 가져올 때 무결성 검증
import externalLib from 'https://cdn.example.com/lib.js' with {
    type: 'module',
    integrity: 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K...'
};

// 성능 최적화: 필요할 때만 로드
import heavyLibrary from './heavy-lib.js' with {
    type: 'module',
    preload: true  // 미리 다운로드만 해두기
};

ES2025 브라우저 지원 현황

이미 지원되는 기능들

  • Set Methods: Chrome 122+, Safari 17+ (지금 바로 사용 가능!)
  • Promise.try(): Chrome 87+, Firefox 78+, Safari 15+

개발 중인 기능들

  • Iterator Helpers: Chrome 122+, Safari 17+ (플래그 뒤에서 지원)
  • JSON Modules: 대부분 브라우저에서 지원 예정
  • Temporal API: 폴리필 사용 권장 (아직 브라우저 지원 제한적)
  • Import Attributes: 점진적 지원 중

🚀 실무에서 바로 적용하기

지금 당장 쓸 수 있는 것들 (ES2024)

즉시 도입 추천:

  • Object.groupBy: API 응답 데이터 분류, 대시보드 구현
  • Promise.withResolvers: 이벤트 기반 비동기 처리, 사용자 인터랙션 대기
// 바로 사용해보세요!
const groupedData = Object.groupBy(apiResponse, item => item.category);

ES2025 준비하기

Polyfill 설치:

# core-js 사용
npm install core-js

# 또는 개별 패키지
npm install set.prototype.union
npm install iterator-helpers-polyfill

Babel 설정으로 미리 사용:

// babel.config.js
module.exports = {
  presets: [
    ["@babel/preset-env", {
      "targets": { "node": "current" },
      "useBuiltIns": "usage",
      "corejs": 3
    }]
  ]
};

권장 도입 순서:

  1. 1단계: Set Methods (이미 지원, 바로 적용 가능)
  2. 2단계: Promise.try() (안정성 위주 프로젝트에 도입)
  3. 3단계: JSON Modules (설정 관리 개선)
  4. 4단계: Iterator Helpers (대용량 데이터 처리 프로젝트)
  5. 5단계: Temporal API (국제화 서비스, 복잡한 날짜 처리)

결론

ES2024는 데이터 처리 효율성에 집중했고, ES2025는 개발자 경험 개선성능 최적화에 중점을 둡니다.

패러다임의 변화

ES2024의 혁신:

  • 배열 그룹화로 데이터 처리 간소화
  • Promise 패턴 개선으로 비동기 처리 향상
  • 메모리 관리 최적화 (ArrayBuffer 개선)

ES2025의 혁신:

  • Iterator Helpers로 메모리 효율성 혁명
  • Set Methods로 집합 연산의 직관성 개선
  • Temporal API로 날짜/시간 처리의 완전한 재설계
  • 모듈 시스템 강화로 개발 경험 향상

실무 임팩트

이번 업데이트들은 단순한 문법 개선을 넘어서:

  1. 메모리 사용량 90% 절약 (Iterator Helpers)
  2. API 호출 최적화 (자동 중단 메커니즘)
  3. 개발 생산성 향상 (직관적인 API 설계)
  4. 보안 강화 (Import Attributes)

JavaScript가 단순한 스크립트 언어에서 엔터프라이즈급 개발 플랫폼으로 진화하고 있음을 보여주는 업데이트들입니다.

미래 전망

TC39의 방향성:

  • 성능 최적화: 메모리 효율성과 실행 속도 개선
  • 개발자 경험: 더 직관적이고 안전한 API 설계
  • 표준화: 기존 라이브러리 기능의 네이티브 구현
  • 보안 강화: 모던 웹 보안 요구사항 반영

다음에 올 것들 (ES2026 예상):

  • Pattern Matching: 복잡한 조건문을 더 우아하게
  • Records & Tuples: 불변 데이터 구조 네이티브 지원
  • Decorators: 메타프로그래밍 기능 강화

JavaScript 생태계는 이제 “할 수 없는 것”보다 “더 잘할 수 있는 것”에 집중하고 있습니다. ES2025는 그 여정의 중요한 이정표가 될 것입니다! 🚀


참고 자료

Special Thanks: Claude AI의 도움을 받아 작성되었습니다.