ES2026 Features You Should Know
ES2026 brings a wave of practical improvements to JavaScript. From date handling to set operations, lazy iterators to typed arrays, these features address long-standing pain points. Let’s explore each one.
1. Temporal API: Finally, Dates Done Right
JavaScript’s Date object has been a pain point since 1995. The Temporal API, arriving in ES2026, provides a modern, intuitive API for date and time operations.
The Problem with Date
// The old way - confusing and error-prone
const date = new Date(2026, 3, 5); // April 5, 2026 (months are 0-indexed!)
const month = date.getMonth(); // 3 (April, but returns 3)
const day = date.getDate(); // 5
// Timezone issues
const now = new Date();
const hours = now.getHours(); // Depends on local timezone
The New Way with Temporal
// Clear and explicit
const date = Temporal.PlainDate.from("2026-04-05");
const month = date.month; // 4 (April)
const day = date.day; // 5
const dayOfWeek = date.dayOfWeek; // 7 (Sunday, 1-indexed)
Core Temporal Types
PlainDate - Date without time or timezone:
const date = Temporal.PlainDate.from("2026-04-05");
const date2 = Temporal.PlainDate.from({ year: 2026, month: 4, day: 5 });
date.year; // 2026
date.month; // 4
date.day; // 5
date.dayOfWeek; // 7 (Sunday)
date.dayOfYear; // 95
PlainTime - Time without date:
const time = Temporal.PlainTime.from("14:30:00");
time.hour; // 14
time.minute; // 30
ZonedDateTime - Full date, time, and timezone:
const zdt = Temporal.ZonedDateTime.from("2026-04-05T14:30:00[Europe/Madrid]");
zdt.timeZone; // Europe/Madrid
zdt.offset; // +02:00
Date Arithmetic
const date = Temporal.PlainDate.from("2026-04-05");
const tomorrow = date.add({ days: 1 });
const nextMonth = date.add({ months: 1 });
const yesterday = date.subtract({ days: 1 });
const date1 = Temporal.PlainDate.from("2026-04-05");
const date2 = Temporal.PlainDate.from("2026-04-10");
const diff = date1.until(date2);
diff.days; // 5
Timezone Handling
const now = Temporal.Now.zonedDateTime("Europe/Madrid");
const ny = now.withTimeZone("America/New_York");
const madrid = Temporal.ZonedDateTime.from("2026-04-05T14:30[Europe/Madrid]");
const ny = madrid.withTimeZone("America/New_York");
ny.toString(); // '2026-04-05T08:30:00-04:00[America/New_York]'
Migration from Date
// Old
const legacy = new Date();
const iso = legacy.toISOString();
// New
const temporal = Temporal.Now.zonedDateTime("UTC");
const iso = temporal.toString();
// Converting between them
const legacy = new Date();
const temporal = Temporal.Instant.fromEpochMilliseconds(legacy.getTime());
Polyfill
npm install @js-temporal/polyfill
import "@js-temporal/polyfill";
// Temporal is now available globally
2. Iterator Helpers: Lazy Evaluation Without Intermediate Arrays
Processing iterators traditionally required converting to arrays first. ES2026 Iterator Helpers bring array methods directly to iterators, enabling efficient lazy evaluation.
The Problem
// Without Iterator Helpers - creates intermediate arrays
function* numbers() {
for (let i = 0; i < 1000000; i++) {
yield i;
}
}
const result = [...numbers()] // Creates array of 1M elements
.filter(n => n % 2 === 0) // Creates another array
.map(n => n * 2) // Creates another array
.slice(0, 10); // Creates final array
This wastes memory creating unnecessary intermediate arrays.
The Solution
// With Iterator Helpers - lazy evaluation
const result = numbers()
.filter(n => n % 2 === 0)
.map(n => n * 2)
.take(10)
.toArray();
No intermediate arrays. Values are computed only when needed.
Available Methods
| Method | Description |
|---|---|
map() | Transform each element |
filter() | Keep elements matching a predicate |
take(n) | Take first n elements |
drop(n) | Skip first n elements |
flatMap() | Map and flatten in one step |
reduce() | Reduce to single value |
toArray() | Convert iterator to array |
forEach() | Iterate without creating array |
some() | Check if any element matches |
every() | Check if all elements match |
find() | Find first matching element |
Real-World Examples
Processing Large Files:
function* readLines(file) {
yield* file.split("\n");
}
const result = readLines(largeFile)
.filter(line => line.includes("error"))
.map(line => line.substring(0, 100))
.take(100)
.toArray();
Infinite Sequences:
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const first10EvenFibs = fibonacci()
.filter(n => n % 2 === 0)
.take(10)
.toArray();
// [0, 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418]
Method Chaining:
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.values()
.filter(x => x % 2 === 0) // [2, 4, 6, 8, 10]
.map(x => x * 3) // [6, 12, 18, 24, 30]
.drop(1) // [12, 18, 24, 30]
.take(3) // [12, 18, 24]
.reduce((a, b) => a + b, 0); // 54
3. Set Methods: Native Set Operations
Set operations have long required custom implementations or libraries. ES2026 adds native methods for intersection, union, difference, and more directly to the Set prototype.
The Old Way
// Before ES2026 - manual implementations
function intersection(setA, setB) {
return new Set([...setA].filter(x => setB.has(x)));
}
function union(setA, setB) {
return new Set([...setA, ...setB]);
}
ES2026 Set Methods
| Method | Returns | Description |
|---|---|---|
intersection(other) | Set | Elements in both sets |
union(other) | Set | Elements in either set |
difference(other) | Set | Elements in first, not second |
symmetricDifference(other) | Set | Elements in either, not both |
isSubsetOf(other) | Boolean | All elements in other set |
isSupersetOf(other) | Boolean | Contains all of other set |
isDisjointFrom(other) | Boolean | No common elements |
equals(other) | Boolean | Same elements |
Examples
Finding Common Tags:
const article1Tags = new Set(["javascript", "css", "web"]);
const article2Tags = new Set(["javascript", "nodejs", "backend"]);
const commonTags = article1Tags.intersection(article2Tags);
// Set { 'javascript' }
Merging User Permissions:
const defaultPermissions = new Set(["read", "write"]);
const adminPermissions = new Set(["read", "write", "delete", "admin"]);
const userPermissions = defaultPermissions.union(adminPermissions);
// Set { 'read', 'write', 'delete', 'admin' }
Finding Unread Items:
const allEmails = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
const readEmails = new Set([1, 3, 5, 7]);
const unreadEmails = allEmails.difference(readEmails);
// Set { 2, 4, 6, 8, 9, 10 }
Role-Based Access Control:
const userRoles = new Set(["editor", "viewer"]);
const requiredRoles = new Set(["admin", "editor"]);
const hasAccess = userRoles.intersection(requiredRoles).size > 0;
// true (user has 'editor')
const hasAllAccess = requiredRoles.isSubsetOf(userRoles);
// false (user doesn't have 'admin')
Chaining Operations:
const a = new Set([1, 2, 3, 4, 5]);
const b = new Set([4, 5, 6, 7, 8]);
const c = new Set([5, 6, 7, 8, 9]);
const result = a
.union(b) // {1, 2, 3, 4, 5, 6, 7, 8}
.intersection(c) // {5, 6, 7, 8}
.difference(new Set([5])); // {6, 7, 8}
4. RegExp.escape: Safe String Escaping for Regex
Building regular expressions from user input has always been error-prone. ES2026’s RegExp.escape provides a standard way to escape special characters.
The Problem
// Dangerous: unescaped user input in regex
function findWord(text, word) {
const regex = new RegExp(word, "gi");
return text.match(regex);
}
findWord("The price is $10", "$10"); // Error: Invalid regex
The Solution
const escaped = RegExp.escape("price: $10 (50% off)");
// 'price: \\$10 \\(50% off\\)'
const regex = new RegExp(escaped, "gi");
Practical Examples
Search Highlighting:
function highlight(text, query) {
const escaped = RegExp.escape(query);
const regex = new RegExp(`(${escaped})`, "gi");
return text.replace(regex, "<mark>$1</mark>");
}
highlight("The price is $10", "$10");
// 'The price is <mark>$10</mark>'
Building Complex Regex:
const prefix = "https://example.com/";
const path = "search?q=test&page=1";
const escapedPrefix = RegExp.escape(prefix);
const escapedPath = RegExp.escape(path);
const regex = new RegExp(`^${escapedPrefix}${escapedPath}$`);
regex.test("https://example.com/search?q=test&page=1"); // true
User-Configurable Filters:
function createFilter(bannedWords) {
const escaped = bannedWords.map(w => RegExp.escape(w));
const pattern = escaped.join("|");
return new RegExp(`\\b(${pattern})\\b`, "gi");
}
const filter = createFilter(["$spam", "free$$", "click.here"]);
const text = "Avoid $spam and free$$ offers";
const matches = text.match(filter);
// ['$spam', 'free$$']
What Gets Escaped
| Character | Escaped To |
|---|---|
. | \\. |
* | \\* |
+ | \\+ |
? | \\? |
^ | \\^ |
$ | \\$ |
{ } | \\{ \\} |
( ) | \\( \\) |
[ ] | \\[ \\] |
/ | \\/ |
\ | \\\\ |
Libraries Replaced
// lodash
import escapeRegExp from "lodash/escapeRegExp";
// escape-string-regexp package
import escapeStringRegexp from "escape-string-regexp";
// Now built-in
const escaped = RegExp.escape(string);
5. Float16Array: 16-bit Floats for ML and Graphics
JavaScript’s typed arrays now include Float16Array, a 16-bit floating point format optimized for machine learning and graphics workloads.
Why Float16?
| Type | Bytes | Precision | Use Case |
|---|---|---|---|
| Float64 | 8 | High | Scientific computing |
| Float32 | 4 | Medium | Graphics, audio |
| Float16 | 2 | Low | ML, GPU textures |
Float16 halves memory compared to Float32, crucial for large ML models.
Usage
// Create from values
const arr = new Float16Array([1.5, 2.7, 3.14159]);
// Float16Array(3) [1.5, 2.7, 3.140625]
// Create with size
const buffer = new Float16Array(1000); // 2000 bytes
// From another typed array
const float32 = new Float32Array([1.0, 2.0, 3.0]);
const float16 = new Float16Array(float32);
Memory Comparison
const size = 10000000; // 10 million elements
const f64 = new Float64Array(size); // 80 MB
const f32 = new Float32Array(size); // 40 MB
const f16 = new Float16Array(size); // 20 MB
Machine Learning Use Case
// Neural network weights (reduced memory)
const weights = new Float16Array(1000000); // 2MB vs 4MB for Float32
function forward(input, weights) {
const hidden = new Float16Array(256);
for (let i = 0; i < 256; i++) {
let sum = 0;
for (let j = 0; j < 784; j++) {
sum += input[j] * weights[i * 784 + j];
}
hidden[i] = Math.max(0, sum); // ReLU activation
}
return hidden;
}
Precision Tradeoffs
const arr = new Float16Array([3.141592653589793]);
arr[0]; // 3.140625 (precision lost)
// Large numbers overflow
const big = new Float16Array([100000]);
big[0]; // Infinity (exceeds max ~65504)
| Property | Float16 | Float32 |
|---|---|---|
| Max value | ~65,504 | ~3.4e38 |
| Min positive | ~6.1e-5 | ~1.2e-38 |
| Decimal digits | ~3-4 | ~7 |
Browser Support
All ES2026 features are standardized and will be supported by:
| Browser | Status |
|---|---|
| Chrome | ES2026 |
| Firefox | ES2026 |
| Safari | ES2026 |
| Edge | ES2026 |
For earlier browser support, use the respective polyfills:
npm install @js-temporal/polyfill # For Temporal API
Summary
| Feature | Problem Solved | Key Benefit |
|---|---|---|
| Temporal API | Date handling pain | Immutable, timezone-aware dates |
| Iterator Helpers | Intermediate arrays | Lazy evaluation, memory efficient |
| Set Methods | Manual set operations | Native intersection, union, difference |
| RegExp.escape | Unsafe regex construction | No more copy-paste escape functions |
| Float16Array | ML memory overhead | Half the memory for ML models |
Each of these features addresses a real pain point. Together, they make JavaScript more expressive, efficient, and safer.