How JavaScript Actually Runs: Engines, Runtimes, and the Languageโs Real Story
JavaScript is the most-deployed programming language in history โ it runs on effectively every phone, laptop, and server-adjacent surface on Earth โ and itโs also the language most people learn backwards. They start with document.getElementById, absorb a pile of framework habits, and never form a model of whatโs actually executing their code. Then the weird parts of JS (and there are weird parts) feel like random hazing instead of explainable history.
This guide is the missing first chapter: where JavaScript came from, what an engine and a runtime actually are, how your code gets executed, and why the language behaves the way it does. Everything else in this series builds on this foundation.
Ten Days in 1995: The History That Explains the Quirks
JavaScript was created by Brendan Eich at Netscape in ten days in May 1995. Thatโs not an exaggeration for effect โ itโs the documented timeline, and it explains more about the language than any other single fact.
Netscape wanted a lightweight scripting language for web pages โ something designers could sprinkle into HTML, forgiving of errors, requiring no compiler. Eich originally wanted to build something Scheme-like; management wanted it to โlook like Javaโ for marketing reasons (Java was the hot new thing). The name โJavaScriptโ was pure marketing โ Java and JavaScript are unrelated languages that share four letters and nothing else of consequence.
The ten-day birth left artifacts you still live with:
- Loose typing and silent coercion (
"5" - 1is4;"5" + 1is"51") โ designed to keep scripts running instead of crashing on a designerโs typo. - Two โemptyโ values (
nullandundefined), and the famoustypeof null === "object"bug โ shipped in 1995, unfixable forever because fixing it would break the web. - Fail-soft everywhere: accessing a missing property gives
undefinedinstead of an error; that only crashes later when you use it. Debugging JS means working backwards from where a bad value exploded to where it was born.
In 1997, the language was standardized as ECMAScript (Netscape submitted it to the Ecma standards body; โJavaScriptโ was trademark-encumbered). Thatโs why you see โES6โ, โES2015โ, โES2023โ โ versions of the ECMAScript specification. The transformative release was ES6/ES2015, which added let/const, classes, modules, arrow functions, promises, and destructuring โ effectively the modern language. Since then, a new spec lands every June, and the language you should learn (and this series teaches) is the post-2015 one.
The other historical constraint that shapes everything: โdonโt break the web.โ Every quirk shipped in 1995 must work forever, because billions of pages depend on old behavior. JavaScript evolves strictly by addition. Thatโs why old bad features (like var, or ==) still exist alongside their replacements (let/const, ===) โ and why learning JS well is partly learning which half of the language to use.
Engine vs. Runtime: The Distinction That Unconfuses Everything
When people say โJavaScript runs in the browser,โ theyโre blurring two layers that are worth separating.
The engine executes the language itself โ parsing your source, compiling it, running it, managing memory. The major engines:
- V8 โ Googleโs engine: Chrome, Edge, Node.js, Deno, Electron.
- JavaScriptCore โ Appleโs: Safari, and the Bun runtime.
- SpiderMonkey โ Mozillaโs: Firefox (and the direct descendant of Eichโs original).
The runtime wraps an engine and provides everything else โ the APIs your code calls that arenโt part of the language:
โโโโโโโโโโโโโโโโ Browser runtime โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ Node.js runtime โโโโโโโโโโโโโโ V8 engine (the language itself) โ โ V8 engine (the same language) โโ + DOM (document, elements, events) โ โ + file system (fs), network sockets โโ + fetch, timers, localStorage, canvas... โ โ + process, streams, fetch, timers... โโ + the event loop (from the browser) โ โ + the event loop (from libuv) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโThis is why document.querySelector doesnโt exist in Node, and why fs.readFile doesnโt exist in a browser โ neither is JavaScript. Theyโre runtime APIs. The language โ closures, promises, arrays, objects โ is identical in both. Internalizing this split pays off constantly: when you read documentation, youโll know whether youโre learning JavaScript (portable everywhere) or a runtimeโs API (portable nowhere).
Notably, even things that feel core to JS โ setTimeout, console.log, fetch โ are runtime APIs, not language features. The ECMAScript spec doesnโt define any of them.
What Happens When Your Code Runs
JavaScript is often called an โinterpreted language,โ which was true in 1995 and is misleading now. Modern engines are sophisticated JIT (just-in-time) compilers, and the pipeline matters for understanding performance:
- Parse โ source code becomes an AST (abstract syntax tree). Syntax errors surface here, before anything runs.
- Baseline execution โ an interpreter (V8โs is called Ignition) starts executing bytecode immediately. Fast to start, modest speed.
- Optimization โ the engine profiles as it runs. Functions that run hot get compiled to optimized machine code (V8โs TurboFan), with aggressive assumptions based on observed behavior: โthis variable has always been a number; compile arithmetic accordingly.โ
- Deoptimization โ if an assumption breaks (that โalways a numberโ variable suddenly gets a string), the engine throws away the optimized code and falls back. Correct behavior, big performance cliff.
You donโt need to think about this daily, but it explains real phenomena: why JS can be shockingly fast (near-native for hot numeric loops), why performance advice says keep object shapes consistent and donโt change a variableโs type mid-flight, and why microbenchmarks lie (they measure whichever tier happened to be active).
One more execution fact that shapes the whole language: JavaScript is single-threaded. One call stack, one statement executing at a time. There is no โspawn a threadโ in the core language. Instead, JS handles concurrency through the event loop โ an architecture where slow operations (network, timers, disk) are delegated to the runtime, and their callbacks run later, one at a time, when the stack is free. This design is why JS is so async-heavy โ callbacks, promises, async/await โ and itโs important enough to get its own deep dive in this series. For now, hold the one-sentence version: JavaScript never waits; it schedules.
Where JavaScript Runs Now
The 1995 pitch was โscripts for web pages.โ The 2026 reality:
- Every browser UI โ the only language browsers execute natively. (WebAssembly runs alongside, but itโs compiled from other languages and still typically glued together with JS.)
- Servers โ Node.js (2009) put V8 on the server; Deno and Bun are younger alternatives. A huge share of APIs, tooling, and real-time backends run server-side JS.
- Desktop apps โ Electron (VS Code, Slack, Discord are all JS/TypeScript applications).
- Mobile โ React Native and friends.
- Nearly all web tooling โ the bundlers, linters, and frameworks that build the web are themselves JS/TS projects.
The strategic consequence: JavaScript is the highest-leverage single language for anyone working near the web, because one language covers client, server, and tooling. Its flaws are real, but โlearn it once, use it everywhereโ has proven to be an unbeatable proposition.
A note on TypeScript, because youโll meet it immediately: TypeScript is JavaScript plus a static type layer, compiled down to plain JS before running. It has become the default for serious projects. Everything in this series is TypeScript-relevant โ TS is JS at runtime โ and learning JS deeply first makes TSโs type system make sense rather than feel like ritual.
Your First Real Look at the Language
You can follow this entire series with zero installation: every browser ships a console (F12 โ Console tab), which is a full JS REPL. Or install Node and run node for the same thing in a terminal. Try this:
// values and variables โ const by default, let when reassignment is neededconst language = "JavaScript";let age = 2026 - 1995;
// template literals โ modern string buildingconsole.log(`${language} is ${age} years old`);
// functions are values you can pass around โ the heart of JS styleconst twice = (f, x) => f(f(x));const inc = (n) => n + 1;console.log(twice(inc, 40)); // 42
// objects are ad-hoc and flexibleconst engine = { name: "V8", vendor: "Google", browsers: ["Chrome", "Edge"] };console.log(engine.browsers.length); // 2
// and the famous coercion quirks are real โ we'll tame them next chapterconsole.log("5" + 1); // "51"console.log("5" - 1); // 4That fifth line โ passing a function to a function โ is the single most JavaScript thing in the snippet. Functions as first-class values shape everything: array methods, event handlers, promises, React components. If you come from Java, this is the mental shift; JS got lambdas-everywhere twenty years before Java 8 did.
A Map of the Weird (So It Doesnโt Ambush You)
An honest orientation to the rough edges, each covered properly later in the series:
| Quirk | One-line preview | Deep dive |
|---|---|---|
== vs === | == coerces types before comparing; always use === | Types & coercion |
var hoisting | var ignores block scope; use let/const | Variables & scope |
this | Depends on how a function is called, not where itโs written | The this keyword |
| Closures | Functions remember variables from where they were born | Closures |
| Async timing | setTimeout(fn, 0) doesnโt run โimmediatelyโ | Event loop |
0.1 + 0.2 !== 0.3 | Floating point, same as every language | Types & coercion |
Two reassurances. First: the modern language, written with current idioms (const, ===, arrow functions, modules, async/await), avoids most of the traps by construction โ the quirks mostly live in the legacy half youโll learn to recognize and not write. Second: every quirk has a mechanical explanation. JS is not random; itโs over-backward-compatible. The aim of this series is that nothing in the language feels like magic โ just history plus rules.
Frequently Asked Questions
Should I learn JavaScript or TypeScript first? JavaScript โ but briefly. Learn the core language (this series), then adopt TypeScript early in real projects. TS errors are incomprehensible without understanding the JS underneath; JS-without-types is unpleasant to maintain at scale. Theyโre one skill with two stages, not competitors.
Do I need to learn jQuery / older patterns? No for new work; recognition-level only for maintaining old code. Modern DOM APIs (querySelector, fetch, classList) absorbed jQueryโs good ideas years ago.
Which runtime should I practice in? Browser console for DOM-adjacent experiments, Node for everything else โ the language is identical. When this series touches runtime-specific APIs (like fetch or the DOM), it says so explicitly.
Is JavaScript slow? For the single-threaded, IO-heavy work it typically does โ no; V8 is an engineering marvel, and the event-loop model handles massive concurrency well. For CPU-parallel number crunching, itโs the wrong tool (thatโs what workers and WebAssembly patch over). Right tool, right job.
How much of this can AI tools write for me now? A lot of the typing โ and none of the judgment. Generated code with a subtle this bug, a swallowed promise rejection, or an accidental type coercion looks exactly like working code. The developers who thrive with AI assistance are the ones who can read a diff and spot whatโs wrong โ which is precisely the mental-model knowledge this series builds.
Whatโs Next
You now have the frame: a ten-day language standardized as ECMAScript, executed by JIT-compiling engines, embedded in runtimes that add the APIs, single-threaded with an event loop, evolving by addition, weird for explainable reasons.
Next: Variables and Scope โ let, const, the var youโll learn to recognize and avoid, hoisting, and the scoping rules that closures (the languageโs crown jewel) are built on.