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