解析 URL Params 为对象
将 URL 查询参数字符串解析为 JavaScript 对象,支持数组、重复参数等场景
问题
在前端开发中,我们经常需要从 URL 中提取查询参数。例如,给定 URL https://example.com?name=张三&age=25&hobby=reading&hobby=coding,需要将查询参数解析为一个对象:
{
name: '张三',
age: '25',
hobby: ['reading', 'coding']
}
这道题要求实现一个函数,能够将 URL 的查询参数部分解析为 JavaScript 对象,并正确处理重复参数、特殊字符编码等情况。
解答
/**
* 解析 URL 参数为对象
* @param {string} url - 完整的 URL 或查询字符串
* @returns {object} 解析后的参数对象
*/
function parseUrlParams(url) {
// 提取查询字符串部分
const queryString = url.includes('?') ? url.split('?')[1] : url;
// 如果没有查询参数,返回空对象
if (!queryString) {
return {};
}
const params = {};
// 按 & 分割参数对
const pairs = queryString.split('&');
pairs.forEach(pair => {
// 按 = 分割键值对
const [key, value] = pair.split('=');
// 解码键和值(处理中文和特殊字符)
const decodedKey = decodeURIComponent(key);
const decodedValue = decodeURIComponent(value || '');
// 如果键已存在,转换为数组
if (params.hasOwnProperty(decodedKey)) {
// 如果已经是数组,直接添加
if (Array.isArray(params[decodedKey])) {
params[decodedKey].push(decodedValue);
} else {
// 如果不是数组,转换为数组
params[decodedKey] = [params[decodedKey], decodedValue];
}
} else {
// 首次出现,直接赋值
params[decodedKey] = decodedValue;
}
});
return params;
}
/**
* 使用 URLSearchParams API 的现代实现方式
* @param {string} url - 完整的 URL 或查询字符串
* @returns {object} 解析后的参数对象
*/
function parseUrlParamsModern(url) {
const queryString = url.includes('?') ? url.split('?')[1] : url;
if (!queryString) {
return {};
}
const params = {};
const searchParams = new URLSearchParams(queryString);
// 遍历所有参数
for (const [key, value] of searchParams.entries()) {
if (params.hasOwnProperty(key)) {
if (Array.isArray(params[key])) {
params[key].push(value);
} else {
params[key] = [params[key], value];
}
} else {
params[key] = value;
}
}
return params;
}
使用示例
// 示例 1: 基本用法
const url1 = 'https://example.com?name=张三&age=25&city=北京';
console.log(parseUrlParams(url1));
// 输出: { name: '张三', age: '25', city: '北京' }
// 示例 2: 处理重复参数
const url2 = 'https://example.com?hobby=reading&hobby=coding&hobby=gaming';
console.log(parseUrlParams(url2));
// 输出: { hobby: ['reading', 'coding', 'gaming'] }
// 示例 3: 处理特殊字符和编码
const url3 = 'https://example.com?name=张%20三&email=test%40example.com';
console.log(parseUrlParams(url3));
// 输出: { name: '张 三', email: 'test@example.com' }
// 示例 4: 只传查询字符串
const queryString = 'page=1&size=10&sort=desc';
console.log(parseUrlParams(queryString));
// 输出: { page: '1', size: '10', sort: 'desc' }
// 示例 5: 空值处理
const url5 = 'https://example.com?name=&age=25';
console.log(parseUrlParams(url5));
// 输出: { name: '', age: '25' }
// 示例 6: 使用现代 API
const url6 = 'https://example.com?tag=js&tag=css&tag=html';
console.log(parseUrlParamsModern(url6));
// 输出: { tag: ['js', 'css', 'html'] }
关键点
-
提取查询字符串:使用
split('?')方法分离 URL 和查询参数部分,兼容传入完整 URL 或纯查询字符串 -
参数分割:先用
&分割各个参数对,再用=分割键值对 -
URL 解码:使用
decodeURIComponent()解码键和值,正确处理中文、空格、特殊字符等编码内容 -
重复参数处理:当同一个键出现多次时,将值转换为数组存储,保留所有值
-
边界情况:处理空查询字符串、空值、缺少值等边界情况
-
现代 API:可以使用
URLSearchParamsAPI 简化实现,但需注意浏览器兼容性 -
性能优化:使用
hasOwnProperty检查属性存在性,避免原型链查找
目录