【前端手撕】url解析

手写 URL 查询字符串解析器,作用是把 https://xxx.com?name=张三&age=18 这种网址后面的参数,解析成一个方便调用的对象 { name: '张三', age: 18 }

思路是先做划分再逐一解析,之后加入到resObj中,需要注意的是:

  1. 如果串里有相同的键,则该键的值应该是一个数组。

  2. 中文或特殊字符会被编码,需要解码。

代码

javascript 复制代码
const parseUrl = (url) => {
    const tmpUrl = url.split('?')[1]
    const resObj = {}
    for (const item of tmpUrl.split('&')) {
        let [key, value] = item.split('=')
        // 解码value
        value = decodeURIComponent(value)
        if (resObj.hasOwnProperty(key)) {
            resObj[key] = [].concat(resObj[key], value)
        } else {
            resObj[key] = value
        }
    }
    return resObj
}

这里讲一下concat,concat作用是拼接两个数组,但传参的话可以是数组也可以是值:

  • 参数是数组:把该数组的每个元素拉平(只会拉平一层)放入新数组。

  • 参数是非数组(普通值):把这个值原封不动作为一项放入新数组。

这样无论 resObj[key] 当前是字符串还是数组,都能干净利落地把它变成数组,并追加新值。

Tip

(d老师说)有几个点可以改进一下:

  1. 没处理 # 锚点 :如果 URL 是 ?a=1#topsplit("?")[1] 拿到的会是 a=1#top,结果对象会变成 { 'a#top': ... },逻辑会崩。

  2. 没处理 + :HTML 表单中,空格常被编码为 +,但 decodeURIComponent 不会把 + 转成空格,导致解析错误。

  3. 值里带了 = 号会崩 :比如 ?q=1+1=2split("=") 会切成三个片段,解构 [key, value] 只拿前两个,后面的 =2 直接丢掉。