在我们工作的过程中经常会遇到从网址url中传递参数的问题,当url中传递了参数,我们就需要从url中去解析这些参数。
举例: www.toutiao.com/search/?key…
这时我们需要从url中将keyword和其对应的值获取到,并应用到我们其他对应的代码逻辑中。
常规做法: 下面我们只针对于?后面的参数进行处理,也就是 keyword=fabu&name=bgcolor
function parse (str) {
if (typeof str !== 'string') return;
return str.split('&').reduce((acc, cur) => {
var [key, value] = cur.split('=');
// 如果不存在value,则不需要
if (!value) return acc;
acc[key] = value;
return acc;
}, {})
}
// 解析url
var url = 'keyword=fabu&name=bgcolor';
parse(url); // 得到的结果 {keyword: 'fabu', name: 'bgcolor'}
到这呢,基本上我们可以解析我们常见的url。
但是在实际开发过程中我们可能遇到的并不是这样的url,往往是相对复杂一点的url, 例如:
var str1 = 'a=1&b[name]=bgcolor&c[0]=c1&c[1]=c2&color=Deep%20color'
如果我们还是按照我们之前的写法去操作这个url的话,会得到什么呢?
parse(str1);
得到的值:
{
"a": "1",
"b['name']": "bgcolor",
"c[0]": "c1",
"c[1]": "c2",
"color": "Deep%20color"
}
而这个结果并不是我们想要的结果,我们希望的结果应该是
{
"a": "1",
"b": {
"name": "bgcolor"
},
"c": [
"c1",
"c2"
],
"color": "Deep color"
}
所以我们需要改造一下我们之前的parse函数
function parse (str) {
if (typeof str !== 'string') return;
return str.split('&').reduce((acc, cur) => {
var [key, value] = cur.split('=');
// 如果不存在value,则不需要
if (!value) return acc;
// acc[key] = value; //此处不能进行直接赋值操作了
// 此时我们需要针对key,value进行一些操作处理,让他按照我们的预期结果返回,此时我们引入处理函数deep_set
deep_set(acc, key, value);
return acc;
}, {})
}
// deep_set函数处理复杂key
function deep_set (o, path, value) {
/*
* 首先我们需要处理一下传的path
* 将path中的[]通过正则转换为 . ,也就是将b[name]或c[0] ==> b.name , c.0
* 将转换后的path分解为一个数组,并去除其中的空项
* 然后我们开始循环一下当前转换后的path
*/
var formatPath = path.replace(/[\[\]]/g, '.').split('.').filter(x => x);
var lens = formatPath.length;
/*
* 遍历的时候由于formatPath的最后一项的值一定是一个原始数据类型,所以我们不需要处理这一项
* 而其他的我们需要根据其属性赋予不同的数据类型
* 例如b[name] ==> [b, name] i+1为string,所以是一个对象,我们赋值为{}
* c[0] ==> [c, 0] i+1匹配数字,所以应该是一个数组,我们赋值 []
*/
for (var i = 0; i < lens - 1; i++) {
if (!o[formatPath[i]]) {
o[formatPath[i]] = formatPath[i+1].match(/^\d+$/g) ? [] : {}
}
o = o[formatPath[i]];
}
o[formatPath[i]] = decodeURIComponent(value);
}
// 重新解析url
var str = 'a=1&b[name]=bgcolor&c[0]=c1&c[1]=c2&color=Deep%20color';
parse(str);
得到的结果:
{
a: '1',
b: { name: 'bgcolor' },
c: [ 'c1', 'c2' ],
color: 'Deep color'
}
其中如果传入deep_set的值没有对应的formatPath[i],我们则给其根据formatPath[i]的类型进行赋值空数组或是空对象。
然后再将 o重新赋值为o[formatPath[i]],直至所有的formatPath项都遍历完之后,我们将最后一项的进行赋值value。
第一次写博客,表达有点乱,不知道如何表达的更好,请各位大佬勿喷,如有问题可在评论中留言。