當你看到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