GuideJavaScript

.4 URL And History APIs

Module 18 Browser APIs And Storage / .4 URL And History APIs

Concept Lesson
Advanced
4 min

Learning Objective

Understand .4 URL And History APIs well enough to explain it, recognize it in JavaScript, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

AndApisUrl ConstructorUrlsearchparams ExamplesHistory API
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

Guide
1 min read18 headings

11.4 URL and History APIs

Overview

The URL API provides utilities for parsing, constructing, and manipulating URLs. The History API allows manipulation of the browser session history, enabling Single-Page Application (SPA) navigation.

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                          URL Anatomy                             │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   https://user:pass@api.example.com:8080/path/to/page?q=1#sec   │
│   ā”œā”€ā”€ā”€ā”¤  ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ ā”œā”€ā”€ā”¤ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤ā”œā”€ā”€ā”¤ā”œā”€ā”€ā”¤   │
│   protocol username        host    port   pathname  search hash  │
│              password                                            │
│                                                                  │
│   ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”   │
│   │ url.protocol  →  'https:'                                │   │
│   │ url.username  →  'user'                                  │   │
│   │ url.password  →  'pass'                                  │   │
│   │ url.hostname  →  'api.example.com'                       │   │
│   │ url.host      →  'api.example.com:8080'                  │   │
│   │ url.port      →  '8080'                                  │   │
│   │ url.pathname  →  '/path/to/page'                         │   │
│   │ url.search    →  '?q=1'                                  │   │
│   │ url.hash      →  '#sec'                                  │   │
│   │ url.origin    →  'https://api.example.com:8080'          │   │
│   │ url.href      →  (full URL)                              │   │
│   ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜   │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

URL Constructor

// Create from full URL
const url = new URL('https://example.com/path?query=value');

// Create with base URL
const url2 = new URL('/api/users', 'https://example.com');
// Result: https://example.com/api/users

// Modify URL parts
url.pathname = '/new-path';
url.hash = '#section';
console.log(url.href);

URLSearchParams

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                     URLSearchParams Methods                       │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   Creating:                                                      │
│   ─────────                                                      │
│   new URLSearchParams()              // Empty                    │
│   new URLSearchParams('?a=1&b=2')    // From string              │
│   new URLSearchParams({ a: '1' })    // From object              │
│   new URLSearchParams([['a','1']])   // From entries             │
│                                                                  │
│   Methods:                                                       │
│   ────────                                                       │
│   .get(name)          │ Get first value                         │
│   .getAll(name)       │ Get all values as array                 │
│   .has(name)          │ Check if param exists                   │
│   .set(name, value)   │ Set value (replaces all)                │
│   .append(name, value)│ Add value (allows duplicates)           │
│   .delete(name)       │ Remove all with name                    │
│   .toString()         │ Serialize to string                     │
│                                                                  │
│   Iteration:                                                     │
│   ──────────                                                     │
│   .keys()             │ Iterator of names                       │
│   .values()           │ Iterator of values                      │
│   .entries()          │ Iterator of [name, value]               │
│   .forEach(fn)        │ Iterate all entries                     │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

URLSearchParams Examples

// Parse current URL query params
const params = new URLSearchParams(window.location.search);

// Get values
const page = params.get('page'); // '1' or null
const tags = params.getAll('tag'); // ['js', 'web']

// Modify
params.set('page', '2');
params.append('sort', 'date');
params.delete('old');

// Build URL
const url = new URL('https://api.example.com/search');
url.search = params.toString();

History API

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                      History API Overview                         │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   Browser History Stack:                                         │
│   ──────────────────────                                        │
│   ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”                 │
│   │ Page 1  →  Page 2  →  Page 3  →  Page 4   │  ← Current      │
│   ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜                 │
│                                ↑                                 │
│                           history.back()                         │
│                         history.forward()                        │
│                            history.go(n)                         │
│                                                                  │
│   Properties:                                                    │
│   ───────────                                                   │
│   history.length       │ Number of entries in history           │
│   history.state        │ State object for current entry         │
│   history.scrollRestoration │ 'auto' or 'manual'                │
│                                                                  │
│   Methods:                                                       │
│   ────────                                                      │
│   history.back()       │ Go back one page                       │
│   history.forward()    │ Go forward one page                    │
│   history.go(n)        │ Go n pages (+ forward, - back)         │
│   history.pushState()  │ Add new entry                          │
│   history.replaceState()│ Replace current entry                 │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

