The only language that runs natively in every browser โ the backbone of the modern web, and increasingly servers too (Node.js). Copy-paste examples plus live Run/Submit exercises, running instantly in your own browser.
console.log("Hello, world!");
let age = 25; // can be reassigned
age = 26;
const name = "Sam"; // cannot be reassigned
// avoid "var" โ it has confusing scoping rules from old JS
let price = 9.99; // number (no separate int/float)
let name = "Mo"; // string
let isValid = true; // boolean
let nothing = null; // intentionally empty
let notSet; // undefined โ declared but never assigned
console.log(typeof price); // "number"
JavaScript has only one number type โ no separate int/float. That makes decimal math a little dangerous for anything involving money.
console.log(0.1 + 0.2); // 0.30000000000000004 โ binary floating-point can't store 0.1 exactly
console.log(0.1 + 0.2 === 0.3); // false!
// industry-standard fix: do money math in CENTS (integers), convert to dollars at the very end
const priceCents = 1090 + 2095;
const dollars = Math.round(priceCents) / 100;
console.log(dollars.toFixed(2)); // "31.85"
const a = 'single quotes'; // preferred default
const b = "double, to avoid escaping";
const c = 'I\'m learning JS'; // \' escapes the quote inside
const qty = 3, total = 2095;
console.log(`Items (${qty}): $${(total / 100).toFixed(2)}`); // template literal, multi-line capable
console.log('2.95' + 20.95); // "2.9520.95" โ string + number CONCATENATES, doesn't add!
+ between a string and a number coerces the number to text instead of doing math โ when building a template literal with math inside, wrap the numeric expression in parentheses first (as in the example above) so it evaluates before becoming part of the string.console.log(5 === '5'); // false โ === checks type AND value
console.log(5 == '5'); // true โ == silently converts types first
// always use === / !== โ never == / != โ to avoid surprise type coercion
if (age >= 18 && hasId) { } // AND โ both must be true
if (isVip || total > 100) { } // OR โ at least one true, short-circuits
if (!isBanned) { } // NOT
false in a condition): false, 0, '', NaN, undefined, null. Everything else โ including "0" and empty arrays/objects โ is truthy.const label = age >= 18 ? 'Adult' : 'Minor'; // condition ? ifTrue : ifFalse
// "default" pattern โ || falls through to a fallback when the left side is falsy
const currency = selectedCurrency || 'USD';
// "guard" pattern โ short-circuits out before running the right-hand side
const isReady = data && data.length > 0;
let age = 20;
if (age >= 18) {
console.log("Adult");
} else if (age >= 13) {
console.log("Teen");
} else {
console.log("Child");
}
for (let i = 0; i < 5; i++) {
console.log(i);
}
let n = 3;
while (n > 0) {
console.log(n);
n--;
}
for (let i = 0; i < 10; i++) {
if (i === 5) break; // stop the loop entirely
if (i % 2 === 0) continue; // skip just this iteration
console.log(i); // prints 1, 3
}
while loop, using continue before the increment step runs is a classic way to accidentally create an infinite loop โ make sure the counter still advances before skipping.let nums = [10, 20, 30];
console.log(nums[0]); // 10
nums.push(40); // add to the end
console.log(nums.length); // 4
for (const n of nums) { // for...of โ loop over VALUES
console.log(n);
}
JavaScript's array methods are how most real code is written โ favor these over manual loops.
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2); // [2,4,6,8,10] โ transform each item
const evens = nums.filter(n => n % 2 === 0); // [2,4] โ keep matching items
const total = nums.reduce((sum, n) => sum + n, 0); // 15 โ combine into one value
const found = nums.find(n => n > 3); // 4 โ first match
nums.forEach((value, index) => { // the preferred way to just LOOP (no return value)
console.log(`${index}: ${value}`);
});
const person = {
name: "Ada",
age: 30,
greet() {
console.log(`Hi, I'm ${this.name}`);
}
};
console.log(person.name); // Ada
person.greet(); // Hi, I'm Ada
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
function calculateTax(cost, taxRate = 0.1) { // default parameter โ used if the caller omits it
return cost * taxRate;
}
console.log(calculateTax(100)); // 10 โ uses the default 0.1
myFn), not the result of calling it (myFn()) โ a very common mistake with callbacks and timers.A shorter function syntax, extremely common in modern JS โ especially with array methods.
const add = (a, b) => a + b;
console.log(add(2, 3)); // 5
const square = n => n * n; // one param -> parens optional
console.log(square(4)); // 16
A function "remembers" the variables from the scope it was created in, even after that outer function has already returned โ this is a closure.
function makeCounter() {
let count = 0; // captured by the inner function below
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2 โ count kept its value between calls, private to this counter
makeCounter() creates a brand-new, independent count โ closures are how you get private, per-instance state without needing a class.const id = setTimeout(() => {
console.log('Ran once, after 1 second');
}, 1000);
const intervalId = setInterval(() => {
console.log('Runs every second, forever');
}, 1000);
clearInterval(intervalId); // stop it โ otherwise it never ends on its own
const name = "Sam", age = 25;
console.log(`${name} is ${age} years old`); // backticks + ${} โ no more string concatenation
const person = { name: "Ada", age: 30 };
const { name, age } = person; // pull fields out into variables
console.log(name, age); // Ada 30
const [first, second] = [10, 20]; // works on arrays too
document is a built-in object that links your JS to the actual webpage, so you can read and change what's on screen.
const buttonEl = document.querySelector('.js-subscribe-button'); // CSS-style selector
buttonEl.innerHTML = 'Subscribed'; // replace what's inside an element (parses HTML)
const allButtons = document.querySelectorAll('button'); // every match, as a list
buttonEl.classList.add('is-subscribed'); // toggle a CSS class from JS
buttonEl.classList.remove('is-subscribed');
innerHTML parses its string as real HTML (tags and all); innerText sets plain text and also strips extra whitespace when you read it back โ they're not interchangeable.addEventListener is the modern, preferred way to react to user actions โ an element can have several listeners, and they can be removed later.
buttonEl.addEventListener('click', () => {
console.log('Button was clicked!');
});
document.body.addEventListener('keydown', (event) => {
if (event.key === 'r') {
console.log('You pressed R');
}
});
data-* HTML attributes (e.g. data-product-id="abc123"), readable in JS as element.dataset.productId โ a clean way to attach an ID for an event handler to read back.JSON (JavaScript Object Notation) is a text format for data that any language can read โ used constantly for sending/storing objects.
const product = { name: 'Shirt', price: 1999 };
const text = JSON.stringify(product); // '{"name":"Shirt","price":1999}' โ object -> string
const back = JSON.parse(text); // string -> object again
console.log(back.name); // Shirt
Lets a page save small amounts of data in the browser that survives a page refresh โ but it only stores strings, so objects need JSON.stringify/parse.
localStorage.setItem('score', JSON.stringify({ wins: 3, losses: 1 }));
const score = JSON.parse(localStorage.getItem('score')) || { wins: 0, losses: 0 };
console.log(score.wins); // 3
localStorage.removeItem('score');
Splitting code across files avoids naming collisions between separate <script> tags โ each module explicitly declares what it shares.
// cart.js
export function addToCart(productId) { /* ... */ }
export const cart = [];
// main.js
import { addToCart, cart } from './cart.js';
addToCart('abc123');
import/export needs <script type="module" src="main.js"></script>, and generally needs to be served over a local dev server rather than opened directly as a file:// path.A class is a blueprint for creating many similar objects, bundling data and behavior together. extends/super let one class build on another.
class Product {
#internalNote; // # = truly private, only accessible inside this class
constructor(name, priceCents) {
this.name = name;
this.priceCents = priceCents;
}
getPrice() {
return (this.priceCents / 100).toFixed(2);
}
}
class Clothing extends Product { // inherits everything from Product
constructor(name, priceCents, size) {
super(name, priceCents); // must call the parent constructor first
this.size = size;
}
}
const shirt = new Clothing('T-Shirt', 1999, 'M');
console.log(shirt.getPrice()); // "19.99" โ inherited method
console.log(shirt instanceof Product); // true
this refers to the object it was called on โ but a plain (non-arrow) callback passed to something like forEach loses that binding. Arrow functions don't have their own this โ they inherit it from where they were written, which is why they're the safe default for callbacks inside a class method.try {
const data = JSON.parse('not valid json');
} catch (error) {
console.log('Something went wrong: ' + error.message);
} finally {
console.log('This always runs');
}
function withdraw(balance, amount) {
if (amount > balance) throw new Error('Insufficient funds');
return balance - amount;
}
A Promise represents a value that isn't ready yet, but will "resolve" (succeed) or "reject" (fail) later โ the fix for deeply nested callbacks.
const waitOneSecond = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done waiting!');
}, 1000);
});
waitOneSecond
.then((result) => console.log(result)) // runs once resolve() fires
.catch((error) => console.log(error)); // runs if reject() fires instead
// Promise.all waits for several promises to finish before continuing
Promise.all([waitOneSecond, fetch('/api/data')]).then(results => { /* ... */ });
fetch() is the modern, Promise-based way to talk to a server. async/await is syntax sugar over Promises that reads like ordinary top-to-bottom code โ the generally preferred style over raw .then() chains.
async function loadOrder(orderId) {
try {
const response = await fetch(`/orders/${orderId}`);
const order = await response.json();
console.log(order);
} catch (error) {
console.log('Unexpected error, please try again later.');
}
}
await only works inside a function marked async. Prefer async/await > raw Promises > nested callbacks โ each step reads top-to-bottom instead of nesting deeper and deeper.Runs instantly in your own browser โ no server round-trip, same as Python.
const nums = [4, 8, 15, 16, 23, 42];
const sum = nums.reduce((a, b) => a + b, 0);
console.log(sum);
function reverse(s) {
return s.split("").reverse().join("");
}
console.log(reverse("javascript"));
const age = 16;
const label = age >= 18 ? 'Adult' : 'Minor';
console.log(label);
const nums = [1, 2, 3, 4, 5, 6, 7, 8];
const result = nums.filter(n => n % 2 === 0).map(n => n * n);
console.log(result.join(","));
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counterA = makeCounter();
const counterB = makeCounter();
console.log(counterA(), counterA(), counterA()); // 1 2 3
console.log(counterB()); // 1 โ totally independent
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound.`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks.`; } // overrides the parent method
}
const animals = [new Animal('Generic'), new Dog('Rex')];
animals.forEach(a => console.log(a.speak()));
function wordCount(text) {
const counts = {};
for (const word of text.split(" ")) {
counts[word] = (counts[word] || 0) + 1;
}
return counts;
}
const result = wordCount("the cat sat on the mat the cat ran");
for (const word in result) {
console.log(`${word}: ${result[word]}`);
}
function fetchUser(id) {
return new Promise((resolve) => {
resolve({ id: id, name: 'Ada' });
});
}
function fetchOrders(user) {
return new Promise((resolve) => {
resolve(['order1', 'order2']);
});
}
fetchUser(1)
.then((user) => fetchOrders(user)) // returning a promise from .then() chains flatly instead of nesting
.then((orders) => console.log(orders.length))
.catch((error) => console.log('Failed: ' + error));
function fetchPrice(itemId) {
return new Promise((resolve, reject) => {
if (itemId < 0) reject(new Error('Invalid item id'));
else resolve(1999);
});
}
async function printTotal(itemId) {
try {
const priceCents = await fetchPrice(itemId);
console.log((priceCents / 100).toFixed(2));
} catch (error) {
console.log('Error: ' + error.message);
}
}
printTotal(1);
printTotal(-1);
Builds Pascal's triangle using nested loops and prior-row lookups.
A closure captures a cache object so repeated calls reuse previously computed Fibonacci values.
A custom Error subclass carries a descriptive message through throw/catch.
runPipeline is awaited fully before the next call starts, so output stays strictly sequential.