JavaScript — Reference
Source: https://tc39.es/ecma262/
JavaScript
- Created: 1995 by Brendan Eich at Netscape (originally “Mocha”, then “LiveScript”); standardized as ECMAScript by Ecma International TC39
- Latest stable: ECMAScript 2025 ratified mid-2025; ES2026 in flight; latest editor’s draft tracks https://tc39.es/ecma262/. Node.js 26 (Current, 2026-05-05), Node.js 24 LTS “Krypton” (2025-05-06)
- Paradigms: multi-paradigm — prototype-based OO, functional, imperative, event-driven; classes are syntactic sugar over prototypes
- Typing: dynamic, weakly typed (with implicit coercion). Static layer via TypeScript or JSDoc.
- Memory: garbage collected — generational, mark-sweep + scavenger; per-engine details (V8, SpiderMonkey, JavaScriptCore)
- Compilation: JIT-compiled in modern engines (V8 Ignition+TurboFan/Maglev, SpiderMonkey IonMonkey/WarpMonkey, JSC LLInt+Baseline+DFG+FTL). Originally interpreted.
- Primary domains: browser frontend, server-side (Node.js, Deno, Bun), desktop (Electron, Tauri), mobile (React Native, Capacitor), serverless / edge, embedded scripting
- Official docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript
At a glance
- Standard: ECMA-262, annual yearly snapshots since ES2015. Living spec at https://tc39.es/ecma262/.
- Engines: V8 (Chrome, Node.js, Deno, Edge), SpiderMonkey (Firefox), JavaScriptCore / Nitro (Safari, Bun uses JSC), Hermes (React Native), QuickJS (embedded).
- Runtimes: browsers, Node.js, Deno (TS-first, secure-by-default), Bun (Zig + JSC, npm-compatible, fast), Cloudflare Workers (V8 isolates), edge platforms (Vercel, Netlify, Fastly Compute).
- Governance: TC39 with stage process 0-4; Stage 4 = in the next yearly snapshot.
Getting started
Install:
- Browsers: built in.
- Node.js: https://nodejs.org/ — installer, or version manager:
nvm(POSIX),fnm(Rust),volta,nvs(Windows). Bun and Deno include their own version managers (bun upgrade,deno upgrade). - For Node 24+ projects, prefer Corepack to pin pnpm/yarn versions.
Hello world (browser):
<script>console.log("Hello, world!");</script>Hello world (Node.js):
// hello.mjs
console.log("Hello, world!");Run: node hello.mjs.
Project layout (Node, ESM):
myapp/
package.json # "type": "module"
src/
index.js
test/
index.test.js
node_modules/
package-lock.json
Package managers:
npm(bundled with Node),pnpm(content-addressed store, fast),yarn(Berry / v4, PnP),bun(built-in).- Lockfiles:
package-lock.json,pnpm-lock.yaml,yarn.lock,bun.lockb.
REPL / playground: node or node --experimental-repl-await. Browser DevTools console. Online: https://playcode.io, https://stackblitz.com, MDN’s “Try it” boxes.
Basics
Primitives: number (IEEE 754 double, 53-bit safe int), bigint (123n), string (UTF-16), boolean, symbol, undefined, null. Plus object (incl. arrays, functions, dates, maps).
Variables / scope:
const x = 10; // block-scoped, immutable binding (value can mutate if object)
let y = 1; // block-scoped, reassignable
var z = 2; // function-scoped, hoisted (legacy — avoid)Closures capture by reference; this is dynamic (fn.call, arrow functions inherit lexical this).
Control flow: if/else, for, for...of (iterables), for...in (enumerable keys, avoid for arrays), while, do/while, switch, try/catch/finally, throw.
Functions:
function add(a, b = 0, ...rest) { return a + b + rest.length; }
const sub = (a, b) => a - b; // arrow — no own `this`, no `arguments`
async function fetchJson(url) { return (await fetch(url)).json(); }
function* range(n) { for (let i = 0; i < n; i++) yield i; } // generatorStrings: template literals (backtick) with ${expr}, tagged templates, raw strings via String.raw.
const name = "world";
console.log(`Hello, ${name}!`);Built-in collections: Array, Object (string-keyed), Map, Set, WeakMap, WeakSet, WeakRef, Date, RegExp, typed arrays (Uint8Array, Float32Array, etc.), ArrayBuffer, SharedArrayBuffer, DataView.
Intermediate
Types & inference: none natively. JSDoc + // @ts-check gives editor-grade typing without TS. Most modern Node/Deno projects use TypeScript directly. Type erasure proposal (Stage 1) would let JS engines parse-and-strip TS-style annotations.
Modules: ESM (import/export, .mjs or "type":"module") is the standard. CommonJS (require/module.exports) is legacy but pervasive in Node. Dynamic import() returns a Promise. Import attributes for non-JS resources: import data from "./d.json" with { type: "json" }.
Errors: throw any value, but throw Error subclasses (TypeError, RangeError, SyntaxError, custom class MyError extends Error). try/catch (err) — err is unknown style; check with instanceof. AggregateError for Promise.any. Error.cause for chaining.
Concurrency:
- Single-threaded event loop per realm. Tasks vs microtasks (
queueMicrotask). Promise(.then/await/Promise.all/Promise.allSettled/Promise.race/Promise.any/Promise.try).- Async iterators (
for await ... of) and async generators. - Workers:
Worker(browsers),worker_threads(Node),Web Worker/Service Worker,SharedWorker. SharedArrayBuffer+Atomicsfor shared-memory parallelism.AbortController/AbortSignalfor cancellation.
File I/O / networking:
- Browser:
fetch,WebSocket,XMLHttpRequest(legacy),IndexedDB,OPFS. - Node:
node:fs/promises,node:fs,node:net,node:http,node:https,node:dgram, plus a built-infetchsince 18,node:testrunner,node:sqlite(24+). - Deno/Bun: web-standard APIs first (
fetch,Request,Response).
Stdlib highlights: Intl (i18n: Intl.NumberFormat, Intl.DateTimeFormat, Intl.Segmenter, Intl.Collator), URL / URLPattern, TextEncoder/TextDecoder, crypto.subtle (Web Crypto), structuredClone, Temporal (Stage 3, shipping in engines).
Advanced
Memory model & GC:
- V8: generational (young / old), Scavenger for young, Mark-Compact for old, Orinoco concurrent / parallel collector. Pointer compression on 64-bit.
- Tune Node:
--max-old-space-size=4096,--max-semi-space-size,--gc-interval,--expose-gcforglobal.gc(). - Inspect heap:
--inspect, Chrome DevTools Heap Snapshot,clinic.js,0x(flamegraphs).
Concurrency deep dive:
- Microtask queue (Promises) drains between macrotasks.
Atomics.wait/notifyfor futex-style sync overSharedArrayBuffer.- Worker pools via
piscina(Node). AsyncContext(Stage 3 TC39) — async-aware context propagation.- Node
node:clusterfor multi-process;worker_threadsfor CPU-bound.
FFI / interop:
- Node: N-API / node-addon-api (stable C ABI), Node-API with
napi-rs(Rust),neon(Rust), legacynan. WASI for portable native modules. - Deno:
Deno.dlopendirect FFI to.so/.dll/.dylib. - Bun:
bun:ffidirect FFI. - Browser: WebAssembly (
WebAssembly.instantiate),Emscripten,wasm-bindgen(Rust).
Reflection / introspection: Object.keys/getOwnPropertyDescriptors/getPrototypeOf/getOwnPropertyNames, Reflect.*, Symbol.iterator/asyncIterator/hasInstance/toPrimitive, instanceof, typeof, Function.prototype.toString returns source.
Performance tuning:
- V8 inspection:
--trace-opt,--trace-deopt,--prof,--prof-process,--print-bytecode,--allow-natives-syntaxthen%OptimizeFunctionOnNextCall(fn). - Tools: Chrome DevTools Performance / Memory,
node --inspect,clinic.js doctor/flame/bubbleprof,0x,autocannon(HTTP load),mitata/tinybench(microbenchmarks). - Avoid hidden-class polymorphism — initialize objects with the same property order; don’t add/delete props on hot paths.
God mode
Proxy & Reflect: intercept any object operation.
const audited = new Proxy(target, {
get(t, p, r) { console.log("get", p); return Reflect.get(t, p, r); },
set(t, p, v, r) { console.log("set", p, v); return Reflect.set(t, p, v, r); },
});Underpins Vue 3 reactivity, immer, MobX, observable proxies.
Iteration & generator protocols: any object implementing [Symbol.iterator]() or [Symbol.asyncIterator]() works in for...of. Generators support .return() / .throw() for cooperative cancellation.
V8 internals: hidden classes (Maps), inline caches (ICs), CodeStubAssembler / Torque for builtins, Sea-of-Nodes IR. --print-code dumps machine code for hot functions. Sparkplug → Maglev → TurboFan tier-up.
AsyncContext: propagate context across await boundaries without monkeypatching. Replaces domain / async-local-storage hacks.
SharedArrayBuffer + Atomics: the only path to true shared-memory parallelism. Requires COOP/COEP cross-origin isolation in browsers. Atomics.waitAsync is non-blocking.
BigInt + Atomics: BigInt64Array works with Atomics; useful for lock-free 64-bit counters and futexes from WASM.
Eval scope tricks: direct eval("x = 1") sees / mutates caller’s local scope; indirect (0, eval)("x = 1") runs in global scope. new Function(...) always global. Both are usually the wrong answer.
Realms / iframes: different realms have different Array, so arr instanceof Array can lie. Use Array.isArray(arr).
Decorators (Stage 3, ES2023+ shipping):
function logged(value, { kind, name }) {
if (kind === "method") return function (...args) { console.log(name); return value.apply(this, args); };
}
class C { @logged greet() {} }Engine embedding: V8 embedder API (v8::Isolate, v8::Context), JSC API (JSContext, JSValue), QuickJS for tiny embeds, Hermes for AOT-compiled bytecode (React Native).
Bytecode:
- V8 Ignition: stack-based, viewable via
--print-bytecode. - JSC LLInt: low-level interpreter, also visible.
- Hermes: AOT to
.hbcbytecode, ship that instead of JS.
Idioms & style
- Naming:
camelCasefor vars/functions,PascalCasefor classes/constructors,SCREAMING_SNAKEfor module-level constants,_private(convention),#truly-private(class private fields, ES2022). - Formatters: Prettier (de facto), Biome (Rust, all-in-one fmt+lint, fast),
dprint. - Linters: ESLint (v9+ flat config), Biome, oxlint (Rust, fast subset). Common configs:
eslint-config-airbnb,@typescript-eslint,eslint-plugin-import. - Idiomatic patterns:
constby default,letonly when reassigning, nevervar.===/!==over==/!=(avoid coercion).- Destructuring + default params:
function f({ a = 1, b } = {}) {}. - Async/await over raw Promise chains.
- Optional chaining
?.and nullish coalescing??over&&/||for null-vs-falsy distinctions. - Module side effects only when intentional; prefer pure exports.
- Avoid
classwhen a closure-returning factory is enough.
- What reviewers flag:
var, missingawait, floating Promises (no-floating-promisesrule),JSON.parse(JSON.stringify(x))for cloning (usestructuredClone), mutating shared state in arrow callbacks, broadcatch (e) {}.
Ecosystem
| Domain | Tools |
|---|---|
| Frontend | React, Vue, Svelte / SvelteKit, SolidJS, Angular, Qwik, Astro, Lit, Preact |
| Meta-frameworks | Next.js, Nuxt, SvelteKit, Remix / React Router 7, Astro, Qwik City |
| Server | Express, Fastify, Koa, Hono, NestJS, AdonisJS, ElysiaJS (Bun) |
| Build / bundle | Vite (Rolldown-based 2026), webpack, esbuild, Rolldown, Turbopack, Parcel |
| Type-aware build | tsc, swc, Babel, oxc |
| Test | Vitest, Jest, node:test, Mocha, Playwright (e2e), Cypress, Testing Library |
| State | Zustand, Redux Toolkit, Jotai, MobX, Pinia (Vue), Effector |
| ORM / DB | Prisma, Drizzle, Kysely, TypeORM, MikroORM, Mongoose |
| Mobile | React Native, Expo, Capacitor, NativeScript |
| Desktop | Electron, Tauri (Rust shell, JS frontend), Neutralino |
| Notable users | Google (V8, Angular), Meta (React, RN, Hermes), Netflix, Microsoft (TS, VS Code), Vercel, Stripe |
Gotchas
==coercion:[] == falseis true,0 == "0"is true,null == undefinedis true. Use===.typeof null === "object"— historical bug, never fixed.NaN !== NaN— useNumber.isNaN(x)orObject.is(x, NaN).- Floating point:
0.1 + 0.2 === 0.3is false. Use BigInt or fixed-point for money. thisrebinding: lost when you pass a method as a callback. Bind it (fn.bind(this)) or use arrows.for...inon arrays — iterates keys as strings, plus inherited enumerable props. Usefor...oforforEach.- Hoisting:
varand function declarations hoist;let/constare in the temporal dead zone until initialized. - Implicit globals: assignment to undeclared name in non-strict mode creates a global. Use
"use strict"or modules (always strict). - Floating Promises: unhandled rejections crash Node by default in 22+. Always
awaitor.catch(). Dateis awful — month is 0-indexed, mutable, no timezone. UseTemporal(Stage 3) ordate-fns/Luxon.- JSON limitations: no BigInt, no
undefined, no functions, no circular refs, dates become strings. - Newcomers from Java/C#: no method overloading, no real privacy except
#field, no compile-time type errors without TS. - Newcomers from Python: truthiness differs (
"",0,null,undefined,NaN,falseare falsy;[]and{}are truthy). Object key order is “integer-like keys ascending, then string keys insertion-order.”
Citations
- MDN Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript
- ECMA-262 (living spec): https://tc39.es/ecma262/
- TC39 finished proposals: https://github.com/tc39/proposals/blob/main/finished-proposals.md
- TC39 process / stages: https://tc39.es/process-document/
- Node.js docs: https://nodejs.org/docs/latest/api/
- Node.js release schedule: https://nodejs.org/en/about/previous-releases
- V8 blog: https://v8.dev/blog
- Deno manual: https://docs.deno.com/runtime/manual
- Bun docs: https://bun.sh/docs
- Temporal proposal: https://tc39.es/proposal-temporal/docs/
- AsyncContext proposal: https://github.com/tc39/proposal-async-context
- Decorators proposal: https://github.com/tc39/proposal-decorators