Refresher Reminder

🌐

JavaScript in the Browser

Everything specific to running JS inside web pages

đŸĒŸ Window 📄 Document đŸŒŗ DOM APIs đŸ“Ļ Script Loading đŸŽ¯ Events 📡 AJAX
📚 General JavaScript refresher content lives in Refresher and stays exactly the same.
🚀

Want to practice? Try our Web Playground!

Write HTML, CSS & JavaScript with live preview. No signup required – start coding instantly!

Launch Playground

The window Global

Each browser tab has a top-level global object: window. It exposes:

đŸĒŸ Window Object Properties

🌍 Environment
location navigator history screen
âąī¸ Timing
setTimeout setInterval requestAnimationFrame
📄 DOM Root
document
đŸ’Ŧ Dialogs / Console
alert prompt confirm console
💡 Tip: You can omit window. for global functions: alert("Hi") equals window.alert("Hi")
console.log("Current URL:", window.location.href);
console.log("User Agent:", window.navigator.userAgent);
console.log("Screen size:", window.screen.width, "x", window.screen.height);

// Timing example
window.setTimeout(() => console.log("Timer fired after 500ms"), 500);

// Another way (window. is optional)
setTimeout(() => console.log("Same timer syntax"), 600);

The document Object

document represents the loaded HTML page. Key properties:

📄 Document Quick Reference

📍 Element Shortcuts
document.documentElement → <html> element
document.head → <head> element
document.body → <body> element
â„šī¸ Info Properties
document.title (read/write)
document.URL
document.referrer
🔄 Ready State
document.readyState
loading interactive complete
// Change the page title (watch the browser title bar!)
document.title = "My Custom Title!";
console.log("Title set to:", document.title);

// Create visible content
document.body.innerHTML = `
  <h1>Hello from JavaScript!</h1>
  <p>This content was created dynamically.</p>
  <div class="demo-box">
    <strong>Document Info:</strong>
    <ul>
      <li>Ready State: ${document.readyState}</li>
      <li>Character Set: ${document.characterSet}</li>
      <li>Content Type: ${document.contentType}</li>
    </ul>
  </div>
`;

console.log("Page content updated!");
console.log("Ready state:", document.readyState);

💡 Tip: Watch the browser preview panel — the title bar will update when you change document.title!

The DOM Tree

The DOM (Document Object Model) is a tree of nodes.

đŸŒŗ DOM Tree Structure

đŸ“Ļ Element nodes 📝 Text nodes đŸ’Ŧ Comment nodes 📎 Attribute nodes

DOM Inheritance Hierarchy

Accurate core DOM type relationships (simplified). Hollow triangle points to the parent.

  • â–ŧ Node
    • 📄 Document
    • 📄 DocumentType
    • 📄 DocumentFragment
    • â–ŧ Element
      • â–ŧ HTMLElement
        • 📄 HTMLDivElement
        • 📄 HTMLButtonElement
        • 📄 HTMLInputElement
        • 📄 HTMLSpanElement
        • ⋯ and many more
      • â–ļ SVGElement
        • 📄 SVGCircleElement
        • 📄 SVGPathElement
        • ⋯ more
    • â–ŧ CharacterData
      • 📄 Text
      • 📄 Comment
      • 📄 CDATASection
    • 📄 ProcessingInstruction
📎 Attr Not a Node (since DOM4)

Selecting Nodes & Elements

đŸŽ¯ Selection Methods

document.getElementById(id) Single element by ID ⚡ Fastest
document.querySelector(css) First match (any CSS selector) 🎨 Flexible
document.querySelectorAll(css) All matches → static NodeList 📋 Static
getElementsByClassName(name) By class → live HTMLCollection 🔄 Live
getElementsByTagName(tag) By tag → live HTMLCollection 🔄 Live
📋 Static NodeList
Snapshot at query time. DOM changes don't affect it.
🔄 Live HTMLCollection
Auto-updates when DOM changes. Can cause issues in loops!
🚀 Direct access: document.body, document.head, document.documentElement
// First, create some demo HTML
document.body.innerHTML = `
  <div id="demo-main" class="demo-box">
    <h2>Main Container</h2>
    <button class="demo-btn primary">Primary Button</button>
    <button class="demo-btn">Secondary</button>
    <p class="demo-text">Some text here</p>
  </div>
`;

// Get element by ID
const main = document.querySelector("#demo-main");
console.log("Found element:", main.tagName);

// Get all buttons
const buttons = document.querySelectorAll(".demo-btn");
console.log("Number of buttons:", buttons.length);

