声明变量的方法
ES6 一共有 6 种声明变量的方法。
ES5 只有两种声明变量的方法:var命令和function命令。
ES6 除了添加let和const命令,还有import命令和class命令。
var命令和function命令声明的全局变量,依旧是顶层对象的属性;let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。
var命令
全局变量和局部变量,变量提升。
function命令
声明函数
let命令
- 声明变量,不存在变量提升,变量在声明之前不可用,同一作用域不能重复声明变量。
- 块级作用域,用大括号包起来,可以声明函数,函数声明类似于var。
const命令
- 声明常量,声明后立即初始化,块级作用域,不存在常量提升,常量在声明之前不可用,同一作用域不能重复声明。
- const命令表示指向的那个内存地址所保存的数据不得改动,并不是变量的值不得改动。
- 简单类型数据:常量;引用类型:指针固定,地址不变。
变量的解构
- 按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
- “模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
- 如果解构失败,变量的值就等于undefined。
数组
- 从数组中提取值,按照对应位置,对变量赋值。
- 按次序排列的,变量的取值由它的位置决定。
- 可以设置默认值,但是只有当一个数组成员严格等于undefined,默认值才会生效。
let a = 1;
let b = 2;
let c = 3;
//等同于
let [a, b, c] = [1, 2, 3];
//不完全解构
let [x, y] = [1, 2, 3];
x // 1
y // 2
对象
- 对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
- 对象的解构赋值,先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
- 解构赋值可以取到继承的属性。
- 可以指定默认值。属性严格等于undefined,默认值生效。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
//等同于
// let{ 同名属性: 变量 } = { 同名属性: 值 }
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
//对象解构还可以写成:
//let { 对象属性, 对象属性} = 对象名
let { log, sin, cos } = Math;
字符串
字符串也可以解构赋值。因为此时,字符串被转换成了一个类似数组的对象。还可以对length属性解构赋值。
数值和布尔值
- 如果等号右边是数值和布尔值,则会先转为对象。
- 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
- 由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
函数参数
- 可以设置默认值。如果解构失败,x和y等于默认值。
圆括号
- 以下三种解构赋值不得使用圆括号:
(1)变量声明语句
(2)函数参数
(3)赋值语句的模式 - 可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。
用途
(1)交换变量的值
(2)从函数返回多个值
(3)函数参数的定义
(4)提取 JSON 数据
(5)函数参数的默认值
(6)遍历 Map 结构
(7)输入模块的指定方法
字符串
字符
将码点放入大括号,就能正确解读被放入的字符。
遍历器
for...of循环遍历
模板字符串
- 模板字符串(template string)是增强版的字符串,用反引号(`)标识。
- 它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
- 如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。
- 如果使用模板字符串表示多行字符串,所有的空格、换行和缩进都会被保留在输出之中,可以使用trim方法消除。
- 模板字符串中嵌入变量,需要将变量名写在${}之中。大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。
- 还能调用函数。如果模板字符串中的变量没有声明,将报错。
标签模板
- 模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。
- 标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。
- 如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
新增方法
String对象上的方法
- String.fromCodePoint()方法,可以识别大于0xFFFF的字符。
- String.raw()方法,可以作为处理模板字符串的基本方法,它会将所有变量替换,而且对斜杠进行转义,方便下一步作为字符串来使用。也可以作为正常的函数使用,它的第一个参数,应该是一个具有raw属性的对象,且raw属性的值应该是一个数组。
字符串实例方法
- codePointAt()方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。于那些两个字节储存的常规字符,它的返回结果与charCodeAt()方法相同。
- normalize()方法,确定一个字符串是否包含在另一个字符串中。可以接受一个参数来指定normalize的方式,参数的四个可选值如下:
- NFC,默认参数,表示“标准等价合成”(Normalization Form Canonical Composition),返回多个简单字符的合成字符。所谓“标准等价”指的是视觉和语义上的等价。
- NFD,表示“标准等价分解”(Normalization Form Canonical Decomposition),即在标准等价的前提下,返回合成字符分解的多个简单字符。
- NFKC,表示“兼容等价合成”(Normalization Form Compatibility Composition),返回合成字符。所谓“兼容等价”指的是语义上存在等价,但视觉上不等价,比如“囍”和“喜喜”。(这只是用来举例,normalize方法不能识别中文。)
- NFKD,表示“兼容等价分解”(Normalization Form Compatibility Decomposition),即在兼容等价的前提下,返回合成字符分解的多个简单字符。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
- 以上三个方法都可以传入第二个参数,表示开始搜索的位置。使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
- repeat方法返回一个新字符串,表示将原字符串重复n次。
- 参数如果是小数,会被取整,如果是负数或者Infinity,会报错。参数NaN等同于 0。如果repeat的参数是字符串,则会先转换成数字。
- padStart(),padEnd() 方法,如果某个字符串不够指定长度,会在头部或尾部补全。
- padStart()用于头部补全,padEnd()用于尾部补全。
- padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。如果省略第二个参数,默认使用空格补全长度。
- trimStart()和trimEnd()方法,它们的行为与trim()一致。
- trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格,trim()消除全部的空格。它们返回的都是新字符串,不会修改原始字符串。
- matchAll()方法返回一个正则表达式在当前字符串的所有匹配。
正则
Generator 函数
- Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。
- next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。
- value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
//Generator 函数
function* gen() {
// ...
}
yield*
- yield*表示在 Generator 函数内部,调用另一个 Generator 函数。
- Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。
- yield*语句也可以跟一个异步遍历器。
Thunk 函数
- 编译器的“传名调用”实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。它是“传名调用”的一种实现策略,用来替换某个表达式。
- 在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。
- 任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。
- Thunk 函数是自动执行 Generator 函数的一种方法。Thunk 函数现在可以用于 Generator 函数的自动流程管理。
async函数
- async函数就是 Generator 函数的语法糖,将 Generator 函数的星号(*)替换成async,将yield替换成await。
- async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
- async函数内部return语句返回的值,会成为then方法回调函数的参数。只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
- async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
- 正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。
- 另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。
- await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。
async函数对 Generator 函数的改进,体现在以下四点:
(1)内置执行器。调用函数,它就会自动执行,输出最后结果。
(2)更好的语义。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)返回值是 Promise。async函数的返回值是 Promise 对象,可以用then方法指定下一步的操作。
使用注意点: - await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。
- 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。
- await命令只能用在async函数之中,如果用在普通函数,就会报错。
- async 函数可以保留运行堆栈。
遍历
- 异步遍历器的最大的语法特点,就是调用遍历器的next方法,返回的是一个 Promise 对象。
- for...of循环用于遍历同步的 Iterator 接口。新引入的for await...of循环,则是用于遍历异步的 Iterator 接口。
函数
- 异步 Generator 函数出现以后,JavaScript 就有了四种函数形式:普通函数、async 函数、Generator 函数和异步 Generator 函数。注意区分每种函数的不同之处。
- 基本上,如果是一系列按照顺序执行的异步操作(比如读取文件,然后写入新内容,再存入硬盘),可以使用 async 函数;如果是一系列产生相同数据结构的异步操作(比如一行一行读取文件),可以使用异步 Generator 函数。