pushState vs replaceState

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                  pushState vs replaceState                        │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   pushState(state, title, url)                                   │
│   ────────────────────────────                                  │
│   • Adds NEW entry to history stack                              │
│   • Back button returns to previous page                         │
│   • history.length increases                                     │
│                                                                  │
│   Before: [Page1, Page2, Page3*]                                 │
│   After:  [Page1, Page2, Page3, NewPage*]                        │
│                                                                  │
│   replaceState(state, title, url)                                │
│   ───────────────────────────────                               │
│   • REPLACES current entry in history                            │
│   • Back button skips replaced page                              │
│   • history.length stays same                                    │
│                                                                  │
│   Before: [Page1, Page2, Page3*]                                 │
│   After:  [Page1, Page2, NewPage*]                               │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

State Object

// pushState(stateObject, title, url)
history.pushState(
  { page: 'products', id: 123 }, // State data (serializable)
  '', // Title (most browsers ignore)
  '/products/123' // New URL (same origin only)
);

// Access state later
console.log(history.state); // { page: 'products', id: 123 }

// replaceState works the same
history.replaceState({ updated: true }, '', '/products/123/edit');

popstate Event

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                      popstate Event                               │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   Fired when:                                                    │
│   • User clicks back/forward buttons                             │
│   • history.back(), forward(), go() called                       │
│                                                                  │
│   NOT fired when:                                                │
│   • pushState() or replaceState() called                         │
│                                                                  │
│   window.addEventListener('popstate', (event) => {               │
│       console.log('State:', event.state);                        │
│       console.log('URL:', location.href);                        │
│                                                                  │
│       // Handle navigation                                       │
│       if (event.state?.page === 'products') {                    │
│           showProductPage(event.state.id);                       │
│       }                                                          │
│   });                                                            │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Location Object

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                     window.location                               │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   Properties (read/write):                                       │
│   ────────────────────────                                      │
│   location.href       │ Full URL (setting navigates)            │
│   location.protocol   │ 'http:' or 'https:'                     │
│   location.host       │ hostname:port                           │
│   location.hostname   │ Domain name                             │
│   location.port       │ Port number                             │
│   location.pathname   │ Path after domain                       │
│   location.search     │ Query string with ?                     │
│   location.hash       │ Fragment with #                         │
│                                                                  │
│   Methods:                                                       │
│   ────────                                                      │
│   location.assign(url)  │ Navigate (adds to history)            │
│   location.replace(url) │ Navigate (replaces history)           │
│   location.reload()     │ Reload current page                   │
│   location.toString()   │ Returns href                          │
│                                                                  │
│   Navigation Examples:                                           │
│   ────────────────────                                          │
│   location.href = '/new-page';        // Navigate                │
│   location = '/new-page';             // Same as above           │
│   location.hash = '#section';         // Change hash only        │
│   location.search = '?page=2';        // Change query            │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Common URL Patterns

Building Query Strings

function buildQueryString(params) {
  const searchParams = new URLSearchParams();

  Object.entries(params).forEach(([key, value]) => {
    if (value === undefined || value === null) return;

    if (Array.isArray(value)) {
      value.forEach((v) => searchParams.append(key, v));
    } else {
      searchParams.set(key, value);
    }
  });

  return searchParams.toString();
}

// Usage
const query = buildQueryString({
  search: 'hello world',
  tags: ['js', 'web'],
  page: 1,
});
// Result: search=hello+world&tags=js&tags=web&page=1

Parsing URLs

function parseURL(urlString) {
  const url = new URL(urlString);
  const params = Object.fromEntries(url.searchParams);

  return {
    protocol: url.protocol,
    host: url.host,
    pathname: url.pathname,
    params,
    hash: url.hash.slice(1),
  };
}