// Loop through buttons
buttons.forEach((btn, i) => {
  console.log("Button " + i + ":", btn.textContent);
  btn.setAttribute("style", "border: 3px solid lime;");
});

// Get first primary button
const primary = document.querySelector(".demo-btn.primary");
if (primary) {
  primary.setAttribute("style", "background: #4CAF50; color: white;");
  console.log("Primary button highlighted!");
}

Content & Attribute Manipulation

📝 Text/Content APIs Comparison

textContent ✅ Safe ⚡ Fast
Raw text only. No layout cost. HTML is escaped as text.
innerText âš ī¸ Reflow
Respects CSS visibility. Triggers layout/reflow reads.
innerHTML âš ī¸ XSS Risk
Parses HTML. Never use with untrusted input!
🔒 Security: Sanitize external HTML (e.g. DOMPurify) or build nodes manually.

📎 Dataset API (data-* attributes)

HTML Attribute
data-user-id="123"
→
JavaScript Access
element.dataset.userId
DELETE
delete el.dataset.key
âš ī¸ Important: Use dataset, not data: el.dataset.ok ✅ vs el.data.ok ❌
// Create demo elements
document.body.innerHTML = `
  <div id="panel" class="demo-box">
    <p>Original content</p>
  </div>
  <input type="text" id="email" placeholder="Enter email">
`;

const panel = document.querySelector("#panel");

// textContent - treats HTML as literal text
panel.textContent = "<span>This shows as TEXT</span>";
console.log("1. textContent set (HTML escaped)");

// After 1s, use innerHTML
setTimeout(() => {
  panel.innerHTML = "<strong style='color:#4CAF50'>Bold HTML!</strong>";
  console.log("2. innerHTML set (renders HTML)");
}, 1000);

// Work with input attributes
const input = document.querySelector("#email");
input.value = "user@example.com";
input.setAttribute("placeholder", "Email updated!");
console.log("Input value:", input.value);

// === Dataset API Examples ===
// CORRECT: use element.dataset (not element.data!)
panel.dataset.state = "active";       // creates data-state="active"
panel.dataset.userId = "12345";       // creates data-user-id="12345"  
panel.dataset.ok = "works!";          // creates data-ok="works!"
panel.dataset.myCustomValue = "abc";  // creates data-my-custom-value="abc"

console.log("dataset.state:", panel.dataset.state);
console.log("dataset.userId:", panel.dataset.userId);
console.log("dataset.ok:", panel.dataset.ok);

// Read via getAttribute too
console.log("getAttribute:", panel.getAttribute("data-ok"));

// Delete a data attribute
delete panel.dataset.ok;
console.log("After delete, ok:", panel.dataset.ok); // undefined

Creating & Inserting Elements

đŸ› ī¸ Creating & Inserting Methods

📍 insertAdjacentHTML positions:
"beforebegin" → before element
<div>
"afterbegin" → first child
...content...
"beforeend" → last child
</div>
"afterend" → after element

🚀 DocumentFragment - Batch Insertions

Every DOM modification triggers a reflow/repaint (expensive!)

❌ Without Fragment
Adding 100 items = 100 reflows!
for (let i = 0; i < 100; i++) {
  parent.appendChild(item);
}
✅ With Fragment
Adding 100 items = 1 reflow!
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  frag.appendChild(item);
}
parent.appendChild(frag); // ONE reflow!
💾 Lives in memory only đŸ‘ģ Fragment disappears after insert 📊 Perfect for lists & tables

🎮 Interactive Playground - Try It!

Choose Method:
Generated Code:
const newEl = document.createElement('div');
newEl.textContent = "New Item ⭐";
container.prepend(newEl);
Live Preview:
âŦ†ī¸ beforebegin zone (outside)
đŸ“Ļ CONTAINER (target element)
afterbegin / prepend
đŸ“Ļ Item 1 (original)
đŸ“Ļ Item 2 (original)
đŸ“Ļ Item 3 (original)
beforeend / append
âŦ‡ī¸ afterend zone (outside)
đŸ”ĩ Original items ✨ New items

📝 Quick Examples

// 1. Create element
const div = document.createElement("div");
div.textContent = "Hello!";
div.className = "my-class";

// 2. Insert methods
const container = document.body;

container.prepend(div);              // First child
container.append(div);               // Last child
container.appendChild(div);          // Same as append

// 3. insertAdjacentHTML positions
container.insertAdjacentHTML("beforebegin", "<p>Before</p>");
container.insertAdjacentHTML("afterbegin", "<p>First inside</p>");
container.insertAdjacentHTML("beforeend", "<p>Last inside</p>");
container.insertAdjacentHTML("afterend", "<p>After</p>");

