01 / 20 · Day 1
Day 1 · Concept 01

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.

The runtime split. The language is one thing; the API depends on the host. 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

js hello.js
// hello.js
console.log("Hello, JavaScript!");

Way 2 — the Node REPL

shell terminal
$ node
Welcome to Node.js v20.x.x
> 1 + 1
2
> const greet = (n) => \`Hello, ${n}!\`
undefined
> greet("Alice")
'Hello, Alice!'
> .exit

Way 3 — browser console

Open any web page. Press F12. Go to the Console tab. Type:

js browser console
console.log("Hello from the browser");
// Outputs: Hello from the browser

document.title  // gives the current page title
window.location.href  // gives the URL

3 · The first program — and what's modern

js hello.js
// 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, not var. let only when you reassign. Never var.
  • Arrow functions(x) => x * 2. Shorter than function; different this binding (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 than for.

4 · npm — the package manager

shell terminal
# 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

CommandWhat it does
node script.jsRun a single file
nodeOpen the REPL
npm init -yCreate 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 testRun 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 = 5const 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 == nullfoo === null || foo === undefined or foo == null (the one case == is fine)
obj.foo && obj.foo.barobj.foo?.bar
foo || defaultValuefoo ?? 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. "" == false is 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 familiarWhat surprises
PythonDynamic typing. First-class functions. Easy to write.this binding rules. Coercion (==). The event loop replaces threads.
GoFirst-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.
RustIterator chains.Garbage collected. null AND undefined. No ownership.

9 · Exercises (~10 min)

  1. FizzBuzz, modern. 1-30. Use const, an arrow function, template literals.
  2. Type-check. Predict what typeof returns for: 42, "go", true, null, undefined, [], {}. Run them. Two surprises.
  3. The arrow vs function difference. Try setTimeout(function() { console.log(this) }, 0) vs setTimeout(() => console.log(this), 0) at the top level of a file. Different output. We'll explain Day 4.
  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 const by default and let when 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".
Found this useful?