A Concise History of JavaScript — From LiveScript to ES2024

How JavaScript went from a 10-day prototype in 1995 to the modern, standardised ECMAScript language powering the web, Node.js, and edge runtimes in 2024.

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, and while from 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.

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.

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:

StageNameMeaning
0StrawpersonIdea, not yet a formal proposal
1ProposalA champion takes it on; problem and solution sketched
2DraftInitial spec text; experimental implementation expected
3CandidateSpec is mostly final; needs implementer feedback
4FinishedTwo 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

EditionYearHighlights
ES11997First standard
ES21998Editorial only (ISO alignment)
ES31999Regex, try/catch, switch, do/while
ES4Abandoned — too ambitious; classes, types, namespaces
ES52009Strict mode, JSON, Object.create, getters/setters
ES5.12011Editorial alignment with ISO/IEC 16262
ES6 / ES20152015let/const, arrow functions, classes, modules, promises, template literals, destructuring
ES2016 (ES7)2016** operator, Array.prototype.includes
ES2017 (ES8)2017async/await, Object.values/entries, string padding
ES2018 (ES9)2018Object rest/spread, async iteration, Promise.finally, RegExp lookbehind
ES2019 (ES10)2019Array.flat/flatMap, Object.fromEntries, optional catch binding
ES2020 (ES11)2020Optional chaining ?., nullish coalescing ??, BigInt, Promise.allSettled
ES2021 (ES12)2021String.replaceAll, logical assignment ??= &&= ||=, WeakRef
ES2022 (ES13)2022Top-level await, class fields (public/private), Array.prototype.at, Object.hasOwn, error cause
ES2023 (ES14)2023findLast/findLastIndex, non-mutating array methods (toSorted, toReversed, toSpliced, with), hashbang grammar
ES2024 (ES15)2024Promise.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:

  1. JavaScript everywhere. Developers could now write both ends of a web app in the same language, sharing validation logic, data shapes, and tests.
  2. npm. The Node Package Manager (2010) became the largest package registry in software history. Today npm hosts over 3 million packages.
  3. 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.

HostEngineTypical use
Chrome, Edge, Brave, OperaV8Browser apps
FirefoxSpiderMonkeyBrowser apps
Safari, iOS WebKit viewsJavaScriptCoreBrowser apps
Node.jsV8Servers, tooling, CLIs
Deno (2018)V8Secure servers, TypeScript-first
Bun (2022)JavaScriptCoreFast servers, bundler, test runner
Cloudflare Workers, Vercel EdgeV8 isolatesEdge functions
Electron, TauriV8 / system WebViewDesktop apps
React Native, NativeScriptHermes / JSC / V8Mobile apps

Feature support varies across engines and versions. The community-maintained compat-table and caniuse.com are the canonical references.


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}

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 var behaves so strangely → it predates let and const by twenty years. See Variables, scope and hoisting.
  • Why arrow functions exist → fixing the long-standing this binding 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

  1. Crockford, D. (2008). JavaScript: The Good Parts. O’Reilly Media. ISBN 978-0596517748. ↩︎

  2. Haverbeke, M. (2024). Eloquent JavaScript (4th ed.). No Starch Press. https://eloquentjavascript.net/ ↩︎