// 4. DocumentFragment for batch inserts
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const item = document.createElement("div");
  item.textContent = "Item " + i;
  fragment.appendChild(item);  // No reflow yet!
}
container.appendChild(fragment);  // ONE reflow!

console.log("Elements created and inserted!");

Traversal & Relationships

🧭 DOM Navigation Properties

PARENT
↓ children
firstElementChild
Child 1
↑ prev │ next ↓
children[1]
Child 2
↑ prev │ next ↓
lastElementChild
Child 3
↑ parentNode
Element Properties
Returns only element nodes (tags)
Node Properties
Includes text, comments, etc.
// Create article container
document.body.innerHTML = `
  <div id="articles">
    <article class="demo-box">Article 1</article>
    <article class="demo-box">Article 2</article>
    <article class="demo-box">Article 3</article>
  </div>
`;

const container = document.querySelector("#articles");

// Children info
console.log("Element children:", container.children.length);
console.log("All child nodes:", container.childNodes.length);

// First and last element child
const first = container.firstElementChild;
const last = container.lastElementChild;
first.setAttribute("style", "background: #4CAF50; color: white; padding: 10px;");
console.log("First child:", first.textContent);

last.setAttribute("style", "background: #2196F3; color: white; padding: 10px;");
console.log("Last child:", last.textContent);

// Sibling navigation
const second = first.nextElementSibling;
second.setAttribute("style", "background: #FF9800; color: white; padding: 10px;");
console.log("Second (via nextElementSibling):", second.textContent);

// Parent access
console.log("Parent tag:", second.parentNode.tagName);
console.log("Parent id:", second.parentNode.id);

Script Loading Strategies

Ways to include JavaScript:

đŸŽŦ Choose a Loading Strategy:

<script src="app.js"></script>
Timeline Visualization
HTML
Script
Events
DCL
load
📍 When do browser events fire?
DOMContentLoaded
HTML fully parsed, DOM ready
window.load
Everything loaded (images, etc.)
âąī¸ With blocking: DOMContentLoaded waits for script to finish
HTML Parsing Blocked Download Execute
🛑 Blocking Script (Default)

How it works: HTML parsing stops, script downloads and executes, then parsing resumes.

🛑
Blocking Behavior
❌ Blocks page rendering
❌ Slows down page load
✅ Scripts execute in order
âš ī¸ Use only when script must run before DOM
Best for: Critical scripts that must modify the page before it renders (rare).

Events: How JavaScript Listens to the Browser

Events are signals the browser sends when something happens — a click, key press, page load, etc. Your code can "listen" and respond.

đŸŽ¯ What is an Event?

An event is the browser saying: "Hey, something just happened!" — a click, a keypress, the page loading, etc.

👆
User Action
→
📡
Browser fires Event
→
⚡
Your Code Runs

📝 How to Listen for Events

