Prerequisites
JavaScript: 10 Days That Changed the Web
Brendan Eich's rush job became the world's most ubiquitous programming language. Here's how.
TL;DR
In May 1995, Netscape gave Brendan Eich ten days to create a programming language for the browser. The result — originally called Mocha, then LiveScript, then JavaScript — was full of quirks and compromises. It was also the only language that shipped inside the thing everyone was using to access the web. That accident of distribution made JavaScript the most widely deployed programming language in history. It gave web pages the ability to respond to clicks, validate forms, update content without reloading, and eventually run full applications. JavaScript didn’t win because it was well-designed. It won because it was there — and because its core ideas, borrowed from Scheme and Self, turned out to be powerful enough to carry the weight of the entire interactive web.
The Brief: Make the Browser Do Things
It’s May 1995. Netscape Navigator owns 80% of the browser market, and Marc Andreessen has a vision: the browser should be a platform, not just a document viewer. Sun Microsystems is about to launch Java, and Netscape has a deal to embed Java applets in the browser. But Andreessen wants something else alongside it — a lightweight scripting language that non-programmers can use to glue components together. Make a button do something when you click it. Validate a form before it’s submitted. Make the page respond.
Brendan Eich was hired to put Scheme in the browser. That plan got overruled by management — the language had to look like Java for marketing reasons. Eich was given ten days to build a prototype.
The result was Mocha. It looked like Java on the surface (curly braces, function keyword, C-style operators) but underneath it was something entirely different — a dynamic, loosely typed, prototype-based language with first-class functions. It was renamed LiveScript in September 1995 when it shipped in a Netscape beta, then renamed again to JavaScript in December as part of the Sun partnership.
The name was a marketing decision, and it caused decades of confusion. JavaScript is not Java. They share syntax the way a cat and a catfish share a syllable.
The Design Decisions
Ten days isn’t enough to design a language from scratch. Eich made it by borrowing aggressively from languages he admired:
| Influence | What It Contributed |
|---|---|
| Scheme | First-class functions, closures |
| Self | Prototype-based inheritance (no classes) |
| Java | Syntax, naming (for marketing) |
| Perl | Regular expressions, some string handling |
| HyperTalk | Event-driven model (onClick, onSubmit) |
The most consequential choice was first-class functions — functions are values, just like numbers or strings. You can pass them as arguments, return them from other functions, and store them in variables. This came from Scheme, a Lisp dialect, and it gave JavaScript a power that Java wouldn’t have for nearly twenty years:
// Functions as values: the core of JavaScript's expressiveness
const greet = function(name) {
return "Hello, " + name;
};
// Pass a function to another function
function repeat(fn, times) {
for (let i = 0; i < times; i++) fn();
}
repeat(() => console.log("hi"), 3);
// Return a function from a function (closure)
function createCounter() {
let count = 0;
return {
increment: () => ++count,
getCount: () => count,
};
}
const counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.getCount()); // 2
// 'count' lives on inside the closure — private state, no class needed
Closures — functions that capture their surrounding variables — became the fundamental building block of JavaScript patterns. Module systems, event handlers, callbacks, React hooks — they’re all closures.
The second major choice was prototype-based inheritance. Most object-oriented languages use classes as blueprints for objects. JavaScript, following Self, let objects inherit directly from other objects:
const animal = {
speak() { return `${this.name} makes a sound`; }
};
const dog = Object.create(animal);
dog.name = "Rex";
dog.bark = function() { return `${this.name} barks`; };
console.log(dog.speak()); // "Rex makes a sound" — inherited from animal
console.log(dog.bark()); // "Rex barks" — own method
No classes, no constructors, no new keyword needed. Objects are just bags of properties that delegate to other objects. This confused an entire generation of Java programmers, and JavaScript eventually added class syntax in 2015 — but it’s sugar over prototypes, not a new model.
The Quirks That Stuck
JavaScript’s ten-day origin left permanent scars. The language shipped with behaviors that couldn’t be fixed later without breaking existing websites:
typeof null // "object" — a bug from day one, never fixed
0.1 + 0.2 // 0.30000000000000004 (IEEE 754 floating point)
"" == false // true (type coercion)
[] == false // true
"" == [] // true
NaN === NaN // false — NaN is not equal to itself
The == operator performs type coercion — it converts values before comparing them, following rules so complex that no one memorizes them. The fix: always use === (strict equality), which compares without coercion. Every JavaScript style guide for the past twenty years has said the same thing.
The this keyword changes meaning depending on how a function is called, not where it’s defined. This single design choice has generated more Stack Overflow questions than perhaps any other feature in any language:
const obj = {
name: "Alice",
greet() { console.log(this.name); }
};
obj.greet(); // "Alice" — this is obj
const fn = obj.greet;
fn(); // undefined — this is now the global object (or undefined in strict mode)
These quirks are real costs. But they didn’t kill the language because JavaScript had something no competitor had: it was already in every browser on earth.
The Browser Wars and JScript
Microsoft couldn’t ignore JavaScript. In August 1996, Internet Explorer 3.0 shipped with JScript — Microsoft’s reverse-engineered implementation. It was almost compatible. Almost.
The differences were maddening. Event handling worked differently. DOM access methods had different names. Code that worked in Netscape broke in IE and vice versa. Web developers spent the late 1990s writing two versions of everything:
// The 1990s: browser detection hell
if (navigator.appName == "Netscape") {
document.layers["menu"].visibility = "show";
} else {
document.all["menu"].style.visibility = "visible";
}
This chaos drove the push for standardization. In 1997, Netscape submitted JavaScript to Ecma International, a European standards body. The standardized version was named ECMAScript (because Sun owned the “Java” trademark). The first edition, ES1, was published in June 1997.
Standardization didn’t end the browser wars, but it established a shared specification that both sides could be measured against. The spec became the language’s constitution — and the mechanism through which JavaScript would eventually evolve.
The Event Loop: Concurrency Without Threads
JavaScript runs on a single thread. There’s no parallel execution, no mutexes, no race conditions. This wasn’t a principled design choice — it was the simplest thing that could work for a scripting language inside a browser.
But single-threaded doesn’t mean single-tasked. JavaScript uses an event loop — a model where the runtime processes one task at a time, but can register callbacks that run later when events occur:
console.log("1: start");
setTimeout(() => {
console.log("3: timeout fires");
}, 0);
console.log("2: end");
// Output: 1, 2, 3 — even with a 0ms delay, the callback waits
The event loop is a queue. When you click a button, the browser queues a click event. When a network request completes, the browser queues a callback. The engine processes them one at a time, in order. No two pieces of JavaScript ever run simultaneously in the same context.
This model is why JavaScript handles I/O-heavy workloads well — a server can manage thousands of concurrent connections by never blocking on any of them. It’s also why a single slow computation freezes the entire page. The event loop is JavaScript’s greatest constraint and its defining architectural feature. It shaped how the language evolved (Promises, async/await) and how every framework built on it handles state.
From Toy Language to Platform
For its first decade, JavaScript was widely dismissed. It could validate forms, swap images on hover, and create annoying pop-up windows. Serious developers wrote serious code on the server in Java or PHP. JavaScript was the language you tolerated, not the language you chose.
Three things changed that:
XMLHttpRequest (2000s) — Microsoft invented it for Outlook Web Access. Jesse James Garrett gave the technique a name in 2005: AJAX (Asynchronous JavaScript and XML). For the first time, JavaScript could fetch data from a server without reloading the page. Google Maps, Gmail, and Google Suggest proved that JavaScript could power rich, responsive applications that felt like desktop software.
// AJAX: the request that changed everything
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/data");
xhr.onload = function() {
const data = JSON.parse(xhr.responseText);
updatePage(data); // update the page without reloading
};
xhr.send();
V8 (2008) — Google built a JavaScript engine that compiled JS to machine code. Performance improved 10–100x overnight. JavaScript stopped being “too slow for real work.”
Node.js (2009) — Ryan Dahl put V8 on the server. JavaScript broke free of the browser. The same language, the same event loop, the same ecosystem — now running web servers, build tools, and command-line applications. JavaScript became the only language that runs on both client and server.
What JavaScript Got Right
JavaScript was designed in ten days by one person under impossible constraints. It should have been a footnote. Instead:
- First-class functions — the Scheme DNA gave JavaScript an expressiveness that languages with ten times the design effort didn’t have. Closures, callbacks, higher-order functions — they made JavaScript surprisingly powerful for a language that was supposed to be “the dumb little brother of Java.”
- The event loop — single-threaded, non-blocking I/O turned out to be a remarkably good model for the web’s interaction-heavy, I/O-heavy workloads. It avoided the concurrency bugs that plagued multi-threaded server-side languages, and it scaled naturally to thousands of connections.
- Distribution as destiny — JavaScript shipped in the browser. Every computer with a web browser had a JavaScript runtime. No installation, no setup, no compatibility matrix. This is why JavaScript survived its own flaws: the language with the most bugs was also the language with the most users, and the most users wins.
- Evolvability — ECMAScript standardization gave JavaScript a path to fix its worst mistakes without breaking the web.
let/constreplacedvar. Arrow functions fixedthis. Promises andasync/awaittamed callback hell.classsyntax papered over prototype confusion. The language Brendan Eich built in ten days has been continuously improved for thirty years — and the ten-day core is still visible underneath.
The web needed a language, and it got one in ten days. That language’s flaws are well-documented and genuine. Its dominance is also well-documented and genuine. JavaScript is the only programming language that billions of people use every day without knowing it — every time they click a button, scroll a feed, or type in a search box. It’s the language of the DOM, the language of the browser, and through Node.js, increasingly the language of everything else.