1. Interaction
  2. JavaScript
  3. The language you can't avoid

Interaction · JavaScript 01

The language you can't avoid

A web client developer has to deal with JavaScript, whatever they think of it. It looks simple, it is not, and much of what people blame it for belongs to the browser it runs in. This page covers why the language is hard to avoid, what makes it difficult, what TypeScript changes, how to separate the language from its host, and how a ten-day prototype from 1995 became a yearly international standard.

The pages in this section teach the JavaScript language and how it behaves in a page. Their goal is that you can read any JavaScript and predict what it does, including the odd parts. The Prof's law of weird stuff applies throughout: focus on what is odd compared with the languages you already know. This first page has little syntax. It sets out the map that the other ten pages fill in.

1. Why JavaScript

Atwood's Law

In 2007 Jeff Atwood wrote a post about Tim Berners-Lee's principle of least power, the idea that you should pick the least powerful language suited to a job. Atwood quoted Berners-Lee's reasoning: "The less powerful the language, the more you can do with the data stored in that language." He then proposed a corollary, and it has been quoted ever since.

Any application that can be written in JavaScript, will eventually be written in JavaScript.

You can respect the law or resent it. Many editors and chat clients are written in JavaScript today, and the course's own editor recommendation, VS Code, is one of them. Whether each of those applications should have been written that way is a question for How much JavaScript?, the last page of this section.

The immovable rock

For most of the web's history, JavaScript was the only programming language a browser would run. The lecture this section comes from calls that an immovable rock and lists three ways to deal with it.

  1. Write native JavaScript. This might be tough.
  2. Write something else that transpiles to JavaScript. You become beholden to tools, and the result often kills performance.
  3. Do the work on the server, deal with network round-trips, and forget about RAIL. This plain ignores performance, because every interaction waits for the network.

This course's position is the first choice. Learn the language itself and start with vanilla JavaScript, meaning the language and the platform with no framework on top. You may well use the second choice at work, and you will debug it better if you know what it turns into.

WebAssembly moved the rock a little

The rock has a crack in it now. Browsers also run WebAssembly, or Wasm, a low-level binary format that serves as a compilation target for languages such as C, C++, C# and Rust. The W3C made its core specification a standard in December 2019, and Wasm 3.0, which added garbage collection, 64-bit memory and exception handling among other features, became the current standard in September 2025. So JavaScript is no longer the only thing a browser can run.

It remains the only thing that reaches most of the browser without help. MDN's description says that WebAssembly "cannot currently directly access the DOM; it can only call JavaScript, which then makes the Web API call." A compiled program therefore ships with JavaScript glue code, and JavaScript controls how the module is downloaded, compiled and started. MDN also says WebAssembly is "not intended as a replacement" for JavaScript and is designed to work alongside it.

That may change. In February 2026, Mozilla's Ryan Hunt described how the WebAssembly Component Model could let a browser bind Web APIs directly, with no JavaScript glue. He labeled that future an aspiration and said its web interactions have not been fully designed. Treat it as a proposal. WebAssembly suits compute-heavy work and existing code in other languages. For a web page's ordinary job of responding to a user and changing a document, JavaScript is still the direct route.

2. Warnings

JavaScript is a non-trivial programming language that looks deceptively simple but is actually quite complex. It looks like a typical C-style language with semicolons and it is useful in small doses. Both of those have led many people to get frustrated with it. You copy a few lines, they work, and you assume you know the language. Then something behaves in a way that C or Java never would.

Each of the challenges below gets its own page in this section.

The playground below runs a small sample of three of those. '5' * 2 converts the string to a number and gives 10, while '5' + 2 converts the number to a string and gives 52. The function counter has finished by the time next is called, and count is still there and still counting. The timer has a delay of zero and still runs after the last line of the script. Predict each line, then read the output. The later pages explain all of these, so you can leave this one puzzled.

3. TypeScript, which will fix everything

A common response to that list is that TypeScript will fix everything. It fixes some of it, and you should know which part.

What TypeScript is

TypeScript is a typed superset of JavaScript. Every JavaScript program is legal TypeScript syntax, and TypeScript adds a layer on top: type annotations, interfaces and generics. The file you write ends in .ts. The compiler, tsc, checks the types and writes out a plain .js file for the edition of JavaScript you choose, and that file is what runs.

TypeScript compiles to JavaScript, and the types do not surviveThree stages from top to bottom. A TypeScript file with type annotations goes to the TypeScript compiler, tsc, which checks the types and reports errors before anything runs. The compiler writes a vanilla JavaScript file with the annotations removed. A note beside that file says no type information remains at run time.TypeScript file (.ts)function add(a: number, b: number): numberTypeScript compiler (tsc)checks the types, then erases themJavaScript file (.js)function add(a, b)Type errors are reportedhere, before anything runs.No type information remains.The engine runs this file.
The checking happens at the middle step. What runs at the bottom is ordinary JavaScript.

The handbook says that once the compiler has checked your code, it "erases the types," and that as a principle, "TypeScript never changes the runtime behavior of JavaScript code." It adds no runtime library. TypeScript describes your program to a checker and, apart from a few features such as enum, has no effect on how the program runs.

What it fixes

TypeScript finds a whole category of mistakes before the code runs. Here is a function that declares it takes two numbers, called with a string.

function add(a: number, b: number): number { return a + b; } console.log(add(1, '2')); $ tsc --noEmit add.ts add.ts(5,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Plain JavaScript would have joined the two values and carried on. On a large codebase that check, together with the completion and renaming it gives an editor, is a large benefit. It also helps with the lack of programming in the large from the warnings list, since a type is documentation that a tool verifies. You can get a good part of this without leaving JavaScript at all: Programming in the large covers @ts-check.

What it does not fix

Every other item on the warnings list is a statement about how JavaScript behaves when it runs, and TypeScript does not change that. Coercion, closures, prototypes, this and the order of asynchronous code all behave as before. The checker warns about some misuses of them, and you still need to know what they do in order to read its warnings and the output.

Types also stop at the edge of your program. A checker can only reason about what it can see, and in a web client a lot of the data arrives while the program runs. JSON.parse returns the type any, which switches off checking, so the sample below compiles with no errors as TypeScript. With the annotations erased, this is the code that runs. The server sent the price as a string, so + joins the values and the total comes out as 19.992.

Three other limits follow from what TypeScript is. A type definition can say that an API exists, and it cannot tell you that a visitor's browser supports it. The output is still JavaScript that a page has to download, parse and run, so a compile step does not make a page fast. And it adds a tool between you and the browser, which is the second choice on the list above and comes with what that choice costs.

The lecture follows the TypeScript slides by observing that TypeScript did not do everything needed, and by asking whether the language was the main problem to begin with. The next section picks up that question, because much of the difficulty of web development belongs to the host.

Can TypeScript run natively?

The lecture's diagram says the browser can't run TypeScript, with a footnote wondering what would happen if it could. That is still accurate for browsers, and some of the surrounding world has moved. "Native" gets used for three separate things.

ClaimStatus
Node runs .ts filesYes, for erasable syntax. Type stripping is on by default since v23.6.0 and v22.18.0 and stable since v25.2.0 and v24.12.0. Node replaces the annotations with whitespace and performs no type checking. Syntax that needs a transform, such as enum, throws an error.
Deno runs .ts filesYes. Deno runs them with no configuration, and type errors do not stop the code unless you ask for a check.
Browsers run .ts filesNo. You still compile or strip the types first.
JavaScript gains type syntaxProposed. The TC39 Type Annotations proposal is at Stage 1, an early stage in TC39's process. Engines would ignore the annotations, treating types as comments, and an external tool would do the checking. Its listed progress updates stop at 2023.
TypeScript has a native compilerYes, and this concerns the tool, not your program. TypeScript 7, released in July 2026, is a port of the compiler to Go, reported as about ten times faster. Your code still ends up as JavaScript.

In every one of those cases, the types are ignored or erased by the time the code runs. Running the earlier add.ts directly in Node shows it. The same mistake that tsc rejected runs with no complaint and prints the wrong answer.

$ node add.ts 12

4. The host environment enters the chat

The host environment of JavaScript adds tremendous challenges to learning the language. It is also the part most tutorials never separate out, so people learn the DOM and the language as one thing and blame the language for both.

The language specification is direct about this. ECMAScript "is not intended to be computationally self-sufficient; indeed, there are no provisions in this specification for input of external data or output of computed results." By itself, the language cannot read a file, draw a pixel or print a line. A host program embeds an engine and gives it those abilities, through objects and functions that the language standard does not describe. MDN's overview names the common engines: V8 in Chrome and Node, SpiderMonkey in Firefox, and JavaScriptCore in Safari.

One language, two host environmentsTwo side-by-side execution environments. In each, your script goes into a JavaScript engine that provides the language, including Math, String, JSON and Promise. Below the engine, each host adds its own APIs. The browser adds window, the DOM, fetch, Canvas, WebGL, the camera and geolocation. Node adds process, Buffer, modules for the file system and HTTP, and libuv for asynchronous I/O. Node also provides fetch, setTimeout and console, as browsers do.Browser or WebViewyour scriptJS engine: V8, SpiderMonkey, JSCMath String JSON Promise ...Host APIswindow, document (the DOM)fetch, XMLHttpRequestCanvas, WebGL, CSS manipulationcamera, geolocationNodeyour scriptJS engine: V8Math String JSON Promise ...Host APIsprocess, Bufferfile system and HTTP moduleslibuv: event loop, asynchronous I/Ofetch, setTimeout, consoleThe gold box is the same language in both. The blue box is what the host adds.
The language lives in the engine. Almost everything a program does to the outside world comes from the host.

APIs vary by host

On the server side, both as a server application and as a command-line tool, the host is usually Node, which offers the file system, the process and so on. On the client side, in a browser or in a mobile WebView, the host offers these instead.

  • The DOM, the Document Object Model.
  • Markup, both HTML and SVG.
  • CSS manipulation.
  • Ajax and fetch for communication, covered in Client-Side Communication.
  • Canvas and WebGL.
  • Various browser APIs, such as the camera and geolocation, along with connection information in the browsers that have it.

Inside a browser, the JavaScript engine is one component alongside the user interface, the rendering engine, networking and data storage. Your code runs on the engine's call stack, a call such as setTimeout hands work to a Web API, and the finished work waits in a queue for the event loop to bring it back. The JavaScript engine and the event loop walks through that in detail.

Node has a similar shape with different parts. Its stack starts from your application and the Node API, goes down through bindings and a standard library, and rests on V8 and on libuv, the library that provides its event loop and asynchronous input and output. It uses the engine from Chrome and has no document, no rendering engine and no user interface. Broadly speaking, JavaScript can run everywhere, and a program's APIs depend on where.

The same script in two hosts

The playground below runs in your browser. It asks typeof about a list of names, which reports undefined for a name that does not exist, where touching the name directly would throw. Below it is what the same file printed under Node, recorded by running it.

$ node hosts.js Math object JSON object Promise function console object setTimeout function fetch function navigator object window undefined document undefined alert undefined navigator.geolocation undefined process object Buffer function require function

Compared side by side, the results fall into four groups. The standard that defines each name tells you who owns it.

NamesBrowserNodeDefined by
Math, JSON, PromiseYesYesECMAScript, the language
console, setTimeout, fetchYesYesWeb standards, which Node also implements
window, document, alertYesNoWeb standards
process, Buffer, requireNoYesNode

Three results deserve a second look. console.log, the first function most people learn, is not part of the JavaScript language. It comes from the Console Standard, and each host supplies its own. Next, the line between hosts moves over time. Node's documentation shows that fetch lost its flag in v18 and that navigator arrived in v21, so older tutorials that say Node has neither are out of date. Last, a shared name does not mean shared contents. Node has a navigator, but it has no navigator.geolocation, and its navigator.userAgent on this version is Node.js/25.

Reaching for a host's API in the wrong host fails immediately. This is what one line of browser code does under Node.

ReferenceError: document is not defined

The language-only part behaves the same anywhere. The next playground uses the core language and the common language APIs, with no host involved beyond the console that prints the output. Paste it into Node and you get these same lines. Note the month in the Date line, which counts from zero, so 11 is December. That oddity belongs to the language, copied from the date class of Java 1.0, so it follows you into every host.

Wrapped JavaScript

The host is sometimes hidden. In many situations you think you are using a purely native app, and you are using a native app shell with JavaScript inside. This is called wrapped JS, or App + WebView. A WebView is a browser's rendering engine with the browser's own interface removed, embedded in an application.

A native app with a WebView, compared with a web appTwo stacks. On the left, a native app with a WebView: web content sits on a WebView containing a web rendering engine and a JavaScript bridge, inside a native app, which connects through a native bridge to the native APIs and platform. On the right, a web app: web content sits on a browser containing a shell and user interface and a web rendering engine, which connects to the native APIs and platform.Native app with a WebViewWeb contentNative appWebViewWeb rendering engineJavaScript bridgeNative bridgeNative APIs and platformWeb appWeb contentBrowserShell and user interfaceWeb rendering engineNative APIs and platform
The web content is the same in both. A wrapped app adds bridges, so that script can reach native APIs a page in a browser could not.

Cordova and Ionic are examples for mobile, along with Capacitor, which offers a migration path from Cordova. On the desktop, Electron "embeds Chromium and Node.js" in the application, so one program has both hosts in it. VS Code, Slack and Discord are built with Electron.

5. Things that smell like trouble

Part of JavaScript's bad reputation comes from how it gets used and talked about, so learn to recognize these early. When any of them appears in a discussion of the language, ask what is being blamed.

  • Legacy framework use. Old sites carry old libraries, and working on them can teach you the library in place of the language.
  • Newer framework abuse and tribalism. People treat a framework as an identity and apply it everywhere, and tool chain tribalism does the same with build tools.
  • Observed performance profiles, and the assumption that the mobile web is inappropriate. Slow script on a phone gets generalized into a claim that the web is unsuited to phones. How much JavaScript? takes up the cost with data.
  • The rapid changing nature of browsers and their variable support for various JavaScript APIs, which makes web development significantly difficult. The tool to keep open is caniuse.com, and Web Platform Status tracks the same question by feature.

6. How we got here

History explains much about this language. The dates below come mostly from JavaScript: The First 20 Years by Allen Wirfs-Brock and Brendan Eich, and the edition dates from Ecma's list for ECMA-262.

JavaScript from 1995 to 2026A vertical timeline. May 1995: the Mocha prototype, built in ten days. September 1995: LiveScript appears in Netscape Navigator 2.0 beta 1. December 1995: Netscape and Sun announce the name JavaScript. March 1996: Navigator 2.0 ships JavaScript 1.0. August 1996: Internet Explorer 3 ships JScript. June 1997: ECMAScript first edition. December 1999: ES3. 2005: the term Ajax is coined. May 2009: first public Node.js. December 2009: ES5. June 2015: ES2015, also called ES6, and yearly editions follow. June 2026: ES2026, the seventeenth edition.May 1995Brendan Eich builds the Mocha prototype in ten daysSep 1995LiveScript appears in Netscape Navigator 2.0 beta 1Dec 1995Netscape and Sun announce the name JavaScriptMar 1996Navigator 2.0 ships with JavaScript 1.0Aug 1996Internet Explorer 3 ships with Microsoft's JScriptJun 1997ECMAScript, first editionDec 1999ES3, the traditional JavaScript of the next decade2005Jesse James Garrett coins the term AjaxMay 2009First public Node.js, from Ryan DahlDec 2009ES5, after the abandoned fourth editionJun 2015ES2015, also called ES6; editions become yearlyJun 2026ES2026, the seventeenth edition
Gold marks Netscape's first releases, blue marks events outside the standard, and green marks editions of the standard.

Netscape, Mocha and LiveScript

JavaScript was invented at Netscape and first introduced in 1995. Brendan Eich joined the company that April expecting to put a version of Scheme in the browser. That spring Netscape was also striking a deal with Sun to include Java in Navigator 2, and it wanted a scripting language as a companion to Java. Marc Andreessen proposed the code name Mocha, in the hope, according to Eich, that it would be renamed JavaScript in due course. Eich built the first prototype in ten contiguous days in May 1995, to show that a language could be ready for the Navigator 2 beta.

The prototype's brief explains much of what you are about to learn. Management at Sun and Netscape required that it "look like Java," and they ruled out anything resembling BASIC. It had to be object-based, without classes, because classes would take too long and risk competing with Java. Eich drew his object model from a language called Self. The authors note the consequence: the Java-like appearance "created an expectation of Java-like behavior." The warning at the top of this page goes back to this decision.

The name

The language reached the public under the name LiveScript, in Navigator 2.0 beta 1 on September 18, 1995. On December 4, while that browser was still in beta, Netscape and Sun issued a joint press release announcing JavaScript, and Sun trademarked the name and licensed it to Netscape. The new name came out of that partnership. JavaScript is not really related to Java beyond a resemblance in syntax. The press release said the language "complements Java," and the two have been confused ever since. Navigator 2.0 shipped with JavaScript 1.0 on March 18, 1996.

JScript and a standard

Microsoft answered with a clone called JScript, built by reverse engineering the Netscape betas with no specification to work from. It first shipped in Internet Explorer 3 on August 13, 1996, six days before Netscape 3. Now two browsers ran two versions of a language that nobody had specified, and compatibility between them became every web developer's problem.

Netscape took the language to the standards body Ecma, whose new committee TC39 first met in November 1996. The committee used "ECMAScript" as a placeholder while it sought a name. Sun declined to license JavaScript, and no better name came along. The standards-oriented language is therefore called ECMAScript. The first edition was approved in June 1997 and published that September, the second in August 1998, and the third in December 1999.

DHTML, Ajax, and apps

The ideas of DHTML and Ajax add even more confusion, because neither is a language. Dynamic HTML meant using JavaScript to change the elements of a loaded page. Combine that with a browser API for fetching data without a reload, and a page can load once and then behave as an application. Jesse James Garrett coined the name Ajax for that style in 2005, and with it JavaScript's job changed from adding touches to a page to running the whole application. That change led to all things apps, and from there to the frameworks. How much JavaScript? takes up framework primacy and the problem of vanilla JavaScript versus "X" as the section's closing argument.

JavaScript also runs on both client and server, in and out of browsers. That goes back further than most people assume: Netscape's own server shipped with server-side JavaScript in March 1996, in the same month as Navigator 2.0. Node, first released in 2009, is what made it common. Each of those places adds its own host, and some of the bad aspects of JavaScript are really the bad aspects of the environment in which it is used. A slow DOM update or an inconsistent browser API gets reported as a language problem, which is why the host section above came first.

From ES3 to the yearly editions

There are many versions, from ES3 through ES2019 and on to the current ES2026. The fourth edition was abandoned after years of work and was never completed, which is why there is no ES4 and why the sequence jumps to ES5 in December 2009. ES2015, also called ES6, was the big one, a set of changes that the committee had been working on for years. Since then TC39 has published on a yearly schedule, and editions are named by year. The two naming systems overlap, so ES6 and ES2015 are the same edition and ES7 is ES2016.

Each edition contains the last, and TypeScript contains themNested circles sharing a left edge. ES3, traditional JavaScript, is the smallest. ES5 surrounds it, only slightly larger. ES2015 is much larger. ES2026 is larger again, and TypeScript surrounds them all. The circles are not to scale.ES3ES5ES2015ES2026TSES3 (1999): traditional JavaScriptES5 (2009): not much different, whateverthe circle size suggestsES2015 (ES6): the large stepES2016 to ES2026: yearly additionsTypeScript: all of those, plus a type layerThe circles are not to scale.
Each edition keeps the one before it, so old scripts continue to run. TypeScript sits outside, because the types are its addition.

Because each edition keeps the last, the traditional JavaScript you find in an old codebase still runs. These two samples do the same job, one in the style of ES3 and ES5 and the other in the style of ES2015. You will read both.

var names = ['ada', 'grace']; var greetings = []; for (var i = 0; i < names.length; i++) { greetings.push('Hello, ' + names[i]); } console.log(greetings.join('; ')); // Hello, ada; Hello, grace let names = ['ada', 'grace']; let greetings = names.map((name) => 'Hello, ' + name); console.log(greetings.join('; ')); // logs: Hello, ada; Hello, grace

7. Where to start

The JavaScript stack

Everything so far fits in one picture, which is the visual starting point for the rest of the section. JavaScript work is a stack. At the top is what you write, and it stands on frameworks and libraries, which stand on the host's APIs, which stand on the language.

The JavaScript stack, and where to start learning itFive layers from top to bottom. Custom code, what you write. Frameworks and libraries, such as jQuery, Vue, React and Angular. Host environment APIs from the browser, Node and so on, such as the DOM, XMLHttpRequest and Canvas. Common language APIs, such as Math, String, Date and RegExp. Core language: data types, expressions, statements, functions and modules. The bottom two layers are marked ECMAScript. A red label, Not here, points at frameworks and at host APIs. A green label, Start here, points at the core language.Custom codewhat you writeFrameworks and librariesjQuery, Vue, React, Angular, ...Host environment APIsBrowser, Node, etc.DOM, XMLHttpRequest, Canvas, ...Common language APIsMath, String, Date, RegExp, ...Core languageData types, expressions, statements,functions, modulesECMAScriptNot hereStart here
Learners often enter at the frameworks or the DOM, with no way to tell which layer caused a problem. Start at the bottom.

Jumping into a framework straight away is the tempting button, and learning the basics is the one to press. If you learned a framework first, you can't tell whether a failure belongs to your code, the framework, the browser or the language. Skipping the bad parts of JavaScript doesn't get you out of learning it either, since you have to know which parts those are and read other people's code that uses them. The closing advice of the lecture is the order of work for this section: get language right first, then attack those details, so you know where to place blame.

About to break that advice

The next page breaks that advice on purpose. Getting script into a page comes before the language, as a preview of the JavaScript learning experience. It fast-forwards to running code in a browser, using DOM methods and event handlers before they have been explained.

The goal is to show that something useful will come and to satisfy some impatience. It also shows the detail tsunami that follows as soon as you do it, with cross-over to browser loading, HTML and CSS interactions, usage patterns and hostile environments. With both fear and hope in mind, you are then ready to learn the language properly, starting with Statements, variables and flow.

Materials and tools

The lecture material behind this section is derived mainly from JavaScript: The Complete Reference (3rd edition), Ajax: The Complete Reference and various sites. There are plenty of other good resources online about JavaScript.

There are also quite poor discussions of JavaScript online, filled with bad information, and you have been warned. Much of it is old, written about a browser or edition that has since changed, so check a tutorial's date and test what it says.

For tools, you need browsers (Chrome, Firefox, Edge and Safari, on desktop and on iOS), Node, a playground such as CodePen or the ones on these pages, the developer tools built into each browser, and a text editor that understands JavaScript, such as VS Code, WebStorm or Nova.

8. Summary

ConceptKey points
Atwood's Law"Any application that can be written in JavaScript, will eventually be written in JavaScript." Jeff Atwood, 2007.
Your choicesWrite native JavaScript, transpile to it, or do the work across the network. This course starts with vanilla JavaScript.
WebAssemblyBrowsers run it too, as a compilation target. It still has to call JavaScript to reach the DOM and most Web APIs.
WarningsDeceptively simple. Weak typing, several object models, functional style, asynchronous code and closures, unusual scoping, and a late start on modules.
TypeScriptA typed superset that finds type mistakes before the code runs. Types are erased, so runtime behavior, data from outside, browser support and page weight are unchanged.
TypeScript nativelyNode and Deno run .ts files without checking them. Browsers do not. The TC39 Type Annotations proposal is at Stage 1. TypeScript 7's native compiler is a faster tool.
Language and hostECMAScript has no input or output of its own. The host adds them, so APIs vary. console and setTimeout are not part of the language.
Wrapped JavaScriptNative shells around web content: Cordova, Ionic and Capacitor on mobile, and Electron on the desktop.
HistoryMocha in May 1995, LiveScript in the first Navigator 2.0 beta, renamed JavaScript that December under a deal with Sun. JScript in IE3 in 1996. ECMAScript from 1997, and yearly since 2015.
Where to startAt the core language, the bottom of the stack, so that you know where to place blame. The next page previews the browser first, on purpose.