AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

14 Modern JavaScript and its tooling / Checkpoint

Checkpoint — Modern JavaScript and its tooling

24 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint covers the ES2020–2022 features and their pitfalls, the 2023+ additions and the TC39 stage process, how to detect features and write spec-faithful polyfills, the build pipeline (resolve, transpile, tree-shake, split, minify, source maps), the quality toolchain (ESLint flat config, Prettier, test runners, mocking, hooks and CI), and the runtime landscape with its web-standard core.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • ?? versus ||; how a?.b.c short-circuits; why BigInt refuses to mix; which 2022 class features exist.
  • What toSorted/with/Object.groupBy/Promise.withResolvers do; the TC39 stages and when a proposal is safe to adopt; why syntax cannot be polyfilled.
  • The build stages; what defeats tree-shaking; how code splitting and hashed chunks work; what source maps are for.
  • Linter versus formatter; the shape of a good test; when to mock; what pre-commit and CI each run.
  • Node/Deno/Bun/edge differences; the WinterCG common APIs; feature detection over sniffing.

The programs are a spec-faithful structuredClone polyfill (cycles, Dates, Maps, Sets, regexes, and a DataCloneError for functions), a miniature bundler that resolves an ESM graph, tree-shakes unused exports and emits one file, and a runtime-support planner that turns feature requirements and a target list into the polyfills and transpile target a build needs.

Common questions

Why can't syntax be polyfilled in JavaScript?

A runtime that lacks a piece of syntax, such as ?. or #private, fails to parse the whole file before any polyfill could run. Only a transpiler can rewrite syntax for an older target; built-in functions and methods can be feature-detected and filled in.

What defeats tree shaking?

Modules with side effects at import time, CommonJS require and other dynamic patterns, a single export default object holding many functions, and packages that omit "sideEffects": false. Named imports from ES modules keep a bundle prunable.

What should a pre-commit hook and CI each run?

A pre-commit hook runs fast checks on staged files — the formatter, eslint --fix and perhaps a type-check — so problems appear before the commit exists. CI runs the full gate on every push: npm ci, lint, tsc --noEmit, tests, the build and end-to-end tests.

Modern JavaScript Quiz: ES2022, Bundlers and Tooling Test

Test modern JavaScript with 12 questions and three programs on ES2020 to ES2025 features, TC39 stages, polyfills, bundlers, tree shaking, testing and runtimes.

  • Course: JavaScript study plan
  • Module: Modern JavaScript and its tooling
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 24 min
  • Runtime: Node 16

Checkpoint — Modern JavaScript and its tooling is the checkpoint that closes the Modern JavaScript and its tooling module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers the ES2020–2022 features and their pitfalls, the 2023+ additions and the TC39 stage process, how to detect features and write spec-faithful polyfills, the build pipeline (resolve, transpile, tree-shake, split, minify, source maps), the quality toolchain (ESLint flat config, Prettier, test runners, mocking, hooks and CI), and the runtime landscape with its web-standard core.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • ?? versus ||; how a?.b.c short-circuits; why BigInt refuses to mix; which 2022 class features exist.
  • What toSorted/with/Object.groupBy/Promise.withResolvers do; the TC39 stages and when a proposal is safe to adopt; why syntax cannot be polyfilled.
  • The build stages; what defeats tree-shaking; how code splitting and hashed chunks work; what source maps are for.
  • Linter versus formatter; the shape of a good test; when to mock; what pre-commit and CI each run.
  • Node/Deno/Bun/edge differences; the WinterCG common APIs; feature detection over sniffing.

The programs are a spec-faithful structuredClone polyfill (cycles, Dates, Maps, Sets, regexes, and a DataCloneError for functions), a miniature bundler that resolves an ESM graph, tree-shakes unused exports and emits one file, and a runtime-support planner that turns feature requirements and a target list into the polyfills and transpile target a build needs.

Common questions

Why can't syntax be polyfilled in JavaScript?

A runtime that lacks a piece of syntax, such as ?. or #private, fails to parse the whole file before any polyfill could run. Only a transpiler can rewrite syntax for an older target; built-in functions and methods can be feature-detected and filled in.

What defeats tree shaking?

