手写 URL 查询字符串解析器,作用是把https://xxx.com?name=张三&age=18这种网址后面的参数,解析成一个方便调用的对象{ name: '张三', age: 18 }。
思路是先做划分再逐一解析,之后加入到resObj中,需要注意的是:
1. 如果串里有相同的键,则该键的值应该是一个数组。
2. 中文或特殊字符会被编码,需要解码。
代码
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直接丢掉。