解析URL查询参数
问题描述
实现一个函数 parseQueryString(url)
,接收一个URL字符串,解析并返回其查询参数(query string)部分的对象。需要处理多种边界情况。
输入示例 :
'https://www.example.com/page?name=John&age=30&hobbies=reading&hobbies=traveling'
期望输出:
arduino
{
name: 'John',
age: '30', // 注意:值是字符串,如果需要数字需额外转换
hobbies: ['reading', 'traveling'] // 相同键的值应合并为数组
}
前端意义:这是前端开发中最常遇到的实际问题之一,用于路由参数解析、API请求参数处理等,直接体现了处理字符串和数据结构的能力。
解题思路
- 提取查询字符串 :使用
URL
API 或字符串分割来获取?
之后的部分。 - 分割键值对 :用
&
符号将查询字符串分割成独立的键值对数组。 - 解析每个键值对 :用
=
符号分割每个键值对。注意处理没有值的参数(如&key
)和空值(如&key=
)。 - 处理重复键:使用一个对象来存储结果。如果遇到重复的键,则将值转换为数组,或将新值推入现有数组。
- URL解码 :使用
decodeURIComponent
对键和值进行解码,将%20
等转换回原始字符。
代码实现
ini
function parseQueryString(url) {
// 1. 使用 URL 构造函数优雅地获取查询字符串部分
// 它自动处理了基础URL、哈希片段等复杂情况
const urlObj = new URL(url);
const searchParams = urlObj.searchParams;
const result = {};
// 2. 使用迭代器遍历 URLSearchParams 对象
// 这是现代浏览器推荐的标准API,比自己 split 更可靠
for (const [key, value] of searchParams) {
// 如果结果对象中已经存在这个键
if (result.hasOwnProperty(key)) {
// 如果当前的值已经是数组,直接 push
if (Array.isArray(result[key])) {
result[key].push(value);
} else {
// 如果不是数组,说明是第二个重复值,创建新数组
result[key] = [result[key], value];
}
} else {
// 如果是第一次遇到这个键,直接赋值
result[key] = value;
}
}
return result;
}
// 如果不允许使用 URLSearchParams,可以使用以下"手写"版本:
function parseQueryStringFallback(url) {
// 1. 手动提取查询字符串
const queryStringStart = url.indexOf('?');
if (queryStringStart === -1) return {}; // 没有查询参数
const queryString = url.slice(queryStringStart + 1);
// 可能还存在哈希片段,需要去除
const hashIndex = queryString.indexOf('#');
const cleanQueryString = hashIndex === -1 ? queryString : queryString.slice(0, hashIndex);
const pairs = cleanQueryString.split('&');
const result = {};
for (const pair of pairs) {
// 跳过空对 (如 "&&")
if (!pair) continue;
let [key, value] = pair.split('=');
// 处理没有等号的参数(如 "key"),将其值设为空字符串
value = value === undefined ? '' : value;
// URL解码非常重要!
key = decodeURIComponent(key);
value = decodeURIComponent(value);
// 处理重复键的逻辑与上面相同
if (result.hasOwnProperty(key)) {
if (Array.isArray(result[key])) {
result[key].push(value);
} else {
result[key] = [result[key], value];
}
} else {
result[key] = value;
}
}
return result;
}
// 示例用法
// const testURL = 'https://www.example.com?name=John&age=30&hobbies=read&hobbies=code';
// console.log(parseQueryString(testURL));
// 输出: { name: "John", age: "30", hobbies: ["read", "code"] }
考察点
- API熟悉度 :是否知道
URL
和URLSearchParams
这两个现代Web API。 - 鲁棒性:能否处理边缘情况,如空值、重复键、哈希片段、URL编码等。
- 数据结构设计:如何优雅地处理单个值和数组值的统一存储。
- 字符串操作 :熟练使用
split
,indexOf
,slice
等方法。