| name | javascript-reference |
| description | Use when writing, reviewing, or debugging JavaScript — reasoning about type coercion, equality, `this`, closures, scope/hoisting, prototypes, async/promises, iterators, modules, or the standard built-in objects, and when checking behavior against the ECMA-262 (ECMAScript 2025) language standard. Covers the language itself; host/runtime APIs (DOM, Node, browser) are out of scope. |
JavaScript Reference (ECMA-262 / ECMAScript 2025)
Overview
ECMA-262 defines the JavaScript language: its syntax, type system, evaluation semantics, and standard built-in objects. It does not define the DOM, fetch, console, Node's fs, timers, or modules resolution — those are host environments layered on top. This skill is the condensed-but-authoritative reference for the language itself.
Core principle: Most JS bugs come from a handful of semantics that are precise but unintuitive — coercion, == vs ===, this binding, closures over mutable bindings, floating-point, and reference vs value semantics. Reason from the spec's rules, not from what "looks right."
ECMAScript is versioned yearly; ES2025 is the 16th edition. Features here are annotated with the edition that introduced them where it matters. When behavior is contested, the linked spec is the source of truth.
When to Use
- Deciding why a coercion/comparison/
this value is what it is, or predicting output of a tricky snippet.
- Choosing the right language construct:
let/const/var, ==/===, for...of/for...in/forEach, class fields vs prototype, Map vs object.
- Writing correct async code: promises,
async/await, the microtask/task ordering, error propagation, cancellation.
- Using the standard library correctly (Array/Object/String/Map/Set/Reflect/Proxy/typed arrays/Intl) including ES2025 additions.
- Reviewing code for subtle correctness bugs (mutation aliasing,
NaN checks, integer precision, prototype pollution).
Not for: DOM/BOM, Node/Deno/Bun APIs, fetch/network, bundlers, TypeScript types, or framework patterns. Those are host/tooling concerns, not ECMA-262.
The Mental Model (read this first)
Everything is one of 8 language types. 7 primitives + object:
| Type | typeof | Notes |
|---|
| Undefined | "undefined" | sole value undefined |
| Null | "object" ⚠️ | sole value null; the typeof null bug is spec-mandated |
| Boolean | "boolean" | true / false |
| Number | "number" | IEEE-754 double; NaN, Infinity, -0 all exist |
| BigInt | "bigint" | arbitrary precision, literal 10n; never mixes with Number in arithmetic |
| String | "string" | immutable sequence of UTF-16 code units (not code points) |
| Symbol | "symbol" | unique immutable identifier |
| Object | "object" / "function" | callable objects report "function" |
Primitives are immutable and compared by value; objects are compared by reference. Assignment and argument passing copy the reference for objects — mutations are shared (aliasing).
Full details → language-core.md (types, coercion, equality, scope, this, prototypes).
Quick Reference
Falsy values (exactly 8) — everything else is truthy (including "0", "false", [], {}):
false 0 -0 0n "" null undefined NaN
=== (strict) — no coercion; different types ⇒ not equal. NaN === NaN is false. +0 === -0 is true.
== (loose) — coerces; avoid it. Only defensible use: x == null (true for null and undefined).
Object.is — like === but Object.is(NaN, NaN) is true and Object.is(+0, -0) is false.
Declarations:
| Scope | Hoist | Reassign | Redeclare | TDZ |
|---|
var | function | yes (→undefined) | yes | yes | no |
let | block | yes (uninit) | yes | no | yes |
const | block | yes (uninit) | no* | no | yes |
*const binds the binding, not the value — a const object is still mutable.
Number checks: Number.isNaN(x) (not global isNaN), Number.isInteger, Number.isSafeInteger, Number.MAX_SAFE_INTEGER (2⁵³−1). 0.1 + 0.2 !== 0.3.
ES2025 Highlights (16th edition)
| Feature | What it gives you |
|---|
| Iterator helpers | Lazy Iterator.prototype.{map,filter,take,drop,flatMap,reduce,toArray,forEach,some,every,find}, Iterator.from() — compose over any iterator without materializing arrays. |
| Set methods | Set.prototype.{union,intersection,difference,symmetricDifference,isSubsetOf,isSupersetOf,isDisjointFrom}. |
Promise.try(fn) | Run a possibly-sync-throwing fn and get a promise (sync throws become rejections). |
RegExp.escape(str) | Escape a string for safe literal use inside a RegExp. |
| Float16 | Float16Array, DataView.prototype.{getFloat16,setFloat16}, Math.f16round. |
| Duplicate named groups | Same (?<name>…) in different regex alternatives. |
| Import attributes + JSON modules | import cfg from "./c.json" with { type: "json" }. |
| RegExp modifiers | Inline flags: (?i:…) / (?-i:…) scope i/m/s to part of a pattern. |
Details and pre-2025 modern features (ES2015→2024) → syntax-and-features.md.
Reference Files
| File | Contents |
|---|
| language-core.md | Types & values, coercion rules (ToPrimitive/ToNumber/ToString), equality algorithms, truthiness, scope/hoisting/TDZ, closures, this binding, prototypes & inheritance, strict mode, class internals. |
| syntax-and-features.md | Modern syntax edition-by-edition (ES2015→ES2025): destructuring, spread/rest, arrow functions, classes & private fields, modules, optional chaining, nullish coalescing, logical assignment, generators, and the full ES2025 additions. |
| async-and-iteration.md | Job queue (microtask vs macrotask), Promises + combinators, async/await, error propagation, iteration protocols, generators, async iterators, for await…of. |
| builtins.md | Standard library: Object, Array, String, Number/Math, Map/Set/WeakMap/WeakSet/WeakRef, JSON, RegExp, Symbol, Reflect, Proxy, typed arrays/ArrayBuffer, Intl, Date (and the emerging Temporal). |
Common Mistakes
| Mistake | Reality / fix |
|---|
if (x == null) conflated with all falsy checks | == null matches only null/undefined; 0/""/NaN are not null. Use it deliberately. |
arr.indexOf(NaN) / === NaN | NaN is never equal to anything. Use Number.isNaN, arr.includes(NaN), or Array.prototype.findIndex. |
Expecting 0.1 + 0.2 === 0.3 | Floating point. Compare with an epsilon, or use integers/BigInt/decimal libs. |
this "lost" in a callback | this is set by call site, not definition (except arrow fns, which capture lexically). Use arrow, .bind, or class fields. |
var/let in a loop with async callbacks | var shares one binding; let/const create a fresh binding per iteration. Prefer let/const. |
| Mutating a shared object/array thinking it's copied | Objects pass by reference. Copy explicitly (spread, structuredClone, Array.from). Spread is shallow. |
for...in to iterate arrays | for...in enumerates string keys incl. inherited; order not guaranteed for integer-like intent. Use for...of, forEach, or entries(). |
sort() without a comparator on numbers | Default sort is by UTF-16 string order: [1,2,10].sort() → [1,10,2]. Pass (a,b)=>a-b. (TypedArray sort is numeric by default — the opposite.) |
typeof x === "object" to detect objects | null is also "object". Use , or , etc. |
Spec Navigation