面试官:如何解析URL参数?

解析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请求参数处理等,直接体现了处理字符串和数据结构的能力。

解题思路

  1. 提取查询字符串 :使用 URL API 或字符串分割来获取 ? 之后的部分。
  2. 分割键值对 :用 & 符号将查询字符串分割成独立的键值对数组。
  3. 解析每个键值对 :用 = 符号分割每个键值对。注意处理没有值的参数(如 &key)和空值(如 &key=)。
  4. 处理重复键:使用一个对象来存储结果。如果遇到重复的键,则将值转换为数组,或将新值推入现有数组。
  5. 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熟悉度 :是否知道 URLURLSearchParams 这两个现代Web API。
  • 鲁棒性:能否处理边缘情况,如空值、重复键、哈希片段、URL编码等。
  • 数据结构设计:如何优雅地处理单个值和数组值的统一存储。
  • 字符串操作 :熟练使用 split, indexOf, slice 等方法。
相关推荐
2501_9387739914 分钟前
文档搜索引擎搜索模块迭代:从基础检索到智能语义匹配升级
人工智能·算法·搜索引擎
CS创新实验室23 分钟前
典型算法题解:长度最小的子数组
数据结构·c++·算法·考研408
我有一些感想……25 分钟前
浅谈 BSGS(Baby-Step Giant-Step 大步小步)算法
c++·算法·数论·离散对数·bsgs
麦麦大数据30 分钟前
F042 A星算法课程推荐(A*算法) | 课程知识图谱|课程推荐vue+flask+neo4j B/S架构前后端分离|课程知识图谱构造
vue.js·算法·知识图谱·neo4j·a星算法·路径推荐·课程推荐
贝塔实验室1 小时前
LDPC 码的度分布
线性代数·算法·数学建模·fpga开发·硬件工程·信息与通信·信号处理
快手技术1 小时前
端到端短视频多目标排序机制框架 EMER 详解
算法
Wenhao.1 小时前
LeetCode LRU缓存
算法·leetcode·缓存·golang
京东零售技术1 小时前
告别 “盲买”!京东 AI 试穿 Oxygen Tryon:让服饰购物从“想象”到“所见即所得”
算法
小白菜又菜1 小时前
Leetcode 2273. Find Resultant Array After Removing Anagrams
算法·leetcode·职场和发展
milanyangbo2 小时前
谁生?谁死?从引用计数到可达性分析,洞悉GC的决策逻辑
java·服务器·开发语言·jvm·后端·算法·架构