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"