手写 URL 查询字符串解析器,作用是把 https://xxx.com?name=张三&age=18 这种网址后面的参数,解析成一个方便调用的对象 { name: '张三', age: 18 }。
思路是先做划分再逐一解析,之后加入到resObj中,需要注意的是:
-
如果串里有相同的键,则该键的值应该是一个数组。
-
中文或特殊字符会被编码,需要解码。
代码
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老师说)有几个点可以改进一下:
-
没处理
#锚点 :如果 URL 是?a=1#top,split("?")[1]拿到的会是a=1#top,结果对象会变成{ 'a#top': ... },逻辑会崩。 -
没处理
+号 :HTML 表单中,空格常被编码为+,但decodeURIComponent不会把+转成空格,导致解析错误。 -
值里带了
=号会崩 :比如?q=1+1=2,split("=")会切成三个片段,解构[key, value]只拿前两个,后面的=2直接丢掉。