Skip to main content

Cloudsoft Zone Build, deploy and scale with practical guides to PHP, Node.js, React, DevOps and AI automation. Explore the guides

Cloudsoft Zone
JavaScriptIndustry update

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.

Cloudsoft Zone

7 min read

Developers gathered around a laptop at a lectern during a code competition at a JSConf event
Photograph: JS Conf / CC BY 2.0, via Wikimedia Commons
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

FeatureChrome / EdgeFirefoxSafariNode.js
Map / WeakMap getOrInsert(), getOrInsertComputed()14514426.226.0.0
Iterator.concat()14614726.426.0.0
Uint8Array Base64 and hex14013318.225.0.0
JSON.parse source text, JSON.rawJSON()11413518.421.0.0
Math.sumPrecise()14713726.2Not yet
Error.isError()13413818.4 (partial)24.3.0
Array.fromAsync()12111516.422.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:

JavaScript
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:

JavaScript
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:

JavaScript
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.

JavaScript code in a dark editor theme that builds a list of weekday names using Temporal.PlainDate and a Map
Code that uses Temporal today relies on a feature expected in ES2027, while Map and iterator improvements are already in ES2026.

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:

JavaScript
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:

JavaScript
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:

JavaScript
[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.30000000000000004

The 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:

JavaScript
Error.isError(new TypeError('bad input'));            // true
Error.isError({ name: 'Error', message: 'fake' });    // false
Error.isError(Object.create(Error.prototype));        // false

Use 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().

Older style JavaScript in the gvim editor using var declarations, new Array() and a manual query string parser
Hand-written parsing and accumulation loops like this are what many ES2026 built-ins make unnecessary.

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:

JavaScript
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 using and DisposableStack.
  • Joint Iteration: Iterator.zip() and Iterator.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 lib setting so the editor knows about the new methods, and check your linter's ecmaVersion.
  • Replace helpers one at a time: a getOrDefault utility with getOrInsert(), a Base64 package with toBase64(), a BigInt JSON parser with a reviver that reads context.source.
  • Feature-detect the newest ones (Iterator.concat, Math.sumPrecise, upserts) for public sites with many older iPhones, for example if (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 on Uint8Array, JSON.parse source text access with JSON.rawJSON(), Math.sumPrecise(), Error.isError() and Array.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 returns 0.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 on Uint8Array, but Math.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 false for DOMException instances. Add an instanceof DOMException check if you handle aborted fetches.

Advertise on CloudSoftZone

Your next customer could start right here.

Introduce your tool, product or business to readers exploring technology.

Advertise with us

Explore placements and request a private quote

Sources

  1. ECMA-262: ECMAScript 2026 language specification, 17th edition — Ecma International, 2026-06-30
  2. ECMAScript 2026 Language Specification — TC39
  3. Finished Proposals — TC39
  4. Math.sumPrecise() — MDN Web Docs
  5. JSON.parse() — MDN Web Docs
  6. 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.

Never published. Used only to contact you about this comment.

Loading the security check…

Comments are moderated before publication.