❌ Inline (Don't Do This)
<button onclick="alert('Hi')">Click</button>
  • Mixes HTML with JavaScript
  • Only ONE handler per event
  • Hard to debug & maintain
✅ addEventListener (Use This!)
element.addEventListener("click", myFunction)
  • Clean separation of HTML/JS
  • Add multiple handlers
  • Can remove listeners later
🔴 Live Demo - Try It!
Type your name above...
Console Output:
// 1. Get references to elements
const likeBtn = document.getElementById('like-btn');
const countBtn = document.getElementById('count-btn');
const nameInput = document.getElementById('name-input');

// 2. Like Button - Toggle on click
let isLiked = false;
likeBtn.addEventListener('click', () => {
  isLiked = !isLiked;
  likeBtn.textContent = isLiked ? 'â¤ī¸ Liked!' : '🤍 Like';
});

// 3. Count Button - Increment on click
let count = 0;
countBtn.addEventListener('click', () => {
  count++;
  countBtn.textContent = `Clicked: ${count}`;
});

// 4. Input - Real-time typing with 'input' event
nameInput.addEventListener('input', (e) => {
  console.log('User typed:', e.target.value);
});

// 5. Focus & Blur events
nameInput.addEventListener('focus', () => console.log('Input focused!'));
nameInput.addEventListener('blur', () => console.log('Input lost focus'));
💡 Key Syntax: element.addEventListener("eventType", callbackFunction)

AJAX with XMLHttpRequest (XHR)

XHR predates fetch; still useful for progress events & legacy code. Prefer async; synchronous XHR blocks the UI thread.

📡 XHR Lifecycle - 5 Steps

STEP 1
Create
new XMLHttpRequest()
→
STEP 2
Configure
xhr.open(method, url)
→
STEP 3
Set Options
xhr.responseType
→
STEP 4
Add Listeners
xhr.addEventListener()
→
STEP 5
Send
xhr.send()
đŸŽ¯ XHR Events
load - Success error - Network fail progress - Downloading loadend - Finished timeout - Too slow abort - Cancelled
📋 Setting Request Headers

Use setRequestHeader(name, value) after open() but before send()

📤 Sending Data with send()
📭 No Data (GET requests)
xhr.send();
xhr.send(null);
đŸ“Ļ JSON Data (POST/PUT)
const data = { name: "John", age: 25 };
xhr.send(JSON.stringify(data));
📝 FormData (File uploads)
const formData = new FormData();
formData.append("file", fileInput.files[0]);
xhr.send(formData);
🔗 URL Encoded
xhr.send("name=John&age=25");
✅ Async (Recommended)
xhr.open("GET", url, true);
  • Non-blocking
  • UI stays responsive
  • Uses event listeners
⛔ Sync (Avoid!)
xhr.open("GET", url, false);
  • Blocks browser
  • UI freezes
  • Deprecated in main thread

📝 Full Async Example

// STEP 1: Create XHR object
const xhr = new XMLHttpRequest();

// STEP 2: Configure request - open(method, url, async)
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", true);

// STEP 3: Set response type
xhr.responseType = "json";

// STEP 4: Add event listeners
xhr.addEventListener("load", () => {
  if (xhr.status === 200) {
    console.log("✅ Success:", xhr.response.title);
  } else {
    console.log("❌ Error:", xhr.status);
  }
});

xhr.addEventListener("error", () => console.log("❌ Network error!"));

// STEP 5: Send the request
xhr.send();

âš ī¸ Sync Example (Not Recommended)

// âš ī¸ SYNCHRONOUS - Browser freezes until complete!
const xhr = new XMLHttpRequest();

// async = FALSE makes it synchronous (blocking)
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", false);

// Code WAITS here - no event listeners needed
xhr.send();

// Runs only after response arrives
if (xhr.status === 200) {
  const data = JSON.parse(xhr.responseText);
  console.log("đŸ“Ļ Title:", data.title);
}
// ❌ UI was frozen the entire time!
console.log("💡 Always use async (true) instead!");
Migration tip: Modern code usually uses fetch() + Promises instead of XHR for simpler APIs.

From Callback Hell to Modern Fetch

Sum of 10 numbers: — = — ⏱ —
👆 Click a button to compare approaches...
đŸšĢ Never Use Deprecated — blocks the entire browser!
âš ī¸
XHR Sync blocks the entire UI! The browser freezes completely — user cannot scroll, click, or interact with anything until the request completes. This is deprecated and should never be used in production!
// đŸšĢ XHR SYNCHRONOUS: NEVER USE THIS!
// The third parameter "false" makes it synchronous
// 📚 Note: We write 10 explicit calls for clarity
// Using DummyJSON API - fetching product prices as random numbers

const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;

const xhr1 = new XMLHttpRequest();
xhr1.open("GET", getAPI(), false); xhr1.send();
const n1 = Math.round(JSON.parse(xhr1.responseText).price);

const xhr2 = new XMLHttpRequest();
xhr2.open("GET", getAPI(), false); xhr2.send();
const n2 = Math.round(JSON.parse(xhr2.responseText).price);

const xhr3 = new XMLHttpRequest();
xhr3.open("GET", getAPI(), false); xhr3.send();
const n3 = Math.round(JSON.parse(xhr3.responseText).price);

// ... (n4 through n9 same pattern) ...

const xhr10 = new XMLHttpRequest();
xhr10.open("GET", getAPI(), false); xhr10.send();
const n10 = Math.round(JSON.parse(xhr10.responseText).price);

const sum = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10;
console.log("Sum:", sum);

// đŸšĢ UI was frozen the whole time!
🔗
Sequential When each request depends on the previous
⚡
Promise.all When requests are independent (fastest!)
đŸ›Ąī¸
Promise.allSettled When you want results even if some fail
🏃
Promise.race When you need only the fastest response
📝

Ready to Practice?

Test your knowledge with practice exercises and prepare for your exam.

Go to Exercises →
? Raccourcis

âŒ¨ī¸ Keyboard Shortcuts

Next section J
Previous section K
Change language L
Toggle theme T
Scroll to top Home
Close modal Esc