← 返回题目列表

如何手写 query string 的解析和序列化?

中等 第 23 / 27 题 更新于 2026/07/29
手写代码URLquery string编码

简化版

query string 解析是把 ?a=1&b=2 转成对象,序列化是把对象转回 URL 参数。核心步骤是去掉开头 ?,按 & 拆键值对,再用 decodeURIComponent 解码;序列化时跳过 undefined,使用 encodeURIComponent 编码。边界包括重复 key、数组、空值、中文、特殊字符和 + 是否代表空格。

详细版

浏览器已有 URLSearchParams,但手写能考察字符串处理和编码意识。

输入输出
?a=1&b=2{ a: "1", b: "2" }
a=1&a=2{ a: ["1", "2"] }
q=前端{ q: "前端" }
function parseQuery(query: string) {
  const res: Record<string, any> = {}
  query.replace(/^\?/, '').split('&').filter(Boolean).forEach(pair => {
    const [rawKey, rawValue = ''] = pair.split('=')
    const key = decodeURIComponent(rawKey)
    const value = decodeURIComponent(rawValue.replace(/\+/g, ' '))
    if (res[key] === undefined) res[key] = value
    else res[key] = Array.isArray(res[key]) ? [...res[key], value] : [res[key], value]
  })
  return res
}

query 处理的核心不是 split,而是编码、重复 key 和空值语义。

完整版教学

一、题目考察点

这题常见于工具函数手写,考察字符串拆分、URL 编码、数组处理和边界意识。

实际项目中推荐使用 URLSearchParams 或成熟库,但面试手写要能说明简化版和工程版差异。

二、解析基础流程

解析流程是:

  • 去掉开头的 ?
  • & 拆成键值对。
  • 按第一个 = 拆 key 和 value。
  • 解码 key/value。
  • 放入结果对象。
function decode(value: string) {
  return decodeURIComponent(value.replace(/\+/g, ' '))
}

+ 在表单编码中常表示空格,是否处理要按约定说明。

三、重复 key 怎么处理

URL 允许重复 key,例如 tag=js&tag=css。常见处理方式有三种:

方式结果说明
后者覆盖前者{ tag: "css" }简单但丢信息
转数组{ tag: ["js", "css"] }更完整
始终数组{ tag: ["js"] }统一但使用麻烦

手写时转数组比较稳。

四、序列化实现

序列化要把对象变成 a=1&b=2

function stringifyQuery(obj: Record<string, any>) {
  const parts: string[] = []
  Object.keys(obj).forEach(key => {
    const value = obj[key]
    if (value === undefined) return
    const values = Array.isArray(value) ? value : [value]
    values.forEach(item => {
      parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(item ?? '')}`)
    })
  })
  return parts.join('&')
}

null 是否序列化为空字符串,也要看项目约定。

五、等号和值里的特殊字符

如果 value 里本身有 =,简单 split('=') 会丢内容。更稳的做法是找第一个等号下标。

const index = pair.indexOf('=')
const key = index >= 0 ? pair.slice(0, index) : pair
const value = index >= 0 ? pair.slice(index + 1) : ''

六、和 URLSearchParams 的区别

URLSearchParams 已经处理了很多标准细节。

const params = new URLSearchParams(location.search)
params.getAll('tag')

但它转普通对象时仍要你决定重复 key、数组和空值如何表达。

七、常见误区与追问

  • 误区:query 只要按 &= split。 编码、重复 key、空值和 value 中的等号都要考虑。
  • 误区:不用 encode/decode 也能跑。 中文、空格、&= 等特殊字符会出问题。
  • 误区:重复 key 一定覆盖。 表单和筛选条件中重复 key 很常见,转数组更完整。
  • 追问:+ 要不要转空格? 表单编码中常需要,严格 URL 百分号编码场景要按约定。
  • 追问:undefined 和 null 怎么处理? 常见做法是跳过 undefined,null 转空字符串或字符串 "null" 需约定。
  • 追问:为什么推荐 URLSearchParams? 标准 API 更可靠,手写主要用于理解和特殊格式适配。

八、加强记忆

query 手写记成“拆、解码、合并;遍历、编码、拼接”。真正的坑在重复 key、特殊字符、空值和标准 API 的取舍。