ECMAScript 6 简介
ECMAScript 6,也称为ECMAScript2015,是ECMAScript标准的最新版本。ES6是该语言的一次重大更新,也是自2009年ES5标准化以来该语言的首次更新。目前正在主要的JavaScript引擎中实现这些功能。
有关ECMAScript 6语言的完整规范,请参阅ES6标准。
(https://262.ecma-international.org/6.0/)
ES6包括以下新功能:
- 箭头函数
- 类
- 增强对象字面量
- 模板字符串
- 解构赋值
- 默认参数、剩余参数、展开操作符
- let、const
- Iterators(迭代器)、for of
- Generators(生成器)
- unicode
- 模块
- 模块加载器(提案,未正式成为ES6的一部分)
- map、set、weakmap、weaakset
- Proxy
- Symbol
- 继承
- Promise
- Math + Number + String + Array + Object APIs
- 二进制,八进制
- Reflect API
- 尾递归
1、箭头函数
箭头是使用=>语法的函数简写。与函数不同,箭头与其周围的代码共享相同的词法this。
1. let age = [20, 22, 24, 26].map(res=>res+1) // [21, 23, 25, 27] 2. 3. // 词法 this 4. var people = { 5. name: 'zhangsan', 6. age: 23, 7. course: ['语文', '数学', '英语'], 8. getCourse () { 9. this.course.forEach(res => 10. console.log(this.name + ' 课程 ' + res) 11. ); 12. } 13. } 14. people.getCourse() 15. // zhangsan 课程 语文 16. // zhangsan 课程 数学 17. // zhangsan 课程 英语 18. 19. // 然后我们把getCourse()方法改一下 20. this.course.forEach(function(res) { 21. console.log(this.name + ' 课程 ' + res) 22. }); 23. // 课程 语文 24. // 课程 数学 25. // 课程 数学 26. // this.name 没有获取到,这时this指向windows对象
2、类
在ES6中,类是基于原型的面向对象的简单补充,类支持基于类型的继承,父级super调用,实例,静态方法,构造函数
1. class animal { 2. constructor(age) { 3. this.walk = '走'; 4. } 5. } 6. class monkey extends animal { 7. constructor(age, name) { 8. super(age); // 调用父类的constructor(age) 9. this.age = 12; 10. } 11. static defaultColor() { 12. rerun 'white' 13. } 14. } 15. let mon = new monkey(33) // 进行实例化 16. console.log(mon) // {walk: '走', age: 33} 17. monkey.defaultColor() // 'white' 这里静态方法可以直接调用,不需要实例化
3、增强对象字面量
1. var faObj = { 2. get Pname () {return '父对象'}, 3. toString () { 4. return 'String' 5. } 6. } 7. var handler = function () {return 'handler'} 8. var obj = { 9. // __proto__ 10. __proto__: faObj, 11. // 简短写法 ‘handler: handler’ 12. handler, 13. // 定义当前对象的toString() 方法 14. toString() { 15. // 调用父对象toString()方法 16. return "d " + super.toString(); 17. }, 18. // 字面量值会进行自动计算 prop_111: 111 19. [ 'prop_' + (() => 111)() ]: 111 20. }; 21. console.log(obj) 22. // {handler: f(), prop_111: 111, toString: toString(), Pname: ()}
4、模板字符串
模板字面量是用反引号(`)分隔的字面量,允许多行字符串、带嵌入表达式的字符串插值和一种叫带标签的模板的特殊结构。
1. // 多行字符串 2. console.log('string text line 1\n' + 'string text line 2'); 3. // "string text line 1 4. // string text line 2" 5. 6. // 嵌入表达式的字符串插值 7. var name = "zhangsan", age = 23; 8. console.log(`Hello ${name}, age ${age}?`) 9. // 'Hello zhangsan, age 23?' 10. 11. // 带标签的模板 12. var age = 23, sex = '男' 13. function tag (string, exp1, exp2) { 14. return `hello ${string} ${exp1} ${exp2}` 15. } 16. tag`zhangsan ${age} ${sex}` 17. // 'hello zhangsan , , 23 男'
5、解构赋值
解构赋值语法是一种 Javascript 表达式。可以将数组中的值或对象的属性取出,赋值给其他变量。
1. var [a,b,c] = [1,2,3] // 数组赋值,进行匹配 2. const obj = { a: 1, b: 2 }; 3. const { a, b } = obj; // 对象解构 4. const foo = ['one', 'two', 'three']; 5. const [red, yellow, green] = foo; // 数组解构 6. // 剩余解构 7. const { a, ...others } = { a: 1, b: 2, c: 3 }; 8. console.log(others); // { b: 2, c: 3 } 9. 10. const [first, ...others2] = [1, 2, 3]; 11. console.log(others2); // [2, 3] 12. // 变量置换 13. let a = 1,b = 2; 14. [a, b] = [b, a];
6、默认参数、剩余参数、展开操作符
1. function f(x, y=1) { // y 默认为1,如果传参,则覆盖默认值 2. return x + y; 3. } 4. f(1) == 2 // true 5. f(1, 2) == 3 // true 6. 7. function f(x, ...y) { 8. // y 是一个数据组 9. return x * y.length; 10. } 11. f(2, "hello", true, 123) == 6 12. 13. function f(x, y, z) { 14. return x + y + z; 15. } 16. // 将数组的每个元素作为参数传递 17. f(...[1,2,3]) == 6
7、let、const
let 语句声明一个块级作用域的局部变量,并可以初始化为一个值(可选)。
let 声明的变量作用域只在其声明的块或子块内部,这一点,与 var 相似。二者之间最主要的区别在于 var 声明的变量的作用域是整个封闭函数。
1. function varTest() { 2. var x = 1; 3. { 4. var x = 2; // 相同 5. console.log(x); // 2 6. } 7. console.log(x); // 2 8. } 9. function letTest() { 10. let x = 1; 11. { 12. let x = 2; // 不同 13. console.log(x); // 2 14. } 15. console.log(x); // 1 16. }
var 声明的变量会在整个封闭函数内有影响,而let之只在区块内有影响。
在全局作用域中,let 和 var 不一样,它不会在全局对象上创建属性。
1. var x = 'global'; 2. let y = 'global'; 3. console.log(this.x); // "global" 4. console.log(this.y); // undefined
在同一个函数或块作用域中重复声明同一个变量会抛出 SyntaxError。
1. if (x) { 2. let foo; 3. let foo; // SyntaxError thrown. 4. }
从一个代码块的开始直到代码执行到声明变量的行之前,let 或 const 声明的变量都处于“暂时性死区”(Temporal dead zone,TDZ)中。
1. { // TDZ starts at beginning of scope 2. console.log(bar); // undefined 3. console.log(foo); // ReferenceError 4. var bar = 1; 5. let foo = 2; // End of TDZ (for foo) 6. }
const 基本用法
常量是块级范围的,非常类似用 let 语句定义的变量。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。
常量在声明的时候可以使用大小写,但通常情况下全部用大写字母。
1. cont MY_AGE = 20; 2. MY_AGE = 20; // caught TypeError: Assignment to constant variable. 3. const MY_AGE = 20; // 尝试重新声明会报错 4. const NAAME; // Uncaught SyntaxError: Missing initializer in const declaration
常量可以定义成对象和数组
1. const MY_OBJECT = {'key': 'value'}; 2. const MY_ARRAY = []
const 声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。
8、迭代器(迭代器)、for of
for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
1. const array1 = ['a', 'b', 'c']; 2. for (const element of array1) { 3. console.log(element); 4. } 5. // a 6. // b 7. // c
迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式,当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。
1. function* fibonacci() { // 一个生成器函数 2. let [prev, curr] = [0, 1]; 3. for (;;) { // while (true) { 4. [prev, curr] = [curr, prev + curr]; 5. yield curr; 6. } 7. } 8. for (let n of fibonacci()) { 9. console.log(n); 10. // 当 n 大于 1000 时跳出循环 11. if (n >= 1000) 12. break; 13. }
迭代基于这些鸭子类型的接口(仅使用TypeScript类型语法进行说明):
1. interface IteratorResult { // 迭代器返回结果接口 2. done: boolean; 3. value: any; 4. } 5. interface Iterator { // 迭代器接口 6. next(): IteratorResult; 7. } 8. interface Iterable { // 可迭代接口 9. [Symbol.iterator](): Iterator 10. }
9、Generators(生成器)
生成器使用函数*和yield简化迭代器的编写。声明为函数*的函数返回一个Generator实例。生成器是迭代器的子类型,其中包括额外的next和throw。这些使值能够返回到生成器,因此yield是一种返回值(或抛出)的表达式形式。
Generator 构造函数并不是全局可用。Generator 的实例必须从生成器函数返回:
1. function* generator() { 2. yield 1; 3. yield 2; 4. yield 3; 5. } 6. const gen = generator(); // "Generator { }" 7. console.log(gen.next().value); // 1 8. console.log(gen.next().value); // 2 9. console.log(gen.next().value); // 3