ES6 学习笔记,如有错误,欢迎指正。
笔记只记录了一些个人认为需要记住的知识点。
Symbol
ES6 中新增了一种数据类型 Symbol 。至此,JavaScript 有 7 种 数据类型:undefined, null , 布尔(boolean),字符串(string),数值(number), 对象 和 Symbol 。
暂时没有发现用处,研究后在补上。
Set 和 Map 数据结构
Set
ES6 提供了新的数据结构 Set。它类似于数组,但是 成员的值都是唯一的,没有重复的值。可以用来 去重 !!!!!!
Set 函数可以接受一个 数组(或者具有 iterable 接口的其他数据结构)作为 参数,用来 初始化。定义的值要放在 数组 里。
![](https://img.haomeiwen.com/i10825669/953d66f6476fdeec.jpg)
Set 实例的属性和方法
![](https://img.haomeiwen.com/i10825669/85edc00903e8fb35.jpg)
add(value):添加某个值,返回 Set 结构本身,类似 数组的 push。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear( ):清除所有成员,没有返回值。
size属性 : 获得Set值的数量,类似 数组的 length。
Set 遍历操作
Set 结构的实例有 四个 遍历方法,可以用于遍历成员。
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
由于 Set 结构没有键名,只有键值(或者说 键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
![](https://img.haomeiwen.com/i10825669/f60af62b897cdeb0.jpg)
上面代码中,entries 方法返回的遍历器,同时包括 键名 和 键值,所以每次输出一个数组,它的两个成员完全相等。
![](https://img.haomeiwen.com/i10825669/01f236f7e54e7e02.jpg)
Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
![](https://img.haomeiwen.com/i10825669/e30ba9b03de87b66.jpg)
Map 也可以接受一个 数组 作为参数。该数组的成员是一个个表示键值对的数组。
![](https://img.haomeiwen.com/i10825669/c91774f3807fa33f.jpg)
遍历方法 和 set 基本一样。
Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
就像 Vue 的 生命周期 ,Proxy 就像 钩子函数,给 目标对象 加上这些 钩子函数 或者为在执行方法前预处理一些代码。
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
![](https://img.haomeiwen.com/i10825669/87cd3b38458daf78.jpg)
target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
可以理解为
var proxy = new Proxy( { },{ } ) ;
![](https://img.haomeiwen.com/i10825669/519b2837628d4605.jpg)
上面代码中,由于设置了存值函数set,任何不符合要求的 sex 属性赋值,都会抛出一个错误,这是数据验证的一种实现方法。利用set方法,还可以数据绑定,即每当对象发生变化时,会自动更新 DOM。
get方法的两个参数分别是 目标对象 和 所要访问的属性名(接收3个参数,另外一个是proxy 实例本身)
set方法用来拦截某个属性的赋值操作。四个参数分别是 目标对象、所要访问的属性名 、属性值、Proxy 实例本身,最后一个参数可选。
Proxy 支持的拦截操作,一共13种,可以参考 阮一峰大神的 ECMAScript 6 入门,在实际运用中在进行理解。
Promise对象
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
![](https://img.haomeiwen.com/i10825669/3250fc0322870d4e.jpg)
then 方法可以接受 两个回调函数 作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用。其中,第二个函数是可选的,不一定要提供 。
then方法返回的是一个 新的Promise实例 (注意,不是原来那个Promise实例)。因此可以采用链式写法,即 then方法后面再调用另一个then方法!!!!!!
![](https://img.haomeiwen.com/i10825669/fcac739fa2ca2141.jpg)
Promise 新建后就会立即执行 !!!!!!
Promise 新建后立即执行,所以首先输出的是 Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。
![](https://img.haomeiwen.com/i10825669/71a53b3b1ed9c076.jpg)
Promise. catch ( )
Promise. catch 方法是.then(null, rejection) 的别名,用于指定发生错误时的回调函数。
![](https://img.haomeiwen.com/i10825669/31a544d92ee9a1d1.jpg)
getJSON 方法返回一个 Promise 对象,如果该对象状态变为 resolved,则会调用then方法指定的回调函数;如果 异步操作抛出错误,状态就会变为 rejected,就会调用catch方法指定的回调函数,处理这个错误。另外,then方法指定的回调函数,如果运行中 抛出错误,也会被 catch方法捕获。
建议在所有队列最后加上 .catch( ),以免漏掉错误出来造成意想不到的问题
![](https://img.haomeiwen.com/i10825669/afdcf82ffbb6802d.jpg)
promise.all ( )
用于将多个Promise 实例,包装成一个新的 Promise 实例,返回的实例就是普通的 Promise
接收一个 数组 作为参数,当所有子 Promise 都完成,该 Promise 完成,返回值是全部值的 数组,有任何一个失败,该Promise 失败,返回值是一个失败的 子Promise 的结果。
Promise . all( ) 最常见的就是和 .map( ) 连用。
promise.race( )
只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
常用用法:把异步操作和定时器放在一起,如果定时器先触发,就认为超时,告知用户
把回调包装成 promise最常见,有2个好处:
1 可读性好;2 返回的结果可以加入任何 promise 队列
Promise.resolve( )
有时需要将 现有对象 转为 Promise 对象,Promise.resolve 方法就起到这个作用。
![](https://img.haomeiwen.com/i10825669/f9d3f5f26939d6ac.jpg)
Promise.reject( )
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
![](https://img.haomeiwen.com/i10825669/b539cf08e2252a0a.jpg)
Generator 函数
Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
形式
![](https://img.haomeiwen.com/i10825669/5cf0c7ce3a2421e6.jpg)
Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用 yield 表达式,定义不同的 内部状态。
上述示例,它内部有两个yield表达式(hello 和 world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。
Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。但是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,必须调用遍历器对象的 next 方法,使得指针移向下一个状态,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的 内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着 value 和 done 两个属性的对象。value 属性表示当前的内部状态的值,是 yield 表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
遍历器对象的next方法的运行逻辑如下。
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的 value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将 return 语句后面的表达式的值,作为返回的对象的 value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
注意
(1) yield表达式只能用在 Generator 函数里面,用在其他地方都会报错。
(2)yield 表达式如果用在另一个表达式之中,必须放在 圆括号 里面。
![](https://img.haomeiwen.com/i10825669/d893659955157f44.jpg)
next 方法的参数
yield 表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该 参数就会被当作上一个yield表达式的返回值。
![](https://img.haomeiwen.com/i10825669/f7458c4c16510ff0.jpg)
由于 nex t方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数是无效的。
具体运用情形在实际运用中分析和总结。
async / await 函数 (重难点)
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句 。
返回 Promise 对象
async函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。
![](https://img.haomeiwen.com/i10825669/dd388989247e25b6.jpg)
上面代码中,函数 f 内部return命令返回的值,会被then方法回调函数接收到。
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
![](https://img.haomeiwen.com/i10825669/a6b5864c56174e85.jpg)
Promise 对象的状态变化
async 函数返回的 Promise 对象,必须等到内部 所有await命令 后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
await 命令
正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象 。
![](https://img.haomeiwen.com/i10825669/cd8f8c880db1f903.jpg)
await命令后面的 Promise 对象如果变为 reject状态,则 reject的参数 会被catch方法的回调函数接收到。
![](https://img.haomeiwen.com/i10825669/f658b3fc59cd72c1.jpg)
只要一个 await 语句后面的 Promise 变为 reject,那么整个async函数都会中断执行。
![](https://img.haomeiwen.com/i10825669/cd9cbc3aa2353ead.jpg)
有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在 try...catch 结构里面,这样不管这个异步操作是否成功,第二个await都会执行。
![](https://img.haomeiwen.com/i10825669/5bd0532d327e7a4f.jpg)
注意
(1) await 命令后面的Promise对象,运行结果可能是 rejected,所以最好把所有await命令放在try...catch代码块中。
(2) 多个await命令后面的异步操作,如果不存在继发关系(即先后触发关系),最好让它们 同时触发,可以节约 程序的时间,提高效率。
![](https://img.haomeiwen.com/i10825669/917ce1f0dd0ab457.jpg)
(3)await命令只能用在 async 函数之中(跟 yield 一样),如果用在普通函数,就会报错。
Class类的使用
JavaScript 语言中,生成实例对象的传统方法是通过构造函数。
![](https://img.haomeiwen.com/i10825669/e78673fb2ef755b0.jpg)
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
![](https://img.haomeiwen.com/i10825669/1774798ecd8bd28a.jpg)
构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。
![](https://img.haomeiwen.com/i10825669/6c37d7d9f309da96.jpg)
constructor 方法是类的 默认方法,通过new命令生成对象实例时,自动调用该方法 !!!!!!!!
一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被 默认添加,
construtor 可以用来 初始化对象。
类必须使用new调用,否则会报错。
Module 的语法
主要用于前端,后端使用 CommonJS 。CommonJS是服务器模块的规范,Node.js采用了这个规范。
模块功能主要由两个命令构成:export 和 import 。export 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。
export
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用 export关键字输出该变量。
![](https://img.haomeiwen.com/i10825669/d528e404d96bbabc.jpg)
注意规范
![](https://img.haomeiwen.com/i10825669/12a7fd081aaf72b6.jpg)
暴露方法也是一样的 export function XXX(){ } 或者 定义好方法 export { 方法名称 }
import
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过 import 命令加载这个模块。
import命令接受 一对大括号, 里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块 对外接口的名称相同。
import { 变量名1,变量名2,变量名3.......... } from 文件路径 ;
注意:
① import命令具有提升效果,会提升到整个模块的头部,首先执行。(类似于function声明)
② 由于 import 是 静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
![](https://img.haomeiwen.com/i10825669/80e6cfd4eede9a76.jpg)
③ 如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。
export default 命令
使用import命令的时候,用户需要知道所要加载的 变量名或函数名,否则无法加载。为了方便,让用户不用阅读文档就能加载模块,就要用到 export default 命令,为模块指定 默认输出 。
![](https://img.haomeiwen.com/i10825669/efcedd90a5bea786.jpg)
export default 命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此 export default 命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能唯一对应export default命令。
本质上,export default就是输出一个叫做 default的变量或方法,然后系统允许你为它取任意名字。
![](https://img.haomeiwen.com/i10825669/3b887f7a7bc3199a.jpg)
正是因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句。
同样地,因为export default 命令的本质是将后面的值,赋给 default 变量,所以可以直接将一个值写在 export default 之后。
比如,export default 100;
export 100 是错误的!!!!!
export 与 import 的复合写法
![](https://img.haomeiwen.com/i10825669/6cca5505e8d507d1.jpg)
注意
但需要注意的是,写成一行以后,foo和bar实际上并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo和bar。
总结:大部分都是 文档 的 原话摘抄, 对实际理解还是不够透彻,在实际项目和实际运用场景中在加以理解。
网友评论