1. 引言
在前端面试的考题中有诸多关于URL的内容,其中经常出现的一题为解构URL地址,应用场景为:对带有许多查询参数的地址,将这些参数截取,转变为json object型式。例子如下:(http://localhost:8080a=1&d&b=2&c=3&a=4&keyword=%E6%89%8B%E6%9C%BA) .最后解构出的结果为
{ a: [ '1', '4' ], d: true, b: '2', c: '3', keyword: '手机' }
2. 设计思想
1.运用正则表达式及split()函数将端口及问号后的查询参数比对切割。
2.将切割下来的数据用数组的contant()方法连接成json object
3.将编码进行解码
3.实现步骤及讲解
1.将 ?后的参数整个拿出
const paramsStr = /.+\?(.+)$/.exec(url)[1];
console.log(paramsStr);
- 正则表达式使用exec函数将url为参数执行匹配,exec函数用于检索字符串中的正则表达式的匹配,返回值是一个数组,但是此数组的内容和正则对象是否是全局匹配有着很大关系。在非局模式下如果没有找到匹配的字符串,那么返回null,否则将返回一个数组,数组的第0个元素存储的是匹配字符串,第1个元素存放的是第一个引用型分组(子表达式)匹配的字符串,第2个元素存放的是第二个引用型分组(子表达式)匹配的字符串,依次类推。此例中第一个子表达式即为
(.+)$,括号包裹的为匹配单元 - ?在正则式中有自身的意义,匹配时要转义 结果如图
2. 去除&,并且初步存储数据
const paramsArr = paramsStr.split('&');
输出
3. 去除=,解码,数据json化,连接(这几步必须在数据的forEach中一起执行)
let paramsObj = {};
paramsArr.forEach(param => {
// 每一个要解构的单元,正确的单元
if (/=/.test(param)) {
let [key, val] = param.split("=");
val = decodeURIComponent(val);
// key in paramr
// if (key in paramsObj)
if (paramsObj.hasOwnProperty(key)) {
paramsObj[key] = [].concat(paramsObj[key], val);
} else {
paramsObj[key] = val;
}
} else {
paramsObj[param] = true;
}
})
最终结果
- paramsObj为最终存储地
- forEach中遍历上一步得到的数组,params代表数组的每项的值作为参数传入箭头函数,用
/=/正则匹配每项值,匹配成功则进行分离 = 操作,key, val] = param.split("=")使用了es6的数组解构和split(),'='前后的值分别被赋予给key和val,组成json object 的键值对。 - 网址编码有解决乱码,不会有重码和字符冲突,不需要调整页面的语言编码设置即可正常浏览,使多种语言字符可以同时共存在页面上。
- 以防意外,将每项val用decodeURIComponent解码
- 针对重复的查询参数,如 a;需要进一步优化存储.此处使用了一个较为高级的解决办法,即使用对象上的
hasOwnProperty函数判断当前项是否已经存在于paramsObj上,如果存在,就使用[].concat()方法将val里加入新的key,[].concat 可以把两个值组成数组,第一个值不必是值 - 对于没有值的参数,遵循约定俗成的规则,使其默认为true
4小结
这个问题的关键在于
- 清楚parseParam解码的规则(值都需要解码,重复出现的key成数组,只有key没有值的默认为true)
- 设计好正确的正则式去匹配和切分
- 正确的循环才能得到正确的存储格式 全部代码如下
function parseParam(url) {
// 协议:域名/路径:端口?
const paramsStr = /.+\?(.+)$/.exec(url)[1];
// console.log(paramsStr);
const paramsArr = paramsStr.split('&');
// console.log(paramsArr);
let paramsObj = {};
paramsArr.forEach(param => {
// 每一个要解构的单元,正确的单元
if (/=/.test(param)) {
let [key, val] = param.split("=");
val = decodeURIComponent(val);
// key in paramr
// if (key in paramsObj)
if (paramsObj.hasOwnProperty(key)) {
paramsObj[key] = [].concat(paramsObj[key], val);
} else {
paramsObj[key] = val;
}
} else {
paramsObj[param] = true;
}
})
console.log(paramsObj);
return paramsObj;
}
parseParam('http://localhost:8080?a=1&d&b=2&c=3&a=4&keyword=%E6%89%8B%E6%9C%BA');
本人大三,正寻实习,与君共勉。寥有拙作,万望指正