JavaScript
JavaScript is a dynamically typed, single-threaded, garbage-collected programming language with first-class functions and prototype-based objects. It began as a browser scripting language in 1995 and is now the only language that runs natively in every web browser, plus a first-class server language via Node.js, Deno, and Bun.
What “JavaScript” actually means
Section titled “What “JavaScript” actually means”Three things get called JavaScript, and keeping them apart removes most confusion:
| Term | What it is |
|---|---|
| ECMAScript | The written language specification, maintained by TC39 and published by Ecma International as ECMA-262. Defines syntax, types, operators, and the built-in objects (Array, Promise, Math, …). |
| JavaScript | The common name for implementations of ECMAScript. The language itself. |
| The host environment | Everything the spec does not define: document, fetch, localStorage in a browser; fs, process, require in Node. These are APIs the host adds. |
This distinction matters constantly. Array.prototype.map works everywhere because it is ECMAScript. document.querySelector only works in a browser because it is a host API defined by the WHATWG DOM standard, not by ECMAScript.
Yearly versions
Section titled “Yearly versions”Since 2015 the spec ships once a year, named by year: ES2015 (also called ES6), ES2016, ES2017, and so on through ES2024, ES2025, and beyond. Each release is small — a handful of features that have already passed through TC39’s four-stage proposal process and shipped in real engines.
You will still see the old numbering: ES5 (2009) is the baseline that pre-modern browsers supported, and ES6 = ES2015 was the huge release that introduced let/const, arrow functions, classes, modules, promises, Map/Set, template literals, and destructuring. Most of what people mean by “modern JavaScript” arrived in ES2015.
Engines
Section titled “Engines”An engine is the program that actually parses and executes JavaScript. The major ones:
- V8 — Chrome, Edge, Node.js, Deno
- SpiderMonkey — Firefox
- JavaScriptCore — Safari, Bun
All modern engines are JIT (just-in-time) compilers: they parse your source to bytecode, interpret it, watch which functions run hot, then compile those to optimized machine code. You do not compile JavaScript ahead of time.
Where JavaScript runs
Section titled “Where JavaScript runs”In the browser
Section titled “In the browser”Every browser embeds an engine. The browser gives your code the DOM (an object model of the page), plus networking, storage, timers, and hundreds of other Web APIs. This is covered in the DOM and the browser.
<!doctype html><html> <body> <h1 id="title">Hello</h1> <script> document.getElementById('title').textContent = 'Hello from JavaScript'; </script> </body></html>On the server with Node.js
Section titled “On the server with Node.js”Node.js embeds V8 and adds APIs for filesystem access, networking, processes, and modules. It is how JavaScript became a general-purpose server language.
node --version# => v22.11.0 (or whatever you have)Deno and Bun are newer runtimes with the same core language. Deno emphasizes security-by-default (explicit permission flags) and built-in TypeScript. Bun emphasizes speed and bundles a package manager, test runner, and bundler. All three run standard ECMAScript; they differ in host APIs and tooling.
Everywhere else
Section titled “Everywhere else”The same engines are embedded in desktop apps (Electron), mobile apps (React Native), edge/serverless platforms (Cloudflare Workers, Vercel), and databases. If you learn the language, the host API is the only new part.
How to run the examples in this section
Section titled “How to run the examples in this section”You have three good options. Use whichever is closest to hand.
1. Browser console. Open any page, press F12 (or Cmd+Option+I on macOS), go to the Console tab, and type. It evaluates immediately and prints the result. Best for quick experiments and anything DOM-related.
2. A file with Node.
# create a filecat > demo.js <<'EOF'const users = ['ada', 'grace', 'alan'];console.log(users.map((n) => n.toUpperCase()));EOF
node demo.js[ 'ADA', 'GRACE', 'ALAN' ]3. The Node REPL. Run node with no arguments for an interactive prompt. It prints the value of every expression, so you do not need console.log.
nodeWelcome to Node.js v22.11.0.Type ".help" for more information.> 2 ** 101024> [1, 2, 3].reduce((a, b) => a + b)6> .exitYou can also run a one-liner without a file:
node -e "console.log(new Date().toISOString())"The nature of the language
Section titled “The nature of the language”Five properties shape almost everything about how JavaScript behaves. Understanding them up front makes the rest of this section click.
1. Dynamically typed
Section titled “1. Dynamically typed”Variables do not have types; values do. A variable can hold a number now and a string later. Types are checked at runtime, not before.
let x = 42;x = 'now a string'; // perfectly legalx = { legal: true }; // still legalThe upside is speed of writing. The downside is that type errors surface at runtime, sometimes far from the mistake. That is precisely the problem TypeScript solves.
2. Weakly typed, with implicit coercion
Section titled “2. Weakly typed, with implicit coercion”When you mix types, JavaScript converts rather than complaining. Sometimes that is convenient; sometimes it is the source of the language’s most famous oddities.
'5' + 3; // => '53' (+ prefers string concatenation)'5' - 3; // => 2 (- has no string meaning, so both become numbers)[] + {}; // => '[object Object]'The rules are learnable and mostly avoidable — see operators and control flow.
3. Prototype-based, not class-based
Section titled “3. Prototype-based, not class-based”Objects inherit directly from other objects through a hidden link called the prototype. There are no classes underneath — the class keyword added in ES2015 is syntax over the prototype system. See objects and prototypes.
4. Functions are first-class values
Section titled “4. Functions are first-class values”A function is an object. You can store it in a variable, pass it as an argument, return it from another function, and attach properties to it. Closures — functions that capture the variables around them — follow directly from this and are used everywhere. See functions and scope.
const twice = (fn) => (x) => fn(fn(x));const inc = (n) => n + 1;twice(inc)(5); // => 75. Single-threaded with an event loop
Section titled “5. Single-threaded with an event loop”Your JavaScript runs on one thread. It never runs two pieces of your code at the same time. Long operations (network requests, file reads, timers) are handed to the host, which calls you back later through the event loop. That is why asynchronous code is not optional in JavaScript — it is the only way to avoid freezing everything. See async JavaScript.
The mental model
Section titled “The mental model”Hold these four ideas and most JavaScript behavior becomes predictable:
-
Values are either primitives or objects. Primitives (
number,string,boolean,null,undefined,symbol,bigint) are immutable and copied by value. Everything else is an object, handled by reference. Nearly every “why did my array change?” bug is this. -
Scope is lexical. What a name refers to is decided by where the code is written, not where it is called from. The one exception is
this, which is decided by how a function is called — which is whythisconfuses people. -
Objects delegate. Looking up
obj.foochecksobj, then its prototype, then that prototype’s prototype, untilnull. Methods you did not define come from up that chain. -
The event loop runs one task at a time to completion. Nothing interrupts a running function. Callbacks, promises, and
awaitcontinuations all wait in queues for the current work to finish.
How this section is organized
Section titled “How this section is organized”Read in order the first time; each page assumes the ones before it.
| # | Page | What it covers |
|---|---|---|
| 2 | Syntax and types | The 8 types, typeof, numbers and BigInt, strings, null vs undefined, symbols, let/const/var, hoisting and the TDZ, ASI, strict mode |
| 3 | Operators and control flow | Operators, == vs === and coercion, truthy/falsy, ??/?./logical assignment, if/switch/loops, for..of vs for..in |
| 4 | Functions and scope | Declarations, expressions, arrows, parameters, closures, lexical scope, the four this binding rules, call/apply/bind, recursion, IIFEs |
| 5 | Objects and prototypes | Object literals, references, copying, descriptors, getters/setters, Object.freeze, the prototype chain, class, extends, private fields |
| 6 | Arrays and iteration | Array methods (mutating vs not), map/filter/reduce, sort gotchas, destructuring, spread/rest, iterators, Map/Set, JSON |
| 7 | Async JavaScript | Call stack, event loop, macrotasks vs microtasks, callbacks, promises, async/await, Promise.all and friends, fetch, timers |
| 8 | Modules and tooling | ES modules, dynamic import(), top-level await, CommonJS and interop, <script type="module">, bundlers and transpilers |
| 9 | The DOM and the browser | The DOM tree, selecting and building nodes, attributes vs properties, events and delegation, forms, fetch, storage, timers |
| 10 | Modern features and gotchas | Floating-point and coercion traps, a bug catalog, modern conveniences, Intl, error-handling patterns |
Conventions used here
Section titled “Conventions used here”- Results are shown as
// =>comments. Multi-line output uses atextblock. - Examples are runnable as written unless the surrounding context is obvious.
- Where behavior depends on the environment (browser vs Node), that is called out.
Key points
Section titled “Key points”- ECMAScript is the spec; JavaScript is the language; the DOM,
fetch, andfsare host APIs, not part of the language. - The spec ships yearly (ES2015 onward); ES2015 introduced most of what “modern JavaScript” means.
- Run code in the browser console, with
node file.js, or in thenodeREPL. - The language is dynamically typed, weakly typed, prototype-based, function-first, and single-threaded with an event loop.
- Primitives copy by value; objects are handled by reference. Scope is lexical;
thisis not.