ECMAScript 6+(ES6+).md
1. 前言
本篇文章主要描述ES6及ES6以上版本,并不只是ES6。
1. ECMASCript 相关介绍
1.1. 什么是 ECMA
ECMA(European Computer Manufacturers Association) 中文名称为欧洲计算机制造商协会, 这个组织的目标是评估、开发和认可电信和计算机标准。 1994 年后该组织改名为 Ecma 国际。
1.2. 什么是 ECMAScript
ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言。
1.3. 什么是 ECMA-262
Ecma 国际制定了许多标准,而 ECMA-262 只是其中的一个,所有标准列表查看
http://www.ecma-international.org/publications/standards/Standard.htm
1.4. ECMA-262 历史
ECMA-262(ECMAScript)历史版本查看网址
http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm
1.5. 谁在维护 ECMA-262
TC39(Technical Committee 39) 是推进 ECMAScript 发展的委员会。其会员都是
公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。 TC39 定期
召开会议,会议由会员公司的代表与特邀专家出席
1.6. 为什么要学习 ES6
- ES6 的版本变动内容最多,具有里程碑意义
- ES6 加入许多新的语法特性,编程实现更简单、高效
- ES6 是前端发展趋势,就业必备技能
1.7. ES6 兼容性
http://kangax.github.io/compat-table/es6/
2. ECMASript 6 新特性
2.1. let 关键字
let 关键字用来声明变量,使用 let 声明的变量有几个特点:
- 不允许重复声明
- 块儿级作用域
- 不存在变量提升
- 不影响作用域链
应用场景:以后声明变量使用 let 就对了
具体原理?JavaScript 预编译、全局对象(GO)、活动对象(AO)、执行上下文
2.2. const 关键字
const 关键字用来声明常量, const 声明有以下特点
- 声明必须赋初始值
- 标识符一般为大写
- 不允许重复声明
- 值不允许修改
- 块儿级作用域
具体原理?JavaScript 预编译、全局对象(GO)、活动对象(AO)、执行上下文
2.3. 变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称
为解构赋值。
1 | //数组的解构赋值 |
2.4. 模板字符串
模板字符串(template string)是增强版的字符串, 用反引号(`)标识,特点:
- 字符串中可以出现换行符
- 可以使用 ${xxx} 形式输出变量
2.5. 简化字面量创建对象
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这
样的书写更加简洁。
1 | let a = "变量a"; |
2.6. 箭头函数
ES6 允许使用「箭头」 (=>)定义函数。
1 | /** |
箭头函数的注意点:
- 如果形参只有一个,则小括号可以省略
- 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的
执行结果 - 箭头函数 this 指向声明时所在作用域下 this 的值
- 箭头函数不能作为构造函数实例化
- 不能使用 arguments
1 | /** |
2.7. rest 参数 …
ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments。
1 | /** |
2.8. spread 扩展运算符
扩展运算符(spread)也是三个点(…)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包。
1 | /** |
2.9. Symbol
2.9.1 Symbol 基本使用
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 特点:
- Symbol 的值是唯一的,用来解决命名冲突的问题。
- Symbol 值不能与其他数据进行运算。
- Symbol 定义的对象属性不能使用 for…in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名。
1 | //创建 Symbol |
注: 遇到唯一性的场景时要想到 Symbol
2.9.2 Symbol 内置值
除了定义自己使用的 Symbol 值以外, ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。 可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
- Symbol.hasInstance 当其他对象使用 instanceof 运算符,判断是否为该对
象的实例时,会调用这个方法 - Symbol.isConcatSpreadable 对象的 Symbol.isConcatSpreadable 属性等于的是一个
布尔值,表示该对象用于 Array.prototype.concat()时,
是否可以展开。 - Symbol.species 创建衍生对象时,会使用该属性
- Symbol.match 当执行 str.match(myObject) 时,如果该属性存在,会
调用它,返回该方法的返回值。 - Symbol.replace 当该对象被 str.replace(myObject)方法调用时,会返回
该方法的返回值。 - Symbol.search 当该对象被 str. search (myObject)方法调用时,会返回
该方法的返回值。 - Symbol.split 当该对象被 str. split (myObject)方法调用时,会返回该
方法的返回值。 - Symbol.iterator 对象进行 for…of 循环时,会调用 Symbol.iterator 方法,
返回该对象的默认遍历器 - Symbol.toPrimitive 该对象被转为原始类型的值时,会调用这个方法,返
回该对象对应的原始类型值。 - Symbol.toStringTag 在该对象上面调用 toString 方法时,返回该方法的返
回值 - Symbol.unscopables 该对象指定了使用 with 关键字时,哪些属性会被 with
环境排除。
2.10. 迭代器与for…of
遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
ES6 创造了一种新的遍历命令 for…of 循环, Iterator 接口主要供 for…of 消费
原生具备 iterator 接口的数据(可用 for of 遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
1
2
3
4
5
6
7
8
9
10
11
12
13
14//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
// 使用 for...of 遍历数组
for (let v of xiyou) {
console.log(v);
}
/* 输出结果
唐僧
孙悟空
猪八戒
沙僧
*/
工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回一个包含 value 和 done 属性的对象
1
2
3
4
5
6
7
8
9
10
11//声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next()); // {value: "唐僧", done: false}
console.log(iterator.next()); // {value: "孙悟空", done: false}
console.log(iterator.next()); // {value: "猪八戒", done: false}
console.log(iterator.next()); // {value: "沙僧", done: false}
console.log(iterator.next()); // {value: undefined, done: true}
注: 需要自定义遍历数据的时候,要想到迭代器。
2.11. 生成器
生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
1 | function* gen() { |
代码说明:
- 的位置没有限制
- 生成器函数返回的结果是迭代器对象,调用迭代器对象的 next 方法可以得到
yield 语句后的值 - yield 相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次 next
方法,执行一段代码 - next 方法可以传递实参,作为 yield 语句的返回值
2.12. Promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,
用来封装异步操作并可以获取其成功或失败的结果。
- Promise 构造函数:
Promise(excutor) {}
Promise.prototype.then
方法Promise.prototype.catch
方法
Promise的详细内容在《JavaScript Promise详解》。
2.13. Set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯
一的,集合实现了 iterator 接口,所以可以使用扩展运算符
和for…of…
进
行遍历,集合的属性和方法:
- size 返回集合的元素个数
- add 增加一个新元素,返回当前集合
- delete 删除元素,返回 boolean 值
- has 检测集合中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
1 | //创建一个空集合 |
2.14. Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。 但是“键”
的范围不限于字符串,各种类型的值(包括对象)都可以当作键。 Map 也实现了
iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。 Map 的属
性和方法:
- size 返回 Map 的元素个数
- set 增加一个新元素,返回当前 Map
- get 返回键名对象的键值
- has 检测 Map 中是否包含某个元素,返回 boolean 值
- clear 清空集合,返回 undefined
1 | //创建一个空 map |
2.15. 类(class)
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对
象的模板。通过 class 关键字,可以定义类。基本上, ES6 的 class 可以看作只是
一个语法糖,它的绝大部分功能, ES5 都可以做到,新的 class 写法只是让对象
原型的写法更加清晰、更像面向对象编程的语法而已。
知识点:
- class 声明类
- constructor 定义构造函数初始化
- extends 继承父类
- super 调用父级构造方法
- static 定义静态方法和属性
- 父类方法可以重写
1 | //父类 |
2.16. 新增数值(Number)的方法
2.16.1. 二进制和八进制
ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示。
2.16.2. Number.isFinite() 与 Number.isNaN()
Number.isFinite() 用来检查一个数值是否为有限的
Number.isNaN() 用来检查一个值是否为 NaN
2.16.3. Number.parseInt() 与 Number.parseFloat()
ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变。
2.16.4. Math.trunc
用于去除一个数的小数部分,返回整数部分。
2.16.5. Number.isInteger
Number.isInteger() 用来判断一个数值是否为整数
2.17. 新增Object对象的方法
ES6 新增了一些 Object 对象的方法
- Object.is() 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN)
- Object.assign() 对象的合并,将源对象的所有可枚举属性,复制到目标对象
- __proto__、 setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型
2.18. 模块化
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。
2.18.1. 模块化的好处
模块化的优势有以下几点:
- 防止命名冲突
- 代码复用
- 高维护性
2.18.2. 模块化规范产品
ES6 之前的模块化规范有:
- CommonJS => NodeJS、 Browserify
- AMD => requireJS
- CMD => seaJS
2.18.3. ES6 模块化语法
模块功能主要由两个命令构成: export 和 import。
- export 命令用于规定模块的对外接口。
- import 命令用于输入其他模块提供的功能。
JS模块化详细内容请看JavaScript 模块化
3. ECMASript 7 新特性
3.1. Array.prototype.includes
Includes 方法用来检测数组中是否包含某个元素,返回布尔类型值
3.2. 指数操作符
在 ES7 中引入指数运算符**
,用来实现幂运算,功能与 Math.pow 结果相同。
4. ECMASript 8 新特性
4.1. async 和 await
async 和 await 两种语法结合可以让异步代码像同步代码一样
4.1.1. async 函数
- async 函数的返回值为 promise 对象,
- promise 对象的结果由 async 函数执行的返回值决定
4.1.2. await 表达式
- await 必须写在 async 函数中
- await 右侧的表达式一般为 promise 对象
- await 返回的是 promise 成功的值
- await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
4.2. Object.values 和 Object.entries
- Object.values()方法返回一个给定对象的所有可枚举属性值的数组
- Object.entries()方法返回一个给定对象自身可遍历属性 [key,value] 的数组。
4.3. Object.getOwnPropertyDescriptors
该方法返回指定对象所有自身属性的描述对象
5. ECMASript 9 新特性
5.1. Rest/Spread 属性
Rest 参数与 spread 扩展运算符在 ES6 中已经引入,不过 ES6 中只针对于数组,
在 ES9 中为对象提供了像数组一样的 rest 参数和扩展运算符
1 | function connect({ host, port, ...user }) { |
5.2.正则表达式命名捕获组
ES9 允许命名捕获组使用符号?<name>
,这样获取捕获结果可读性更强。
1 | let str = '<a href="http://www.lautung.com">博客</a>'; |
5.3. 正则表达式反向断言
ES9 支持反向断言,通过对匹配结果前面的内容进行判断,对匹配进行筛选。
1 | //声明字符串 |
5.4. 正则表达式 dotAll 模式
正则表达式中点.匹配除回车外的任何单字符,标记『s』 改变这种行为,允许行终止符出现。