ES6学习笔记
一、迭代器Iterator
迭代器是一个接口,能快捷的访问数据。
一个数据结构只要具有Symbol.iterator
属性,就可以认为是“可遍历的”
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
next()
方法返回一个对象,这个对象包含value
和done
两个属性,value
属性返回当前位置的成员,done
属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next
方法。
原生具备 Iterator 接口的数据结构如下
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象
二、生成器Generator
定义一个生成器函数需要在function后面加*
号
function* obj(){
}
1、yield
Generator函数每次遍历需要调用next()
方法,而next()
方法从函数头部或者上一次停下来的地方开始执行,遇到yield表达式就会暂停。所以yield表达式就是暂停标志。
遍历器对象的next方法的运行逻辑如下。
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
function* add() {
console.log('start');
let x = yield '2';
console.log('one:' + x);
let y = yield '3';
console.log('two:' + y);
return x + y;
}
const fn = add();
console.log(fn.next(20)); // start {value: '2', done: false}
console.log(fn.next(20)); // one:20 {value: '3', done: false}
console.log(fn.next(30)); // two:30 {value: 50, done: true}
console.log(fn.next()); // {value: undefined, done: true}
在这里面我们会发现,当我们第一次调用next,并赋值20的时候,x并没有被赋值,这是因为yield暂停了,只有当下一次调用next并赋值,才会对上一个赋值
2、Generator与 Iterator 接口的关系
之前我们说到,只要对象有Symbol.iterator
属性,就可以调用该方法生成一个迭代器遍历对象,那么当对象没有iterator接口,我们该如何添加?
只需要把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。
var obj = {};
obj[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...obj] // [1, 2, 3]
三、Promise
这章节看文档吧,文档写的更好
四、aysnc的用法
async 函数是什么?一句话,它就是 Generator 函数的语法糖。
作用:使异步操作更加方便
当你给函数前面加上async,这个函数就会变成Generator函数
当我们定义一个函数obj,把它变为Generator是这样的:
const obj = function* () {
const f1 = yield 1;
const f2 = yield 2;
console.log(f1);
console.log(f2);
};
当我们用async函数写是这样的:
const obj = async function() {
const f1 = await 1;
const f2 = await 2;
console.log(f1);
console.log(f2);
};
一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
1、async函数对 Generator 函数的改进,体现在以下四点:
(1)内置执行器。
Generator函数的执行必须靠执行器,所以才有了co模块,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
asyncReadFile();
上面的代码调用了asyncReadFile函数,然后它就会自动执行,输出最后结果。这完全不像Generator 函数,需要调用next方法,或者用co模块,才能真正执行,得到最后结果。(2)更好的语义。
async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。
(3)更广的适用性。
co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
(4)返回值是 Promise。
async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator对象方便多了。你可以用then方法指定下一步的操作。
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
2、返回 Promise 对象
定义的async函数,里面的return语句返回的值,会成为then方法回调函数的参数
async function f() {
return 'hello world';
}
f().then(v => console.log(v))
// "hello world"
3、await
处理异步操作有三个状态(1)Pending(进行)(2)Resolved (成功)(3)Rejected (失败)
async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log('resolve', v),
e => console.log('reject', e)
)
//reject Error: 出错了
只要await语句后面的Promise对象变为了reject状态,name整个async函数就会中断执行
假如我们希望在一个异步操作失败,但也不要中断后面的异步操作的时候,可以将第一个await放在try…catch结构里面,然后catch里面不写东西,如果出现错误,就会自动跳过当前await
async function f() {
try {
await Promise.reject('出错了');
} catch (e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v));
// hello world
await命令只能用在async函数之中,如果用在普通函数,就会报错
这一块和promise一样多看文档吧,后面我把promise学会练熟再多理解
五、class类的用法
在ES5中构造函数造类是这样的:
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
return this.name;
}
let p1 = new Person('zh',22);
console.log(p1); // Person {name: 'zh', age: 22}
在ES6中造类是这样的:
class Person1{
constructor(name,age){
this.name = name;
this.age = age;
}
sayName(){
return this.name;
}
sayAge(){
return this.age;
}
}
let p2 = new Person1('zh',22);
console.log(p2); // Person1 {name: 'zh', age: 22}
1、类的继承extends
Class可以通过extends关键字实现继承,让子类继承父类的属性和方法。
定义一个People类继承上面的Person类的方法:
class People extends Person {
constructor(name, age, color) {
super(name, age);
this.color = color;
}
}
let zh = new People('zh', 22, 'blue');
console.log(zh); // People {name: 'zh', age: 22, color: 'blue'}
super
在这里表示父类的构造函数,用来新建一个父类的实例对象。注意:super一定要写在this前面