ES6 新特性总结
- let const
- 模板字符串
- 解构赋值
- 函数的参数默认值
- Spread/Rest操作符...
- 箭头函数
- for ... of
- class类
- 导入导出
- Promise
- async/await
- Symbol
- Set集合
- 对象的简化赋值
- Set和Map数据结构
- Proxy
- Reflect
- Module
1. let const
let命令
①let和var类似,但let声明的变量只在所在地代码块最有效
②for循环计数器,就很合适使用let命令
- for循环10个代码块,每个代码块用独自的i
for (let i = 0; i < 10; i++) {
// ...
}
console.log(i); // ReferenceError: i is not defined
- for循环10个代码块,每个代码块共用一个i
for (var i = 0; i < 10; i++) {
// ...
}
console.log(i); // 10
③不存在变量提升
- var会发生变量提升,值为undefined,这种现象其实是多多少少有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用
- let为了纠正这种现象,let命令改变了语法行为
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError: b is not defined
let b = 2;
④暂时性死区
- 使用let声明的变量,当前块级区域内,无论外部的变量重名与否,都与这块级区域内的变量名无关
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
⑤let不允许重复声明
let a = 1;
let a = 2; // 报错
⑥let变量的不会绑定在window对象上(及时是在最外层定义的也不刽),而var会
- 这一点是ES6在把全局变量与顶层对象(window)的属性分割开来,之前的var是全局变量,而且会绑定在window顶层对象上,意思就是全局变量没有与顶层对象发的属性分割开来,会出现一些问题。
const命令
①const命令声明一个只读的常量,一旦声明,常量的值就不能改变 (重新赋值会报错)
②const命令声明的变量须在定义的时候就立即初始化,不能留到以后赋值(定义时不赋值会报错)
③const与let的作用域相同,只在声明所在的块级作用域有效
④const声明的常量也不进行变量提升,也存在暂时性死区
⑤const声明的常量与let一样不可以重复声明
⑥const定义的变量也不会绑定在window上,会于顶层对象window上的属性分割开来
const命令本质
- const命令实际上保证的不是变量的值不能改动,而是所保存的地址不能改动(地址指向保存的那个变量),例如简单的数据类型(number,string,boolean),改变值就相当于改变了地址,所以不能改动,而复合数据类型(Object,Array),只要不改变整体的值,就不会改变其地址,所以对象或数组内存储的数据是可以改变的。
2. 模板字符串
- 模板字符串是增强版的字符串,用反引号(`)标识。
- 使用${ }的形式添加变量 用法:
var a = "张三", b = "李四"
console.log(`我是${a},你好${b}`);
// 等同于
console.log("我是" + a + ", 你好" + b)
3. 解构赋值
数组的解构
let [a, b, c] = [1, 2, 3]
let [a, [[b], c]] = [1, [[2],3]]
let [a, , b] = [1, 2, 3] // a =1, b =3
let [a = 1, b] = [] // a = 1, b = undefined
let [a, ...b] = [1, 2, 3] // a = 1, b = [2, 3]
let [a, b, c, d, e] = "hello" // a = 'h', b = 'e', ...
let [a = 2] = [undefined] // a = 2
let [a = 3, b = a] = [] // a = 3, b = 3
let [a = 3, b = a] = [1, 2] // a = 1, b = 2
对象的结构
let { a, b } = { a: 1, b: 2 } // a = 1, b = 2
let { a: data } = { a: 123 } // data = 123
let { p: [x, { y }] } = { p: ["hello", {y: "world"}] } // x = "hello", y = "world"
let { p: [{ y }, x] } = { p: [{ y: "world" }] } // x = undefined, y = "world"
let { a, b, ...rest } = { a: 10, b: 20, c: 30, d: 40 } // rest = { c: 30, d: 40 }
let { a = 10, b = 5 } = { a: 3 } // a = 3, b = 5
let { a: aa = 10, b: bb = 5 } = { a: 3} // aa = 3, bb = 5
4. 函数的参数默认值
- ES6之前,在传参时,不能给参数设定默认值,在ES6中,函数传参时可以设置默认值
function foo(a = 1, b = 2){
console.log(a + b); // 3
}
foo() // 3
5. Spread / Rest 操作符 ...
Spread操作符
- 当...用于函数调用,传递实参,或类似的表达式中,它就是Spread操作符,它会把一个数组展开为逗号分割的元素列表
function foo(x, y, z){
console.log(x, y, z)
}
let arr = [1, 2, 3]
foo(...arr) // 1 2 3
- 当...用于函数的参数列表时,及用于形参的表示时,它就是Rest操作符,它会把...对应的实参收集到一个数组当中
function foo(...args){
console.log(args)
}
foo(1, 2, 3, 4, 5) // [1, 2, 3, 4, 5]
6. 箭头函数
箭头函数出现的目的
- 箭头函数出现的目的是为了解决this指向问题
箭头函数的特性
- 箭头函数使用" => "定义
- 箭头函数比function定义的函数更简洁,有一些简便写法
- 箭头函数本身没有绑定this,其内的this指向在定义时就确定了(指向定义时所在对象或者可以理解为指向临近的外层作用用)
- 因为箭头函数本身没有绑定this,所以不能用作构造函数
const foo = (a) => console.log(a)
foo(3) // 3
7. for ... of
for ... in
- for ... in:遍历对象的属性,及key
for ... of
- for ... of:遍历对象的属性的值,及value
8. class类
ES6的class类实际上可以看成是一个原型链的语法糖
- class的绝大部分功能,使用ES5的原型链及原型对象都可以实现
function Point(x, y){
this.x = x;
this.y = y;
}
Point.prototype.toString = function (){
return `(${this.x}, ${this.y})`
}
var p = new Point(1, 2)
console.log(p.toString()) // (1, 2)
等同于:
class Point {
constructor(x, y){
this.x = x;
this.y = y;
}
toString(){
return `(${this.x}, ${this.y})`
}
}
var p = new Point(1, 2);
console.log(p.toString())
类的继承
class Point{
}
class ColorPoint extends Point{
}
9. 导入导出
导入
- import ES6新规范
- required CommonJs的语法(CommonJs用于node)
导出
- export ES6新规范,直接通过export导出变量或内容
- exports CommonJS的语法,通过module.exports导出模块中的内容
10. Promise
Promise出现的目的
- 解决异步编程的一种方法,及解决回调地狱的问题(回调地狱问题就是,在请求到的成功回调函数里继续写函数,形成了回调地狱,层级多时代码可读性低,不好维护)
- 于是乎,Promise就出现了,通过.then()的方法来写成功后的回调函数,然后若再想操作,再写.then(),以此类推