Hello, JavaScript
Three ways to run JavaScript: in Node, in the browser, in the REPL. Five minutes from install to running script. The language is small; the runtime API surface differs depending on where it runs — that's the only complication.
1 · The intuition
JavaScript started as a 10-day scripting hack for Netscape in 1995. Modern JS (ES2015+) is unrecognisable — closures, classes, async/await, modules, generators. It runs everywhere: browsers, Node.js, Deno, Bun, Cloudflare Workers, Electron desktop apps, React Native mobile.
fs.readFileSync works in Node but not browsers.
document.querySelector works in browsers but not Node. The week is
mostly about the language; we'll point out runtime differences as they come up.2 · Try it — three ways to run JS
Way 1 — node script.js
// hello.js
console.log("Hello, JavaScript!");Way 2 — the Node REPL
$ node
Welcome to Node.js v20.x.x
> 1 + 1
2
> const greet = (n) => \`Hello, ${n}!\`
undefined
> greet("Alice")
'Hello, Alice!'
> .exitWay 3 — browser console
Open any web page. Press F12. Go to the Console tab. Type:
console.log("Hello from the browser");
// Outputs: Hello from the browser
document.title // gives the current page title
window.location.href // gives the URL3 · The first program — and what's modern
// Modern JS — three syntactic moves to internalize
const greet = (name) => \`Hello, ${name}!\`;
const names = ["Alice", "Bob", "Carol"];
// Array.map + arrow function — chain instead of loop
const greetings = names.map(greet);
console.log(greetings);
// String interpolation with backticks
const summary = \`Greeted ${names.length} people\`;
console.log(summary);const, notvar.letonly when you reassign. Nevervar.- Arrow functions —
(x) => x * 2. Shorter thanfunction; differentthisbinding (more on this Day 4). - Template literals — backticks with
$${...}interpolation. Multi-line strings work natively. - Array methods —
.map,.filter,.reduce. Chain them. Almost always cleaner thanfor.
4 · npm — the package manager
# Initialise a project
$ mkdir myapp && cd myapp
$ npm init -y
# Creates package.json
# Add a dependency
$ npm install lodash
# Installs to ./node_modules and records in package.json
# Run a script
$ node index.js
# Or run an installed CLI
$ npx prettier --write .npm handles dependencies, scripts, and metadata. npx
runs binaries from local node_modules or fetches from the registry
temporarily. The ecosystem is huge — over 2 million packages on npm — which is
both a strength and a footgun.
5 · The five commands you'll use daily
| Command | What it does |
|---|---|
node script.js | Run a single file |
node | Open the REPL |
npm init -y | Create package.json with defaults |
npm install <pkg> | Add dependency |
npm install (no args) | Install all deps from package.json |
npm run <script> | Run a named script from package.json |
npm test | Run the "test" script |
npx <binary> | Run a CLI without global install |
6 · Modern vs legacy JS — the cheat sheet
| Old way (avoid) | Modern way (use) |
|---|---|
var x = 5 | const x = 5 or let x = 5 |
'Hello, ' + name + '!' | `Hello, ${name}!` |
function (x) { return x * 2; } | x => x * 2 |
arr[arr.length - 1] | arr.at(-1) |
Object.assign({}, a, b) | {...a, ...b} |
foo == null | foo === null || foo === undefined or foo == null (the one case == is fine) |
obj.foo && obj.foo.bar | obj.foo?.bar |
foo || defaultValue | foo ?? defaultValue (when 0 / '' / false are valid) |
.then().then().catch() | async/await with try/catch |
7 · Common mistakes (and surprises)
- Using
var. Function-scoped, hoisted, easy to shadow. Never use it in new code. - Using
==. Coerces."" == falseis true.0 == "0"is true. Always===. - Missing semicolons. JS has Automatic Semicolon Insertion (ASI). It works 99% of the time and then bites you. Add them or use a formatter.
typeof null === "object". A historical bug, preserved for compatibility. Don't rely on it. Use=== null.- Floating point.
0.1 + 0.2 !== 0.3. JS uses IEEE 754 floats. For money, use integers (cents) or a decimal library. - Array destructuring requires order.
const [a, b] = arr. For named extracts, use objects:const {name} = user.
8 · Coming from another language
| If you know… | What's familiar | What surprises |
|---|---|---|
| Python | Dynamic typing. First-class functions. Easy to write. | this binding rules. Coercion (==). The event loop replaces threads. |
| Go | First-class functions. Modern JS feels more typed than expected (TS). | Dynamic types unless using TS. Event-loop concurrency. npm install hell. |
| Java / C# | Classes (since ES6). Type system with TS feels familiar. | Prototypal inheritance under classes. Single-threaded. No checked exceptions. |
| Rust | Iterator chains. | Garbage collected. null AND undefined. No ownership. |
9 · Exercises (~10 min)
- FizzBuzz, modern. 1-30. Use
const, an arrow function, template literals. - Type-check. Predict what
typeofreturns for:42,"go",true,null,undefined,[],{}. Run them. Two surprises. - The arrow vs function difference. Try
setTimeout(function() { console.log(this) }, 0)vssetTimeout(() => console.log(this), 0)at the top level of a file. Different output. We'll explain Day 4. - Add a dep.
npm init -y,npm install chalk, write 3 lines that import chalk and print colored text.
10 · When it clicks
- You reach for
constby default andletwhen reassigning. - Template literals (
`${...}`) come out before string concatenation. - You don't type
==anymore. - You know that "JS runtime" is the variable to control for, not "JavaScript".