ECMAScript 2026 is final: 7 new JavaScript features explained
ES2026 adds Map upserts, Iterator.concat, Base64 on Uint8Array, JSON source text, Math.sumPrecise, Error.isError and Array.fromAsync. Examples and support.
7 min read

In this article
ECMAScript 2026, the 17th edition of the JavaScript language standard, was published by Ecma International in June 2026. It adds seven features: Map upserts, Iterator.concat(), Base64 and hex conversion on Uint8Array, source-text access in JSON.parse, Math.sumPrecise(), Error.isError() and Array.fromAsync(). All seven already run in current Chrome, Edge, Firefox and Safari, so this is a release you can use rather than just read about.
Below is what each feature solves, a short example, and the browser versions that support it according to MDN's compatibility data (version 8.1.5, 8 October 2026). At the end you will find what is lined up for ECMAScript 2027, including Temporal and using declarations.
ES2026 at a glance
| Feature | Chrome / Edge | Firefox | Safari | Node.js |
|---|---|---|---|---|
Map / WeakMap getOrInsert(), getOrInsertComputed() | 145 | 144 | 26.2 | 26.0.0 |
Iterator.concat() | 146 | 147 | 26.4 | 26.0.0 |
Uint8Array Base64 and hex | 140 | 133 | 18.2 | 25.0.0 |
JSON.parse source text, JSON.rawJSON() | 114 | 135 | 18.4 | 21.0.0 |
Math.sumPrecise() | 147 | 137 | 26.2 | Not yet |
Error.isError() | 134 | 138 | 18.4 (partial) | 24.3.0 |
Array.fromAsync() | 121 | 115 | 16.4 | 22.0.0 |
Safari on iOS has the same version numbers as desktop Safari for these entries. The current releases listed in the same data are Chrome 155, Firefox 157 and Safari 27, so every feature is in the latest version of every major engine. Whether you can drop fallbacks depends on how many of your visitors run older versions, especially older iPhones that have not updated to Safari 26.
1. Map upserts: getOrInsert() and getOrInsertComputed()
"Get the value for this key, or set a default first" is one of the most common Map patterns, and it usually takes a has(), a set() and a get(). The upsert proposal turns it into one call:
const counts = new Map();
for (const word of ['js', 'css', 'js']) {
counts.set(word, counts.getOrInsert(word, 0) + 1);
}
// Map(2) { 'js' => 2, 'css' => 1 }
const byCategory = new Map();
for (const post of posts) {
byCategory.getOrInsertComputed(post.category, () => []).push(post.title);
}Use getOrInsertComputed() when the default is expensive or must be a fresh object, such as an array: the callback runs only when the key is missing. Both methods also exist on WeakMap, which makes per-element caches tidy:
const layoutCache = new WeakMap();
const measure = (el) => layoutCache.getOrInsertComputed(el, () => el.getBoundingClientRect());2. Iterator.concat(): join iterables lazily
ES2025 brought iterator helpers such as map(), filter() and take(). ES2026 adds Iterator.concat(), which chains several iterables into one iterator without building an intermediate array:
function* recentPosts() {
yield 'post-3';
yield 'post-2';
}
const pinned = ['post-9'];
[...Iterator.concat(pinned, recentPosts(), new Set(['post-1']))];
// ['post-9', 'post-3', 'post-2', 'post-1']
Iterator.concat(pinned, recentPosts()).take(2).toArray();
// ['post-9', 'post-3']Because it is lazy, the second example never asks recentPosts() for more than one value. That matters when a source is a generator that reads from the DOM or a paginated cache.

3. Base64 and hex on Uint8Array
btoa() and atob() work on "binary strings" and throw on characters outside Latin-1, which is why many projects carry a Base64 helper. ES2026 adds conversions directly on byte arrays:
const bytes = new TextEncoder().encode('héllo');
bytes.toBase64(); // "aMOpbGxv"
bytes.toBase64({ alphabet: 'base64url', omitPadding: true }); // URL-safe variant
bytes.toHex(); // "68c3a96c6c6f"
new TextDecoder().decode(Uint8Array.fromBase64('aMOpbGxv')); // "héllo"
Uint8Array.fromHex('cafe'); // Uint8Array [202, 254]There are also setFromBase64() and setFromHex(), which decode into an existing array and return { read, written }, useful when you want to avoid allocating.
4. JSON.parse with access to the source text
JSON numbers larger than Number.MAX_SAFE_INTEGER lose precision when parsed, which is a real problem for 64-bit IDs from databases and payment APIs. Reviver functions now receive a third context argument whose source property holds the original text of a primitive value:
const text = '{"id": 12345678901234567890}';
JSON.parse(text).id; // 12345678901234567000 (precision lost)
const data = JSON.parse(text, (key, value, context) =>
key === 'id' ? BigInt(context.source) : value,
);
data.id; // 12345678901234567890n
JSON.stringify({ id: JSON.rawJSON(data.id.toString()) });
// '{"id":12345678901234567890}'JSON.rawJSON() works in the other direction: it marks a string as already-serialised JSON, so JSON.stringify() emits it unquoted. JSON.isRawJSON() tells you whether a value was created that way.
5. Math.sumPrecise(): sums without drift
Adding floating-point numbers one at a time rounds after every step. Math.sumPrecise() takes an iterable and, as MDN puts it, works as if the numbers were added using their exact mathematical values before rounding once at the end:
[1e20, 0.1, -1e20].reduce((a, b) => a + b, 0); // 0
Math.sumPrecise([1e20, 0.1, -1e20]); // 0.1
Math.sumPrecise([0.1, 0.2]); // 0.30000000000000004The last line is the important caveat: it does not fix the fact that 0.1 cannot be represented exactly. For money, keep using integer minor units (cents, paise). Two more details: it throws a TypeError if any element is not a number, and an empty iterable returns -0.
6. Error.isError(): a reliable error check
instanceof Error fails for errors created in another realm, such as an iframe, and it can be fooled by objects that inherit from Error.prototype. Error.isError() checks for a genuine error object:
Error.isError(new TypeError('bad input')); // true
Error.isError({ name: 'Error', message: 'fake' }); // false
Error.isError(Object.create(Error.prototype)); // falseUse it in logging and error-reporting code that receives values from catch blocks, since JavaScript lets you throw anything. One caveat from MDN's data: Safari's implementation is marked partial because it returns false for DOMException instances, such as the AbortError thrown by a cancelled fetch().

