当你看到parseUrl
的时候,首先映入眼帘的应该是曾几什么时候在面试的时候,或多或少都有被说起到的问题前端
咱们不用太关心面试方面的东西,放轻松,不要带着心理压力,即便它是套路满满,咱们也依然能轻松搞定面试
parseUrl主要的用途就是解析URL的查询字符串数组
那么,咱们也无论什么hash写在#
号后面的东东了,只回归到?
号后面的查询字符串这里bash
遥想当年,当你看到这样的字符串'q=nba&src=home&fr=so'
,第一反应就是,小场面,用split一顿分割呗,先分割&
,再分割=
,小case的事函数
既然你们都会,我也就不卖关子了,开始撸一把啦测试
写出一个普普统统的parseUrl,特别的normal,对于咱们前端儿来讲仍是小菜一碟的ui
function parseUrl(str) {
return str.split('&').reduce((obj, pair) => {
// 解构数组所对应的值
const [key, value] = pair.split('=');
// 将键值对写入obj
obj[key] = value;
return obj;
}, {});
}
// 测试用例1
let s1 = 'q=nba&src=home&fr=so';
console.log(parseUrl(s1)); // {q:'nba',src:'home',fr:'so'}
复制代码
But,谁曾想,在你一顿操猛如虎的时候,其实已经埋下了一个小小的隐患编码
若是测试用例是'q=nba&src=home&fr=so&fe'
,就会出现小问题了,请看大屏幕spa
function parseUrl(str) {
return str.split('&').reduce((obj, pair) => {
const [key, value] = pair.split('=');
obj[key] = value;
return obj;
}, {});
}
// 测试用例2
let s2 = 'q=nba&src=home&fr=so&fe';
console.log(parseUrl(s2)); // {q:'nba',src:'home',fr:'so',fe:undefined}
复制代码
因为测试用例中的fe
是没有value值的,因此直接就是unfefined,看似也不影响什么code
不过这种状况能处理的话,咱们就不能视而不见,下面来修改一下,很是的简单
function parseUrl(str) {
return str.split('&').reduce((obj, pair) => {
const [key, value] = pair.split('=');
++++++
// 没有value值的状况,就返回obj中已有的内容
if (!value) {
return obj;
}
++++++
obj[key] = value;
return obj;
}, {});
}
// 测试用例2
let s2 = 'q=nba&src=home&fr=so&fe';
console.log(parseUrl(s2)); // {q:'nba',src:'home',fr:'so'}
复制代码
小小的隐患被咱们轻易搞定了,咱们再来看另一种状况
URL的查询字符串是能够输入这样的字符的'q=nba&fe[pro]=news&fe[pid]=result'
按照上面的写法,打印出来是这样的{q:'nba','fe[pro]':'news','fe[pid]':'result'}
实际上,以咱们熟知的知识体系来说,明显能看出来fe
实际上是个对象类型,因此本不应是这样的,起码是这样的{q:'nba',fe:{pro:'news', pid:'result'}}
那么让咱们来再研究研究吧
原理也是并不复杂,其实就是若是遇到这种看似对象类型的字符出现,咱们就把它当成对象来处理,处理完第一层后,再处理第二层,以此类推下去
function parseUrl(str) {
return str.split('&').reduce((obj, pair) => {
const [key, value] = pair.split('=');
if (!value) {
return obj;
}
// obj[key] = value 废弃废弃废弃
// 深刻到obj的内部去搞
deepObj(obj, key.split(/[\[\]]/g).filter(v => v), value);
return obj;
}, {});
}
// 深度设置对象
function deepObj(obj, keys, value) {
// 下面咱们全部涉及注释部分,都用fe[pro]来讲明一下
// fe[pro]被正则处理,匹配[和],以[或]分割出来的数组是这样的['fe', 'pro', '']
// 而后咱们只取非空值部分,就用filter过滤了一下,获得['fe', 'pro']
console.log(keys); // ['fe', 'pro']
let i = 0;
for (; i < keys.length - 1; i++) {
let key = keys[i];
// key值为fe
if (!obj[key]) { // obj中没有fe
obj[key] = {}; // { fe: {} }
}
// 深刻到obj的下一层
obj = obj[key]; // 引用fe这个对象{}
}
// 至关于在fe对象里加属性,fe:{pro: 'news'}
obj[keys[i]] = value;
}
// 测试用例3
let s3 = 'q=nba&fe[pro]=news&fe[pid]=result';
console.log(parseUrl(s3)); // {q:'nba',fe:{pro:'news', pid:'result'}}
复制代码
上面的代码,经过注释的方式进行了简单分析,但愿你们均可以理解
接下来,咱们继续说一种与对象相似的,那就是写成数组的形式,且听风吟,来看这个用例'q=nba&box[0]=one&box[1]=two'
这样的写法对于解析来讲,应该是返回以下格式{q:'nba',box:['one', 'two']}
那么,事不宜迟,咱们再回到deepObj里看看如何处理吧
function parseUrl(str) {
...省略
}
function deepObj(obj, keys, value) {
let i = 0;
for (; i < keys.length - 1; i++) {
let key = keys[i];
if (!obj[key]) {
++++++
// 若是是数组的话,keys应该是这样的['box', '0']
// 因此来判断keys的i+1位置(就是索引为1),是否是数字就行
// 是数字的话就当作数组类型来处理便可了
if (keys[i + 1].match(/^\d+$/)) {
obj[key] = [];
} else {
obj[key] = {};
}
++++++
}
obj = obj[key]
}
obj[keys[i]] = value;
}
// 测试用例4
let s4 = 'q=nba&box[0]=one&box[1]=two';
console.log(parseUrl(s4)); // {q:'nba',box:['one', 'two']}
复制代码
最后一种状况是这样的,'q=you%2Bme&name=jay%20chou'
,咱们看到了%
号,也就是说好比像空格,+号
这样的特殊字符都被编码了
因此,别慌,既然被编码了,咱们就能够利用提供好的解码方法搞定,它就是decodeURIComponent
代码也是很是好修改的,在deepObj函数中,只要将obj[keys[i]] = value
改成obj[keys[i]] = decodeURIComponent(value)
便可了,大功告成
function parseUrl(str) {
...省略
}
function deepObj(obj, keys, value) {
...省略
obj[keys[i]] = decodeURIComponent(value);
}
// 测试用例5
let s5 = 'q=you%2Bme&name=jay%20chou';
console.log(parseUrl(s5)); // {q:'you+me',name:'jay chou'}
复制代码
经过上面的4种套路,其实已经能考到不少人了,没想到一个小小的解析查询字符串的操做,竟然隐藏着如此神通
这也不得不让人唏嘘,JS的世界老是那么的博大精深,不过,咱们仍是不会停下脚步,继续努力学下去的
感谢你们的观看,886