Object 类型

大多数引用类型都是 Object 类型的实例

Object 类型示例

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
// 创建 Object 实例的方式
// 1. 使用 new 操作符
let person = new Object()
person.name = 'Nicholas'
pserson.age = 29
console.log(person)
// {
// "name": "Nicholas",
// "age": 29
// }
// 2. 对象字面量表示法
let person = {
name: 'zs',
age: 29
}
console.log(person)
// {
// "name": "zs",
// "age": 29
// }

// 定义只包含默认属性和方法的对象
let person = {}
person.name = 'Nicholas'
pserson.age = 29
console.log(person)
// {
// "name": "zs",
// "age": 29
// }

Array 类型

Array类型是JavaScript中最常用的类型。JavaScript中的数组与其他多数语言中的数组有着相当大的区别。与其他不一样的是JavaScript的数组的每一项可以保存任何类型的数据,并且数组的大小是可以动态调整的。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 创建数组
// 方式一:构造函数
let nums1 = new Array() // 创建一个空数组
// 创建已知长度的字符串
let num2 = new Array(20) // 创建一个长度为20的数组,数组的每一个元素为,undefined
console.log(num2.length, num[0]) // length属性能够得到数组的长度:20 undefined
// 注意:构造函数传数值和其他类型的区别
let num3 = new Array(3) // 创建长度为3的空数组
let str = new Array("zs") // 创建长度为1,仅有字符串类型zs元素的数组

// 方式二:字面量的方式
let num4 = [1, 2, 3] // 创建长度为3的数组
let num5 = [] // 创建空数组

检测数组

使用instanceof操作符可以确定某个对象是不是数组。

1
2
// instanceof 用法
console.log(value instanceof Array) // 返回布尔值 true/false

注意: instanceof 操作符在单一的全局执行环境中没有问题,但网页包含多个框架,拥有多个不同的全局执行环境,从而存在不同的Array构造函数,则instanceof 操作符可能无法满足需求。

为了解决instanceof操作符的不足,可以使用Array.isArray()方法。这个方法能够最终确定某个值到底是不是数组,并且不受执行环境的影响。

1
2
// Array.isArray() 方法示例
console.log(Array.isArray()) // 返回布尔值 true/false

转换方法

所有对象都具有 toLocaleString()toString()valueOf() 方法。调用 toString() 方法会返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。调用 valueOf() 返回的还是数组

1
2
3
4
5
6
// 转换方法
let names = ['zs', 'ls', 'ww'] // 定义名字数组
console.log(names.toString()) // zs,ls,ww
console.log(names.valueOf()) // ['zs', 'ls', 'ww']
console.log(names.toLocaleString()) //zs,ls,ww
console.log(names) // ['zs', 'ls', 'ww']

栈方法

JavaScript 数组提供了一种让数组行为类似于栈(LIFO Last-In-First-Out 后进先出)数据结构的方法。数组提供了 push()pop() 方法。

push() 方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后的数组长度。pop()方法则从数组末尾移除最后一项,减少数组的length,并返回移出的元素。

1
2
3
4
5
6
7
8
9
10
// push() 和 pop() 示例
let names = [] // 字面量创建空数组
let count = names.push('zs', 'ls') // 推入两个元素, count = 2
console.log(names) // [zs, ls]

count = names.push('ww')
console.log(names) // [zs, ls, ww]

let element = names.pop()
console.log(element, names, names.length) // ww, [zs, ls], 2

队列方法

队列(FIFO First-In-First-Out 先进先出)数据结构,
shift()方法能够移除数组中第一个项的元素并返回该元素,数组长度减1,

1
2
3
4
5
6
7
8
9
10
// push() 和 shift() 实现队列操作
let names = [] // 字面量创建空数组
let count = names.push('zs', 'ls') // 推入两个元素, count = 2
console.log(names) // [zs, ls]

count = names.push('ww')
console.log(names) // [zs, ls, ww]

let element = names.shift()
console.log(element, names, names.length) // zs, [ls, ww], 2

unshift()方法可以在数组前端添加任意项元素,并返回数组的长度,它与shift()方法用途相反

1
2
3
4
5
6
7
8
9
10
// pop() 和 unshift() 实现反向队列操作
let names = [] // 字面量创建空数组
let count = names.unshift('zs', 'ls') // 推入两个元素, count = 2
console.log(names) // [zs, ls]

count = names.push('ww')
console.log(names) // [ww, zs, ls]

let element = names.pop()
console.log(element, names, names.length) // ls, [ww, zs], 2

注意: unshift()传入多个元素项时时,元素项的入队的顺序不会改变

重排序方法

重排序数组的方法有:reverse()sort()

1
2
3
4
5
6
7
8
9
10
11
// 示例:
const nums = [5, 1, 3, 4, 2]
// 调用sort方法排序
const sortNums = nums.sort()
console.log(sortNums) // [1, 2, 3, 4, 5]
// 调用reverse()方法实现逆序
const reverseNums = sortNums.reverse()
console.log(reverseNums) // [5, 4, 3, 2, 1]
// sort() 方法可以传入一个函数(作为参数)实现自定义排序规则
const sortNums2 = nums.sort((value1, value2) => value2 - value1)
console.log(sortNums2) // [1, 2, 3, 4, 5]

注意:reverse()sort() 方法的返回值都是经过排序之后的数组,需要使用变量接收。

操作方法

concat() 方法可以基于当前数组中所有的项创建一个新数组。具体方式为:创建当前数组的副本,再将参数添加到副本的末尾,返回新数组。如果concat()传递一个或多个数组,则会将这些数组中的每一项都添加到结果数组中。如果传递的参数不是数组,则会被简单的天骄到数组的末尾。

1
2
3
4
5
// 示例
const names1 = ['zs', 'ls', 'ww']
const names2 = names1.concat('zl', ['atm', 'gtx'])
console.log(names1) // ['zs', 'ls', 'ww']
console.log(names2) // ['zs', 'ls', 'ww', 'zl', 'atm', 'gtx']

