学习链接
【Q429】实现一个函数用来解析 URL 的 querystring
【Q440】实现一个函数用来对 URL 的 querystring 进行编码
解析 URL
URL 对象
new URL(url, [base])
**url**—— 完整的 URL,或者仅路径(如果设置了 base),**base**—— 可选的 base URL:如果设置了此参数,且参数url只有路径,则会根据这个base生成 URL。
let url = new URL('https://test.com/profile/user');let newUrl1 = new URL('/tester', 'https://test.com/profile/user');let newUrl2 = new URL('/tester', url);let newUrl3 = new URL('/tester', 'https://test.com/profile/user'); //let newUrl4 = new URL('/tester', 'https://test.com/profile/');let newUrl5 = new URL('tester', 'https://test.com/profile/user');let newUrl6 = new URL('tester', 'https://test.com/profile/');let newUrl7 = new URL('//tester', 'https://test.com/profile/');console.log('newUrl1.href: ', newUrl1.href); // https://test.com/testerconsole.log('newUrl2.href: ', newUrl2.href); // https://test.com/testerconsole.log('newUrl3.href: ', newUrl3.href); // https://test.com/testerconsole.log('newUrl4.href: ', newUrl4.href); // https://test.com/testerconsole.log('newUrl5.href: ', newUrl5.href); // https://test.com/profile/testerconsole.log('newUrl6.href: ', newUrl6.href); // https://test.com/profile/testerconsole.log('newUrl7.href: ', newUrl7.href); // https://tester/

自动编码,转换不合法字符。
(new URL('https://site.com/pat h')).href // 'https://site.com/pat%20h'
编码字符串
- encodeURI —— 编码整个 URL。
- decodeURI —— 解码为编码前的状态。
- encodeURIComponent —— 编码 URL 组件,例如搜索参数,或者 hash,或者 pathname。
- decodeURIComponent —— 解码为编码前的状态。
https://site.com:8080/path/page?p1=v1&p2=v2#hash
在 URL 中 :,?,=,&,# 这类字符是被允许的。
另一方面,对于 URL 的单个组件,例如一个搜索参数,则必须对这些字符进行编码,以免破坏 URL 的格式。
encodeURI仅编码 URL 中完全禁止的字符。encodeURIComponent也编码这类字符,此外,还编码#,$,&,+,,,/,:,;,=,?和@字符。
所以,对于一个 URL 整体,我们可以使用 encodeURI,
而对于 URL 参数,我们应该改用 encodeURIComponent。
解析 URL 的 queryString
function parse(urlStr) {const queryString = urlStr.match(/(?<=\?)[^\?#]*/)?.[0];// const queryString = new URL(urlStr).search.slice(1);if (!queryString) return {};queryObj = queryString.split('&').reduce((params, block) => {// const [k, v = ''] = decodeURIComponent(block).split('=');// 如此操作无法正确识别 title=1%2B1%3D2 即 1+1=2// 如果未赋值,则默认为空字符串const [k, v = ''] = block.split('=').map(e => decodeURIComponent(e));if (params[k] !== undefined) {// 处理 key 出现多次的情况,设置为数组params[k] = [].concat(params[k], v);} else {params[k] = v;}return params;}, {})return queryObj;}// {}const str1 = 'https://shanyue.tech'// {a: ''}const str2 = 'https://shanyue.tech?a'// {name: '名字'}const str3 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97'// {name: '名字', a: 3}const str4 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3'// {name: '名字', a: [3, 4]}const str5 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3&a=4'// {name: '名字', a: 3}const str6 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3#hash'// {name: '1+1=2'}const str7 = 'https://shanyue.tech?name=1%2B1%3D2'console.log('parse(str1): ', parse(str1));console.log('parse(str2): ', parse(str2));console.log('parse(str3): ', parse(str3));console.log('parse(str4): ', parse(str4));console.log('parse(str5): ', parse(str5));console.log('parse(str6): ', parse(str6));console.log('parse(str7): ', parse(str7));
编码 URL 的 queryString
function stringify(queryObj) {const queryArr = [];for (let [k, v] of Object.entries(queryObj)) {if (v === null || v === undefined || typeof v === 'object') {v = '';}queryArr.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));}return queryArr.join('&');}const data = {a: 123,b: '啊?',c: null}const queryString = stringify(data);console.log('queryString: ', queryString);