Modules with side effects at import time, CommonJS require and other dynamic patterns, a single export default object holding many functions, and packages that omit "sideEffects": false. Named imports from ES modules keep a bundle prunable.

What should a pre-commit hook and CI each run?

A pre-commit hook runs fast checks on staged files — the formatter, eslint --fix and perhaps a type-check — so problems appear before the commit exists. CI runs the full gate on every push: npm ci, lint, tsc --noEmit, tests, the build and end-to-end tests.

Exercises

A structuredClone polyfill

Node 16 lacks structuredClone. Write structuredClonePolyfill(value) following the structured-clone algorithm: primitives returned as-is; functions and symbols throw an error named DataCloneError; a Map from originals to clones preserves cycles and shared references; Date, RegExp (source + flags), Map, Set, arrays and plain objects are cloned deeply; class instances become plain objects (prototype and methods lost). The starter builds an object with a cycle, a shared reference, a Date, a regex, a Map, a Set and a class instance, plus the JSON from line 1; print the checks: distinct=<> dataEqual=<> dataDistinct=<>, cycle=<clone.self === clone> sharedRefPreserved=<>, date=<> regex=<>, map=<> set=<>, pointIsPlain=<> x=<> distMethod=<typeof>, then function: DataCloneError and symbol: DataCloneError.

Example →

distinct=true dataEqual=true dataDistinct=true
cycle=true sharedRefPreserved=true
date=true regex=true
map=true set=true
pointIsPlain=true x=3 distMethod=undefined
function: DataCloneError
symbol: DataCloneError

A miniature bundler

Line 1 is entry: <file>; the rest are modules as blocks starting // file: <name>, containing one-line statements: import { a, b } from "./x.js";, export const|let|function|class <name> …, and ordinary lines. Build the dependency graph from the entry (post-order so dependencies come first; a circular import prints warning: circular import <from> -> <to> and is not followed), tree-shake exports that no module imports (the entry keeps all of its own), and emit the bundle: for each module // ---- <name> followed by its lines with the import statements removed and the export keyword stripped. End with // dropped: <module:export, …> | order: <a -> b -> c> | unused modules: <names or ->. Names are unique across modules.

Example (excerpt): an entry importing slugify and log, a utils module also exporting unused debounce/throttle, a logger with unused warn, and an unreferenced module →

// ---- logger.js
const log = (m) => console.log(m);
// ---- utils.js
const slugify = (s) => s.toLowerCase().replace(/\s+/g, "-");
// ---- main.js
const title = slugify("Hello World");
log(title);
// dropped: logger.js:warn, utils.js:debounce, utils.js:throttle | order: logger.js -> utils.js -> main.js | unused modules: unused.js

A runtime-support planner

Line 1 lists targets as runtime version pairs (node 16.17 chrome 100 safari 15.4); the following lines are features. Using the starter's table of minimum versions and kinds, decide per feature: supported everywhere, polyfill (missing in <targets>) for built-ins, or transpile (missing in <targets>) for syntax; unknown names print unknown feature. Compare versions as dotted tuples — 16.17 is newer than 16.6, so never compare as floats. Finish with transpile target: ES<year> (the lowest level any target supports: Node 18+/Chrome 94+/Safari 15.4+ → 2022; Node 16/Chrome 85/Safari 14.1 → 2021; Node 14/Chrome 80/Safari 13.1 → 2020; else 2019), polyfills: <list or none>, syntax to transpile: <list or none>.

Example: node 16.17 chrome 100 safari 15.4 with optional-chaining, at, structuredClone, toSorted, using, fetch, flying-cars →

optional-chaining: supported everywhere
at: supported everywhere
structuredClone: polyfill (missing in node 16.17)
toSorted: polyfill (missing in node 16.17, chrome 100, safari 15.4)
using: transpile (missing in node 16.17, chrome 100, safari 15.4)
fetch: polyfill (missing in node 16.17)
flying-cars: unknown feature
transpile target: ES2021
polyfills: structuredClone, toSorted, fetch
syntax to transpile: using

In this module: Modern JavaScript and its tooling

← Runtimes and the ecosystem — Node, Deno, Bun, browsers, edge, and the web-standard core · How V8 runs your code — parsing, tiers, hidden classes and inline caches →