URL参数解析

实现 getParams 函数,将 URL 查询字符串解析为对象

问题

实现一个 getParams 函数,将 URL 中的查询参数解析为对象。

getParams('https://example.com?name=张三&age=18&hobby=reading&hobby=coding')
// { name: '张三', age: '18', hobby: ['reading', 'coding'] }

解答

方法一:使用 URLSearchParams

function getParams(url) {
  const result = {}
  // 创建 URL 对象,获取查询字符串
  const searchParams = new URL(url).searchParams

  // 遍历所有参数
  for (const [key, value] of searchParams) {
    if (result.hasOwnProperty(key)) {
      // 已存在的 key,转为数组
      result[key] = [].concat(result[key], value)
    } else {
      result[key] = value
    }
  }

  return result
}

方法二:手动解析

function getParams(url) {
  const result = {}
  // 获取 ? 后面的查询字符串
  const queryString = url.split('?')[1]

  if (!queryString) return result

  // 按 & 分割,处理每个键值对
  queryString.split('&').forEach(pair => {
    // 按第一个 = 分割(值中可能包含 =)
    const [key, ...rest] = pair.split('=')
    // 解码 URI 组件
    const value = decodeURIComponent(rest.join('=') || '')
    const decodedKey = decodeURIComponent(key)

    if (result.hasOwnProperty(decodedKey)) {
      // 重复的 key 转为数组
      result[decodedKey] = [].concat(result[decodedKey], value)
    } else {
      result[decodedKey] = value
    }
  })

  return result
}

测试用例

// 基本解析
getParams('https://example.com?name=tom&age=18')
// { name: 'tom', age: '18' }

// 重复参数
getParams('https://example.com?tag=js&tag=css&tag=html')
// { tag: ['js', 'css', 'html'] }

// 中文编码
getParams('https://example.com?name=%E5%BC%A0%E4%B8%89')
// { name: '张三' }

// 空值处理
getParams('https://example.com?empty=&flag')
// { empty: '', flag: '' }

// 无参数
getParams('https://example.com')
// {}

关键点

  • 使用 URLSearchParams 是最简洁的方案,自动处理编码
  • 手动解析需要用 decodeURIComponent 解码中文和特殊字符
  • 相同 key 出现多次时,应合并为数组
  • 注意处理边界情况:无参数、空值、值中包含 =
  • split('=') 只按第一个 = 分割,避免值被截断