JavaScript 中的new url( )用法

1,439 阅读5分钟

1.起因

事情的起因是在前端交流群里,有人询问这样一个问题,要求实现这个parseUrl函数。

 const url = 'https://www.gaotu.cn?user=gsx&user=gt&user=王麻子&id=111&name=%E5%BC%A0%E4%B8%89';
console.log(parseUrl(url));
// 输出:{ user: [ 'gsx', 'gt', '王麻子' ], id: '111', name: '张三' }

我最开始想到的实现方法是通过字符串的分割,划分成数组,在一步一步拼接成最后的数据。

  1. 最开始的思路,就能得到想要的结果
const url = 'https://www.gaotu.cn?user=gsx&user=gt&user=王麻子&id=111&name=%E5%BC%A0%E4%B8%89';
function parseUrl (url) {
  const arr1 = url.split('&')
  let arr2 = arr1[0].split('?')
  arr1[0] = arr2
  let arr3 = arr1.flat()
  let arr4 = []
  let obj = {}
  let obj1 = {}
  let obj2 = {}
  for (let value of arr3) {
    if (value.split('=')[0] === 'user') {
      arr4.push(value.split('=')[1])
    } else if (value.split('=')[0] === 'id') {
      obj1.id = value.split('=')[1]
    } else if (value.split('=')[0] === 'name') {
      obj2.name = decodeURI(value.split('=')[1])
    }
  }
  obj.user = arr4
  return Object.assign(obj, obj1, obj2)
}
  1. 后面发现群友的方法更优雅,实现也相对容易。涉及了new url()的相关知识。所以总结一个笔记,方便以后学习。

2. JS 中的new url

  1. URL 接口用于解析,构造,规范化和编码 URL。它通过提供允许你轻松阅读和修改 URL 组件的属性来工作。
  2. 通常,通过在调用 URL 的构造函数时将 URL 指定为字符串或提供相对 URL 和基本 URL 来创建新的 URL 对象。

image.png

2.1 new URL()

创建并返回一个URL对象,该 URL 对象引用使用绝对 URL 字符串,相对 URL 字符串和基本 URL 字符串指定的 URL。

image.png

image.png

 hash: "" ,//其中包含域(即主机名),后跟(如果指定了端口)“:”和 URL 的端口。
 host: "www.gaotu.cn"//其中包含域(即主机名),后跟(如果指定了端口)“:”和 URL 的端口。
 hostname: "www.gaotu.cn"//URL域名
 href: "https://www.gaotu.cn/?user=gsx&user=gt&user=%E7%8E%8B%E9%BA%BB%E5%AD%90&id=111&name=%E5%BC%A0%E4%B8%89"//完整的url
 origin: "https://www.gaotu.cn"//返回一个包含协议名
 域名、端口号
 password: "",//包含在域名前面指定的密码
 pathname: "/",//以 '/' 起头紧跟着 URL 文件路径
 port: "",//包含 URL 端口号
 protocol: "https:",//包含 URL 协议名
 //指示 URL 的参数字符串;如果提供了任何参数,则此字符串包括所有参数,并以开头的“?”开头 字符。
 search: "?user=gsx&user=gt&user=%E7%8E%8B%E9%BA%BB%E5%AD%90&id=111&name=%E5%BC%A0%E4%B8%89",
 searchParams: URLSearchParams {size5},//对象,可用于访问`search`中找到的各个查询参数
 username: "",//包含在域名前面指定的用户名

new URL(url, base)

  • url 一个表示绝对或相对 URL 的 DOMString或任何具有字符串化方法的对象,例如 <a> 或 <area> 元素。如果 url 是相对 URL,则会将 base 用作基准 URL。如果 url 是绝对 URL,则无论参数 base 是否存在,都将被忽略。
  • base 可选。 一个表示基准 URL 的字符串,当 url 为相对 URL 时,它才会生效。如果未指定,它默认为 undefined

2.2 URLSearchParams