slice() 方法能够基于当前数组中的一个或者多个项创建一个新数组。slice() 方法可以接受一个或者两个参数,即要返回的数组的起始位置和结束位置(不包括结束位置的项)。传递一个参数时,会返回数组从起始位置到数组末尾的项。

注意: slice() 方法返回的是数组的副本,并不会改变原数组。

1
2
3
4
5
6
7
// 示例
const names1 = ['zs', 'ls', 'ww']
const names2 = names1.slice(1)
console.log(names2) // ['ls', 'ww']
const names3 = names1.slice(0, 2)
console.log(names3) // ['zs', 'ls']
console.log(names1) // ['zs', 'ls', 'ww']

注意: 如果slice()方法的参数中有一个负数,则用数组长度加上该数来确定相应的位置。

1
2
3
const names1 = ['zs', 'ls', 'ww']
const names2 = names1.slice(-2, -1) // 等价于names1.slice(3-2, 3-1)
console.log(names2) // ['ls']

splice() 方法是数组中最强大的方法,它能够实现数组的删除、插入、替换操作。

  • 删除: 可以删除任意数量的项,需要指定两个参数:要删除的第一项的位置和要删除的项数。
  • 插入: 可以向指定位置插入任意数量的项,需要三个参数:起始位置(插入的第一个项的位置)、0(表示删除0项)和要插入的项。如果需要插入多个项,可以传递第四、第五、第六…个参数。
  • 替换: 可以向指定位置插入任意数量的项,且同时删除任意数量的项,需要指定三个参数:起始位置、删除的项数、插入的项…。插入项可以和删除项不相等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 示例
const names = ['zs', 'ls', 'ww']
// 删除:删除ls
const lsname = names.splice(1, 1) // 删除索引在1的1个元素。
console.log(lsname) // [ 'ls' ]
console.log(names) // [ 'zs', 'ww' ]

//插入元素: 在 zs 后插入 atm gtx zzx
const insNames = names.splice(1, 0, 'atm', 'gtx', 'zzx') // 插入三个元素
console.log(insNames) // [],插入删除0个元素,返回空数组
console.log(names); // [ 'zs', 'atm', 'gtx', 'zzx', 'ww' ]

// 替换元素: 替换 atm 为 zsf
const repNames = names.splice(1, 1, 'zsf')
console.log(repNames); // [ 'atm' ]
console.log(names); // [ 'zs', 'zsf', 'gtx', 'zzx', 'ww' ]

位置方法

数组中的位置方法有 indexOf()lastIndexOf()。两个方法都需要传递参数:要查找的元素, 查找的起始位置(可选参数),indexOf() 从数组开头查找符合的元素,返回元素索引,lastIndexOf() 从数组的末尾开始查找符合的元素,返回元素索引, 再比较第一个参数和数组的元素项时必须严格相等(===)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 示例
const names = ['zs', 'ls', 'ww', 'ls']
// 不指定起始位置查找ww
const wwNameIndex = names.indexOf('ww')
console.log(wwNameIndex) // 2
// 指定位置查找zs
const zsNameIndex = names.indexOf('zs', 1)
console.log(zsNameIndex) // -1, 由于从索引 1 开始,跳过了 zs 因此没找到 zs 返回 -1
// 从末尾寻找ls
const lsNameIndex1 = names.lastIndexOf('ls')
console.log(lsNameIndex1) // 3, 找到第一个匹配项
// 从末尾寻找ls,指定从索引 3 开始
const lsNameIndex2 = names.lastIndexOf('ls', 2)
console.log(lsNameIndex2); // 1

迭代方法

数组拥有 5 个迭代方法。每个方法接受两个参数:要在每一项上运行的函数、运行该函数的作用域对象 – 影响 this 的值。传入方法的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。

迭代方法的作用:

  • every():对数组中的每一项运行给定函数,如果函数每一项都返回 true,则返回 true
  • filter()对数组中的每一项运行给定函数,返回该函数返回 true 的项组成的数组。
  • forEach():对数组中的每一项运行给定函数。无返回值
  • map():对数组中的每一项运行给定函数,返回每次调用的结果组成的数组
  • some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true

上面所有方法都不会修改原数组的值。

对于 every()some() 方法,它们都用来查询数组中的元素是否满足某个条件。 every() 的使用类似于 运算,当每一个元素都返回 true 时,这个方法才会返回 true 否则返回 false。而 some() 类似于 运算,只要数组中有一个元素返回true,这个方法就会返回 true,当数组中所有元素返回 false 才会返回 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 示例
const nums = [1, 2, 3, 4, 6, 8, 7, 5, 1, 5, 6, 9]
// every() 方法 对每个数组元素进行判断,结果进行与运算
const everyNums = nums.every((item, index, array) => item > 2)
console.log(everyNums) // false, 只要有一项小于 2 就会返回 false

// some() 方法 对每个数组元素进行判断,结果进行或运算
const someNums = nums.some((item, index, array) => item > 2)
console.log(someNums) // true, 只要有一项大于 2 就会返回 true

// filter 方法 对数组元素进行过滤,得到符合条件的元素组成的新数组
const filterNums = nums.filter((item, index, array) => item > 2)
console.log(filterNums); // [3, 4, 6, 8, 7, 5, 5, 6, 9] 返回所有大于 2 的项组成的新数组,原数组不变

// map() 方法 对数组元素进行操作,得到处理后的元素组成的新数组
const mapNums = nums.map((item, index, array) => item * 2)
console.log(mapNums); // [2, 4, 6, 8, 12, 16, 14, 10, 2, 10, 12, 18] 返回所有元素 * 2 后的结果组成的新数组,原数组不变

// forEach() 对数组元素进行迭代
const forEachNums = nums.forEach((item, index, array) => {
// 执行某些操作
})

缩小方法

