[javascript核心-10] 解析params参数的多种方案

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

功能说明

queryUrlPramas()接收两个参数url,attr。如果不传第二个参数,那么返回解析url的对象,如果传入attr,则只返回attr对应的值。

实现方式一:字符串拆分

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askIndex = url.indexOf('?'),
        hashIndex = url.lastIndexOf('#'),
        askText = '',
        hashText = '',
        params = {};
    hashText = url.substring(hashIndex + 1);
    askText = url.substring(askIndex + 1, hashIndex)

    params['hash'] = hashText
    const askTextArr = askText.split('&')
    askTextArr.forEach(element => {
        let [key, val] = element.split('=')
        params[key] = val
    })
    return typeof attr !== 'undefined' ? params[attr] : params
}

const url = 'https://www.bilibili.com/video/eeee/?p=256&spm_id_from=333.7777.top_right_bar_window_history.content.click&vd_source=29aaaa68d14f71bbbb#video'

console.log(queryUrlPramas(url))
/*
{
  hash: 'video',
  p: '256',
  spm_id_from: '333.7777.top_right_bar_window_history.content.click',
  vd_source: '29aaaa68d14f71bbbb'
}
*/
console.log(queryUrlPramas(url, 'p')) // 256

问题:#?不存在时会索引计算会出现问题,导致解析出错;如果#出现在?前时,解析也会出现问题。

考虑各种情况:

  1. #不存在,?存在,?后的参数直接截取到末尾
  2. #存在,?不存在,#后的参数直接截取到末尾
  3. #?都不存在,不做任何处理
  4. #?后面,?后的参数从?截取到#,hash从#截取到末尾
  5. #?前面,hash从#截取到??后的参数直接截取到末尾

字符串解析考虑各种情况:

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askIndex = url.indexOf('?'),
        hashIndex = url.lastIndexOf('#'),
        askText = '',
        hashText = '',
        params = {};

    // 1. `#`不存在,`?`存在,`?`后的参数直接截取到末尾
    if(hashIndex === -1 && askIndex >= 0){
        askText = url.substring(askIndex + 1)
    }
    // 2. `#`存在,`?`不存在,`#`后的参数直接截取到末尾
    else if(hashIndex >= 0 && askIndex === -1){
        hashText = url.substring(hashIndex + 1)
    }
    else if(hashIndex >= 0 && askIndex >= 0){
        // 4. `#`在`?`后面,`?`后的参数从`?`截取到`#`,hash从`#`截取到末尾
        if(hashIndex > askIndex){
            askText = url.substring(askIndex + 1, hashIndex)
            hashText = url.substring(hashIndex + 1)
        }
        // 5. `#`在`?`前面,hash从`#`截取到`?`,`?`后的参数直接截取到末尾
        else {
            hashText = url.substring(hashIndex + 1, askIndex)
            askText = url.substring(askIndex + 1)
        }
    }
    hashText !== '' ? params['hash'] = hashText : null
    if(askText !== ''){
        const askTextArr = askText.split('&')
        askTextArr.forEach(element => {
            let [key, val] = element.split('=')
            params[key] = val
        })
    }
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在,`?`后的参数直接截取到末尾
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在,`#`后的参数直接截取到末尾
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在,不做任何处理
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面,`?`后的参数从`?`截取到`#`,hash从`#`截取到末尾
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面,hash从`#`截取到`?`,`?`后的参数直接截取到末尾
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // { hash: 'ccc', a: '1', b: '2' }

实现方式二:利用<a>标签

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askText = '',
        hashText = '',
        params = {};
    let linkObj = document.createElement('a');
    linkObj.href = url;
    askText = linkObj.search.substring(1); // 去掉?
    hashText = linkObj.hash.substring(1); // 去掉#
    linkObj = null;

    // 解析参数
    params['hash'] = hashText
    const askTextArr = askText.split('&')
    askTextArr.forEach(element => {
        let [key, val] = element.split('=')
        params[key] = val
    })
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // {hash: 'ccc?a=1&b=2'}

会发现在第 5 中情况下,即#?前面的情况下,无法正常处理,需要手动进行判断修正。

另外可以使用ES6 提供的URLSearchParams类进行参数字符串处理,简化解析:

javascript 复制代码
new URLSearchParams('a=1&b=2').forEach((val, key)=> console.log(val,key)) // 1 a ; 2 b

因此可以用

javascript 复制代码
new URLSearchParams(askText).forEach((val, key)=> params[key] = val)

替换之前的代码:

javascript 复制代码
const askTextArr = askText.split('&')
askTextArr.forEach(element => {
    let [key, val] = element.split('=')
    params[key] = val
})

实现方式三:利用正则表达式

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let params = {};
    url.replace(/#([^?=#&]+)/g,(_,hash)=>params['hash']=hash)
    url.replace(/([^?=#&]+)=([^?=#&]+)/g, (_,key,val)=>params[key]=val)
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // { hash: 'ccc', a: '1', b: '2' }

每种情况结果都正常。

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

相关推荐
夏殇之殁1 天前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
新中地GIS开发老师1 天前
WebGIS开发学生作品|低空航天管理与航线规划系统
前端·javascript·webgis·三维gis开发
丙氨酸長鏈1 天前
Web前端入门第 问:JavaScript 一个简单的 IndexedDB 数据库入门示例
前端·javascript·数据库
kyriewen1 天前
面试官让我手写虚拟列表——AI生成的版本,快速滚动几下就白屏了
前端·javascript·面试
许彰午1 天前
政务督办的分合模式:主办协办的并发审批
前端·javascript·政务
易筋紫容1 天前
创建型模式:对象的诞生艺术
开发语言·前端·javascript
0_Error_2 天前
猫国建设者 修改资源 自动采集
javascript
贩卖黄昏的熊2 天前
NestJS简明教程——安全
开发语言·javascript·安全·typescript·nest.js
贩卖黄昏的熊2 天前
NestJS简明教程——异常处理和日志
javascript·node.js·nest.js
海带紫菜菠萝汤2 天前
FFmpeg.wasm 实践:在浏览器中运行 FFmpeg 的能力边界与性能瓶颈
前端·javascript·ffmpeg·音视频·wasm