接口可用于构建和处理 URL 查询字符串。要从当前窗口的 URL 获取搜索参数,可以执行以下操作

  1. 构造函数
  • URLSearchParams() 返回一个 URLSearchParams 对象。
  1. 实例属性
  • size 只读 返回 URLSearchParams 对象中查询参数的总个数。
  1. 实例方法
  • URLSearchParams.[@@iterator]()

    • 返回一个 iterator,允许以键/值对在查询字符串中出现的顺序迭代包含在该对象的键/值对。
  • URLSearchParams.append() 插入一个指定的键/值对作为新的查询参数。

  • URLSearchParams.delete() 从查询参数列表里删除指定的查询参数及其对应的值。

  • URLSearchParams.entries() 返回一个iterator可以遍历所有键/值对的对象。

  • URLSearchParams.forEach() 通过回调函数迭代此对象中包含的所有值。

  • URLSearchParams.get() 获取指定查询参数的第一个值。

  • URLSearchParams.getAll() 获取指定查询参数的所有值,返回是一个数组。

  • URLSearchParams.has() 返回 Boolean判断是否存在此查询参数。

  • URLSearchParams.keys() 返回iterator 此对象包含了键/值对的所有键名。

  • URLSearchParams.set() 设置一个查询参数的新值,假如原来有多个值将删除其他所有的值。

  • URLSearchParams.sort() 按键名排序。

  • URLSearchParams.toString() 返回查询参数组成的字符串,可直接使用在 URL 上。

  • URLSearchParams.values() 返回iterator 此对象包含了键/值对的所有值。

const paramsString = "q=URLUtils.searchParams&topic=api";
const searchParams = new URLSearchParams(paramsString);

// 迭代查询参数
for (let p of searchParams) {
  console.log(p);
}

const urlParams = new URL(window.location.href);//将字符串变成url对象
urlParams.searchParams.has("topic") === true; // true //判断url是否存在这个key值
urlParams.searchParams.get("topic") === "api"; // true //获取这个key值的value
urlParams.searchParams.getAll("topic"); // ["api"] //获取url所有的key
urlParams.searchParams.get("foo") === ""; // true //key值为空的情况
urlParams.searchParams.append("topic", "webdev"); //url追加一个key-value
urlParams.searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
//将参数对象转为字符串并且进行了拼接
urlParams.searchParams.set("topic", "More webdev"); //设定key-value
urlParams.searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
urlParams.searchParams.delete("topic"); //删除key-value
urlParams.searchParams.toString(); // "q=URLUtils.searchParams"

3. 解决方法

这个parseUrl函数的实现思路如下:

  1. 将url按问号分割,获取查询参数部分。
  2. 使用URLSearchParams类解析查询参数部分。
  3. 遍历所有查询参数的键值对,如果该参数已经存在,则将其转换成数组;否则,存储单个值。
  4. 返回解析结果。
const url = 'https://www.gaotu.cn?user=gsx&user=gt&user=王麻子&id=111&name=%E5%BC%A0%E4%B8%89';
    function parseUrl (url) {
      const params = {};
      const searchParams = new URLSearchParams(url.split('?')[1]); // 获取查询参数部分
      for (const [key, value] of searchParams.entries()) {
        if (params[key]) { // 如果该参数已经存在,则将其转换成数组
          if (Array.isArray(params[key])) {
            params[key].push(decodeURIComponent(value)); // 对数组进行追加
          } else {
            params[key] = [params[key], decodeURIComponent(value)]; // 转换为数组
          }
        } else {
          params[key] = decodeURIComponent(value); // 存储单个值
        }
      }
      return params;
    }
  console.log('parseUrl', parseUrl(url));
  // { user: [ 'gsx', 'gt', '王麻子' ], id: '111', name: '张三' }

其他

decodeURIComponent介绍:用于解码由 encodeURIComponent方法或者其他类似方法编码的部分统一资源标识符(URI)。

  • decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。
  • decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。

从W3C的定义和用法来看,两者没有什么区别,但是两者的参数是有区别的:

decodeURI(URIstring)       
//URIstring    一个字符串,含有要解码的 URI 或其他要解码的文本。
decodeURIComponent(URIstring)      
//URIstring   一个字符串,含有编码 URI 组件或其他要解码的文本。

区别:

  • encodeURIComponentdecodeURIComponent可以编码和解码URI特殊字符(如#,/,¥等),
  • decodeURI则不能。
encodeURIComponent('#')
"%23"
decodeURI('%23')
"%23"
decodeURIComponent('%23')
"#"
encodeURI('#')
"#"