JavaScript内建对象¶
约 6382 个字 513 行代码 1 张图片 预计阅读时间 28 分钟
解构赋值¶
基本使用¶
在前面进行赋值操作时,每一次只能对一个变量进行赋值,如果有很多变量,则需要依次赋值,这个过程就会很繁琐。在JavaScript中,为了解决这个问题,提出了一种新的赋值方式:解构赋值
解构赋值的基本语法如下:
| JavaScript | |
|---|---|
1 | |
例如下面的代码:
| JavaScript | |
|---|---|
1 2 | |
如果右侧为数组或者是对象也可以使用解构赋值:
| JavaScript | |
|---|---|
1 2 3 | |
但是如果右侧是数组或者对象,手动取出其中的值再进行赋值不够优雅,所以也可以直接将数组引用或者对象引用给左侧的变量,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 | |
当数组引用给左侧的变量集时,数组中的元素会依次赋值给左侧对应的变量,所以如果数组中的元素个数少于左侧的变量数,则多余的变量值为undefined,例如下面的代码
| JavaScript | |
|---|---|
1 2 3 | |
有了解构赋值,如果函数返回一个数组,则接收函数的返回值也可以使用解构赋值同时用多个变量接收函数的返回值,函数的返回值会依次填充变量,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 | |
解构赋值用于变量交换¶
在使用解构赋值交换变量中的值前,先想想之前交换变量的写法:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 | |
有了解构赋值后,就可以写成下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 | |
这个代码看似会产生变量的覆盖,但是实际上在赋值符号的右侧方括号中,变量b代表的实际上是20,变量a代表的实际上是10,在整个赋值过程中,右侧的值使用都是字面量,不会改变,所以上面的解构赋值相当于[a, b] = [20, 10];
对象的解构赋值¶
前面提到了原始值和数组的解构赋值,下面考虑如果将对象中的值通过解构赋值给指定的变量
首先需要明白的是,前面原始值和数组的解构赋值,左侧的变量名可以随意,但是在对象中,左侧的变量名必须和对象中对应的对象名相同
其次,前面原始值和数组的解构赋值使用的都是[],但是对于对象的解构赋值来说,需要使用{}
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
假设现在不希望直接使用类内的属性作为外部的变量名,则可以使用别名的方式,在对象的解构赋值中,在左侧的与类属性同名的变量后加上:+别名就可以为对应的属性取别名,后面再使用对应的变量时就可以直接使用别名,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 | |
与数组一样,如果类对象中没有指定的属性,则对应的变量就是undefined,这就是为什么上面如果不给外部属性变量取别名,就必须用与类对象中的属性名相同的变量名的原因
对象的序列化与JSON¶
在JavaScript中,有的时候希望将对象中的内容可以保存在本地或者让其他语言也可以识别通过JavaScript创建的对象,就需要用到对象的序列化
在JavaScript中,对象使用时都是存在于计算机的内存中的,序列化指将对象转换为一个可以存储的格式,而在JavaScript中,对象的序列化通常是将一个对象转换为字符串(JSON字符串)
对象的序列化一般除了上面的用途外还有一种用途:编写配置文件,例如常玩vscode的玩家应该经常看到setting.json文件
介绍完JavaScript中的对象的序列化后,下面讲解如何进行对象序列化:在JavaScript中,有一个工具类 JSON (JavaScript Object Notation) JS对象表示法,JavaScript的对象通过序列化后会转换为一个字符串,这个字符串我们称其为JSON字符串
在JSON工具类,有两个方法:
JSON.stringify():其作用是将JavaScript对象转换成JSON字符串,其参数传递一个对象,返回值是一个字符串,这个字符串满足JSON的规范JSON.parse():其作用是将符号JSON字符串规范的字符串转换成JavaScript对象,其参数传递一个JSON字符串
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
JSON字符串除了可以使用特定的工具类转换以外,还可以手动编写,但是要符合JSON字符串的规范,其规范如下:
- JSON字符串有两种类型:JSON对象
{}和JSON数组[] - JSON字符串的类型是对象或者数组时,其中可以使用的属性值(元素)
- 数字(Number)
- 字符串(String) 必须使用双引号
- 布尔值(Boolean)
- 空值(Null)
- 对象(Object
{}) - 数组(Array
[])
- JSON的格式和JavaScript对象的格式基本上一致的,注意:JSON字符串如果属性是最后一个,则不要再加
,
使用JSON进行对象的深拷贝¶
因为JSON字符串转JavaScript对象的过程是深拷贝,所以可以使用JSON进行对象的深拷贝,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | |
Map容器¶
基本介绍和使用¶
与其他变成语言一样,Map用来存储键值对结构的数据(key-value), 而Object中存储的数据就可以认为是一种键值对结构,但是二者也存在一定的区别:
- Object中的属性名只能是字符串或符号,如果传递了一个其他类型的属性名,JavaScript解释器会自动将其转换为字符串
- Map中任何类型的值都可以称为数据的
key
例如下面的Object对象:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 | |
上面代码中,需要注意的是最后一个[obj2],取obj中obj2的属性值时,使用obj[obj2]没问题,但是同样可以使用obj[{}]取obj2的属性值,因为obj2本质还是一个空对象,有的时候并不想出现这种情况,此时就可以考虑使用Map
Map中常用的方法如下:
- 构造方法
Map(),直接new则代表创建一个空Map size:Map对象属性,获取Map中键值对的数量set(key, value):Map对象方法,向Map中添加键值对get(key):Map对象方法,根据key获取值,返回key对应的valuedelete(key):Map对象方法,删除key对应的数据,返回true或者falsehas(key):Map对象方法,检查Map中是否包含指定键,返回true或者falseclear():Map对象方法,删除全部的键值对
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 | |
现在使用Map解决前面的问题:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 | |
可以使用数组中的静态方法Array.from()将Map中的内容存储到数组,其参数传递一个数组对象,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 | |
此时Map的每一个键值对就是一个一维数组,整个数组arr就是一个二维数组
Map对象的遍历¶
前面提到for-of可以遍历数组,同样,可以使用for-of遍历Map对象,因为本质for-of中的of后面跟的就是可迭代对象
需要注意,不同于数组,数组使用for-of时,for后面的变量代表是数组中的元素,而Map使用for-of时,for后面的变量代表的是Map中的键值对
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
如果想获取到Map对象中的key或者value时,则可以使用for-of遍历keys()方法的结果或者values()方法的结果,例如下面的结果:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Set容器¶
Set容器和Map容器类似,Set用来创建一个集合,不同点在于Set中的key和value相同,与数组的不同点是,Set不允许有相同的元素
Set容器基本使用如下:
- 使用
Set()构造,直接使用new Set()时创建一个空Set对象;如果在构造函数中传入可迭代的对象时,则Set会根据可迭代对象中的值构造Set,此时的Set对象不为空 size:Set对象的属性,获取Set对象中元素的数量add(key):Set对象的方法,向Set对象中添加元素has(key):Set对象的方法,检查指定的元素delete(key):Set对象的方法,删除指定元素
除了上面提到的构造方式创建Set对象以外,还可以直接向Set的构造方法中传入一个数组对象引用,即使用数组构造一个Set对象
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 | |
在上面的代码中,对于第二种方式,注意不可以是let set2 = new Set(1);,因为原始值1不是可迭代对象
其他方法的使用与Map类似,此处不再演示
Math工具类¶
在JavaScript中,存在一个Math工具类,其中提供了数学运算相关的一些常量和方法,具体内容可以见官方文档
下面基于官方文档对于常用的方法进行演示:
Math.PI:Math类中的常量,表示圆周率Math.abs():Math类中的静态方法,表示对参数中的数值取绝对值Math.min():Math类中的静态方法,表示在参数的多个值中取出最小值Math.max():Math类中的静态方法,表示在参数的多个值中取出最大值Math.pow():Math类中的静态方法,表示求幂,第一个参数为底数,第二个参数为指数(但是现在基本上用求幂运算符**)Math.sqrt():Math类中的静态方法,表示对参数中的数值求平方根Math.floor():Math类中的静态方法,表示对参数中的数值进行向下取整Math.ceil():Math类中的静态方法,表示对参数中的数值进行向上取整Math.round():Math类中的静态方法,表示对参数中的数值进行四舍五入Math.trunc():Math类中的静态方法,表示对参数中的数值的小数部分进行截断Math.random():Math类中的静态方法,表示生成0到1之间的随机数
Note
对于Math.random()来说,官方文档对其的解释是生成包含0,但不包含1的随机数,实际上生成的大部分随机数都不会为0
基本使用如下:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
对于取随机数来说,常见的公式有以下几种:
-
得到一个两数之间的随机数
JavaScript 1 2 3
function getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; } -
得到一个两数之间的随机整数
JavaScript 1 2 3 4 5 6 7 8
function getRandomInt(min, max) { const minCeiled = Math.ceil(min); const maxFloored = Math.floor(max); return Math.floor( Math.random() * (maxFloored - minCeiled) + minCeiled); // 不包含最大值,包含最小值 } -
得到一个两数之间的随机整数,包括两个数在内
JavaScript 1 2 3 4 5 6 7 8
function getRandomIntInclusive(min, max) { const minCeiled = Math.ceil(min); const maxFloored = Math.floor(max); return Math.floor( Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // 包含最小值和最大值 }
例如下面代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
日期类与格式化¶
Date类¶
在JavaScript中,同样与Java有着表示日期和时间的类:Date类。在JavaScript中,所有的和时间相关的数据都由Date对象来表示
创建Date对象时,同样使用new关键字,一般有三种方式:
new Date():直接创建一个Date对象,该对象表示当前的日期和时间new Date(表示时间的字符串):通过一个表示时间的字符串创建对象时,该对象表示的时间和日期即为指定的时间和日期,字符串的格式:月/日/年 时:分:秒或者年-月-日T时:分:秒new Date(年, 月, 日, 时, 分, 秒):通过指定的数值表示相应的字段创建对象,该对象表示的时间和日期即为指定的时间和日期
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 | |
在Date类中,也提供了一系列方法,常用的方法如下:
getFullYear():Date对象方法,获取完整的年份数值(四位数)getMonth():Date对象方法,获取月份,但是需要注意,其月份计数从0开始,所以0表示1月、1表示2月,以此类推getDate():Date对象方法,获取月份中的第几天getDay():Date对象方法,获取星期,同样,其星期计数从0开始,并且0表示周日getTime():Date对象方法,返回当前对象时间对应的时间戳now():Date静态方法,返回当前系统时间的时间戳
日期格式化¶
在JavaScript中,提供了两个Date类对象方法进行格式化:
toLocaleDateString(): 将日期转换为本地的字符串toLocaleTimeString():将时间转换为本地的字符串
但是更加常用的是:toLocaleString(),该方法根据指定格式将日期和时间转换成字符串,其参数有两个:
- 第一个参数
locales:表示缩写语言代码的字符串,或由此类字符串组成的数组,常见的缩写语言代码的字符串有: zh-CN:中文中国zh-HK:中文香港en-US:英文美国- 第二个参数
options:一个调整输出格式的对象,在对象中可以通过对象的属性来对日期的格式进行配置,常见的配置有: dateStyle和timeStyle:表示日期和时间的风格,其取值有:full、long、medium和shorthour12:表示是否使用12小时制,其取值有true和falseweekday:表示星期的显示方式,其取值有:long、short和narrowyear:表示年份的显示方式,其取值有:numeric(完整数值型)和2-digit(两位数)
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 | |
包装类¶
在Java中,每一个基本数据类型对应着各自的包装类,例如int对应Integer,在JavaScript中也不例外,原始值也对应着自己的包装类:
- String包装类:将字符串包装成String对象
- Number包装类:将数值包装成Number对象
- Boolean包装类:将布尔值包装成Boolean对象
- BigInt包装类:将大整数包装成BigInt对象
- Symbol包装类:将符号包装成Symbol对象
Note
尽管有包装类的存在,但是在JavaScript中,不推荐使用包装类的构造函数创建对应的对象
与Java一样,包装类存在的意义就是为了使原始值可以调用方法和属性。如果使用一个原始值调用方法或属性时,JavaScript解释器会临时将原始值包装为对应的对象,然后调用这个对象的属性或方法
因为原始值会被临时转换为对应的对象,这就意味着对象中的方法都可以直接通过原始值来调用,例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 | |
字符串的方法¶
在JavaScript中,字符串本质就是一个字符数组,所以它的方法与数组比较类似,详细的方法见官方文档,下面列举常用的方法:
length:String类对象的方法,获取当前字符串的长度at():String类对象的方法,表示根据索引获取字符,与[]不同的时,at()可以传递负数(目前为实验性方法)charAt():String类对象的方法,表示根据索引获取字符,但是不能传递负数concat():String类对象的方法,参数传递一个或多个字符串,表示将参数的字符串和调用对象的字符串进行拼接includes():String类对象的方法,参数传递一个字符串,表示对象字符串是否包含参数字符串,存在返回true,否则返回falseindexOf():String类对象的方法,参数传递一个字符串,表示对象字符串是否包含参数字符串,存在返回第一次出现位置的索引,否则返回-1lastIndexOf():String类对象的方法,参数传递一个字符串,表示对象字符串是否包含参数字符串,存在返回第一次出现位置的索引,否则返回-1,不同于indexOf(),lastIndexOf()是反向查找startsWith():String类对象的方法,参数传递一个字符串,表示对象字符串是否以参数字符串开头,是返回true,否则返回falseendsWith():String类对象的方法,参数传递一个字符串,表示对象字符串是否以参数字符串结尾,是返回true,否则返回falsepadStart():String类对象的方法,一共两个参数,第一个参数代表字符串的目标总长度(如果该值小于等于对象字符串的长度,则直接返回对象字符串),第二个参数代表指定的填充字符,表示在对象字符串的开头以指定字符填充,直到对象字符串的长度达到目标总长度,返回填充后的字符串padEnd():String类对象的方法,一共两个参数,第一个参数代表字符串的目标总长度(如果该值小于等于对象字符串的长度,则直接返回对象字符串),第二个参数代表指定的填充字符,表示在对象字符串的结尾以指定字符填充,直到对象字符串的长度达到目标总长度,返回填充后的字符串replace():String类对象的方法,一共两个参数,第一个参数代表匹配模式,可以传递正则表达式,也可以传递一个字符串,如果这个参数为空字符串,则默认将替换内容插入到对象字符串的开头,第二个参数代表用于替换的字符串,返回替换后的字符串。注意,如果对象字符串中有多个匹配的字符串,则当前方法只会替换第一个replaceAll():String类对象的方法,一共两个参数,第一个参数代表匹配模式,可以传递正则表达式,也可以传递一个字符串,如果这个参数为空字符串,则默认将替换内容插入到对象字符串的开头,第二个参数代表用于替换的字符串,返回替换后的字符串。本方法会替换所有匹配的字符串slice():String类对象的方法,表示对字符串进行切片,一共两个参数,使用方式与数组的slice()方法类似substring():String类对象的方法,表示截取字符串,与slice()方法使用和功能类似split():String类对象的方法,一共两个参数,第一个参数代表分隔符,第二个参数代表一个非负整数,指定数组中包含的子字符串的数量限制,表示从一个对象字符串中根据分隔符取出指定个数的子字符串存入数组中,返回该数组toLowerCase():String类对象的方法,表示将对象字符串中的字符全部转换为小写toUpperCase():String类对象的方法,表示将对象字符串中的字符全部转换为大写trim():String类对象的方法,表示去除字符串中开头和结尾的空格,注意不会去除字符串中间的空格trimStart():String类对象的方法,表示去除字符串中开头的空格,注意不会去除字符串中间的空格trimEnd():String类对象的方法,表示去除字符串中结尾的空格,注意不会去除字符串中间的空格
上面的方法使用方式与数组基本一致,不再演示,详情见官方文档
正则表达式¶
创建正则表达式¶
在关于正则表达式部分介绍过正则表达式的基本语法,在JavaScript中,有两种创建正则表达式字符串的方式
new RegExp():使用正则表达式构造函数,其可以接收两个参数(字符串),第一个参数表示正则表达式,第二个参数表示匹配模式/正则/匹配模式:使用正则表达式字面量
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 | |
正则表达式示例¶
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
正则表达式相关方法¶
正则表达式对象的截取方法:exec(),参数传递一个待检查的字符串,返回值前面的字符串表示匹配到的子字符串,index表示第一次匹配到的字符位于原始字符串的基于 0 的索引值,input表示匹配的原始字符串
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
字符串对象中与正则表达式相关的方法:
split():根据正则表达式对对象字符串进行拆分search():搜索符合正则表达式的内容第一次在字符串中出现的位置replace():根据正则表达式替换字符串中的指定内容match():根据正则表达式去匹配字符串中符合要求的内容,本方法一次只会匹配第一个符合正则表达式的字符串,如果需要匹配全部,需要在正则表达式的匹配模式中写上gmatchAll():根据正则表达式去匹配字符串中符合要求的内容(必须设置g全局匹配),它返回的是一个迭代器
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | |
Promise对象¶
Info
了解此部分内容先了解JavaScript中的定时器
在编写定时器时,因为其中需要用到回调函数,所以假设有需求:设置三个定时器,延迟2秒之后输出1, 完了之后延迟1秒输出2, 完了之后延迟1秒输出3,那么直接使用定时器写出的代码如下:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 | |
但是上面的上面的代码存在回调地狱问题,也就是回调函数的嵌套。为了解决这个问题,可以考虑使用Promise
Promise是Javascript中的对象,专门用于处理JavaScript异步编程的问题。创建Promise对象时需要一个回调函数,该函数有两个参数,第一个参数表示异步代码成功执行时调用的函数,第二个参数表示异步代码执行失败时调用的函数
Promise有三种状态: 1. Pending(等待) 2. Fulfilled(成功执行) 3. Rejected(执行失败)
这三种状态只有两种状态转换: 1. Pending->Fulfilled(表示从执行开始到成功执行) 2. Pending->Rejected(表示从执行开始到执行失败) 一旦状态确定(Fulfilled或者Rejected中的一种)就无法再改变状态(因为已经调用了对应状态的函数)
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 | |
Promise对象有then方法,该方法存在两个参数。这两个参数对应着创建Promise对象时其回调函数中的两个参数,then方法中的回调函数的参数用于接收上面resolve和reject中的参数,所以有下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 | |
直接使用Promise解决前面的需求就需要利用到then的链式调用,因为then的返回值是Promise对象,所以可以实现链式调用。同样对于上面的需求:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
如果调用不返回一个新的Promise对象,则此时需要执行的内容不确定,那么在上面的回调函数的参数的message自然也就为null:
| JavaScript | |
|---|---|
1 2 3 4 5 | |
但是很明显仅仅使用Promise还是缺少阅读性,尽管其解决了回调嵌套的问题。所以还需要结合await和async关键字,使用await和async关键字需要注意三点:
await关键字修饰包装的异步代码会直接取到resolve或者reject的参数值- 如果一个函数内部使用了
await关键字,那么这个函数就需要被async修饰 - 一个函数内部有被
await关键字修饰的多个执行语句,那么多个语句的执行顺序是有序的,即依次执行。这一个特点就让本为异步执行的定时器变成了同步
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Web存储¶
Web存储包含两种机制:
sessionStorage该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复),仅为会话存储数据,这意味着数据将一直存储到浏览器(或选项卡)关闭。数据永远不会被传输到服务器,一般存储限额大于Cookie(最大5MB)localStorage即使浏览器关闭并重新打开也仍然存在。存储的数据没有过期日期,只能通过JavaScript、清除浏览器缓存或本地存储的数据来清除
下面以localStorage为例演示Web存储的添加、删除和获取:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 8 | |
如果存取对象,就需要进行序列化和反序列化:
| JavaScript | |
|---|---|
1 2 3 4 5 6 7 | |
在浏览器调试工具界面找到Application即可看到Local Storage,此处就是通过localStorage保存的内容
JavaScript垃圾回收机制(了解)¶
垃圾回收(Garbage collection),和生活一样,生活时间长了以后会产生生活垃圾,程序运行一段时间后也会产生垃圾。如果一个对象没有任何的变量对其进行引用,那么这个对象就是一个垃圾,垃圾对象的存在,会严重的影响程序的性能
在JavaScript中有自动的垃圾回收机制,这些垃圾对象会被解释器自动回收,无需程序员手动处理,对于垃圾回收来说,程序员唯一能做的事情就是将不再使用的对象引用设置为null
例如下面的代码:
| JavaScript | |
|---|---|
1 2 3 4 5 6 | |
