Skip to main content

URL 参数解析与序列化

解析 query 参数(parse)

要点:处理 decodeURIComponent、无值参数(?a)、同名参数转数组。

function parseQuery(url) {
const query = {};
const index = url.indexOf("?");
if (index === -1) return query;

const search = url.slice(index + 1).split("#")[0]; // 去掉 hash
if (!search) return query;

search.split("&").forEach((pair) => {
if (!pair) return;
let [key, value = ""] = pair.split("=");
key = decodeURIComponent(key);
value = decodeURIComponent(value);

if (key in query) {
// 同名参数收集成数组
query[key] = [].concat(query[key], value);
} else {
query[key] = value;
}
});

return query;
}

parseQuery("https://x.com/path?a=1&b=2&a=3&c");
// { a: ["1", "3"], b: "2", c: "" }

序列化(stringify)

function stringifyQuery(obj) {
return Object.entries(obj)
.filter(([, value]) => value !== undefined && value !== null)
.flatMap(([key, value]) =>
// 数组值展开成多个同名参数
[].concat(value).map(
(v) => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`
)
)
.join("&");
}

stringifyQuery({ a: ["1", "3"], b: "2" }); // "a=1&a=3&b=2"

原生 API

工程里优先用原生,但面试要会手写:

const url = new URL("https://x.com/p?a=1&b=2");
url.searchParams.get("a"); // "1"
url.searchParams.getAll("a"); // ["1"]

const sp = new URLSearchParams({ a: 1, b: 2 });
sp.toString(); // "a=1&b=2"