InterviewsVector
intermediateCommon5 min read · Updated Aug 24, 2026

Modern JavaScript (ES2024–ES2025): The Interview Feature Guide

The modern JavaScript features interviewers now expect — Object.groupBy, Promise.withResolvers, Set methods, iterator helpers with lazy evaluation, RegExp.escape, and how to use them under interview pressure.


Short answer: Senior interviews increasingly close an implementation question with a twist — "does the language give you this for free now?" The modern built-ins worth knowing cold: Object.groupBy/Map.groupBy (grouping without a hand-rolled reduce), Promise.withResolvers (the standardized deferred pattern), Set methods (intersection/union/difference for O(n) set algebra), and iterator helpers (map/filter/take directly on iterators, evaluated lazily). Knowing each and its limits signals that you keep current.

Why modern features are now interview material

The pattern is consistent: you implement something by hand, and the interviewer asks whether the language now ships it. Reaching for Object.groupBy instead of a hand-rolled reduce, or Promise.withResolvers instead of the deferred pattern, shows you track the platform — and knowing each feature's limits is what separates recognition from fluency. This page is the shortlist that actually comes up, and how to deploy each under pressure.

ES2024 highlights

Object.groupBy and Map.groupBy

Grouping — previously the most-written reduce in existence — is now built in:

const orders = [
  { id: 1, status: "paid" },
  { id: 2, status: "pending" },
  { id: 3, status: "paid" },
];
 
const byStatus = Object.groupBy(orders, (o) => o.status);
// { paid: [{id:1},{id:3}], pending: [{id:2}] }
 
const map = Map.groupBy(orders, (o) => o.status); // Map for arbitrary keys

Interview notes: the result of Object.groupBy has a null prototype (no inherited keys — see prototypal inheritance), and Map.groupBy is the right choice when group keys are objects.

Promise.withResolvers

Creates a promise plus its resolve/reject functions in one call — the standardized "deferred" pattern. Full treatment in the Promises guide.

const { promise, resolve, reject } = Promise.withResolvers();

The RegExp v flag

A stricter, more powerful Unicode mode enabling set operations in character classes:

/[\p{Script=Latin}&&\p{Uppercase}]/v.test("A"); // intersection: uppercase Latin

You won't be asked to write these, but recognizing && (intersection) and -- (difference) inside [...] shows currency.

Well-formed Unicode strings

String.prototype.isWellFormed() and toWellFormed() detect/repair lone surrogates — relevant when an interviewer probes string edge cases (pairs nicely with the string-polyfill follow-ups in the Polyfills guide).

Atomics.waitAsync

Await a change to shared memory without blocking the thread — niche, but name-droppable when worker communication comes up.

ES2025 highlights

Iterator helpers (and why lazy evaluation matters)

Until ES2025, map/filter/reduce lived only on Array.prototype. To transform an iterator — a generator, a Map's entries, a stream of ids — you spread it into an array first ([...iter].map(...), materializing everything) or hand-wrote generator plumbing. Iterator helpers put the familiar methods directly on iteratorsmap, filter, take, drop, flatMap, reduce, toArray, forEach, some, every, find, plus Iterator.from() to wrap any iterable — evaluated lazily:

function* naturals() { let n = 1; while (true) yield n++; }
 
const firstFiveEvenSquares = naturals() // infinite source — no problem
  .filter((n) => n % 2 === 0)
  .map((n) => n * n)
  .take(5)
  .toArray(); // [4, 16, 36, 64, 100] — no infinite array materialized

The interview point is lazy vs eager. Array chaining is eager — each step builds a full intermediate array:

huge.map(f).filter(g).slice(0, 10);
// walks all of huge twice, allocates two intermediate arrays

Iterator chaining flows one element through the whole pipeline at a time, and take(10) stops the source after ten survivors:

Iterator.from(huge).map(f).filter(g).take(10).toArray();
// touches only as many elements as needed to produce 10 results

