前端面试常客之URL的parseParam解构

755 阅读3分钟

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个元素存放的是第二个引用型分组(子表达式)匹配的字符串,依次类推。此例中第一个子表达式即为(.+)$,括号包裹的为匹配单元
  • ?在正则式中有自身的意义,匹配时要转义 结果如图

image.png

2. 去除&,并且初步存储数据

const paramsArr = paramsStr.split('&');

输出

image.png

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;
      }
    })

最终结果

image.png

  • 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');

本人大三,正寻实习,与君共勉。寥有拙作,万望指正