SPA Routing Pattern

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                    SPA Router Pattern                             │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   1. Define Routes                                               │
│   ────────────────                                              │
│   const routes = {                                               │
│       '/': HomePage,                                             │
│       '/products': ProductsPage,                                 │
│       '/products/:id': ProductDetailPage                         │
│   };                                                             │
│                                                                  │
│   2. Handle Navigation                                           │
│   ────────────────────                                          │
│   function navigate(path, state = {}) {                          │
│       history.pushState(state, '', path);                        │
│       renderCurrentRoute();                                      │
│   }                                                              │
│                                                                  │
│   3. Listen for Back/Forward                                     │
│   ──────────────────────────                                    │
│   window.addEventListener('popstate', () => {                    │
│       renderCurrentRoute();                                      │
│   });                                                            │
│                                                                  │
│   4. Match and Render                                            │
│   ───────────────────                                           │
│   function renderCurrentRoute() {                                │
│       const path = location.pathname;                            │
│       const Component = matchRoute(path);                        │
│       Component.render();                                        │
│   }                                                              │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

URL Encoding

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                     URL Encoding Methods                          │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   encodeURI(str)                                                 │
│   ──────────────                                                │
│   • Encodes full URI                                             │
│   • Preserves: : / ? # [ ] @ ! $ & ' ( ) * + , ; =              │
│   • Use for: Complete URLs                                       │
│                                                                  │
│   encodeURIComponent(str)                                        │
│   ───────────────────────                                       │
│   • Encodes URI component                                        │
│   • Encodes everything except: A-Z a-z 0-9 - _ . ! ~ * ' ( )    │
│   • Use for: Query parameters, path segments                     │
│                                                                  │
│   Examples:                                                      │
│   ─────────                                                     │
│   encodeURI('https://example.com/path?name=John Doe')           │
│   → 'https://example.com/path?name=John%20Doe'                  │
│                                                                  │
│   encodeURIComponent('name=John&age=30')                         │
│   → 'name%3DJohn%26age%3D30'                                     │
│                                                                  │
│   // Building URL safely                                         │
│   const param = encodeURIComponent(userInput);                   │
│   const url = `https://api.com/search?q=${param}`;               │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

hashchange Event

// Listen for hash changes
window.addEventListener('hashchange', (event) => {
  console.log('Old URL:', event.oldURL);
  console.log('New URL:', event.newURL);
  console.log('New hash:', location.hash);

  // Handle hash-based navigation
  handleHashRoute(location.hash);
});

// Change hash (triggers event)
location.hash = '#/products';

// Read hash
const hash = location.hash.slice(1); // Remove # prefix

Best Practices

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                      Best Practices                               │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                                  │
│   URL Construction:                                              │
│   ─────────────────                                             │
│   āœ“ Use URL constructor for parsing                              │
│   āœ“ Use URLSearchParams for query strings                        │
│   āœ“ Always encode user input with encodeURIComponent             │
│   āœ“ Validate URLs before using                                   │
│                                                                  │
│   History API:                                                   │
│   ────────────                                                  │
│   āœ“ Keep state objects small and serializable                    │
│   āœ“ Always handle popstate for SPAs                              │
│   āœ“ Use replaceState for redirects                               │
│   āœ“ Consider scroll position management                          │
│                                                                  │
│   Security:                                                      │
│   ─────────                                                     │
│   āœ“ Validate URLs before navigation                              │
│   āœ“ Avoid using user input in location.href directly             │
│   āœ“ Check origin before processing postMessage                   │
│                                                                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Browser Compatibility

FeatureChromeFirefoxSafariEdge
URL32+26+7+12+
URLSearchParams49+44+10.1+17+
history.pushState5+4+5+12+
popstate event5+4+5+12+

Key Takeaways

  1. URL API - Parse and construct URLs safely
  2. URLSearchParams - Easy query string manipulation
  3. pushState - Add to history without reload
  4. replaceState - Modify current history entry
  5. popstate - Handle back/forward navigation
  6. location - Navigate and read current URL
  7. Always encode - Use encodeURIComponent for user input

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue