AI 시대에도 JS는 진화한다! ECMAScript 2026 핵심 기능 7가지와 제가 애타게 기다리는 2가지
2026. 6. 25.
AI 시대에도 JS는 진화한다! ECMAScript 2026 핵심 기능 7가지와 제가 애타게 기다리는 2가지
두 주 전, 가볍고 쉬운 글만 쓰겠다고 약속했던 제가 기억나시나요? (사실 스스로에게 한 약속이었죠 😄) 음… 그 약속을 깨버렸습니다. 지난주엔 상상할 수 있는 가장 재미없는 주제 중 하나인 레거시 애플리케이션에 대한 방대한 글을 발행했거든요. 그런데도 DEV 에디토리얼 팀은 이 글을 이번 주 TOP 7 포스트에 선정할 만큼 마음에 들어 했으니, 아이러니하죠? ❤️
하지만 오늘은 드디어 좀 더 가벼운 이야기를 할 시간입니다. 그리고 제가 생각하기에 훨씬 더 많은 관심이 필요한 주제이기도 하고요.
요즘 우리는 AI 에이전트에 대해 많은 시간을 할애하며 이야기합니다. 왜 그런지 충분히 이해합니다. 정말 매혹적인 분야니까요. 하지만 가끔은 우리가 매일 사용하는 프로그래밍 언어들도 꾸준히 발전하고 있다는 사실을 잊고 있는 건 아닌가 하는 생각이 들어요.
저는 대부분의 시간을 JavaScript (정확히는 TypeScript겠죠, 당연히! 😄) 코드를 작성하며 보냅니다. 지난 몇 년 동안 자바스크립트 생태계는 정말 많이 성숙해졌습니다. 더 이상 끝없는 React vs Angular 전쟁을 벌이지도 않고요. 한 달은 모두가 Redux를 사랑하다가 6개월 뒤에는 "너무 과하게 설계된 괴물이야!"라며 모든 애플리케이션에서 걷어내는 시절도 대체로 지나갔죠 😅.
하지만 생태계와 ECMAScript 표준 모두 끊임없이 진화하고 있습니다.
2015년에 프런트엔드 개발의 판도를 영원히 바꿔놓았던 전설적인 ES6 릴리스 이후, TC39 위원회는 반복적인 접근 방식을 채택하여 매년 새로운 기능을 출시하기 시작했습니다.
그리고 정말 좋은 점은 최신 브라우저나 런타임을 사용한다면, 이러한 새로운 기능들을 거의 즉시 활용할 수 있다는 것이죠.
그렇다면 ECMAScript 2026에는 어떤 기능들이 우리를 기다리고 있을까요?
아, 그리고 재미를 더하기 위해 이 글의 모든 코드 예제는 아주 강한 의견을 가진 상상 속의 LinkedIn 구루(guru)들의 내면의 독백을 기반으로 합니다. 실제 인물과의 유사성은 물론, 순전히 우연의 일치일 뿐입니다 😇
이 시리즈의 다른 글들:
- Stop Installing Libraries: 10 Browser APIs That Already Solve Your Problems
- 9 Things You're Overengineering — The Browser Already Solved Them
- 16 Modern JavaScript Features That Might Blow Your Mind
1. Map.prototype.getOrInsert() / Upsert
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/getOrInsert
이 기능은 정말이지 "잠깐… 왜 이게 10년 전에는 없었지?"라는 질문을 던지게 만드는 유형의 기능입니다.
LinkedIn 구루들의 의견을 수집한다고 상상해 봅시다. 지금까지는 대략 이런 식으로 코드를 작성해야 했습니다.
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);
계산된 값을 삽입하는 버전도 있습니다.
const opinions = new Map();
opinions
.getOrInsertComputed(
"Nobody writes clean code anymore",
() => []
)
.push("DDD Purist");
정말 훨씬 깔끔하고 읽기 쉽지 않나요? 캐싱 로직에도 완벽하게 들어맞습니다! 코드량은 줄고, API는 훨씬 더 직관적이죠. 제가 실무에서 캐싱 로직을 구현할 때마다 has 체크하고 set하는 반복적인 패턴이 늘 아쉬웠는데, 이제 훨씬 깔끔하게 처리할 수 있게 됐죠.
2. Iterator.concat()
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/concat
concat()에 대해 이야기하기 전에, 한 가지 질문에 빠르게 답해봅시다.
이터레이터란 무엇인가요?
이터레이터는 기본적으로 데이터를 한 번에 한 요소씩 소비할 수 있도록 해주는 커서와 같습니다. 모든 데이터를 메모리에 한꺼번에 저장하지 않고도 말이죠.
예를 들어 볼까요?
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]);
제 생각에 이러한 이터레이터 기능들은 마땅히 받아야 할 만큼의 관심을 받지 못하고 있는 것 같습니다. 사실 이터레이터 관련 기능들이 생각보다 현업에서 빛을 발할 때가 많습니다. 특히 대용량 데이터를 스트리밍 처리하거나 무한 스크롤 같은 UI를 구현할 때 메모리 효율성 측면에서 톡톡히 제 역할을 하죠.
3. Array.fromAsync()
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync
이것은 우리가 사랑하는 Array.from()의 비동기 버전이라고 할 수 있습니다.
주로 비동기 이터레이터(async iterators)를 위해 설계되었지만, 대부분의 JavaScript 개발자들이 매일 비동기 이터레이터를 사용하지는 않을 겁니다. 예를 들어, LinkedIn에서 댓글이 하나씩 도착한다고 상상해 봅시다.
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);
// This could have been a plain HTML form.
// Angular is dead.
// etc
하지만 많은 사람이 모르는 사실이 있습니다. 바로 이것이 프로미스(promises)에도 작동한다는 점이죠.
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()
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sumPrecise
이 기능은 인터넷 자체만큼이나 오래된 부동 소수점 문제를 해결해 줍니다 😄 많은 분이 아시겠지만, JavaScript에서는 다음과 같습니다.
console.log(0.1 + 0.2);
// 0.30000000000000004
오늘은 왜 이런 일이 발생하는지 자세히 다루지는 않겠습니다. 그러다 밤을 새울 수도 있으니까요 😄.
중요한 것은 ES2026이 Math.sumPrecise()를 도입하여 훨씬 더 정확한 합산을 수행하고 반올림 오류의 누적을 방지한다는 것입니다.
한 LinkedIn 구루가 생산성을 높인다고 주장하는 모든 것들을 나열하고 있다고 가정해 봅시다.
const productivityBoosts = [
0.1, // cold showers
0.2, // AI agents
0.3, // journaling
0.4, // waking up at 4 AM
];
console.log(
Math.sumPrecise(productivityBoosts)
);
솔직히 말해서, 대부분의 프런트엔드 개발자들은 이 기능을 거의 필요로 하지 않을 겁니다. 평범한 덧셈은 일상적인 용도로 완벽하게 잘 작동하니까요.
하지만 수천, 수백만 번의 연산에서 미세한 오류가 누적될 수 있는 금융, 통계, 시뮬레이션, 또는 AI/ML 분야에서 작업한다면 이 기능은 훨씬 더 흥미로워질 것입니다.
5. Error.isError()
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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
간단하고 아름답죠. 과거에 크로스-realm 에러 때문에 instanceof 검사가 예상치 못한 버그를 일으켜 골머리를 앓았던 기억이 생생합니다. 이젠 이런 불필요한 삽질을 막을 수 있게 되었네요.
6. Base64 for Uint8Array
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64
빠른 상기: Base64는 이진 데이터를 일반 텍스트로 변환하는 방법일 뿐입니다. 왜 그렇게 할까요? 많은 프로토콜과 형식이 원시 바이트보다 텍스트를 다루는 것을 훨씬 더 좋아하기 때문입니다. 예를 들어, 이미지를 Base64 문자열로 보낼 수 있습니다.
어떤 사람은 이렇게 말할지도 모릅니다: "잠깐, Base64는 JavaScript에 이미 있었잖아!" 네, 맞습니다. 하지만 주로 문자열과 함께 작동했습니다.
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();
console.log(base64);
훨씬 깔끔합니다. 그리고 아마 더 중요하게는, 6개월 뒤에 다시 봐도 훨씬 이해하기 쉽겠죠.
7. JSON.parse Source Text Access
MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
JSON.parse()는 훌륭합니다. 누군가 엄청나게 큰 숫자를 보내기 전까지는요. 한 LinkedIn 구루가 999조 팔로워를 가지고 있다고 주장한다고 가정해 봅시다.
const json = `
{
"followers":
999999999999999999999999999999
}
`;
const data = JSON.parse(json);
console.log(data.followers);
이런. JavaScript 숫자는 한계가 있어서, 아주 큰 정수는 정밀도를 잃을 수 있습니다.
ES2026에서는 리바이벌 콜백(reviver callback)이 원본 소스 텍스트에 접근할 수 있게 되어, 큰 값들을 안전하게 복구할 수 있습니다.
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
TC39 proposal: https://github.com/tc39/proposal-temporal
프런트엔드 개발을 충분히 오래 해보셨다면, 날짜와 관련된 적어도 한 번의 트라우마적인 경험이 있을 겁니다. 아마 이런 식이었을까요?
const date = new Date("2026-03-30");
console.log(date);
당신의 시간대에 따라, 축하합니다! 이제 "왜 어제지?"라는 흥미진진한 세계에 진입하셨습니다.
아니면 모두가 가장 좋아하는 이 상황을 경험하셨을 수도 있습니다.
const today = new Date();
today.setMonth(today.getMonth() + 1);
그리고 갑자기 3월에 한 달을 더했더니 어떻게 5월이 되었는지 디버깅하고 있는 자신을 발견하게 되죠.
아니면 운이 좋아서 시간대(time zone) 문제와 씨름해야 했을 수도 있습니다.
그 지점에서 시간 자체가 환상이고, 일광 절약 시간제(daylight saving time)가 프로그래머의 삶을 망치기 위해 특별히 발명되었다는 사실을 깨닫게 됩니다.
이것이 많은 사람들이 Moment.js 같은 라이브러리를 사용하게 된 이유입니다. 아이러니하게도, Moment.js 개발팀조차 이제는 다른 솔루션을 사용할 것을 권장하고 있습니다. 그리고 date-fns, Luxon 등 이성을 되찾기 위한 다양한 시도들이 뒤따랐죠.
물론 이런 라이브러리들은 도움이 됩니다. 누군가 "참고로, 호주 사용자들은 이상한 버그를 보고하고 있습니다"라고 말하기 전까지는요. 그리고 보통 그때부터 진정한 재미가 시작됩니다.
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]"
);
갑자기 모든 것이 훨씬 더 명확해지죠. 말도 많고 탈도 많았던 JavaScript의 Date 객체는 저에게도 개발 인생의 여러 밤샘을 선물했습니다. 이제 드디어 그 고통에서 벗어날 희망이 보이는 듯합니다.
참고로, Temporal이 실제로 ES2026에 포함되었는지 알아내느라 민망할 정도로 많은 시간을 보냈습니다. 결국 TC39 저장소에서 이 제안이 이미 Stage 4에 도달했지만, 예상 발행 연도는 2027년이라고 명시되어 있는 것을 발견했습니다.
그러니 아주 가까워졌습니다. 정말 코앞이죠. 그리고 저는 정말 기다려집니다 ❤️
Explicit Resource Management (using)
TC39 proposal: https://github.com/tc39/proposal-explicit-resource-management
이것은 C#과 Python 개발자들이 조용히 즐겨왔던 기능 중 하나인데, 우리 JavaScript 개발자들은 try/finally가 완벽하게 괜찮다고 계속해서 주장해왔죠 😄.
때로는 사용 후 정리가 필요한 것들을 생성할 때가 있습니다. 파일, 데이터베이스 연결, 스트림, WebSocket 등이 그렇죠. 오늘날 우리는 보통 다음과 같이 코드를 작성합니다.
const webinar =
createAIAgentsWebinar();
try {
webinar.start();
}
finally {
webinar.close();
}
finally 블록은 유닛 테스트를 작성할 때와 비슷한 열정으로 쓰이는 경우가 많습니다. 더 나쁜 것은, 만약 우리가 그것을 완전히 잊어버린다면, 리소스 누수와 알 수 없는 버그로 이어질 수 있다는 거죠.
using을 사용하면 스코프를 벗어날 때 자동으로 정리 작업이 이루어집니다.
using webinar =
createAIAgentsWebinar();
webinar.start();
스코프를 벗어나면 JavaScript가 자동으로 정리 로직을 호출합니다. 정말 멋지지 않나요?
이것은 일반적인 프런트엔드 개발자에게 매일 영향을 주지는 않을 수도 있지만, Node.js 개발자, 라이브러리 개발자, 그리고 스트림 및 파일과 함께 작업하는 사람들에게는 엄청나게 유용할 수 있는 기능입니다.
휴…
솔직히, 이 글이 처음에 예상했던 것보다 훨씬 더 많은 작업이 필요했다는 것을 인정해야겠습니다 😅 짧고 쉬운 글이 될 줄 알았는데, 어쩌다 보니 TC39 제안, MDN 페이지, 브라우저 구현들을 뒤져보고, Temporal이 실제로 ES2026에 들어갔는지 아닌지 알아내려고 애쓰고 있었네요.
하지만 그만한 가치가 있었고, 여러분도 즐거우셨기를 바랍니다 ❤️
여러분은 어떠신가요? 어떤 기능이 가장 놀라웠나요? 그리고 여러분도 Temporal이 마침내 모든 날짜 관련 고통에서 우리를 해방시켜 주기를 간절히 기다리고 계신가요?
(아니면 적어도 다음 주에 LinkedIn 구루들이 우리에게 그렇게 말해주겠죠 😇)
이 글이 마음에 드셨다면, LinkedIn에서 저와 연결해 주세요 😊
원문: https://dev.to/sylwia-lask/7-new-javascript-features-and-2-im-still-waiting-for-2ck8 수집일: 2026-06-25 00:25:13