数组的缩小方法有:reduce()reduceRight()。这两个方法也会迭代数组的每一项,reduce() 从数组第一项开始遍历,reduceRight() 从数组的最后一项开始遍历。两个方法都接收四个参数:前一个值、当前值、当前项的索引和数组对象。第一次迭代发生在第二个项上,此时第一项作为第一个参数传递到方法中。这个方法会把前一次执行的返回值作为第一个参数传递到方法中执行(方便进行统计运算)。

1
2
3
4
5
6
7
8
// 示例
// reduce() 方法
const nums = [1, 2, 3, 4, 5]
const sumNums = nums.reduce((prev, cur, index, array) => prev + cur)
console.log(sumNums) // 15 = ((((1 + 2) + 3) + 4) + 5)
// reduceRight() 方法
const sumNums2 = nums.reduceRight((prev, cur, index, array) => prev + cur)
console.log(sumNums2) // 15 = ((((5 + 4) + 3) + 2) + 1)

Date 类型

ES5 中的 Date 类型是在早期 Java 中的 java.util.Date 类的基础上构建的。Date 类型使用自 UTC(Coordinated Universal Time, 国际协调时间) 197011日午夜(零时)开始经过的毫秒数来保存日期。Date 类型保存的时间能够精确到197011之前或者之后的285616年。

1
2
3
4
5
6
7
// node中得到的是美国时间
// 创建一个日期对象
let now = new Date()
console.log(now) // 2022-03-23T07:39:32.740Z 得到当前时间
// 创造指定日期和时间的日期对象
let ago = new Date('2022-03-23T15:54:00')
console.log(ago) // 2022-03-22T16:00:00.000Z

得到时间的方法有:Date.parse()Date.UTC()

1
2
3
4
5
6
7
8
9
10
11
// 示例
// Date.UTC()
let date1 = new Date(Date.UTC(2000, 0))
console.log(date1); // 2000-01-01T00:00:00.000Z
let date2 = new Date(Date.UTC(2022, 2, 23, 16, 13, 0))
console.log(date2) // 2022-03-23T16:13:00.000Z
// Date.parse()
let date3 = new Date(Date.parse('2022-03-23 16:15:00'))
console.log(date3) // 2022-03-23T08:15:00.000Z

let time = Date.now() // 1648023615403 返回当前时间的时间戳,单位 秒

注意:在调用Date构造方法时传入日期字符串会自动调用 Date.parse(),在调用Date.UTC()构造日期时,月份是从 0 开始。

继承的方法

Date类型也重写了 toLocaleString()toString()valueOf() 方法。Date类型的toLocaleString()方法会按照浏览器设置的地区相适应的格式返回日期和时间。toString() 方法会返回带有时区信息的日期和时间。valueOf() 方法可以用于比较日期的值。

1
2
3
4
5
6
// 比较日期
let date1 = new Date(2020, 0, 0)

let date2 = new Date(2022, 0, 0)

console.log(date1 < date2);

日期格式化方法

Date 类型有一些专门用将日期格式化为字符串的方法:

  • toDateString() —— 以特定于实现的格式显示星期几、月、日和年
  • toTimeString() —— 以特定于实现的格式显示时、分、秒和时区
  • toLocalDateString() —— 以特定于地区的格式显示星期几、月、日和年
  • toLocalTimeString() —— 以特定于地区的格式显示时、分、秒
  • toUTCString() —— 以特定于实现的格式完整的UTC日期

toLocaleString()toString() 方法一样,以上这些字符串格式方法输出也是因浏览器的不同而不同的。

1
2
3
4
5
6
let date = new Date()
console.log(date.toDateString()) // Wed Mar 23 2022
console.log(date.toTimeString()) // 19:20:28 GMT+0800 (中国标准时间)
console.log(date.toLocaleDateString()) // 2022/3/23
console.log(date.toLocaleTimeString()) // 19:20:28
console.log(date.toUTCString()) // Wed, 23 Mar 2022 11:20:28 GMT

日期/时间组件方法

Date类型有许多方法,能够帮助开发者获得日期中的特定部分。

方法 说明
getTime() 返回日期的毫秒数;与valueOf()方法返回的值相同
setTime(毫秒) 以毫秒设置日期,会改变整个日期
getFullYear() 取得4位数年份
getUTCFullYear() 返回UTC日期的4位年份
setFullYear(年) 设置日期的年份,传入的年份值必须是4位数字
setUTCFullYear(年) 设置UTC日期的年份。传入的年份值必须是4位数字
getMonth() 返回日期中的月份,其中0表示一月,11表示十二月
getUTCMonth() 返回UTC日期中的月份,其中0表示一月,11表示十二月
setMonth(月) 设置日期的月份。传入的月份值必必须大于0,超过11则郑家年份
setUTCMonth(月) 设置UTC日期的月份。传入的月份值必必须大于0,超过11则郑家年份
getDate() 返回日期月份中的天数(1到31)。
getUTCDate() 返回UTC日期月份中的天数(1到31) 。
setDate(日) 设置日期的月份中的天数,如果传入的值超过了该月中应有的天数,则增加月份
setUTCDate() 设置UTC日期的月份中的天数,如果传入的值超过了该月中应有的天数,则增加月份
getDay() 返回日期中星期几(其中0表示星期日,6表示星期六)
getUTCDay() 返回UTC日期中星期几(其中0表示星期日,6表示星期六)
getHours() 返回日期中的小时数(0到23)
getUTCHours() 返回UTC日期中的小时数(0到23)
setHours(时) 设置日期中的小时数。传入的值超过了23则增加月份中的天数
setUTCHours(时) 设置UTC日期中的小时数。传入的值超过了23则增加月份中的天数
getMinutes() 返回日期中的分钟数
getUTCMinutes() 返回UTC日期中的分钟数
setMinutes(分) 设置日期中的分钟数,传入的值超过59则增加小时
setUTCMinutes(分) 设置UTC日期中的分钟数,传入的值超过59则增加小时
getSeconds() 返回日期中的秒数(0到59)
getUTCSeconds() 返回UTC日期中的秒数(0到59)
setSeconds(秒) 设置日期中的秒数,传入的值超过59会增加分钟数
setUTCSeconds(秒) 设置UTC日期中的秒数,传入的值超过59会增加分钟数
getMilliseconds() 返回日期中的毫秒数
getUTCMilliseconds() 返回UTC日期中的毫秒数
setMilliseconds(毫秒) 设置日期中的毫秒数
setUTCMilliseconds(毫秒) 设置UTC日期中的毫秒数
getTimezoneOffset() 返回本地时间与UTC时间相差的分钟数

RegExp 类型

JavaScript 通过 RegExp 类型来支持正则表达式。创建正则表达式:

1
const expression = / pattern / flags

正则表达式中的模式(pattern)部分可以是任何简单或者复杂的正则表达式,可以包含字符类、限定符、分组、向前查找及反向引用。每个正则表达式都可以带有一胡总多个标志(flag),用来表示正则表达式的行为。

正则表达式的修饰符

正则表达式的匹配模式的3个标志:

  • g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止
  • i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式于字符串的大小写
  • m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中舒服存在与模式匹配的项
1
2
3
4
5
6
7
8
// 全局模式
const pattern1 = /a/g

// 不区分大小写模式
const pattern2 = /a/i

// 多行模式
const patterb3 = /a/m

正则表达式模式

方括号

表达式 模式
[abc] 查找方括号之间的任何字符
[^abc] 查找任何不在方括号之间发字符
[0-9] 查找任何从09的数字
[a-z] 查找任何从小写a到小写z的字符
[A-Z] 查找任何从大写A到大写Z的字符
[A-z] 查找任何从大写A到小写z的字符
[adgk] 查找给定集合的任何字符
[^adgk] 查找给定集合外的任何字符
`(a b

元字符

元字符 描述
- 查找单个字符,除了换行和行结束符
\w 查找数字、字母及下划线
\W 查找非单词字符
\d 查找数字
\D 查找非数字字符
\s 查找空白字符
\S 查找非空白字符
\b 匹配单词边界
\B 匹配非单词边界
\0 查找NULL字符
\n 查找换行符
\f 查找换页符
\r 查找回车符
\t 查找制表符
\v 查找垂直制表符
\xxx 查找以八进制数 xxx 规定的字符
\xdd 查找十六进制数 dd 规定的字符
\uxxxx 查找十六进制数 xxx 规定的 Unicode 字符

量词

量词 描述
n+ 匹配任何包含至少一个n的字符串
n* 匹配任何包含零个或者多个n的字符串
n? 匹配任何包含零个或者一个n的字符串
n{X} 匹配包含X个n的序列字符串
n{X,} X是一个正整数,前面的秘书n连续出现至少X次时匹配
n{X, Y} X和Y为正整数,前面的n连续出现至少X次,至多出现Y次时匹配
n$ 匹配任何结尾为n的字符串
^n 匹配任何开头为n的字符串
?=n 匹配任何其后紧接字符串n的字符串
?!n 匹配任何其后没有进阶指定字符串n的字符串

RegExp 实例属性

RegExp 的每个实例都具有下列属性:

  • global:布尔值,表示是否设置了g标志
  • ignoreCase:布尔值,表示是否设置了i标志
  • lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起
  • multiline:布尔值,表示是否设置了m标志
  • source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
1
2
3
4
5
6
7
const pattern = /a/g

console.log(pattern.global) // true
console.log(pattern.ignoreCase) // false
console.log(pattern.multiline) // false
console.log(pattern.lastIndex) // 0
console.log(pattern.source) // a

RegExp 对象方法

exec() 方法是为捕获组设计的,exec() 接收一个参数:要应用模式的字符串,返回包含第一个匹配项信息的数字,在没有匹配项的情况会返回 null。返回的数组虽然是Array实例,但包含另外两个属性:indexinputindex 表示匹配项在字符串中的位置,input 表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。

1
2
3
4
let text = 'mom and dad and bady'
const pattern = /mom (and dad (and bady)?)?/gi
const matches = pattern.exec(text)
console.log(matches); // ['mom and dad and bady', 'and dad and bady', 'and bady', index: 0, input: 'mom and dad and bady', groups: undefined]

test() 方法检查字符串中指定的值,他接受一个字符串参数,在模式与该参数匹配的情况下该返回 true 否在 false

1
2
3
4
let email = '123456789@qq.com'

const emailPaatern = /^\w+@\w+.[A-z0-9]{2,5}$/
console.log(emailPaatern.test(email)); // true

toLocaleString()toString() 方法都会返回正则表达式的字面量。

1
2
3
const pattern = new RegExp('hello .*', 'gi')
console.log(pattern.toString()); // /hello .*/gi
console.log(pattern.toLocaleString()); // /hello .*/gi

Function 类型

JavaScript中函数实际上是对象。每个函数都是Function 类型的实例,而且都与其他引用类型一样具有属性和方法。

函数名实际上是指向函数对象的指针,不会与某个函数绑定。

声明函数:

1
2
3
4
// 定义 sum 函数
function sum(a, b){
return a + b
}
1
2
3
const sum = function(a, b) {
return a + b
};
1
const sum = new Function('a', 'b', 'return a + b')

上面三种方式都可以声明一个函数,但是第三种方式不推荐使用,这种语法会导致解析两次代码(第一次是解析常规ECMAScript代码, 第二次是解析传入构造函数的字符串),影响代码的性能。

没有重载

函数名想象成为指针,可以知道ECMAScript实现重载是不现实的。

1
2
3
4
5
6
7
8
9
function sum(a, b){
return a + b + 100
}

function sum(a, b){
return a + b + 200
}

console.log(sum(10, 90)) // 300 = 10 + 90 + 200

从上面代码的结果可以看到,第二次声明的sum函数覆盖了第一次声明的sum函数,因此无法实现重载。

函数声明与函数表达式

函数声明:

1
2
3
4
console.log(sum(10, 20)) // 30
function sum(a, b) {
retrun a + b
}

函数表达式:

1
2
3
4
console.log(sum(10, 20)) // 报错
const sum = function (a, b) {
retrun a + b
}

由上面的例子我们可以看到函数声明和函数表达式的区别,实际上解析器在指向环境加载数据是,对函数声明和函数表达式的操作并不一样。解析器会先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须要等到解析器执行到它所在的代码行,才会被解释执行。这也就是为什么函数表达式的方式会出现报错的情况,解析器还没执行到函数表达式,但是已经调用函数,环境中此时没有sum函数,因此报错!

1
2
3
4
// 声明sum函数
const sum = function sum (a, b) {
return a + b
}

注意:这种写法不可取,在部分浏览器会报错

作为值的函数

ECMAScript 中的函数名是指向该函数的指针变量,因此函数可以作为值来传递。也就是说函数可以作为参数传递给另一个函数执行,也可以作为另一个函数的返回值返回。

1
2
3
4
5
6
7
8
9
// 作为值的函数
function add(num) {
return num + 10
}
function print(fun, str) {
let num = 90
console.log(add(num) + str)
}
print(add, '元') // 100元

在使用Arraysort()方法时,使用的也是同样的原理

函数内部属性

在函数内部有两个特殊的对象:argumentsthisarguments 是一个类数组对象,它包含传入函数的所有参数。arguments 还有一个名叫 callee 的属性,该属性是一个指针,指向拥有 arguments 对象的函数

1
2
3
4
5
6
7
8
9
// 阶乘函数
function factorial(num) {
if (num <= 1){
return 1
} else {
return num * arguments.callee(num - 1)
}
}
console.log(factorial(5)) // 120

这样写递归求解阶乘的函数的好处在于,无论函数的名称换成什么,都不影响函数的递归调用。

this 对象与 JavaC# 中的 this 大致类似。 this 引用的是函数的执行环境对象(当在网页的全局作用域中调用函数时, this 对象引用的就是window)

1
2
3
4
5
6
7
8
9
10
11
// node中是没有window对象的 node指向 global
window.name = 'window'
const object = {
name: 'object'
}
function sayName() {
console.log(this.name)
}
sayName() // window 默认是window调用
object.sayName = sayName
object.sayName() // object

在上面实例中,当在浏览器直接调用 sayName() 时,默认是由 window 对象调用,因此输出 window 对象的 name 属性,当把这个函数给对象 object 时,用 object.sayName() 调用该函数 此时调用者变成了 object 因此输出的 name 是 objectname 属性。

注意:函数名仅仅是指向函数的指针变量,因此,在不同的环境中执行的都是同一个函数

ECMAScript 5 也规范了另一个函数对象的属性: caller 。 除了 Opera 的早期版本不支持,其他浏览器都支持这个 ECMAScript 3 并没有定义属性。这个属性中保存着调用当前函数的引用,如果是在全局作用域中调用当前函数,它的值为 null.

1
2
3
4
5
6
7
function outer() {
inner()
}
function inner() {
console.log(inner.caller) // [Function: outer] 等价于 arguments.callee.caller
}
outer()

函数属性和方法

ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性: lengthprototype

length 属性表示函数希望接收的命名参数的个数。

1
2
3
4
5
6
7
8
function sayName(name) {
console.log(name)
}
function sum(num1, num2) {
return num1 + num2
}
console.log(sayName.length) // 1
console.log(sum.length) // 2

prototype 属性是保存它们所有实例方法的真正所在。 toString()valueOf() 等方法实际上都保持在 prototype 名下,只不过是通过各自对象的实例访问。在创建自定义引用类型及实现继承时, prototype 属性的作用是极为重要的。

ECMAScript 5 中,prototype 属性是不可枚举,因此使用 for-in 无法发现

每个函数都包含两个非继承而来的方法:apply()call() 。 这两个方法的用途都是在特定的作用域调用函数,实际上等于设置函数体内 this 对象的值。

apply() 方法接收两个参数:一个是在其中运行的函数的作用域,另一个是参数数组(可以是 Array 的实例,也可以是 argument 对象)

1
2
3
4
5
6
7
8
9
10
11
12
function sum(num1, num2) {
return num1 + num2
}
function applySum1(num1, num2) {
console.log(this); // node中为 global 浏览器中为 window
return sum.apply(this, arguments)
}
function applySum2(num1, num2) {
return sum.apply(this, [num1, num2])
}
console.log(applySum1(10, 20)) // 30
console.log(applySum2(10, 20)) // 30

注意:传入 arguments参数数组 效果相同,不使用 arguments 时,一定要将参数作为数组传入。

call()apply() 方法的作用相同,它们的区别仅在于接收参数的方式不同。 call() 方法第一个参数是 this ,其余参数需要逐个传递。

1
2
3
4
5
6
7
8
function sum(num1, num2) {
return num1 + num2
}
function callSum(num1, num2) {
console.log(this); // node中为 global 浏览器中为 window
return sum.call(this, num1, num2)
}
console.log(callSum(10, 20)) // 30

apply()call() 真正强大的地方是能够扩充函数的运行环境。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 需要在浏览器环境运行,指定执行环境运行函数
window.name = 'window'
object = {
name: 'object'
}
function sayName() {
console.log(this.name)
}
sayName() // window
sayName.call(this) // window
sayName.call(window) // window
sayName.call(object) // object

sayName.apply(this) // window
sayName.apply(window) // window
sayName.apply(object) // object

ECMAScript 5 还定义了一个方法: bind() 。这个方法会创建一个函数实例, this 值会被绑定到传给 bind() 函数的值, 并返回被绑定后的函数引用。

1
2
3
4
5
6
7
8
9
10
// 需要在浏览器环境运行,指定执行环境运行函数
window.name = 'window'
object = {
name: 'object'
}
function sayName() {
console.log(this.name)
}
const objectSayName = sayName.bind(object)
objectSayName() // object

基本包装类型 Number Boolean String

ECMAScript 提供了 3 个特殊的引用类型: BooleanNumberString.

Boolean 类型

Boolean 类型是布尔值类型的引用类型。

1
2
3
// 创建一个 Boolean 对象
const boolObject = new Boolean(true)
console.log(boolObject) // true

基本数据类型和引用类型的布尔值的区别:

  • typeof 操作符对基本数据类型返回 “boolean”,对引用类型返回 “object”
  • 由于 Boolean 对象是 Boolean 类型的实例,所有使用 instanceof 操作符测试 Boolean 对象会返回 true, 而基本类型的布尔值返回 false
1
2
3
4
5
6
7
8
const falseObject  = new Boolean(false)
const res = falseObject && true
console.log(res) // true

console.log(typeof falseObject) // object
console.log(typeof false) // boolean
console.log(falseObject instanceof Boolean) // true
console.log(false instanceof Boolean) // false

建议:由于 Boolean 的特殊性,建议不要使用 Boolean 对象。

Number 类型

Number 是数值类型对应的引用类型。

1
2
// 创建一个 Number 对象。
const numObject = new Number(10)

Number 类型方法

toString() 方法可以传递一个表示基数的参数,返回数值几进制的字符串形式。

1
2
3
4
5
6
7
// Number 的 toString() 方法
let num = 10
console.log(num.toString()) // '10' 十进制(默认)
console.log(num.toString(2)) // '1010' 二进制
console.log(num.toString(8)) // '12' 八进制
console.log(num.toString(10)) // '10' 十进制
console.log(num.toString(16)) // 'a' 十六进制

toFixed() 方法能按照指定的效数位数返回数组的字符串表示

1
2
3
// Number 的 toFixed() 方法
let num = 10
console.log(num.toFixed(2)) // "10.00"

toExponential() 方法能够返回以指数表示法(数学中称为科学计数法),表示的数值的字符串形式。

1
2
3
// Number 的 toExponential() 方法
let num = 10
console.log(num.toExponential()) // 1e+1

toPrecision() 方法能够返回固定位数的数值的字符串表示,方法接收一个参数:表示数值的所有数的位数(不包括指数部分)。

1
2
3
4
5
// Number 的 toPrecision() 方法
let num = 99
console.log(num.toPrecision(1)) // 1e+2
console.log(num.toPrecision(2)) // 99
console.log(num.toPrecision(3)) // 99.0

注意:toPrecision() 方法可以表现 1 到 21 为小数,不同的浏览器能现实的范围可能不同。

1
2
3
4
5
6
const numObject  = new Number(10)

console.log(typeof numObject) // object
console.log(typeof 10) // number
console.log(numObject instanceof Number) // true
console.log(10 instanceof Number) // false

String 类型

String 类型是字符串对象的包装类。每个 String 类型的实例都有一个 length 属性

1
2
3
// 创建 String 对象
const strObject = new String('hello world')

字符方法

charAt()charCodeAt() 方法用于访问字符串中特定字符。这个两个方法都接收一个参数:需要访问的字符的索引。 charAt() 方法以单字符串的形式返回指定位置的字符(ECMAScript 中没有字符类型)。

1
2
3
4
let str = 'hello'
console.log(str.charAt(1)) // e 返回字符
console.log(str.charCodeAt(1)) // 101 返回字符编码
console.log(str[1]) // e

字符串操作方法

concat() 方法用于将一或多个字符串拼接起来,参数:一个或多个字符串,返回拼接后的字符串。

1
2
3
4
5
6
// concat() 方法的使用
let str = "hello"
let concatStr = str.concat(" world!") // 等价于 hello + world!
// 或者使用 let concatStr = str.concat(" world", "!") 等价于 hello + world + !
console.log(str) // hello
console.log(concatStr) // hello world!

slice()substr()substring() 方法会返回被操作组非常的一个子字符串。接收1~2两个参数:第一个参数指定子字符串的开始位置,第二个参数(可选参数)表示子字符串到哪里结束。 slice()substring() 的第二个参数是子字符串最后一个字符的后面的位置(不包括第二个参数的索引位置的字符)。substr() 方法的第二个参数是指定返回的字符个数。如果没有传递第二个参数,则到字符串结束位置为止。三个方法都不对元字符串做改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// slice() substr() substring() 方法的使用
let str = "hello world"
console.log(str.slice(1)) // ello world
console.log(str.substring(1)) // ello world
console.log(str.substr(1)) // ello world
console.log(str.slice(1, 7)) // ello w
console.log(str.substring(1, 7)) // ello w
console.log(str.substr(1, 7)) // ello wo

console.log(str.slice(-3)) // rld 等价于 str.slice(11 - 3)
console.log(str.substring(-3)) // hello world 等价于 str.substring(0)
console.log(str.substr(-3)) // rld 等价于 str.substr(11 - 3)
console.log(str.slice(3, -4)) // lo w 等价于 str.slice(3, 11 - 4)
console.log(str.substring(3, -4)) // hel 等价于 str.substring(3, 0) 将小数作为开始位置 等价于 str.substring(0, 3)
console.log(str.substr(3, -4)) // "" 等价于 str.substr(3, 0) 返回0个字符

注意: substr() 目前已经被弃用,当第一个参数传递负值时, slice()substr() 会自动转换为 数组长度 - 传递的值,而 substring() 会将负值自动转换为 0 。当第二个参数传递负值时,slice() 会将负值变为 数组长度 - 传递的值;substring() 会将负值转化为 0,并将较小的数作为开始位置,较大的数作为结束位置。substr() 会将负值转换为 0,然后返回 ""

字符串位置方法

indexOf()lastIndexOf() 方法是从字符串中搜索给定的子字符串,然后返回子字符串的位置(如果没有找到符合的子字符串,则返回 -1 )。indexOf() 方法从字符串的开头开始搜索,lastIndexOf() 方法在字符串的末尾开始搜索。

参数:第一个参数是需要搜索的子字符串,第二个参数的开始搜索的位置

1
2
3
4
// indexOf() 和 lastIndexOf() 方法的使用
let str = "hello world"
console.log(str.indexOf('l', 6)) // 9
console.log(str.lastIndexOf('l', 6)) // 3

trime() 方法

ECMAScript 5 为所有字符串定义了 trime() 方法。这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,并返回处理后的字符串。

1
2
3
4
5
6
7
// trime() 方法的使用
let str = " hello world ! "
console.log(str.trim()) // hello world !
console.log(str.trimStart())// hello world !
console.log(str.trimEnd()) // hello world !
console.log(str.trimLeft())//hello world !
console.log(str.trimRight()) // hello world !

注意:除了 trime() 方法外,还有 trimStart()trimLeft() 方法用于去除首部/左边的空格,trimEnd()trimRight() 方法用于去除尾部/右边的空格,在新的 ECMAScript 中,trimLeft()trimRight() 方法已被弃用

字符串大小写转换方法

toLowerCase()toLocaleLowerCase() 方法可以将字符串转换为小写, toUpperCase()toLocaleUpperCase() 方法可以将字符串转换为大写

1
2
3
4
5
6
// toLowerCase() toLocaleLowerCase() toUpperCase() toLocaleUpperCase() 方法的使用
let str = 'Hello World !'
console.log(str.toLowerCase()) // hello world !
console.log(str.toUpperCase()) // HELLO WORLD !
console.log(str.toLocaleLowerCase()) // hello world !
console.log(str.toLocaleUpperCase()) // HELLO WORLD !

字符串正则匹配

match() 方法可以用于字符串的正则匹配,参数:正则表达式 或者 RegExp 对象

1
2
3
4
5
6
7
8
// match() 方法的使用
let text = 'cat, bat, sat, fat'
const pattern = /.at/

let matches = text.match(pattern)
console.log(matches.index) // 0
console.log(matches[0]) // cat
console.log(matches.lastIndex) // undefined

search() 方法可以返回匹配项的索引,参数: 正则表达式,RegExp 对象或字符串

1
2
3
4
5
// search() 方法的使用
let text = 'cat, bat, sat, fat'
const pattern = /at/
let searchIndex = text.search(pattern)
console.log(searchIndex) // 1

replace() 方法和 replaceAll() 方法可以替换字符串匹配项。参数:第一个参数为字符串或者正则表达式,第二个参数为需要替换的字符,或者是一个函数。两个方法的区别在于 replace() 仅会替换第一个符合的字符,replaceAll() 会进行全局替换,替换所有符合条件的字符串。

1
2
3
4
5
6
7
8
9
10
// replace() 和 replaceAll() 方法的使用
let text = 'cat, bat, sat, fat'
let reText1 = text.replace('at', 'ut') // 替换第一次出现的符合字符
let reText2 = text.replaceAll('at', 'ut') // 替换所有符合的字符
let reText3 = text.replace(/at/, 'ut') // 替换第一次出现的匹配字符
let reText4 = text.replace(/at/g, 'ut') // 替换所有匹配的字符
console.log(reText1) // cut, bat, sat, fat
console.log(reText2) // cut, but, sut, fut
console.log(reText3) // cut, bat, sat, fat
console.log(reText4) // cut, but, sut, fut
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// replace() 方法传递函数的使用,实现HTML转义
function htmlEscape(text) {
return text.replce(/[<>"&]/g, (match, pos, originalText) => {
switch(match){
case '<':
return '&lt'
case '>':
return '&gt'
case '&':
return '&amp'
case '\"':
return '&quot;'
}
})
}

split() 方法可以指定分隔符将一个字符串分隔成多个子字符串,并将结果放在一个数值中。参数:第一个参数是分隔符(既可以是字符串又可以是正则表达式),第二个参数为可选参数,用于指定数组的大小。

1
2
3
4
5
6
7
8
// split() 方法的使用
const names = 'zs,ls,ww,zs,eg'
const name1 = names.split(',')
const name2 = names.split(',', 2)
const name3 = names.split(/[^\,]+/)
console.log(name1) // [ 'zs', 'ls', 'ww', 'zs', 'eg' ]
console.log(name2) // [ 'zs', 'ls' ]
console.log(name3) // [ '', ',', ',', ',', ',', '' ]

localCompare() 方法

localCompare() 能够实现两个字符串的比较,返回值有如下情况:

  • 如果字符串在字母表中应该排在字符串参数之前,则返回应一个负数(大多数情况下是-1)
  • 如果字符串等于字符串参数,则返回 0
  • 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是1)
1
2
3
4
5
// localCompare() 方法的使用
const names = 'lx'
console.log(names.localeCompare('ds')) // 1
console.log(names.localeCompare('lx')) // 0
console.log(names.localeCompare('zs')) // -1

如果你在疑惑为什么基本数据类型拥有包装类的方法,那么非常好,下面将给你展示原理:

1
2
3
4
5
6
let str = 'hello'
let s2 = str.substring(0, 3)
// 第二行实际执行
const s = new String('hello')
s2 = s.substring(0, 3)
s = null

单体内置对象

开发人员不需要显示的实例化内置对象,因为它们在执行时已经实例化了。内置对象主要包括: ObjectArrayStringGlobalMath。

Global 对象

Global 对象是全局对象,在 ECMAScript 中的 Global 对象在某种意义上是作为一个终极对象(兜底的对象)的。任何不属于其他对象的属性和方法都是属于 Global 对象的属性和方法。实际上,全局变量和全局函数,所有在全局作用域定义的属性和方法都是 Global 对象的属性。 isNaN()isFinite()parserInt() 以及 parserFloat() 都是 Global 对象的方法。

URI 编码方法

Global 对象的 encodeURI()encodeURIComponent() 方法可以对 URI(Uniform Resource Identifiers, 通用资源标识符) 进行编码,以便可以发送给浏览器(有效的URI不能包含某些字符)。

1
2
3
4
// encodeURI() 和 encodeURIComponent() 的使用
let uri = "https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990"
console.log(encodeURI(uri)) // https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990
console.log(encodeURIComponent(uri)) // https%3A%2F%2Fwww.paddlepaddle.org.cn%2Ftutorials%2Fprojectdetail%2F3465990

encodeURI()encodeURIComponent() 的区别在于 encodeURI() 只会对空格进行编码,encodeURIComponent()会对冒号、正斜杠、问号和井字号进行编码。

tips: URLURI 的区别
URL(Uniform Resource Locator) 是全球资源定位符的缩写, URL(Universal Resource Identifiers) 。两者的区别在于: URL 是由 协议 + 主机IP + 端口 + 资源地址构成, URI 是由 访问资源的机制 + 存放资源的主机名 + 资源名称构成。简单的来说, URLURI 的一个子集。

分别对应于 encodeURI()encodeURIComponent() 的两个解码方法是: decodeURI()decodeURIComponent()decodeURI() 只能对 encodeURI() 进行解码,对应的 decodeURIComponent() 只能对 encodeURIComponent() 进行解码。

1
2
3
4
5
6
7
// decodeURI() 和 decodeURIComponent() 的使用
let uri = "https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990"
let encodeUri = encodeURI(uri) // https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990
let encodeUriCom = encodeURIComponent(uri) // https%3A%2F%2Fwww.paddlepaddle.org.cn%2Ftutorials%2Fprojectdetail%2F3465990

console.log(decodeURI(encodeUri)) // https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990
console.log(decodeURIComponent(encodeUriCom)) // https://www.paddlepaddle.org.cn/tutorials/projectdetail/3465990

encodeURI()encodeURIComponent()decodeURI()decodeURIComponent() 用于替代以及弃用的 escape()unespace()

eval() 方法

eval()ECMAScript 中最强大的方法,eval() 像是一个完整的 ECMAscript 解析器,参数为: 需要执行的 ECMAscript 的代码字符串。

1
2
3
// eval() 函数的使用
let name = 'zs'
eval("console.log('someone called you, ' + name)") // someone called you, zs

Global 对象的属性

Global 对象包含的属性:

属性 说明
undefined 特殊值
NaN 特殊值
Infunity 特殊值
Object 构造函数
Array 构造函数
Function 构造函数
Boolean 构造函数
String 构造函数
Number 构造函数
Date 构造函数
RegExp 构造函数
Error 构造函数
EvalError 构造函数
RangeError 构造函数
ReferenceError 构造函数
SyntaxError 构造函数
TypeError 构造函数
URIError 构造函数

windows 对象

ECMAScript 虽然没有指出如何直接访问 Global 对象,但 Web 浏览器都是将这个全局对象作为 window 对象的一部分加以实现。因此,全局作用域中声明的所有变量和函数,都成为了 window 对象的属性。

1
2
3
4
5
6
7
8
9
10
11
12
// window 对象
val name = 'zs' //
function sayName() {
console.log(window.name)
}
window.sayName() // zs

// 获取 Global 对象
var global = function() {
return this
}
console.log(global())

Math 对象

ECMAScript 提供了保存数学公式和信息的对象—— Math 对象。

Math 对象属性

属性 说明
Math.E 自然对数的底数,即常量e的值
Marh.LN10 10的自然对数
Math.LN2 2的自然对数
Math.LOG2E 2为底e的对数
Math.LOG10E 10为底e的对数
Math.PI Π 圆周率的值
Math.SQRT1_2 1/2的平方根(2的平方根的倒数)
Math.SQRT2 2的平方根

min() 和 max() 方法

min()max() 方法用于确定数值中的最小值和最大值。

1
2
3
4
5
// min() 和 max() 方法的使用
let maxNum = Math.max(1, 5, 2, 4, 3)
console.log(maxNum) // 5
let minNum = Math.min(1, 5, 2, 4, 3)
console.log(minNum) // 1

获得数组最大值可以使用 Math.max.apply(Math, values),这种做法的关键在于:把 Math 对象作为 apply() 的第一个参数,保证 this 的指向 Math ,然后将数值传入第二个参数(apply() 的第二参数必须为数组)。

1
2
3
4
5
6
// 使用 Math.max() 获得数值最大值
const array = [1, 5, 2, 4, 3]
let arrayMax = Math.max.apply(Math, array)
console.log(arrayMax) // 5
let arrayMin = Math.min.apply(Math, array)
console.log(arrayMin) // 1

舍入方法

舍入方法

  • Math.ceil() 执行向上舍入(向上取整)
  • Math.floor() 执行向下舍入(向下取整)
  • Math.round() 执行四舍五入
1
2
3
4
5
// Math.ceil()  Math.floor() Math.round() 方法的使用
let num = 22.5
console.log(Math.ceil(num)) // 23
console.log(Math.floor(num)) // 22
console.log(Math.round(num)) // 23

random() 方法

Math.random() 方法返回介于 0 和 1 之间的随机数。不包括 0 和 1。

1
2
3
4
// 获得某个范围内的随机数 val = Math.floor(Math.random() * 可能的值的数量 + 第一个可能的值)
// 获取 1 - 10 的随机数
let randomNum = Math.floor( Math.random() * 10 + 1)
console.log(randomNum) // 10, 8, 5, 5, 4, 8, 6

其他方法

方法 说明
Math.abs(num) 返回 num 的绝对值
Math.exp(num) 返回 Math.Enum 次幂
Math.log(num) 返回 num 的自然对数
Math.pow(num, power) 返回 numpower 次幂
Math.sqrt(num) 返回 num 的平方根
Math.acos(x) 返回 x 的反余弦值
Math.asin(x) 返回 x 的反正弦值
Math.atan(x) 返回 x 的反正切值
Math.atan2(y, x) 返回 y/x 的反正切值
Math.cos(x) 返回 x 的余弦值
Math.sin(x) 返回 x 的正弦值
Math.tan(x) 返回 x 的正切值