So "how would you get the first 100 matches from a 10-million-row dataset?" is O(matches) work and constant memory, not O(n) allocations. Helpers work on anything iterablemap.entries().filter(…).map(…).toArray() with no intermediate spread.

The implementation question ("polyfill take and map for iterators") is a generator exercise:

function* mapIter(iter, fn) {
  for (const value of iter) yield fn(value);
}
function* takeIter(iter, limit) {
  if (limit <= 0) return;
  let count = 0;
  for (const value of iter) {
    yield value;
    if (++count >= limit) return; // early return also runs the source's finally (cleanup)
  }
}
[...takeIter(mapIter(naturals(), (n) => n * 2), 3)]; // [2, 4, 6]

Two things to say while writing it: for…of calls next() and, on early exit, the iterator's return() (how generators run finally blocks for resource cleanup); and these are iterator helpers, not iterable helpers — the result is single-pass, so call the source again for a fresh run. Async counterparts (AsyncIterator.prototype.map) are on their own track; today the interview-safe way to transform an async stream is an async generator (for await … yield), which bridges to cancellation and batching.

Set methods

Real set algebra, finally:

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
 
a.intersection(b);          // Set {2, 3}
a.union(b);                 // Set {1, 2, 3, 4}
a.difference(b);            // Set {1}
a.symmetricDifference(b);   // Set {1, 4}
a.isSubsetOf(b);            // false
a.isDisjointFrom(new Set([9])); // true

If an interviewer asks you to dedupe-and-compare arrays, converting to Set and using these beats nested loops — and stating the O(n) vs O(n·m) difference earns the point.

RegExp.escape

Safely embed user input in a dynamic regex — the standard answer to a long-standing footgun:

const re = new RegExp(RegExp.escape(userInput), "i");

Import attributes and JSON modules

import config from "./config.json" with { type: "json" };

Worth knowing as the standardized form of a thing bundlers faked for years.

Float16 support

Math.f16round, Float16Array — mention-only, relevant to graphics/ML-adjacent roles.

How to use these in an interview

  1. Implement first, then name the built-in. "Here's my groupBy with reduce — in ES2024 I'd reach for Object.groupBy" is the strongest possible framing.
  2. Know the limits. structuredClone doesn't clone functions (details here); iterator helpers don't exist on plain arrays' values in old runtimes; Object.groupBy returns a null-prototype object.
  3. Don't gamble on availability. If asked "can you use X in production," the senior answer covers runtime support and transpilation/polyfill strategy in one sentence.

Frequently asked questions

Are ES2024 and ES2025 features fair game in interviews?
Yes, increasingly. Object.groupBy, Promise.withResolvers, Set methods (intersection/union/difference), and iterator helpers now appear in senior frontend interviews — often as a follow-up to an implementation question: 'you built it; does the language provide it now?' Knowing the built-in and its limits is a strong seniority signal.
What is the difference between eager array chaining and lazy iterator helpers?
Array methods (map/filter/slice) are eager: each step builds a full intermediate array, so map(f).filter(g) walks the whole array twice. Iterator helpers are lazy: each element flows through the whole pipeline one at a time, and take(n) stops the source after n results — O(matches) work and constant memory instead of O(n) allocations.
What does Object.groupBy return?
A plain object with a null prototype (so it has no inherited keys like 'toString'), whose values are arrays of the grouped items. Use Map.groupBy instead when the group keys need to be objects rather than strings.

  • Implement groupBy from scratch, then meet the ES2024 built-ins — including the null-prototype result and Map.groupBy for object keys.

  • The prototype chain, __proto__ vs prototype, and what class syntax actually does under the hood.

  • Debounce

    beginner

    Implement debounce from scratch, with leading/trailing options and the classic search-input use case.

  • The this Keyword

    intermediate

    The four binding rules, arrow-function behavior, and the lost-this bugs that call, apply, and bind exist to fix.