Location API and URL parsing
window.location represents the current page's URL, broken into useful pieces. Pair it with the modern URL and URLSearchParams classes and you have a complete toolkit for parsing and building URLs without ever reaching for a regex or string-splitting hack.
Anatomy of window.location
// Suppose location.href === "https://shop.example.com:8443/cart?id=42&qty=2#summary" location.href; // the whole URL string location.protocol; // "https:" location.host; // "shop.example.com:8443" location.hostname; // "shop.example.com" location.port; // "8443" location.pathname; // "/cart" location.search; // "?id=42&qty=2" location.hash; // "#summary" location.origin; // "https://shop.example.com:8443"
origin is the security boundary: protocol + host + port. Same-origin policy, CORS, cookies and storage are all scoped by it.
Navigating
location.href = "/login"; // full navigation (adds a history entry)
location.assign("/login"); // identical to above
location.replace("/login"); // navigate WITHOUT adding a history entry
location.reload(); // refresh the current pageassign— like clicking a link; back button returns here.replace— like a server-side redirect; back button skips this page.reload()— full page reload, hits the network unless the response is cacheable.
The URL class — parse without pain
const url = new URL("https://shop.example.com/cart?id=42&qty=2#summary");
url.pathname; // "/cart"
url.searchParams.get("id"); // "42"
url.searchParams.get("qty"); // "2"
url.hash; // "#summary"
// Build incrementally:
url.searchParams.set("qty", 3);
url.searchParams.delete("id");
url.toString();
// "https://shop.example.com/cart?qty=3#summary"/cart 42 2 https://shop.example.com/cart?qty=3#summary
Relative URLs and the second argument
The URL constructor takes an optional base. This is how you safely resolve relative paths against any URL — including location.href.
new URL("/about", "https://example.com/blog/").href;
// "https://example.com/about"
new URL("../images/x.png", "https://example.com/blog/post/").href;
// "https://example.com/blog/images/x.png"
// Most common in practice:
const next = new URL("/dashboard", location.href);URLSearchParams — read and write query strings
const params = new URLSearchParams(location.search);
params.get("q"); // "shoes"
params.has("page"); // true
params.getAll("tag"); // ["new", "sale"] — multi-value
for (const [key, value] of params) {
console.log(key, value);
}
// Mutate then write back to the URL bar without reloading:
params.set("page", 2);
params.delete("debug");
history.replaceState(null, "", `?${params}`);Building a URL from scratch
Construct a search URL
function searchUrl(query, page) {
const url = new URL("/search", location.origin);
url.searchParams.set("q", query);
if (page > 1) url.searchParams.set("page", page);
return url.toString();
}
searchUrl("hello world", 2);
// "https://example.com/search?q=hello+world&page=2"Validating and normalising user input
function safeUrl(input) {
try {
const u = new URL(input, location.origin);
return u.protocol === "https:" || u.protocol === "http:" ? u : null;
} catch {
return null;
}
}
safeUrl("javascript:alert(1)"); // null — safe
safeUrl("relative/path"); // resolved against the current origin
safeUrl("https://other.example/x"); // URL objectComparing URLs
// Same-origin check:
const target = new URL(linkHref, location.origin);
if (target.origin !== location.origin) {
// external link
}
// Comparison should always use parsed parts, not raw strings.
// "/path" and "/path/" are different URLs to most servers.Reading the hash safely
location.hash includes the leading #. Strip it before use, and remember that hash routing libraries store route info there.
const route = location.hash.slice(1) || "/";
addEventListener("hashchange", () => console.log("hash is now", location.hash));Cheat-sheet
Parse:
new URL(str)ornew URL(str, base). Wrap in try/catch.Query string:
URLSearchParams. Use.set/.get/.has/.getAll/.delete.Navigate:
location.assign(with history) orlocation.replace(without).Update the URL without reloading:
history.pushState/history.replaceState.Compare origins as
url.origin, never as substring matches onhref.