JavaScript is the programming language every browser understands: it is what turns a static HTML page into something that reacts to clicks, keystrokes and network responses. This guide explains what the language actually is, the host environments that run it (browser, Node.js, and a few less obvious ones), and why the language and the engine that executes it are two separate things.
What is JavaScript, exactly?
JavaScript is a high-level, dynamically typed, garbage-collected programming language. High-level means you never manage memory by hand. Dynamically typed means a variable's type follows the value it holds rather than a type you declare. Garbage-collected means the engine reclaims memory it can prove you no longer reference, so there is no free() to call.
Notice what that definition leaves out. The core language — variables, functions, arrays, objects, loops, error handling — contains no browser at all. Save this file as hello.js and it behaves identically in Chrome, Firefox, Node.js, Deno and Bun:
const greeting = "Hello from the JavaScript engine";
console.log(greeting);
console.log("2 + 2 =", 2 + 2);
What is browser-specific is the layer of APIs sitting on top: document, window, fetch, localStorage. Those are extra rooms in the building, not the building itself. That separation is why you can learn JavaScript properly in a terminal and add web APIs later, once a project actually needs them.
Where does JavaScript actually run?
JavaScript needs a host environment to run in. The language has no entry point, no file access and no network stack of its own — the host supplies those. In practice you will meet five kinds of host.
| Host | What it adds to JavaScript | Typical use |
|---|---|---|
| Browser (Chrome, Firefox, Safari, Edge) | DOM, window, timers, fetch, storage, canvas, WebAssembly | Web pages and web apps |
| Node.js | File system, process, npm packages, HTTP server APIs | Servers, scripts, command-line tools, build tooling |
| Deno and Bun | A Node-like API surface with modern defaults such as built-in TypeScript support and a bundler | Modern server and scripting work |
| Web Workers and Service Workers | A thread with no DOM, plus offline caching and background sync | Heavy computation and offline-first apps |
| Embedded engines (Electron, React Native) | Native operating-system calls exposed as JavaScript APIs | Desktop and mobile applications |
You can detect which host you are in at runtime, because each host injects a different set of globals:
console.log("globalThis available:", typeof globalThis !== "undefined");
console.log("running in a browser:", typeof document !== "undefined");
console.log("running under Node.js:", typeof process !== "undefined");
if (typeof process !== "undefined") {
console.log("runtime version:", process.versions.node);
}
Run that with node where-am-i.js and the browser row prints false while the Node row prints true. Open the same file in a browser and the two flip. The version line is wrapped in a check because process does not exist there — a bare process.versions.node in a browser throws a ReferenceError immediately.
Is JavaScript the language or the engine?
JavaScript is the language: the syntax and semantics you write. The engine is the program that reads your source and executes it. V8 (Chrome, Edge, Node.js), SpiderMonkey (Firefox) and JavaScriptCore (Safari) are three separate engines, free to differ in speed and in how quickly they adopt new proposals, as long as they agree on the standard.
That standard is called ECMAScript. ECMAScript is the specification; JavaScript is the language people actually write, and the two terms have drifted so far apart that versions are named after the specification: ES2023, ES2024 and so on, while the everyday word stays JavaScript. When you read that a feature is "ES2022", the real question is not whether it counts as JavaScript but whether your target engine has caught up with it yet.
// Core language features run identically in every host.
function fibonacci(n) {
const table = [0, 1];
for (let i = 2; i <= n; i += 1) {
table.push(table[i - 1] + table[i - 2]);
}
return table[n];
}
console.log("fibonacci(10) =", fibonacci(10));
The function above touches nothing host-specific. Its output, fibonacci(10) = 55, is the same on a phone, a server and a laptop because nothing about it depends on where it landed.
Is JavaScript related to Java?
No. The names collide and essentially nothing else does. Java is a compiled, statically typed, class-based language designed to run on a virtual machine. JavaScript is interpreted, dynamically typed and built on prototypes, created by Brendan Eich at Netscape in 1995.
The confusion has a single historical cause worth remembering: the browser that first shipped JavaScript also had a Java applets runtime, and the marketing borrowed the more familiar word. So if your notes say that Java is a subset of JavaScript, or that JavaScript is a stripped-down Java, both are wrong, and both trace back to that naming accident rather than to the languages themselves.
What happens between writing code and seeing it work?
Roughly three stages. The engine reads the source text, parses it into a structure it can walk, then executes that structure. Parsing is where syntax errors are caught: a missing bracket produces a SyntaxError before a single statement of your program runs, which is why one typo near the bottom of a file can stop the top from working at all.
Execution is not a top-to-bottom march. The engine keeps a stack of what it is currently doing — that is how it knows which function to return into — and a queue of work waiting to happen, such as timers, network callbacks and click handlers. The event loop is the mechanism that moves finished work from that queue onto the stack. Code inside a callback therefore runs later, after the current block has finished, no matter where it appears in the file.
How is JavaScript different from HTML and CSS?
Three jobs, three constraints. HTML supplies structure and meaning. CSS supplies presentation. JavaScript supplies behaviour, and because it runs while the page is live, it can change structure and presentation after the fact.
The constraint that catches beginners out is this: a script cannot rewrite the page wholesale. The browser parses your HTML into a live tree of nodes, and your script edits that tree node by node. There is no document object you can replace in one go. That is also why where you put your script tag in the HTML matters, which is the subject of the next lesson.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Where am I?</title>
</head>
<body>
<p>Open the console and read the output.</p>
<script src="where-am-i.js"></script>
</body>
</html>
What to carry forward
- JavaScript is the language, ECMAScript is the specification that defines it, and V8, SpiderMonkey and JavaScriptCore are the engines that run it.
- The core language is host-independent. The DOM,
windowandfetchare host extras you opt into deliberately. - Node.js gives you the same language plus a file system, a package ecosystem and a process object. That is the whole reason server-side JavaScript exists.
- A syntax error kills the entire file. A runtime error kills only the statement that hit it, and everything after it may still run.
Try it yourself: make a folder, put the host-detection snippet above into a file named where-am-i.js, and run node where-am-i.js — note which two lines print true. Next, copy that file into a page that loads it with a <script src="where-am-i.js"> tag at the end of <body>, open it in a browser, and confirm the browser and Node rows swap. One file, two hosts, two different answers — that is runtime detection working.