![f02c1c3c8fef9a8ea8dd603d47b64cca.png](https://i-blog.csdnimg.cn/blog_migrate/16a06d2a18b4bfe42ce6d0b084ac9ef6.jpeg)
URL 是互联网的基础设施之一。浏览器提供了一些原生对象(Location 对象,URL 对象,URLSearchParams 对象),用来在浏览器端管理 URL(不影响服务器)。
1 Location 对象
Location对象是浏览器提供的原生对象,提供 URL 相关的信息和操作方法。通过window.location和document.location属性,可以拿到这个对象。
1.1 属性
Location对象提供以下属性:
- Location.href:整个 URL。
- Location.protocol:当前 URL 的协议,包括冒号(:)。
- Location.host:主机。如果端口不是协议默认的80和433,则还会包括冒号(:)和端口。
- Location.hostname:主机名,不包括端口。
- Location.port:端口号。
- Location.pathname:URL 的路径部分,从根路径/开始。
- Location.search:查询字符串部分,从问号?开始。
- Location.hash:片段字符串部分,从#开始。
- Location.username:域名前面的用户名(安全起见,这种明文的形式已经越来越少了)。
- Location.password:域名前面的密码(安全起见,这种明文的形式已经越来越少了)。
- Location.origin:URL 的协议、主机名和端口。
![67d78c7d09c30d263d8c032a17de0315.png](https://i-blog.csdnimg.cn/blog_migrate/adfd41e8a65fc1087373014279ea29b4.png)
这些属性里面,只有origin属性是只读的,其他属性都可写。
注意,如果对Location.href写入新的 URL 地址,浏览器会立刻跳转到这个新地址:
// 跳转到新网址
这个特性常常用于让网页自动滚动到新的锚点:
document
直接改写location,相当于写入href属性:
document
另外,Location.href属性是浏览器唯一允许跨域写入的属性,即非同源的窗口可以改写另一个窗口(比如子窗口与父窗口)的Location.href属性,导致后者的网址跳转。Location的其他属性都不允许跨域写入。
1.2 方法
(1)Location.assign()
assign方法接受一个 URL 字符串作为参数,使得浏览器立刻跳转到新的 URL。如果参数不是有效的 URL 字符串,则会报错:
// 跳转到新的网址
(2)Location.replace()
replace方法接受一个 URL 字符串作为参数,使得浏览器立刻跳转到新的 URL。如果参数不是有效的 URL 字符串,则会报错。
它与assign方法的差异在于,replace会在浏览器的浏览历史History里面删除当前网址,也就是说,一旦使用了该方法,后退按钮就无法回到当前网页了,相当于在浏览历史里面,使用新的 URL 替换了老的 URL。它的一个应用是,当脚本发现当前是移动设备时,就立刻跳转到移动版网页。
// 跳转到新的网址
(3)Location.reload()
reload方法使得浏览器重新加载当前网址,相当于按下浏览器的刷新按钮。
它接受一个布尔值作为参数。如果参数为true,浏览器将向服务器重新请求这个网页,并且重新加载后,网页将滚动到头部(即scrollTop === 0)。如果参数是false或为空,浏览器将从本地缓存重新加载该网页,并且重新加载后,网页的视口位置是重新加载前的位置。
// 向服务器重新请求当前网址
(4)Location.toString()
toString方法返回整个 URL 字符串,相当于读取Location.href属性。
2 URL 的编码和解码
网页的 URL 只能包含合法的字符。合法字符分成两类。
- URL 元字符:分号(;),逗号(,),斜杠(/),问号(?),冒号(:),at(@),&,等号(=),加号(+),美元符号($),井号(#)
- 语义字符:a-z,A-Z,0-9,连词号(-),下划线(_),点(.),感叹号(!),波浪线(~),星号(*),单引号('),圆括号(())
除了以上字符,其他字符出现在 URL 之中都必须转义,规则是根据操作系统的默认编码,将每个字节转为百分号(%)加上两个大写的十六进制字母。
比如,UTF-8 的操作系统上,http://www.example.com/q=春节这个 URL 之中,汉字“春节”不是 URL 的合法字符,所以被浏览器自动转成http://www.example.com/q=%E6%98%A5%E8%8A%82。其中,“春”转成了%E6%98%A5,“节”转成了%E8%8A%82。这是因为“春”和“节”的 UTF-8 编码分别是E6 98 A5和E8 8A 82,将每个字节前面加上百分号,就构成了 URL 编码。
JavaScript 提供四个 URL 的编码/解码方法:
- encodeURI()
- encodeURIComponent()
- decodeURI()
- decodeURIComponent()
2.1 encodeURI()
encodeURI()方法用于转码整个 URL。它的参数是一个字符串,代表整个 URL。它会将元字符和语义字符之外的字符,都进行转义:
![5932ae9b59d4e48cae4f0665e02647d4.png](https://i-blog.csdnimg.cn/blog_migrate/0048c6cb895f0c4f386c59e6190fbc79.png)
2.2 encodeURIComponent()
encodeURIComponent()方法用于转码 URL 的组成部分,会转码除了语义字符之外的所有字符,即元字符也会被转码。所以,它不能用于转码整个 URL。它接受一个参数,就是 URL 的片段:
![6ebc199a4f341614f1203a1022224901.png](https://i-blog.csdnimg.cn/blog_migrate/633568b94a0e04ef197ff1afb778c3c8.png)
上面代码中,encodeURIComponent()会连 URL 元字符一起转义,所以如果转码整个 URL 就会出错。
2.3 decodeURI()
decodeURI()方法用于整个 URL 的解码。它是encodeURI()方法的逆运算。它接受一个参数,就是转码后的 URL:
![ae9187b6ba240fc35149ab10d0fa380d.png](https://i-blog.csdnimg.cn/blog_migrate/ce250dc1ca3bc87070e132a195492591.png)
2.4 decodeURIComponent()
decodeURIComponent()用于URL 片段的解码。它是encodeURIComponent()方法的逆运算。它接受一个参数,就是转码后的 URL 片段:
![44b4f0dfb1c2eec1d92888570c8dd3c9.png](https://i-blog.csdnimg.cn/blog_migrate/e3977bbbfc93f6fe9207261f48d0aeb2.png)
3 URL 接口
URL接口是一个构造函数,浏览器原生提供,可以用来构造、解析和编码 URL。一般情况下,通过window.URL可以拿到这个构造函数。
3.1 构造函数
URL作为构造函数,可以生成 URL 实例。它接受一个表示 URL 的字符串作为参数。如果参数不是合法的 URL,会报错。
![d7b59bbdb54b1d175d13ac6245a2445f.png](https://i-blog.csdnimg.cn/blog_migrate/16b9e399302040f415ff19e46282c6ca.png)
如果参数是另一个 URL 实例,构造函数会自动读取该实例的href属性,作为实际参数。
如果 URL 字符串是一个相对路径,那么需要表示绝对路径的第二个参数,作为计算基准:
![33dbac816435421363042330f8a96049.png](https://i-blog.csdnimg.cn/blog_migrate/d5dd8446be0c74ee6c0446a1368849ad.jpeg)
上面代码中,返回的 URL 实例的路径都是在第二个参数的基础上,切换到第一个参数得到的。最后一个例子里面,第一个参数是..,表示上层路径。
3.2 实例属性
URL 实例的属性与Location对象的属性基本一致,返回当前 URL 的信息。
- URL.href:返回整个 URL
- URL.protocol:返回协议,以冒号:结尾
- URL.hostname:返回域名
- URL.host:返回域名与端口,包含:号,默认的80和443端口会省略
- URL.port:返回端口
- URL.origin:返回协议、域名和端口
- URL.pathname:返回路径,以斜杠/开头
- URL.search:返回查询字符串,以问号?开头
- URL.searchParams:返回一个URLSearchParams实例,该属性是Location对象没有的
- URL.hash:返回片段识别符,以井号#开头
- URL.password:返回域名前面的密码
- URL.username:返回域名前面的用户名
![736d49a288f57c50466b7d801ea4363a.png](https://i-blog.csdnimg.cn/blog_migrate/e2dcd746de749533062dc2f1987e3819.jpeg)
这些属性里面,只有origin属性是只读的,其他属性都可写:
![8fdc7fcb77ca75afa61db2846d963057.png](https://i-blog.csdnimg.cn/blog_migrate/ebd7fc6488f8f98a8f7f20edf290962d.png)
上面代码中,改变 URL 实例的pathname属性和hash属性,都会实时反映在 URL 实例当中。
3.3 静态方法
(1)URL.createObjectURL()
URL.createObjectURL()方法用来为上传/下载的文件、流媒体文件生成一个 URL 字符串。这个字符串代表了File对象或Blob对象的 URL:
![c0121f45550399d22d1ef609a9e434c4.png](https://i-blog.csdnimg.cn/blog_migrate/6d564f0dff6474bc3edaa9e95182999b.jpeg)
![b193a0856270270e88e40a049ae48ce5.png](https://i-blog.csdnimg.cn/blog_migrate/0d69f86e6665cc34c5601c915f5a8f50.jpeg)
上面代码中,URL.createObjectURL()方法用来为上传的文件生成一个 URL 字符串,作为<img>元素的图片来源。
该方法生成的 URL 就像下面的样子:
![703ee55131480970351d7b62910efae9.png](https://i-blog.csdnimg.cn/blog_migrate/e0d4eba6764034b907eacd8721145d0c.png)
注意,每次使用URL.createObjectURL()方法,都会在内存里面生成一个 URL 实例。如果不再需要该方法生成的 URL 字符串,为了节省内存,可以使用URL.revokeObjectURL()方法释放这个实例。
(2)URL.revokeObjectURL()
URL.revokeObjectURL()方法用来释放URL.createObjectURL()方法生成的 URL 实例。它的参数就是URL.createObjectURL()方法返回的 URL 字符串。
下面为上一段的示例加上URL.revokeObjectURL():
![2be0d3f9da19fa4a9ba51e7ea764f6a9.png](https://i-blog.csdnimg.cn/blog_migrate/b3473896ab49b590ad6da98c202bd497.jpeg)
其实仅仅是在for循环当中增加了这样的代码:
img
上面代码中,一旦图片加载成功以后,为本地文件生成的 URL 字符串就没用了,于是可以在img.onload回调函数里面,通过URL.revokeObjectURL()方法卸载这个 URL 实例。
4 URLSearchParams 对象
4.1 概念
URLSearchParams对象是浏览器的原生对象,用来构造、解析和处理 URL 的查询字符串(即 URL 问号后面的部分)。
它本身也是一个构造函数,可以生成实例。参数可以为查询字符串,起首的问号?有没有都行,也可以是对应查询字符串的数组或对象:
// 方法一:传入字符串
URLSearchParams会对查询字符串自动编码:
![0b4f80d2eb44995240574221b9ba9339.png](https://i-blog.csdnimg.cn/blog_migrate/d66ff8588ce71f74d522135e24c1de50.png)
上面代码中,foo的值是汉字,URLSearchParams对其自动进行 URL 编码。
浏览器向服务器发送表单数据时,可以直接使用URLSearchParams实例作为表单数据:
const
上面代码中,fetch命令向服务器发送命令时,可以直接使用URLSearchParams实例。
URLSearchParams可以与URL接口结合使用:
let
上面代码中,URL 实例的searchParams属性就是一个URLSearchParams实例,所以可以使用URLSearchParams接口的get方法。
URLSearchParams实例有遍历器接口,可以用for...of循环遍历(详见异步操作(3),也就是有关于遍历器的那个章节)。
![4109fb91f7cbe8f69edc7a956d23506e.png](https://i-blog.csdnimg.cn/blog_migrate/7652c87db000f1218eda4b36eaabcf3c.png)
URLSearchParams没有实例属性,只有实例方法。
4.2 URLSearchParams.toString()
toString方法返回实例的字符串形式:
![5376462bd5fc774ef1f7e58834200d28.png](https://i-blog.csdnimg.cn/blog_migrate/a077c9c1f131fdf669afbf570e8db75f.png)
那么需要字符串的场合,会自动调用toString方法:
let
上面代码中,location.href赋值时,可以直接使用params对象。这时就会自动调用toString方法。
4.3 URLSearchParams.append()
append()方法用来追加一个查询参数。它接受两个参数,第一个为键名,第二个为键值,没有返回值:
![5fdbe09a3dd7e5e92693f16e76a87d06.png](https://i-blog.csdnimg.cn/blog_migrate/9d1e5aef394142d866a441a9e07584d8.png)
append()方法不会识别是否键名已经存在:
![52b4a558d1d6f48fdc0e7186df8cb0f5.png](https://i-blog.csdnimg.cn/blog_migrate/4df2b1b72b7c451c2efcf75a767d6276.png)
上面代码中,查询字符串里面z已经存在了,但是append依然会追加一个同名键。
4.4 URLSearchParams.delete()
delete()方法用来删除指定的查询参数。它接受键名作为参数:
![df3bd2de160173560ae2286f2d3df4ab.png](https://i-blog.csdnimg.cn/blog_migrate/313c79e4780157e602c4c0cdccbfa7fd.png)
4.5 URLSearchParams.has()
has()方法返回一个布尔值,表示查询字符串是否包含指定的键名:
![12346755f2432dfa6af2c41fb85b9850.png](https://i-blog.csdnimg.cn/blog_migrate/ae645ac200bd10536327a931615f76c1.png)
4.6 URLSearchParams.set()
set()方法用来设置查询字符串的键值。
它接受两个参数,第一个是键名,第二个是键值。如果是已经存在的键,键值会被改写,否则会被追加:
![ca73216d82d14927c95b3dd4872d8674.png](https://i-blog.csdnimg.cn/blog_migrate/71deb8b7535fe1fa68b57c98f6f4f04f.png)
如果有多个的同名键,set会移除现存所有的键:
![c032510891fb29108a334ad75f9d93ec.png](https://i-blog.csdnimg.cn/blog_migrate/090abc0c777ec9e1e5cf037bdeec4fda.png)
下面是一个替换当前 URL 的例子:
// URL: https://example.com?version=1.0
4.7 URLSearchParams.get(),URLSearchParams.getAll()
get()方法用来读取查询字符串里面的指定键。它接受键名作为参数:
![cf27eed06de610656b016647f3f8eda6.png](https://i-blog.csdnimg.cn/blog_migrate/a8340c0c86892a17f421527608a62c8c.png)
两个地方需要注意。第一,它返回的是字符串,如果原始值是数值,需要转一下类型;第二,如果指定的键名不存在,返回值是null。
如果有多个的同名键,get返回位置最前面的那个键值:
![e9b517a21ed247b8968785dea72153f2.png](https://i-blog.csdnimg.cn/blog_migrate/044db941d9d5465b2f8ebb83bf7a2661.png)
上面代码中,查询字符串有两个z键,get方法返回最前面的键值996。
getAll()方法返回一个数组,成员是指定键的所有键值。它接受键名作为参数:
![59efda7fb6abe632b565905a2548a967.png](https://i-blog.csdnimg.cn/blog_migrate/2705fbb02e4b1b3f09733eeb7e13a120.png)
上面代码中,查询字符串有两个z键,getAll返回的数组就有两个成员。
4.8 URLSearchParams.sort()
sort()方法对查询字符串里面的键进行排序,规则是按照 Unicode 码点从小到大排列。
该方法没有返回值,或者说返回值是undefined:
![a4d1062b764e278a68c91550cce2a439.png](https://i-blog.csdnimg.cn/blog_migrate/6f6d95a21a482cf73b3f1fa92c115b4a.png)
上面代码中,有两个同名的键z,它们之间不会排序,而是保留原始的顺序。
4.9 URLSearchParams.keys(),URLSearchParams.values(),URLSearchParams.entries()
这三个方法都返回一个遍历器对象,供for...of循环遍历。它们的区别在于,keys方法返回的是键名的遍历器,values方法返回的是键值的遍历器,entries返回的是键值对的遍历器:
![432d6bc3c5ecc7587546fe86b0f19041.png](https://i-blog.csdnimg.cn/blog_migrate/e72df4b9075d3815099fa0a9a021ba8a.png)
如果直接对URLSearchParams进行遍历,其实内部调用的就是entries接口:
for