JavaScript was prototyped in ten days in May 1995 to make static web pages interactive. Three decades later it is the only programming language that runs natively in every web browser, powers servers through Node.js, and ships in edge runtimes worldwide. This post traces that journey — from Netscape's LiveScript and the marketing-driven rename, through the ECMA standardisation that gave us ECMAScript, the watershed ES6 release in 2015, the yearly cadence that followed, and the latest features landing in ES2022, ES2023 and ES2024.
The early web and the need for interactivity
In the early 1990s the web was a read-only medium. Pages were static documents — text, images, hyperlinks, basic styling — and every interaction required a full round trip to the server. Submitting a form meant a full page reload. Validating a phone number meant waiting on the network. Showing or hiding a section meant a new HTTP request.
Developers and users alike wanted local, immediate behaviour in the browser itself. The race to add that interactivity is what produced JavaScript.
Two browsers, one race
Two browsers dominated the era:
- Netscape Navigator — the commercial descendant of the original Mosaic browser, led by Marc Andreessen.
- Microsoft Internet Explorer — bundled with Windows from 1995 onward and rapidly catching up.
Both vendors knew that whoever shipped a browser-side scripting language first would shape the future of the web. Netscape moved first.
Brendan Eich and the ten-day prototype
In April 1995, Netscape hired Brendan Eich with a brief that read more like a koan than a job spec: design a “Scheme for the browser” — but make it look like Java so management would approve. Eich had ten days.
The original prototype was called Mocha. It borrowed:
- First-class functions and closures from Scheme.
- Prototype-based objects from Self (a Smalltalk derivative from Sun).
- C-like syntax with curly braces,
if/else,for, andwhilefrom Java and C.
That unusual genetic mix is why JavaScript today still feels both functional (map, filter, closures, first-class functions) and imperative (loops, mutation, classes added later as syntactic sugar). It also explains some of the language’s stranger corners — type coercion, this binding, and prototype lookup — none of which a more leisurely design process would have shipped unchanged.
LiveScript to JavaScript: a quick rebranding
Mocha was renamed LiveScript in September 1995, then renamed again to JavaScript in December 1995 as part of a co-marketing deal with Sun Microsystems. Java was the hottest language in the industry at that moment; tying the new browser language to the Java brand was pure marketing.
Important
JavaScript and Java are not related. They share four letters and a curly-brace syntax. Their type systems, runtime models, and design goals are entirely different. The name has caused thirty years of confusion in interviews, books, and search results.
Microsoft’s response: JScript
Microsoft quickly reverse-engineered the Netscape implementation and shipped JScript in Internet Explorer 3 (August 1996). Subtle behavioural differences between JScript and Netscape’s JavaScript — different DOM models, different timer semantics, different regex quirks — produced the cross-browser nightmares that dominated front-end development for the next decade. They are also what motivated the push toward a vendor-neutral standard.
Standardisation: from JavaScript to ECMAScript
In November 1996 Netscape submitted JavaScript to Ecma International (then ECMA) for standardisation. The resulting specification is called ECMA-262, and the language it defines is ECMAScript. “JavaScript” survives as the everyday name for implementations that conform to ECMAScript.
Note
Ecma does not write code. It publishes a specification that engine implementers — V8 (Google), SpiderMonkey (Mozilla), JavaScriptCore (Apple), formerly ChakraCore (Microsoft) — follow when building runtimes. The spec is what gives
Array.prototype.mapandPromise.allidentical semantics in every browser.
Why the name “ECMAScript”?
The name was deliberately ugly. Sun (later Oracle) held the trademark on “Java”, which meant the standards body could not use “JavaScript” either. “ECMAScript” was the safe legal compromise. Eich himself called it “an unwanted trade name that sounds like a skin disease.”
The TC39 process
ECMAScript is maintained by TC39 (Technical Committee 39 within Ecma International), a group of engine implementers, framework authors, and language designers. Anyone can read meeting notes and proposals on GitHub.
Every feature moves through five stages:
| Stage | Name | Meaning |
|---|---|---|
| 0 | Strawperson | Idea, not yet a formal proposal |
| 1 | Proposal | A champion takes it on; problem and solution sketched |
| 2 | Draft | Initial spec text; experimental implementation expected |
| 3 | Candidate | Spec is mostly final; needs implementer feedback |
| 4 | Finished | Two compliant implementations, tests pass; ships in next yearly edition |
This staged process is why you can read about upcoming features (pattern matching, decorators, record/tuple, pipeline operator) years before they appear in any release. It also means anything stage 4 is safe to learn — it will ship.
ECMAScript editions at a glance
| Edition | Year | Highlights |
|---|---|---|
| ES1 | 1997 | First standard |
| ES2 | 1998 | Editorial only (ISO alignment) |
| ES3 | 1999 | Regex, try/catch, switch, do/while |
| ES4 | — | Abandoned — too ambitious; classes, types, namespaces |
| ES5 | 2009 | Strict mode, JSON, Object.create, getters/setters |
| ES5.1 | 2011 | Editorial alignment with ISO/IEC 16262 |
| ES6 / ES2015 | 2015 | let/const, arrow functions, classes, modules, promises, template literals, destructuring |
| ES2016 (ES7) | 2016 | ** operator, Array.prototype.includes |
| ES2017 (ES8) | 2017 | async/await, Object.values/entries, string padding |
| ES2018 (ES9) | 2018 | Object rest/spread, async iteration, Promise.finally, RegExp lookbehind |
| ES2019 (ES10) | 2019 | Array.flat/flatMap, Object.fromEntries, optional catch binding |
| ES2020 (ES11) | 2020 | Optional chaining ?., nullish coalescing ??, BigInt, Promise.allSettled |
| ES2021 (ES12) | 2021 | String.replaceAll, logical assignment ??= &&= ||=, WeakRef |
| ES2022 (ES13) | 2022 | Top-level await, class fields (public/private), Array.prototype.at, Object.hasOwn, error cause |
| ES2023 (ES14) | 2023 | findLast/findLastIndex, non-mutating array methods (toSorted, toReversed, toSpliced, with), hashbang grammar |
| ES2024 (ES15) | 2024 | Promise.withResolvers, grouping (Object.groupBy, Map.groupBy), ArrayBuffer.prototype.resize, well-formed JSON.parse |
ES6 in 2015 was the watershed. After it, TC39 moved to a yearly release cadence. Editions are now small, predictable, and shippable.
The lost decade: why ES4 failed
ES4 was meant to land in the early 2000s with classes, types, packages, namespaces, and many ideas later adopted by ActionScript 3. Disagreements between Mozilla and Microsoft about scope and complexity stalled the work for years. The committee eventually scrapped ES4 entirely in 2008 and shipped the much smaller ES5 the following year.
Most of the abandoned ES4 features eventually returned — classes in ES6, types in TypeScript, decorators still in the proposal pipeline. The lesson the committee took from ES4 is ship smaller, more often.
Visualising the timeline
The Node.js inflection point (2009)
For its first fourteen years JavaScript ran only in the browser. That changed in 2009 when Ryan Dahl released Node.js — a server-side runtime built on Google’s V8 engine with a non-blocking I/O model designed for high-concurrency network servers.
Three things made Node significant:
- JavaScript everywhere. Developers could now write both ends of a web app in the same language, sharing validation logic, data shapes, and tests.
- npm. The Node Package Manager (2010) became the largest package registry in software history. Today npm hosts over 3 million packages.
- A tooling explosion. Every modern front-end build tool — webpack, Babel, ESLint, Prettier, Vite, esbuild, Bun — runs on Node (or a Node-compatible runtime).
Without Node, ES6 modules, TypeScript, React, and the modern web stack would look very different.
Where JavaScript runs today
JavaScript always needs a host environment — a runtime that provides the I/O, timers, networking, and bindings the language itself does not define.
| Host | Engine | Typical use |
|---|---|---|
| Chrome, Edge, Brave, Opera | V8 | Browser apps |
| Firefox | SpiderMonkey | Browser apps |
| Safari, iOS WebKit views | JavaScriptCore | Browser apps |
| Node.js | V8 | Servers, tooling, CLIs |
| Deno (2018) | V8 | Secure servers, TypeScript-first |
| Bun (2022) | JavaScriptCore | Fast servers, bundler, test runner |
| Cloudflare Workers, Vercel Edge | V8 isolates | Edge functions |
| Electron, Tauri | V8 / system WebView | Desktop apps |
| React Native, NativeScript | Hermes / JSC / V8 | Mobile apps |
Feature support varies across engines and versions. The community-maintained compat-table and caniuse.com are the canonical references.
Note
Modern engines all implement the latest ECMAScript edition within months of its release. The “what works in IE11” problem is largely historical — IE11 reached end-of-life in June 2022.
TypeScript: a complementary story
Microsoft released TypeScript in October 2012 as a typed superset of JavaScript that compiles down to plain ECMAScript. TypeScript does not extend the runtime — it adds a static type system on top, and erases types at build time. Most modern frameworks (Angular, Next.js, NestJS, SvelteKit, Astro, Nuxt) default to TypeScript today, but everything they produce is still ECMAScript.
1// TypeScript source (with types)
2function greet(name: string): string {
3 return `Hello, ${name}`;
4}
5
6// What ships to the runtime (types erased)
7function greet(name) {
8 return `Hello, ${name}`;
9}
Important
TypeScript is not an ECMAScript edition. It tracks ECMAScript and adds types. Anything in TypeScript that is not a type annotation is plain JavaScript.
A taste of modern JavaScript (ES2022+)
To anchor how much the language has changed, here is the same “fetch a user, group by role” task written in ES3-era and ES2024 styles.
ES3-era (circa 2008):
1function fetchUsers(callback) {
2 var xhr = new XMLHttpRequest();
3 xhr.open('GET', '/api/users');
4 xhr.onreadystatechange = function () {
5 if (xhr.readyState === 4 && xhr.status === 200) {
6 var users = JSON.parse(xhr.responseText);
7 var grouped = {};
8 for (var i = 0; i < users.length; i++) {
9 var role = users[i].role;
10 if (!grouped[role]) grouped[role] = [];
11 grouped[role].push(users[i]);
12 }
13 callback(null, grouped);
14 }
15 };
16 xhr.send();
17}
ES2024:
1const users = await (await fetch('/api/users')).json();
2const grouped = Object.groupBy(users, (u) => u.role);
Two lines instead of fifteen, with await and Object.groupBy (both ES2022+). That compression is the practical legacy of three decades of TC39 work.
Why the history still matters
Understanding the history clears up several daily confusions:
- Why
varbehaves so strangely → it predatesletandconstby twenty years. See Variables, scope and hoisting. - Why arrow functions exist → fixing the long-standing
thisbinding mess of ES3-era code. See Modern function features. - Why classes look the way they do → syntactic sugar over the prototype model that has been in the language since day one. See ES6 classes.
- Why modules took until 2015 → the language was originally embedded in
<script>tags with no module system. See JavaScript modules. - Why type coercion is so quirky → it dates from the ten-day prototype and could never be fixed without breaking the web.
JavaScript’s journey from a ten-day prototype to a standardised, yearly-released language is unique in computing. The constraints of that history are still visible in the syntax — but the modern ES2022+ language is genuinely pleasant to write.
Further reading
- TC39 proposals — every proposal at every stage.
- ECMA-262 latest — the living specification.
- MDN: JavaScript reference — the practical reference.
- Node.js history — the runtime that took JavaScript off the browser.
- JavaScript: The Good Parts, Douglas Crockford (2008) — historical, but still illuminating.1
- Eloquent JavaScript, Marijn Haverbeke (4th edition, 2024) — free online, modern.2
Crockford, D. (2008). JavaScript: The Good Parts. O’Reilly Media. ISBN 978-0596517748. ↩︎
Haverbeke, M. (2024). Eloquent JavaScript (4th ed.). No Starch Press. https://eloquentjavascript.net/ ↩︎










