Tutorial
🟨JavaScript Tutorial
The JavaScript you actually ship. Values, functions, the DOM, modules, and async, with code you can run.
What JavaScript is
JavaScript runs in the browser and in Node. A .js file is a list of statements. A newline does not end a statement. A semicolon can, and a line break often does, but do not rely on that when the next line starts with ( or [.
The language is the same in both places. The browser adds the page (document, window). Node adds the disk and the network (fs, fetch in current Node). This page is the language, then the page.
A file you can run
Save this as hello.js and run node hello.js.
const site = "https://thewhitewitchtm.github.io/mira/"
function greet(name) {
return `Hello, ${name}`
}
console.log(greet("Mira"))
console.log(site)
const is a name you do not reassign. let is a name you do. Skip var. It leaks out of the block.
Values
const n = 42
const label = "Tailwind"
const on = true
const missing = null
const bag = { title: "Markdown", year: 2026 }
const list = ["text", "headings", "lists"]
typeof null is "object". That is a long-standing lie. Check value === null.
=== compares without converting types. == converts first, and "1" == 1 is true. Use ===.
A string and a number add by turning the number into text:
"4" + 2 // "42"
Number("4") + 2 // 6
Functions
function area(w, h) {
return w * h
}
const area2 = (w, h) => w * h
The first form has its own this and can be called before the line it is written on. The arrow form takes this from the surrounding function, and it is the one you want for a callback.
Default values and a rest list:
function tag(name, ...words) {
return words.map((word) => `${name}:${word}`)
}
tag("lang", "js", "ts")
Objects and arrays
const post = { title: "The lab", tags: ["lab", "next"] }
const { title, tags } = post
const [first] = tags
const next = { ...post, draft: false }
const more = [...tags, "static"]
... copies the top level. Nested objects are still shared. Do not mutate a value you received as an argument if the caller still holds it.
map, filter, and find return a new array. push and sort change the one you have.
const published = posts.filter((post) => !post.draft)
const titles = published.map((post) => post.title)
The page
The browser builds a tree from the HTML. You read it and you change it.
<button id="copy" type="button">Copy</button>
<p id="out"></p>
const button = document.querySelector("#copy")
const out = document.querySelector("#out")
button.addEventListener("click", () => {
out.textContent = "Copied"
})
textContent writes text. innerHTML writes HTML and will run whatever markup you hand it. If the string came from a person, use textContent.
A form field is a string until you convert it.
const form = document.querySelector("form")
form.addEventListener("submit", (event) => {
event.preventDefault()
const data = new FormData(form)
const title = String(data.get("title") || "").trim()
if (!title) return
})
Modules
One file, one job. export marks what other files may use. import names it.
export function slug(title) {
return title.toLowerCase().replaceAll(" ", "-")
}
import { slug } from "./slug.js"
In the browser, the script tag needs type="module". Modules are deferred, and they run once.
Async
fetch returns a promise. await pauses the function until the promise settles. The function must be async.
async function loadPosts() {
const response = await fetch("/mira/feed.xml")
if (!response.ok) throw new Error(String(response.status))
return response.text()
}
await without try rejects the promise of the caller. Catch it where you can show the failure.
try {
const xml = await loadPosts()
console.log(xml.length)
} catch (error) {
console.error(error)
}
Promise.all runs the independent ones together. If one fails, the whole all fails.
What bites people
- A missing property is
undefined, andundefined.foothrows. Optionalpost?.titlestops at the missing step. forEachignores a returned promise. Usefor...ofwhen the body usesawait.- Dates:
new Date("2026-01-30")is UTC midnight. Format with the calendar day you stored, not the local timezone, if the day is the point. const list = []can stillpush.constblocks a new binding, not a change inside the value.
The Markdown page is the writing. The Tailwind page is the styling. TypeScript is the same language with the shapes named. That page is next.
