!!本文着重主要是对ES6语法常用知识点的说明,不会讲解一些API层面的语法
1.let/const
ES5只有两种声明变量的方法: var和function
①
- var和function命令存在变量提升(var只会先提前声明 function既提前声明又定义)
- let命令不存在变量提升(const一样)
②
- var变量可以重复声明
- let变量不允许在相同作用域内重复声明(const一样)(通常说一个{}就是一个作用域)
③
- var和function命令声明的变量会提升到全局变量window对象中
- let命令声明的变量在一个叫script作用域下(const一样)
④
- 在块级作用域下 var和function声明的变量还是会提升到全局作用域下
- 在块级作用域下 let声明的变量是私有的(const一样)(在if(){}中的function命令只会声明 条件为true时才会定义)
⑤
- const声明变量的时候必须赋值 ,而且声明的变量不能改变(如果声明的是一个引用类型,则不能改变它的内存地址)
2.解构赋值
①
- 只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值
②
- 数组的解构赋值是按次序排列的;对象的属性没有次序,变量必须与属性同名
③
- 解构赋值的变量都会重新声明
bar是匹配的模式,ba才是变量;真正被赋值的是变量ba ,而不是模式bar
只有name是变量,a和b都是模式,不会被赋值
④
- 解构赋值可以设置默认值
3.模板字符串
①
- 用反引号(``)表示;如果嵌入变量需要将变量名写在 ${} 之中
4.函数的扩展
①
- 函数的默认参数
双重默认值:
②
- rest参数/扩展运算符
rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中(rest 参数之后不能再有其他参数:
- 扩展运算符(…)
③
- 箭头函数
箭头函数没有arguments;
箭头函数没有prototype属性,没有constructor,即不能用作与构造函数(不能用new关键字调用);
箭头函数没有自己this,它的this是词法的,引用的是上下文的this;
箭头函数不能用作Generator函数
5.对象的扩展
①
- 属性和值相同时,可以简写
②
- 属性名使用[ ],里面可以写变量
③
- 方法简写
var o = {
method() {
return "Hello!";
}
};
// 等同于
var o = {
method: function() {
return "Hello!";
}
};
④
- 对象的取值函数与设值函数
6.Set和WeakSet
①
- 去重,Set数据只有value,没有key
②
-
WeakSet的成员只能是对象,而不能是其他类型的值;而且WeakSet是不可遍历的
a和b的成员必须要为对象才不会报错
7.Map
①
- Map结构和Object结构类似,但是Object结构的“键”的为字符串,Map结构的“键”各种类型
的值(包括对象)都可以当作键(Object:“字符串—值”;Map:“值—值”)
Map可以接受一个数组作为参数。数组的成员是一个个表示键值对的数组
var map = new Map([
['name', '张三'],
['title', 'Author']
]);
=====>实际上执行的是下面的算法:
var items = [
['name', '张三'],
['title', 'Author']
];
var map = new Map();
items.forEach(([key, value]) => map.set(key, value));
②
- Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键
var map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
=========》
var map = new Map();
var k1 = ['a'];
var k2 = ['a'];
map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
8.Promise对象
①
- Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject (也是两个函数)
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value); //在异步操作成功时回调,并将异步操作的结果,作为参数传递出去
} else {
reject(error);//在异步操作失败时回调,并将异步操作报出的错误,作为参数传递出去
}
});
用then方法分别指定 Resolved 状态和 Reject 状态的两个回调函数:
================================================================>>>
方法1
promise.then(function(value) {
// success
}, function(error) {
// failure
});
方法2(推荐)
promise.then(function(value) {
// success
})
.catch( function(error) {
// failure
});
②
- Promise.resolve()/Promise.reject()
如果要将现有对象转为Promise对象
Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))
===================================================>>
Promise.reject('出错了');
// 等同于
new Promise((resolve, reject) => reject('出错了'))
9.Iterator和for…of循环
①
- Iterator(遍历器)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作
模拟 next 方法返回值:
②
- 对于可遍历的数据结构,ES6在内部部署了一个[Symbol.iterator]属性,它是一个函数,执行后会返回iterator对象(遍历器对象),所以拥有[Symbol.iterator]属性的对象即被视为可遍历的
默认具有iterator接口的数据结构有:Array,Map,Set,String,TypedArray(类数组),函数的 arguments 对象,NodeList 对象…
例:
变量 arr 是一个数组,原生就具有遍历器接口(部署在 arr的[Symbol.iterator] 属性上面)所以,调用这个属性并执行,就会返回一个iter的遍历器对象
③
- 一个数据结构只要部署了 [Symbol.iterator] 属性,就被视为具有iterator接口,就可以用 for…of 循环遍历它的成员。也就是说, for…of 循环内部调用的是数据结构的 Symbol.iterator 方法。
例:for…of 循环本质上就是调用这个接口产生的遍历器对象
10.Generator函数
①
- Generator 函数是一个状态机,封装了多个内部状态;执行 Generator 函数会返回一个遍历器对象(是一个遍历器对象生成函数)
上例生成器函数执行返回一个遍历器对象a,有三个状态:Liu,Jian和Feng;
遍历器对象的 next 方法的运行逻辑:
1.遇到 yield 语句,就暂停执行后面的操作,并将紧跟在 yield 后面的那个表达式的值,作为返回的对象的 value 属性值。
2.下一次调用 next 方法时,再继续往下执行,直到遇到下一个 yield 语句。
3.如果没有再遇到新的 yield 语句,就一直运行到函数结束,直到 return 语句为止,并将 return 语句后面的表达式的值,作为返回的对象的 value 属性值。
4.如果该函数没有 return 语句,则返回的对象的 value 属性值为 undefined 。
②
- next方法的参数
yield 句本身没有返回值,或者说总是返回 undefined 。 next 方法可以带一个参数,该参数就会被当作上一个 yield 语句的返回值
1.定义了一个可以无限运行的 Generator 函数 f ,如果 next 方法没有参数,每次运行到 yield 语句,变量 reset 的值总是 undefined
2.当 next 方法带一个参数 true 时,变量 reset 就被重置为这个参数(即 true ),因此 i 会等于 -1 ,下一轮循环就会从 -1 开始递增。
1.第一次调用 b 的 next 方法时,返回 x+1 的值6;
2.第二次调用 next 方法,将上一次 yield 语句的值设为12,因此 y 等于24,返回 y / 3 的值8
3.第三次调用 next 方法,将上一次 yield 语句的值设为13,因此 z 等于13,这时 x 等于5, y 等于24,所以 return 语句的值等于42
注:由于 next 方法的参数表示上一个 yield 语句的返回值,所以第一次使用 next 方法时,不能带有参数
③
- for…of 自动遍历Generator函数时生成的 Iterator 对象(会依次显示yield语句后面的值,不需要使用next方法)
*** yield* 语句在 Generator 函数内部,调用另一个 Generator 函数 ***
function *caoncat(iter1,iter2){
yield *iter1();
yield *iter2();
}
等价于
============>
function *caoncat(iter1,iter2){
for(var value of iter1()){
yield value;
}
for(var value of iter2()){
yield value;
}
}
11.async函数
①
- async 表示函数里有异步操作, await必须在async函数的上下文中,紧跟在后面的表达式需要等待结果(主要的意图是用来等待 Promise 对象的状态被 resolved,也就是为了异步操作同步化);
- async 函数的返回值是 Promise 对象,可以使用then方法指定下一步操作(只有 async 函数内部的异步操作全部执行完,除非遇到 return 语句或者抛出错误,才会执行 then 方法指定的回调函数)
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
解决办法:把 await 命令放在 try…catch 代码块中
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// hello world
②
- 多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
// 写法一(推荐)
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
***优秀的例子***
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc)); // 发送post请求
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}