This is an interactive guide. All modules are open by default. You can click any module title to hide or show its content, or use the Table of Contents to jump to a specific section.
Explanation: To make a webpage interactive, you need to add JavaScript. The <script> tag is how you do this. You can either write your code directly inside the tag or, more commonly, put your code in a separate file (like app.js) and link to it using the src attribute. This keeps your HTML clean and your JavaScript organized.
<!DOCTYPE html>
<html>
<head>
<title>My First JS Page</title>
</head>
<body>
<h1>Welcome</h1>
<!-- The script tag links to our external JavaScript file -->
<script src="app.js"></script>
</body>
</html>
app.js:
console.log("Hello from an external file!");
Explanation: JavaScript can display data in several ways. The most common method for developers is console.log(), which writes messages to the browser's developer console for debugging. You can also change the content of an HTML element with innerHTML, create a pop-up alert box with window.alert(), or write directly to the HTML document with document.write() (though this last one is rarely used).
// 1. Write to an HTML element with the id "demo"
document.getElementById("demo").innerHTML = "Hello World!";
// 2. Write to the document output (use with caution)
document.write("This can overwrite the page content.");
// 3. Write to an alert box
window.alert("This is an alert!");
// 4. Write to the browser console for debugging
console.log("Check the browser console to see this message.");
Explanation: A JavaScript program is a sequence of **statements**. Each statement is an instruction for the computer to perform an action, and they are typically ended with a semicolon ;. You can also leave notes in your code called **comments**. Single-line comments start with //, and multi-line comments are enclosed in /* ... */. The browser ignores comments, so they are purely for humans to read and understand the code.
// This is a single-line comment
/*
This is a
multi-line comment.
*/
// A program is a series of statements
let x, y, z; // Statement 1: Declare variables
x = 5; // Statement 2: Assign a value to x
y = 6; // Statement 3: Assign a value to y
z = x + y; // Statement 4: Assign the sum of x and y to z
console.log(z); // Outputs 11
Before looking at the code, it's important to understand two core concepts: variables and data types. Think of a variable as a labeled box where you can store information 📦. You give the box a name (the variable name) so you can find it later. In JavaScript, we use keywords like let, const, and var to create these boxes.
The information you put inside the box has a specific data type. JavaScript needs to know what kind of data it's working with. The most common types are:
"Hello World").42 or 3.14).true or false.{ name: "John", age: 30 }).Explanation: This code demonstrates creating variables with the let and const keywords. We assign values of different data types to them: a String for text, a Number for a numeric value, a Boolean for a true/false state, and an Object for a collection of related data. The typeof operator is used to check the data type of a variable.
// String
let name = "Alice";
// Number
let age = 30;
// Boolean
const isStudent = true;
// Object
let person = {firstName: "John", lastName: "Doe"};
// Undefined
let car;
console.log(typeof age); // Outputs "number"
Explanation: Operators are symbols that perform operations on values and variables. This example shows an **arithmetic** operator (+) for addition, an **assignment** operator (+=) to add a value to an existing variable, and **comparison** (>) and **logical** (&&) operators to check if multiple conditions are true at the same time.
let a = 10;
let b = 4;
// Arithmetic Operator
let sum = a + b; // 14
// Assignment Operator
a += 5; // a is now 15
// Comparison & Logical Operators
if (a > sum && b < 5) {
console.log("Both conditions are true!");
}
Explanation: Sometimes JavaScript automatically converts data types for you, which is called **implicit conversion** or "coercion." In the first example, adding a number to a string causes the number to be converted to a string. You can also explicitly convert types yourself using built-in functions like Number() or String(). This **explicit conversion** is safer and makes your code's intent clearer.
// Implicit conversion (coercion)
let result = "5" + 5; // JavaScript converts 5 to a string -> "55"
console.log(result);
// Explicit conversion
let score = "100";
let scoreAsNumber = Number(score);
console.log(scoreAsNumber + 10); // Outputs 110
Explanation: Conditional statements allow your program to make decisions and execute different blocks of code based on whether a condition is true or false. The if...else if...else structure tests a series of conditions in order until one is met. The code block associated with that condition is executed, and the rest are skipped.
let time = 14; // 2 PM
if (time < 12) {
console.log("Good morning!");
} else if (time < 18) {
console.log("Good afternoon!");
} else {
console.log("Good evening!");
}
Explanation: Loops are used to execute a block of code repeatedly. The for loop is perfect when you know how many times you want to repeat the action. It has three parts: an initializer (let i = 0), a condition (i < fruits.length), and an incrementer (i++). This loop will run once for every item in the fruits array, printing each one to the console.
const fruits = ["Apple", "Banana", "Cherry"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
Explanation: You can control the flow of loops with the break and continue keywords. The continue statement skips the rest of the current iteration and moves to the next one (the example skips printing the number 3). The break statement terminates the loop entirely, regardless of whether the loop's condition is still true (the example stops the loop when it reaches 8).
for (let i = 1; i <= 10; i++) {
if (i === 3) {
continue; // Skip this iteration
}
if (i === 8) {
break; // Exit the loop completely
}
console.log(i); // Outputs 1, 2, 4, 5, 6, 7
}
Explanation: A **function** is a reusable block of code that performs a specific task. You define the function once (here, greet) and can then "call" or "invoke" it as many times as you need. Functions can accept inputs, called **parameters** (like name), and can produce an output using the return keyword.
function greet(name) {
return "Hello, " + name + "!";
}
let message = greet("Bob");
console.log(message); // Outputs "Hello, Bob!"
Explanation: An **object** is a data structure that groups related data and functionality. Think of a real-world object, like a car. It has properties (brand, model, year) and things it can do (display its info). In JavaScript, we store these as key-value pairs. When a function is part of an object (like displayInfo), it's called a **method**.
const car = {
brand: "Ford",
model: "Mustang",
year: 1969,
// This is a method
displayInfo: function() {
return this.brand + " " + this.model;
}
};
console.log(car.displayInfo()); // Outputs "Ford Mustang"
Explanation: JavaScript can respond to user actions on a webpage, like clicks, mouse movements, or key presses. These actions are called **events**. You can "listen" for an event on a specific HTML element and run a function when that event occurs. Here, we select the button and assign a function to its onclick property, causing an alert to pop up when it's clicked.
// In the HTML:
document.getElementById("myButton").onclick = function() {
alert("Button was clicked!");
};
Explanation: A **string** is a sequence of characters used to represent text. Strings have many built-in methods to manipulate them, such as toUpperCase() which converts the string to uppercase. The example also shows a **template literal** (using backticks ` `), which is a modern way to create strings that makes it easy to embed variables directly inside them using the ${...} syntax.
let text = "Hello World";
// Using a built-in string method
console.log(text.toUpperCase()); // "HELLO WORLD"
// Using a template literal to embed a variable
let name = "User";
let greeting = `Welcome back, ${name}!`;
console.log(greeting); // "Welcome back, User!"
Explanation: The **number** data type is used for all numeric values, both integers and decimals. JavaScript provides a built-in Math object that has useful properties and methods for performing mathematical tasks. The code below uses Math.random() to get a random decimal between 0 and 1, and Math.floor() to round it down to a whole number, creating a random integer.
// Generate a random integer between 1 and 10
let randomNumber = Math.floor(Math.random() * 10) + 1;
console.log(randomNumber);
An array is a special type of variable that can hold more than one value at a time. Think of it like a numbered list or a filing cabinet with numbered drawers 🗄️. Instead of creating a separate variable for each item, you can store them all in one array.
Items in an array are called elements, and they are accessed by their numerical position, called an index. Crucially, JavaScript arrays are zero-indexed, which means the first element is at index 0, the second is at index 1, and so on. They are created using square brackets [].
Explanation: This code shows an array of numbers. Arrays come with many powerful built-in methods. The forEach() method is used here to iterate over every element in the array and execute a function for each one. In this case, it multiplies each number by 2 and prints the result.
const numbers = [1, 2, 3, 4, 5];
// Using a built-in array method to loop through each item
numbers.forEach(function(number) {
console.log(number * 2);
});
Explanation: To work with dates and times, you create an instance of the Date object. By default, new Date() creates an object representing the current date and time. This object has many methods to get specific parts of the date, such as getFullYear() to get the four-digit year, or toLocaleDateString() to get a formatted string of the date.
const today = new Date();
console.log(today.toLocaleDateString()); // e.g., "9/17/2025"
console.log(`The current year is ${today.getFullYear()}.`);
Explanation: **Scope** determines the accessibility of variables. Variables declared with var have **function scope**, meaning they are accessible anywhere within the function they are declared in. Variables declared with let and const have **block scope**, meaning they are only accessible within the block (the {...}) where they are defined. This is why functionScopedVar is accessible outside the if block, but trying to access blockScopedVar would cause an error.
if (true) {
let blockScopedVar = "I'm inside the block";
var functionScopedVar = "I'm available outside";
}
console.log(functionScopedVar); // "I'm available outside"
// console.log(blockScopedVar); // This would cause a ReferenceError
Explanation: **Hoisting** is JavaScript's default behavior of moving all declarations to the top of their current scope. Because of this, you can use a variable declared with var before it is declared without getting an error. However, only the declaration is hoisted, not the initialization. This is why myVar logs as undefined instead of its assigned string value.
console.log(myVar); // Outputs "undefined", not an error
var myVar = "I am hoisted";
Explanation: The this keyword is a special identifier whose value depends on the context in which it is used. When used inside an object's method (like in the sayHi function), this refers to the object itself (in this case, the user object). This allows the method to access other properties of the same object, like this.name.
const user = {
name: "Charlie",
sayHi: function() {
// Here, 'this' refers to the 'user' object
console.log(`Hi, I'm ${this.name}.`);
}
};
user.sayHi(); // "Hi, I'm Charlie."
Explanation: By putting the string "use strict"; at the beginning of a script or a function, you opt into a stricter, more secure version of JavaScript. It helps you catch common coding mistakes by throwing errors for actions that would otherwise fail silently. For example, in strict mode, assigning a value to a variable without declaring it first (with let, const, or var) will throw a ReferenceError.
"use strict";
// This will cause an error in strict mode
x = 3.14; // Uncaught ReferenceError: x is not defined
Explanation: JavaScript often has to wait for long-running operations, like fetching data from a network. A **callback** is a function that you pass as an argument to another function, which is then executed after the operation completes. In this example, setTimeout simulates a network delay, and the function that logs the message is the callback, which only runs after 2 seconds.
function fetchData(callback) {
setTimeout(() => {
const data = { message: "Data fetched successfully!" };
callback(data);
}, 2000);
}
fetchData(function(data) {
console.log(data.message);
});
Explanation: A **Promise** is an object that represents the eventual completion or failure of an asynchronous operation. It provides a cleaner way to handle async code than nested callbacks. A Promise can be in one of three states: pending, fulfilled (with a value), or rejected (with an error). You handle these outcomes using the .then() method for success and the .catch() method for failure.
const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("The operation was successful!");
} else {
reject("The operation failed.");
}
});
myPromise
.then((message) => console.log(message))
.catch((error) => console.log(error));
Explanation: async/await is modern syntax built on top of Promises that makes asynchronous code much easier to read and write. An async function always returns a Promise. The await keyword can be used inside an async function to pause its execution until a Promise settles (resolves or rejects). This allows you to write async code that looks and feels synchronous.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => { resolve('resolved'); }, 2000);
});
}
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
}
asyncCall();
Explanation: The **Document Object Model (DOM)** is a programming interface for HTML documents. It represents the page as a tree of objects, where each HTML tag is an object. JavaScript can access and manipulate these objects to change the content, structure, and style of a webpage dynamically. The code below finds an element by its ID and changes its text and color.
<p id="message">Old Text</p>
<script>
const messageElement = document.getElementById("message");
messageElement.innerHTML = "New Text!";
messageElement.style.color = "blue";
</script>
Explanation: The **Browser Object Model (BOM)** allows JavaScript to interact with the browser itself, outside of the content of the webpage. The global window object is the main entry point to the BOM. It provides access to information like the browser window's size (window.innerWidth), the current URL (window.location), and methods for browser actions like alerts and redirects.
// Get the width of the browser window
let windowWidth = window.innerWidth;
console.log(`The window width is ${windowWidth} pixels.`);
Explanation: **Web APIs** are built-in browser interfaces that extend JavaScript's capabilities. They provide easy access to complex features. The **Web Storage API**, for example, allows you to store key-value pairs locally in the user's browser, which persist even after the browser is closed. The code shows how to save an item with setItem() and retrieve it with getItem().
// Web Storage API example
localStorage.setItem('username', 'David');
const username = localStorage.getItem('username');
console.log(`Username from storage: ${username}`);
Explanation: This example ties together several concepts to create an interactive form. When the button is clicked, the submitFeedback() function is called. Inside the function, document.getElementById() is used to find each form input. The .value property is then used to read the text the user has entered. Finally, this data is formatted and displayed in an alert.
Code for the example above:
<script>
function submitFeedback() {
const name = document.getElementById('userNameLive').value;
const email = document.getElementById('userEmailLive').value;
const message = document.getElementById('userMessageLive').value;
const feedbackSummary = `Thank you!\n\nName: ${name}\nEmail: ${email}\nMessage: ${message}`;
alert(feedbackSummary);
}
</script>
Explanation: JavaScript can interact with browser features like the print dialog. The window.print() function triggers the browser's print functionality, allowing the user to print the page or save it as a PDF. We can also add special CSS inside an @media print block to hide elements like the "Print" button itself, so they don't show up on the final printed page.
<!-- This button will be hidden from the printout by the CSS -->
<button onclick="window.print()" class="no-print">
Print to PDF
</button>
<!-- In your CSS file or <style> tag -->
<style>
@media print {
.no-print {
display: none;
}
}
</style>
Explanation: **JSON (JavaScript Object Notation)** is a standard text-based format for representing structured data. It's commonly used to transmit data between a server and a web application. The syntax is very similar to JavaScript object literals. You can convert a JavaScript object into a JSON string with JSON.stringify() and parse a JSON string back into a JavaScript object with JSON.parse().
const book = { title: "The Hobbit", author: "J.R.R. Tolkien" };
// Convert JavaScript object to JSON string
const jsonString = JSON.stringify(book);
console.log(jsonString);
// Convert JSON string back to JavaScript object
const bookObject = JSON.parse(jsonString);
console.log(bookObject.title); // "The Hobbit"
Explanation: **AJAX** (Asynchronous JavaScript and XML) is a technique for fetching data from a server without having to reload the page. The modern way to perform AJAX requests is with the **Fetch API**, which is Promise-based. The fetch() function takes a URL, and its first .then() handles the raw response (which we convert to JSON), while the second .then() works with the actual data.
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error fetching data:', error));
Explanation: **Arrow functions** were introduced in ES6 and provide a more concise syntax for writing function expressions. They are especially useful for short, anonymous functions. The example shows how a simple add function can be written in a single line using the arrow (=>) syntax, which implicitly returns the result of the expression.
// Traditional Function
function add(a, b) { return a + b; }
// Arrow Function
const addArrow = (a, b) => a + b;
console.log(addArrow(5, 5)); // Outputs 10
Explanation: A **class** is a blueprint for creating objects. It provides a much cleaner and more organized syntax for object-oriented programming compared to older methods. The constructor method is a special method for creating and initializing an object created with a class. Other methods, like speak(), define the behavior of the objects created from the class.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
const dog = new Animal('Dog');
dog.speak(); // "Dog makes a noise."
Explanation: **Modules** allow you to split your JavaScript code into separate, reusable files. You can choose which variables or functions to make available to other files using the export keyword. You can then bring that exported code into another file using the import keyword. This is essential for keeping large codebases organized and maintainable.
// utils.js:
export function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// main.js:
import { capitalize } from './utils.js';
console.log(capitalize('hello')); // "Hello"
Explanation: Modern JavaScript includes many useful syntax improvements. **Destructuring** is a convenient way to extract values from objects or arrays into distinct variables. The **spread operator** (...) allows an iterable (like an array) to be expanded into individual elements, which is useful for creating copies or combining arrays.
// Destructuring
const person = { fName: 'Jane', lName: 'Doe' };
const { fName, lName } = person;
console.log(`${fName} ${lName}`); // "Jane Doe"
// Spread Operator
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5];
console.log(arr2); // [1, 2, 3, 4, 5]
Explanation: No code is perfect, and finding and fixing errors (**debugging**) is a critical skill. The two most common tools are console.log(), which you can use to print the value of variables at different points in your code, and the debugger statement. When the browser's developer tools are open, the debugger statement will pause the execution of your code, allowing you to inspect variables and step through the code line by line.
function calculateTotal(price, quantity) {
console.log(`Calculating for price: ${price}`); // 1. Log variables
debugger; // 2. Pause execution here if dev tools are open
let total = price * quantity;
return total;
}
calculateTotal(10, 5);
Explanation: This shows the complete HTML structure for a user feedback form. Key elements include the <form> tag which acts as a container, <label> for accessible descriptions, and various <input> types (like text and email) for data entry. The name attribute on each input is crucial, as it becomes the key for the data when it's submitted to a server.
<form action="#" method="post">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="customer_name" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="customer_email" required>
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea id="message" name="customer_message" rows="5" required></textarea>
</div>
<button type="submit">Submit Feedback</button>
</form>
Explanation: The method attribute on a form tells the browser how to send the data to the server specified in the action attribute. There are two main methods:
<!-- Data is sent in the URL: /process?customer_name=John... -->
<form action="/process" method="get">
<!-- ... form inputs ... -->
<button type="submit">Submit with GET</button>
</form>
POST Example:
<!-- Data is sent securely in the request body -->
<form action="/process" method="post">
<!-- ... form inputs ... -->
<button type="submit">Submit with POST</button>
</form>