7. Array.fromAsync(): collect async iterables
Array.fromAsync() is the async counterpart of Array.from(). It has shipped in browsers since 2023 and is now part of the standard:
async function* pages() {
yield 1;
yield 2;
}
await Array.fromAsync(pages()); // [1, 2]
await Array.fromAsync(pages(), (n) => n * 10); // [10, 20]
await Array.fromAsync([Promise.resolve('a'), 'b']); // ['a', 'b']It awaits each value in turn, so it does not run promises in parallel. For a list of independent requests, Promise.all() is still faster. Where Array.fromAsync() shines is with sources that are naturally sequential: an async generator that follows "next page" links, the chunks of a stream you have wrapped in an async iterator, or a queue that yields values as they arrive. It replaces the familiar boilerplate of declaring an empty array, looping with for await...of and pushing each value.
What is coming in ECMAScript 2027
A feature becomes part of an edition once it reaches Stage 4 in the TC39 process, which requires two shipping implementations and tests. TC39's list of finished proposals already gives 2027 as the expected publication year for seven more features:
- Temporal, the replacement for
Date. - Explicit Resource Management:
using,await usingandDisposableStack. - Joint Iteration:
Iterator.zip()andIterator.zipKeyed(). - Iterator chunking, Iterator Includes and Iterator Join, which extend iterator helpers further.
Atomics.pause, a hint for spin-wait loops in shared-memory code.
Unlike the ES2026 set, several of these are not yet in every engine. MDN's data shows Temporal and using in Chrome and Firefox but only in Safari Technology Preview, and Iterator.zip() in Chrome 153 and Firefox 148 only.
What to do next
- Update your TypeScript
libsetting so the editor knows about the new methods, and check your linter'secmaVersion. - Replace helpers one at a time: a
getOrDefaultutility withgetOrInsert(), a Base64 package withtoBase64(), a BigInt JSON parser with a reviver that readscontext.source. - Feature-detect the newest ones (
Iterator.concat,Math.sumPrecise, upserts) for public sites with many older iPhones, for exampleif (typeof Map.prototype.getOrInsert === 'function'), or use a core-js polyfill. - Do not rely on a version label alone. "ES2026" in a build tool target means syntax and built-ins from this edition, but your visitors' browsers decide what actually runs.
Frequently asked questions
When was ECMAScript 2026 published?
Ecma International lists ECMA-262 17th edition, ECMAScript 2026, as published in June 2026. The normative version is the HTML specification at tc39.es.
Which new features are in ES2026?
Seven: Map and WeakMap upserts (
getOrInsert,getOrInsertComputed),Iterator.concat(), Base64 and hex onUint8Array,JSON.parsesource text access withJSON.rawJSON(),Math.sumPrecise(),Error.isError()andArray.fromAsync().Is Temporal part of ES2026?
No. TC39's finished proposals list gives 2027 as Temporal's expected publication year. It already ships in Chrome and Firefox, but only in Safari Technology Preview.
Does Math.sumPrecise fix 0.1 + 0.2?
No.
Math.sumPrecise([0.1, 0.2])still returns0.30000000000000004, because 0.1 and 0.2 cannot be stored exactly. It only avoids extra rounding between steps when you add many numbers.Can I use ES2026 features in Node.js?
Mostly. MDN's data shows Node.js 26 supports upserts and
Iterator.concat(), Node.js 25 added Base64 onUint8Array, butMath.sumPrecise()is not yet supported in Node.js.Why does Error.isError return false for an AbortError in Safari?
MDN marks Safari's implementation as partial: it returns
falseforDOMExceptioninstances. Add aninstanceof DOMExceptioncheck if you handle aborted fetches.
Your next customer could start right here.
Introduce your tool, product or business to readers exploring technology.
Explore placements and request a private quote
Sources
- ECMA-262: ECMAScript 2026 language specification, 17th edition — Ecma International, 2026-06-30
- ECMAScript 2026 Language Specification — TC39
- Finished Proposals — TC39
- Math.sumPrecise() — MDN Web Docs
- JSON.parse() — MDN Web Docs
- MDN browser-compat-data 8.1.5 (data.json) — MDN Web Docs, 2026-10-08
Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.
Comments
No comments yet. Be the first to join the conversation.
Leave a comment
Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.
More from Cloudsoft Zone

TutorialJavaScript
JavaScript using declarations: automatic cleanup without finally
Learn JavaScript's using and await using declarations, Symbol.dispose and DisposableStack, with tested browser recipes and October 2026 support data.
By Cloudsoft Zone

Architecture guideJavaScript
Ship JavaScript without a bundler: import maps and JSON modules
How to structure a front end as native ES modules: import maps for bare imports, JSON modules, modulepreload against waterfalls, and cache-busting.
By Cloudsoft Zone

ComparisonJavaScript
structuredClone vs JSON vs spread: deep copy JavaScript safely
Spread is shallow, JSON loses dates, Maps, Sets and undefined, and structuredClone keeps them. A tested comparison of JavaScript copy methods and their limits.
By Cloudsoft Zone
