ES2026, 자바스크립트에 이런 기능까지? 10년차 실무자가 기대하는 7가지 업데이트와 2가지 희망사항
2026. 6. 28.
ES2026, 자바스크립트에 이런 기능까지? 10년차 실무자가 기대하는 7가지 업데이트와 2가지 희망사항
2주 전, '앞으로는 가볍고 쉬운 글만 쓰겠다'고 (스스로에게) 다짐했던 제가 기억납니다. 음… 그 약속을 깨버렸네요 😅 지난주에는 개발자들이 가장 피하고 싶은 주제 중 하나인 레거시 애플리케이션에 대한 방대한 글을 발행했죠. 그럼에도 불구하고 DEV 편집팀이 좋게 봐주셨는지, 주간 인기 글 Top 7에 선정되는 기염을 토했습니다 ❤️
하지만 드디어 오늘은 좀 더 가벼운 주제로 돌아왔습니다. 게다가 이 주제는 충분히 더 많은 관심을 받을 자격이 있다고 생각해요.
요즘 우리는 AI 에이전트에 대한 이야기를 많이 나누고 있습니다. 물론 저도 왜 그런지 충분히 이해합니다. 정말 매력적인 분야니까요. 하지만 가끔은 우리가 매일 사용하는 프로그래밍 언어 자체도 끊임없이 발전하고 있다는 사실을 잊고 지내는 것 같아요.
저는 대부분의 시간을 자바스크립트(물론… 타입스크립트겠죠? 😄)를 작성하며 보냅니다. 지난 몇 년간 생태계가 정말 많이 성숙해졌죠. 더 이상 끝없는 리액트 vs 앵귤러 전쟁도 없고, "한 달 전에는 리덕스를 사랑하다가 6개월 뒤에는 과하게 복잡한 괴물이라며 모든 앱에서 제거했던" 그런 시대도 대체로 지나갔습니다 😅.
하지만 생태계와 더불어 ECMAScript 표준 역시 진화를 멈추지 않습니다.
2015년 프론트엔드 개발의 판도를 영원히 바꿔놓은 전설적인 ES6 릴리스 이후, TC39 위원회는 반복적인 접근 방식을 채택해 매년 새로운 기능을 출시하기 시작했습니다.
그리고 정말 좋은 점은 현대적인 브라우저나 런타임을 사용한다면, 이러한 신기능들을 거의 즉시 활용할 수 있다는 것이죠.
그럼, ECMAScript 2026에서는 어떤 것들을 만나볼 수 있을까요?
아, 그리고 흥미를 더하기 위해 이 글의 모든 코드 예시는 매우 강한 의견을 가진 가상의 '링크드인 현자'들의 내면의 독백을 기반으로 합니다. 실제 인물과의 유사성은 물론, 순전히 우연입니다 😇.
이 시리즈의 다른 글들도 살펴보세요:
- 라이브러리 설치를 멈춰라: 이미 문제를 해결하는 10가지 브라우저 API
- 과도하게 설계하는 9가지 — 브라우저가 이미 해결했습니다
- 당신을 놀라게 할 수도 있는 16가지 현대 자바스크립트 기능
1. Map.prototype.getOrInsert() / Upsert
이 기능은 "잠깐… 왜 이게 10년 전에는 없었지?"라는 생각을 들게 하는 종류입니다.
링크드인 현자들의 의견을 수집한다고 가정해봅시다. 지금까지는 이렇게 코드를 작성해야 했습니다.
const opinions = new Map();
function addOpinion(topic, author) {
if (!opinions.has(topic)) {
opinions.set(topic, []);
}
opinions.get(topic).push(author);
}
addOpinion("React is dead", "10x Engineer");
addOpinion("React is dead", "Principal AI Evangelist");
잘 작동하지만, 반복적인 코드가 꽤 많습니다.
ES2026에서는 상황이 훨씬 깔끔해집니다.
const opinions = new Map();
opinions
.getOrInsert("React is dead", [])
.push("10x Engineer");
opinions
.getOrInsert("React is dead", [])
.push("Principal AI Evangelist");
console.log(opinions);
계산된 버전(getOrInsertComputed)도 제공됩니다.
const opinions = new Map();
opinions
.getOrInsertComputed(
"Nobody writes clean code anymore",
() => []
)
.push("DDD Purist");
정말 훨씬 더 간결하고 읽기 쉽지 않나요? 캐싱 로직을 짤 때마다 이 기능의 부재가 아쉬웠는데, 이제야 빛을 보게 되는군요. 코드 양이 줄어들고 API도 훨씬 직관적입니다.
2. Iterator.concat()
concat()에 대해 이야기하기 전에, 한 가지 질문에 답해봅시다.
이터레이터(Iterator)란 무엇인가요?
이터레이터는 기본적으로 데이터를 한 번에 하나의 요소씩 소비할 수 있게 해주는 커서입니다. 모든 데이터를 메모리에 한꺼번에 저장하지 않아도 된다는 장점이 있죠.
예를 들면 다음과 같습니다.
const posts = [
"Angular is dead",
"JavaScript was a mistake"
];
const iterator = posts.values();
console.log(iterator.next());
// { value: "Angular is dead", done: false }
console.log(iterator.next());
// { value: "JavaScript was a mistake", done: false }
console.log(iterator.next());
// { value: undefined, done: true }
그리고 이터레이터는 '게으르기(lazy)' 때문에, 메모리를 폭파시키지 않고도 무한 시퀀스를 생성할 수 있습니다.
function* endlessHotTakes() {
while (true) {
yield "Everything should be rewritten in Rust.";
}
}
const iterator = endlessHotTakes();
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);
작년에는 map(), filter() 같은 도우미 함수들을 포함하는 Iterator Helpers가 도입되었습니다.
function* linkedinFeed() {
yield "Use Rust for everything";
yield "JavaScript was a mistake";
yield "Clean code is dead";
yield "Angular is dead";
}
const controversialTakes =
linkedinFeed()
.filter(post => post.includes("dead"))
.map(post => `🔥 ${post}`);
console.log([...controversialTakes]);
그리고 이제 또 다른 유용한 기능인 Iterator.concat()이 추가되었습니다. 프론트엔드 현자들과 백엔드 현자들이 각각 자신들의 지혜의 스트림을 가지고 있다고 가정해봅시다.
function* frontendExperts() {
yield "React is dead";
yield "Nobody needs Redux";
}
function* backendExperts() {
yield "Microservices solve everything";
yield "Frontend developers don't understand architecture";
}
이제 이들을 우아하게 결합할 수 있습니다.
const feed = Iterator.concat(
frontendExperts(),
backendExperts()
);
console.log([...feed]);
제 생각에 이러한 이터레이터 관련 기능들은 받아 마땅한 관심만큼 주목받지 못하는 경향이 있습니다.
3. Array.fromAsync()
이 기능은 우리가 사랑하는 Array.from()의 비동기 버전이라고 생각하면 쉽습니다.
주로 비동기 이터레이터를 위해 설계되었지만, 대부분의 자바스크립트 개발자들이 비동기 이터레이터를 매일 사용하지는 않을 겁니다. 예를 들어, 링크드인에서 댓글이 하나씩 도착하는 상황을 상상해 보세요.
async function* angryComments() {
yield "This could have been a plain HTML form.";
yield "Angular is dead.";
yield "React is dead.";
yield "JavaScript was a mistake.";
}
const comments = await Array.fromAsync(
angryComments()
);
console.log(comments);
// 이 코드는 일반 HTML 폼으로 만들 수도 있었습니다.
// Angular는 죽었습니다.
// 등등
하지만 많은 사람이 모르는 사실이 있습니다. 이것은 프로미스(Promise)와도 함께 작동합니다.
const opinions = [
Promise.resolve("Nobody should use classes."),
Promise.resolve("Signals change everything."),
Promise.resolve("Microservices ruined software.")
];
const takes = await Array.fromAsync(opinions);
console.log(takes);
심지어 값을 즉시 매핑할 수도 있습니다.
const comments = await Array.fromAsync(
angryComments(),
opinion => opinion.toUpperCase()
);
console.log(comments);
정말 편리하죠.
4. Math.sumPrecise()
이것은 인터넷 자체만큼이나 오래된 부동 소수점 문제를 해결해줍니다 😄 아마 많은 분이 아시다시피 자바스크립트에서는 다음과 같습니다.
console.log(0.1 + 0.2);
// 0.30000000000000004
오늘은 왜 이런 현상이 발생하는지 자세히 설명하지 않겠습니다. 그랬다간 밤새도록 이야기해야 할 테니까요 😄.
중요한 것은 ES2026이 Math.sumPrecise()를 도입하여 훨씬 더 정확한 합계를 계산하고 반올림 오류의 누적을 방지한다는 점입니다.
링크드인 현자가 생산성을 높인다고 주장하는 모든 것들을 나열하고 있다고 가정해봅시다.
const productivityBoosts = [
0.1, // 냉수 샤워
0.2, // AI 에이전트
0.3, // 일기 쓰기
0.4, // 새벽 4시 기상
];
console.log(
Math.sumPrecise(productivityBoosts)
);
솔직히 말해, 대부분의 프론트엔드 개발자는 이 기능을 거의 필요로 하지 않을 것입니다. 일상적인 사용에는 기존의 덧셈이 완벽하게 잘 작동하니까요.
하지만 금융, 통계, 시뮬레이션, 또는 AI/ML 분야에서 수천 또는 수백만 번의 연산에서 미세한 오류가 누적될 수 있는 작업을 한다면, 이 기능은 훨씬 더 흥미로워집니다. 프론트엔드 개발자인 제가 직접적으로 쓸 일은 많지 않겠지만, 금융 관련 데이터를 다루는 백엔드 팀이 이 부동 소수점 문제로 겪던 고통을 옆에서 지켜본 적이 있어 그들에게는 단비 같은 기능일 겁니다.
5. Error.isError()
이 기능은 아마도 라이브러리 개발자나 고급 개발자를 위한 것일 겁니다. 아니면 아닐까요? 😉 지금까지 어떤 것이 실제로 에러인지 확인하는 방법은 보통 다음과 같았습니다.
try {
throw new Error(
"Angular is dead."
);
}
catch (e) {
console.log(
e instanceof Error
);
}
대부분의 경우 이것은 완벽하게 잘 작동했습니다. 작동하지 않을 때까지는요.
에러가 다른 '영역(realm)', 예를 들어 iframe, Web Worker, 또는 VM 컨텍스트에서 발생했다면—instanceof Error는 갑자기 당신을 배신할 수 있었습니다.
const strangeThing =
window.frames[0].eval(
"new Error('JavaScript was a mistake.')"
);
console.log(
strangeThing instanceof Error
);
// false
이 문제는 수년간 라이브러리 개발자들을 괴롭혀왔고, 그래서 많은 프레임워크와 라이브러리가 에러를 감지하기 위한 자체 헬퍼 함수를 가지고 있었습니다. 이제 드디어 내장된 해결책을 얻게 되었습니다.
console.log(
Error.isError(strangeThing)
);
// true
간단하고 아름답습니다.
6. Uint8Array를 위한 Base64 인코딩/디코딩
간단히 상기하자면, Base64는 이진 데이터를 일반 텍스트로 변환하는 방법입니다. 왜 그렇게 할까요? 많은 프로토콜과 형식은 원시 바이트보다 텍스트를 다루는 것을 훨씬 더 선호하기 때문입니다. 예를 들어, 이미지를 Base64 문자열로 전송할 수 있죠.
누군가는 이렇게 말할지도 모릅니다: "잠깐만, 자바스크립트에 이미 Base64가 있었잖아!" 네, 맞습니다. 하지만 주로 문자열과 함께 작동했습니다.
btoa("JavaScript was a mistake.");
이진 데이터를 다룰 때는 상황이 빠르게 지저분해졌습니다.
const bytes = new Uint8Array(buffer);
const base64 = btoa(
String.fromCharCode(...bytes)
);
아주 나쁘지는 않지만, 확실히 우아하다고는 할 수 없는 코드였습니다.
이제는 단순히 이렇게 작성할 수 있습니다.
const screenshot =
await fetch(
"/proof/react-is-dead.png"
);
const bytes =
new Uint8Array(
await screenshot.arrayBuffer()
);
const base64 =
bytes.toBase64(); // toBase64() 뿐만 아니라 fromBase64()도 추가됩니다!
console.log(base64);
훨씬 깔끔해졌고, 어쩌면 더 중요한 것은 6개월 뒤에 다시 봐도 훨씬 이해하기 쉽다는 점입니다.
7. JSON.parse Source Text Access
JSON.parse()는 훌륭합니다. 하지만 누군가가 거대한 숫자를 보낼 때까지는요. 링크드인 현자가 999조 명의 팔로워를 가지고 있다고 주장한다고 가정해봅시다.
const json = `
{
"followers":
999999999999999999999999999999
}
`;
const data = JSON.parse(json);
console.log(data.followers);
이런. 자바스크립트 숫자는 한계가 있고, 매우 큰 정수는 정밀도를 잃을 수 있습니다.
ES2026에서는 reviver 콜백이 원래 소스 텍스트에 접근할 수 있게 되어, 큰 값을 안전하게 복구할 수 있습니다.
const data = JSON.parse(
json,
(key, value, context) => {
if (key === "followers") {
return BigInt(context.source);
}
return value;
}
);
console.log(data.followers);
더 이상 거대한 숫자의 우발적인 손상은 없을 겁니다.
우리 대부분은 이 기능을 매일 필요로 하지는 않을 겁니다. 하지만 ID, 금융 데이터, 또는 거대한 정수 값을 다루는 경우, 이것은 심각한 버그를 방지하는 데 도움이 될 수 있습니다.
보너스: 위대한 부재자들
솔직히 이 기능들이 ES2026에 포함되기를 정말 바랐지만, 아쉽게도 1년을 더 기다려야 할 것 같습니다.
음, 어느 정도는요. 최신 브라우저와 런타임은 이미 이 기능들을 구현하기 시작했지만, 아직 ECMAScript 2026 사양의 공식적인 일부는 아닙니다.
이 두 가지는 제가 개인적으로 가장 기대하는 기능들입니다.
Temporal API
프론트엔드 개발을 오래 했다면, 날짜와 관련된 최소 한 번의 트라우마를 겪었을 가능성이 높습니다. 아마도 이런 식이었겠죠.
const date = new Date("2026-03-30");
console.log(date);
당신의 시간대에 따라, 축하합니다! 당신은 방금 "왜 어제지?"라는 흥미진진한 세계에 진입했습니다.
아니면 모두가 좋아하는 이런 경험을 했을지도 모릅니다.
const today = new Date();
today.setMonth(today.getMonth() + 1);
그리고 갑자기 3월에 한 달을 더했는데 왜 5월이 되었는지 디버깅하고 있는 자신을 발견하죠.
혹은 운 좋게도 시간대(timezone)를 다뤄야 했을 수도 있습니다.
그 시점에서 당신은 시간 자체가 환상이고 일광 절약 시간(daylight saving time)은 프로그래머의 삶을 망치기 위해 특별히 발명되었다는 사실을 깨닫게 될 겁니다.
이것이 바로 우리 중 많은 사람이 Moment.js와 같은 라이브러리를 사용하게 된 이유입니다. 아이러니하게도 Moment.js 개발자들조차 이제는 다른 솔루션을 권장합니다. 그리고 date-fns, Luxon 등 제정신을 되찾기 위한 다양한 시도들이 뒤를 이었죠.
분명 도움이 됩니다. 누군가가 "아, 그런데 호주 사용자들에게 이상한 버그가 보고되고 있어요"라고 말하기 전까지는요. 보통 거기서부터 재미있는 일이 시작됩니다. 진정코 말하건대, 제 10년 개발 인생에서 시간/날짜 관련 버그 디버깅에 쓴 시간만 모아도 한 달은 족히 넘을 겁니다.
Temporal은 올바른 날짜 및 시간 유형을 도입하여 이 모든 것을 해결하는 것을 목표로 합니다.
다음과 같이 사용하는 대신:
const now = new Date();
이제 다음과 같은 것을 얻게 됩니다.
const now = Temporal.Now.instant();
const birthday =
Temporal.PlainDate.from(
"1987-07-23"
);
const meeting =
Temporal.ZonedDateTime.from(
"2026-11-03T10:00:00[Europe/Warsaw]"
);
그리고 갑자기 모든 것이 훨씬 더 명시적이 됩니다.
참고로, Temporal이 실제로 ES2026에 포함되었는지 알아내려고 엄청난 시간을 보냈습니다. 결국 TC39 저장소에서 제안이 이미 Stage 4에 도달했지만, 예상 출판 연도는 2027년이라고 명확히 나와 있는 것을 발견했습니다.
그러니 아주 가깝습니다. 정말 가깝죠. 그리고 저는 정말 기다릴 수 없습니다 ❤️. Temporal이 이런 지옥에서 우리를 구원해 줄 거라 믿어 의심치 않습니다.
명시적 리소스 관리 (using)
이것은 C#과 Python 개발자들이 조용히 즐기고 있을 때, 우리 나머지 개발자들은 try/finally가 완벽하게 괜찮다고 가장했던 기능 중 하나입니다 😄.
가끔은 나중에 정리(cleanup)해야 하는 것을 생성할 때가 있습니다. 파일, 데이터베이스 연결, 스트림, WebSocket 등이죠. 오늘날 우리는 보통 다음과 같이 작성합니다.
const webinar =
createAIAgentsWebinar();
try {
webinar.start();
}
finally {
webinar.close();
}
finally 블록은 종종 유닛 테스트를 작성하는 것과 같은 열정으로 쓰입니다. 더 나쁜 것은, 만약 우리가 그것을 완전히 잊어버린다면, 리소스 누출과 알 수 없는 버그로 이어질 수 있다는 겁니다.
using을 사용하면, 스코프를 벗어날 때 정리가 자동으로 이루어집니다.
using webinar =
createAIAgentsWebinar();
webinar.start();
스코프를 벗어나면 자바스크립트가 자동으로 정리 로직을 호출합니다. 정말 멋지지 않나요?
이 기능은 일반적인 프론트엔드 개발자에게 매일 영향을 미치지는 않을 수 있지만, Node.js 개발자, 라이브러리 개발자, 그리고 스트림과 파일을 다루는 사람들에게는 엄청나게 유용할 수 있습니다.
휴…
솔직히 이 글이 제가 처음 예상했던 것보다 훨씬 더 많은 작업이 필요했습니다 😅 짧고 쉬운 글이 될 줄 알았는데, 어쩌다 보니 TC39 제안 문서, MDN 페이지, 브라우저 구현체를 파헤치고 Temporal이 ES2026에 실제로 포함되었는지 아닌지 알아내려 애쓰는 저를 발견했네요.
하지만 그럴 가치가 있었고, 여러분이 즐겁게 읽으셨기를 바랍니다 ❤️
여러분은 어떠신가요? 어떤 기능이 가장 놀라웠나요? 그리고 여러분도 날짜 관련 모든 고통에서 벗어나게 해줄 Temporal을 애타게 기다리고 있나요?
(아니면 다음 주에 링크드인 현자들이 아마 그렇게 말할 겁니다 😇)
이 글이 유용하셨다면, LinkedIn에서 저와 연결해주세요 😊.
원문: https://dev.to/sylwia-lask/7-new-javascript-features-and-2-im-still-waiting-for-2ck8 수집일: 2026-06-28 00:22:24