JS解析query参数

以下是一个 JavaScript 实现,用于在查询字符串(query string)和对象之间进行相互转换,并自动处理 URL 编码和解码:

javascript 复制代码
/**
 * 将查询字符串解析为对象
 * @param {string} queryString - 可选,默认为当前 URL 的查询部分
 * @returns {Object} 解析后的对象
 */
function parseQuery(queryString = window.location.search) {
  // 移除开头的 ? 字符
  if (queryString.startsWith('?')) {
    queryString = queryString.substring(1);
  }

  const result = {};
  if (!queryString) return result;

  // 分割参数对
  const pairs = queryString.split('&');

  for (const pair of pairs) {
    const [encodedKey, encodedValue] = pair.split('=', 2);
    
    // 处理没有值的参数(如 ?key 或 ?key=&value=1)
    const key = encodedKey ? decodeURIComponent(encodedKey) : '';
    const value = encodedValue !== undefined ? decodeURIComponent(encodedValue) : '';

    // 处理重复键(转为数组)
    if (result[key] !== undefined) {
      if (!Array.isArray(result[key])) {
        result[key] = [result[key]];
      }
      result[key].push(value);
    } else {
      result[key] = value;
    }
  }

  return result;
}

/**
 * 将对象转换为查询字符串
 * @param {Object} obj - 需要转换的对象
 * @returns {string} 转换后的查询字符串(不含 ? 前缀)
 */
function stringifyQuery(obj) {
  if (!obj || typeof obj !== 'object') return '';

  const parts = [];

  for (const [key, value] of Object.entries(obj)) {
    // 跳过值为 undefined 或 null 的属性
    if (value === undefined || value === null) continue;

    // 处理数组值
    const values = Array.isArray(value) ? value : [value];

    for (const v of values) {
      // 处理空字符串
      const encodedKey = encodeURIComponent(key);
      const encodedValue = v !== '' ? encodeURIComponent(v) : '';
      parts.push(`${encodedKey}=${encodedValue}`);
    }
  }

  return parts.join('&');
}

// 示例用法
const queryObj = {
  name: 'John Doe',
  age: 30,
  hobbies: ['coding', 'reading'],
  specialChar: '@#$',
  empty: '',
};

// 对象转查询字符串
const queryString = stringifyQuery(queryObj);
console.log(queryString); 
// 输出: "name=John%20Doe&age=30&hobbies=coding&hobbies=reading&specialChar=%40%23%24&empty="

// 查询字符串转对象
const parsedObj = parseQuery('?name=John%20Doe&age=30&hobbies=coding&hobbies=reading&specialChar=%40%23%24&empty=');
console.log(parsedObj);
// 输出: 
// {
//   name: "John Doe",
//   age: "30",
//   hobbies: ["coding", "reading"],
//   specialChar: "@#$",
//   empty: ""
// }

核心特性:

  1. 完整的编码处理

    • 使用 encodeURIComponentdecodeURIComponent 处理特殊字符
    • 正确处理空格(转换为 %20 而非 +
    • 支持所有需要编码的 URI 组件字符
  2. 数组参数处理

    • 自动识别重复参数名并转换为数组
    • 保持参数顺序(在支持的浏览器中)
  3. 空值处理

    • 正确处理空字符串参数(key=
    • 跳过 undefinednull
  4. 兼容性

    • 不依赖任何外部库
    • 支持现代浏览器和 Node.js 环境
  5. 边缘情况处理

    • 自动去除查询字符串开头的 ?
    • 处理没有值的参数(如 ?key
    • 处理 URL 中可能出现的双重编码问题

使用场景:

  • 解析 URL 查询参数
  • 构建 API 请求参数
  • 处理表单提交数据
  • 实现 URL 状态管理

注意事项:

  1. 该实现将所有参数值视为字符串,数字或布尔值会被保留为字符串格式
  2. 对于复杂对象结构(嵌套对象),建议先转换为 JSON 字符串再作为参数值
  3. 编码遵循 RFC 3986 标准,空格会被编码为 %20 而非 +
  4. 如果需要支持 + 表示空格的旧格式,可以在解码时添加额外处理