JavaScript
Status: 🟩 COMPLETE Last updated: 2026-06-20 Plain-English tagline: The programming language of the web — and now the language behind servers, mobile apps, build tools, and most of the modern dev ecosystem.
In plain English
JavaScript is the language that makes web pages interactive. When you click a button and a menu opens, when a form validates as you type, when a page updates without reloading — all JavaScript. It runs inside every browser; it also runs on servers via Node.js. One language, both sides.
Created in 1995 by Brendan Eich in 10 days at Netscape. The name was a marketing move (Java was hot; JavaScript had nothing to do with Java). For two decades it was dismissed as a toy language. Then the modern web happened, and JavaScript ate everything.
JavaScript is officially called ECMAScript — that’s the standard. New versions ship roughly yearly (ES2024, ES2025, etc.), each adding features. Browsers and Node support new features quickly.
Modern JavaScript looks very different from 2010 JavaScript. The language is much better now: arrow functions, async/await, destructuring, modules, classes, optional chaining. Most of what you’ll write in 2026 is modern JS.
Why it matters
- It’s the only language browsers run. Period. Other languages (TypeScript, Sass, etc.) compile to JavaScript before reaching the browser.
- Node.js made it the dominant backend language too. Same code on both sides.
- The tooling ecosystem is JavaScript. npm packages, build tools (Webpack, Vite, esbuild), test runners — all JS.
- Every modern web framework is JavaScript — React, Vue, Svelte, Next.js, Nuxt, SvelteKit, Remix.
If you’re going to learn one programming language for the modern web, this is the one. Knowing it well opens up everything else.
A 5-minute tour of the language
Variables
let count = 0; // can be reassigned
const name = "George"; // can't be reassigned (but contents can mutate for arrays/objects)
var x = 1; // old-style; basically never use this in modern codeUse const by default. Reach for let when you need to reassign. Avoid var.
Primitive types
const a = 42; // number
const b = 3.14; // also number — no separate float type
const c = "hello"; // string
const d = `template ${a}`; // template string with interpolation
const e = true; // boolean
const f = null; // null
const g = undefined; // undefined
const h = Symbol("id"); // unique symbol (rare)
const i = 9007199254740993n; // bigint (for very large numbers)Arrays and objects
const arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.length; // 4
arr[0]; // 1
const obj = { name: "George", age: 99 };
obj.name; // "George"
obj["name"]; // also "George"
obj.email = "g@x.com"; // add new propertyFunctions
// Function declaration
function add(a, b) {
return a + b;
}
// Arrow function (modern, shorter)
const add = (a, b) => a + b;
// With default values
const greet = (name = "world") => `Hello, ${name}`;
// Higher-order: function that takes/returns functions
const double = (fn) => (x) => fn(x) * 2;Control flow
if (count > 0) {
doSomething();
} else if (count === 0) {
doSomethingElse();
} else {
doDefault();
}
// Ternary (inline if/else)
const message = count > 0 ? "positive" : "non-positive";
// Switch (less common in modern JS)
switch (status) {
case "loading": return <Spinner />;
case "ready": return <Result />;
default: return null;
}Loops
// for-of (most common)
for (const item of items) {
console.log(item);
}
// for-in (object keys)
for (const key in obj) {
console.log(key, obj[key]);
}
// .forEach (array method)
items.forEach((item) => console.log(item));
// Traditional for (rarely needed)
for (let i = 0; i < items.length; i++) { ... }Array methods (the workhorse)
const nums = [1, 2, 3, 4, 5];
nums.map((n) => n * 2); // [2, 4, 6, 8, 10] — transform each
nums.filter((n) => n % 2 === 0); // [2, 4] — keep matching
nums.reduce((sum, n) => sum + n, 0); // 15 — combine
nums.find((n) => n > 3); // 4 — first match
nums.some((n) => n > 4); // true — any match
nums.every((n) => n > 0); // true — all match
nums.includes(3); // true
nums.slice(1, 3); // [2, 3] — sub-array (non-mutating)These are used constantly. map/filter/reduce especially.
Destructuring
// Object
const { name, age } = obj;
// equivalent to: const name = obj.name; const age = obj.age;
// With renaming
const { name: userName } = obj;
// With defaults
const { name = "anonymous" } = obj;
// Array
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]Spread
// Array spread
const merged = [...arr1, ...arr2];
// Object spread (shallow merge)
const merged = { ...obj1, ...obj2 };
// In function calls
const max = Math.max(...nums);Equality
1 == "1" // true — loose equality (avoid)
1 === "1" // false — strict equality (use)
1 === 1 // trueUse === and !==. Always. The loose versions (==, !=) have surprising rules.
null vs undefined
undefined— “this variable was never assigned”null— “this variable was intentionally set to nothing”
null === undefined is false. null == undefined is true. Use === and don’t worry about it.
Modern features (ES2020+)
// Optional chaining
const city = user?.address?.city;
// undefined if user or user.address is null/undefined; no error
// Nullish coalescing
const name = user.name ?? "anonymous";
// "anonymous" only if user.name is null or undefined (not 0, "" or false)
// Logical assignment
user.name ||= "anonymous"; // assign if falsy
user.config ??= {}; // assign if null/undefinedThese three save dozens of lines per project once you internalize them.
Async — the most important concept
JavaScript is single-threaded but asynchronous. Long-running operations (network calls, file reads, timers) don’t block — they return immediately and notify you later.
Promises
A Promise represents an eventual result:
fetch("/api/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));Async/await — the modern way
async function loadData() {
try {
const response = await fetch("/api/data");
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}Same as the Promise version, but reads top-to-bottom. await pauses the function until the Promise resolves.
async marks a function as asynchronous (it implicitly returns a Promise). await only works inside async functions (or at the top level in modules).
Modules — splitting code across files
Modern JavaScript uses ES Modules:
// lib/math.js
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// app.js
import { add, multiply } from "./lib/math.js";
console.log(add(2, 3));export makes something available; import brings it in. Same concept in React/Next.js (import { useState } from "react").
What JavaScript runs on
- Browsers: Chrome (V8), Firefox (SpiderMonkey), Safari (JavaScriptCore), Edge (V8). All implement the same standard.
- Servers: Node.js (V8), Deno, Bun.
- Desktop apps: Electron (uses Node + Chromium).
- Mobile apps: React Native, Capacitor, Ionic.
- Edge environments: Vercel Edge, Cloudflare Workers (V8 isolates).
One language, almost everywhere.
Common gotchas
-
==vs===. Always use===. The loose equality has surprising coercion rules. -
typeof null === "object". A 25-year-old bug in the language, never fixed for compatibility. Usevalue === nullto check. -
Arrays are objects.
Array.isArray()is the safe check, nottypeof === "array". -
thisis weird. Its value depends on how a function is called. Arrow functions inheritthisfrom where they’re defined (almost always what you want). Regular functions getthisfrom the caller. -
Async ≠parallel.
awaitruns sequentially. To parallelize, usePromise.all([promise1, promise2]). -
Mutation surprises.
const obj = {}; obj.x = 1;is legal —constprevents reassignment, not mutation. Use Object.freeze or libraries like Immer for true immutability. -
0,"",null,undefined,NaN,falseare all “falsy.”if (value)skips on all of them. Sometimes that’s what you want; sometimes not. -
Dateis unfriendly. JavaScript’s built-in Date object has odd quirks (months are 0-indexed!). Use a library like date-fns or the newTemporalAPI. -
parseInt("08")was once0(octal). Modern engines fixed this, but always pass the radix:parseInt("08", 10). -
Floating-point math.
0.1 + 0.2 === 0.30000000000000004. Not a JavaScript bug — that’s IEEE 754. Use rounding or libraries for precise money math. -
forEachdoesn’t await. If you need to await inside a loop, usefor-ofwithawait, orPromise.all(items.map(...))for parallel. -
Hoisting. Function declarations are “hoisted” — usable before their definition.
varis also hoisted (withundefined).const/letare not. Just declare things before using them. -
asyncfunctions always return Promises. Even if they justreturn 42, the caller getsPromise<42>, not42.
See also
- TypeScript 🟩 — JavaScript with types
- The DOM 🟩 — how JS talks to HTML
- HTML đźź©
- CSS đźź©
- React đźź©
- Node.js đźź©
- Async & concurrency đźź©
- Glossary: JavaScript, Async, Promise
Sources
- MDN — JavaScript reference — canonical, free
- JavaScript.info — excellent free tutorial
- Eloquent JavaScript (free online)
- You Don’t Know JS (book series) — deep dives
- ECMAScript 2025 spec — the actual standard