迭代器(iterator)是一种统一的接口机制,它是一种接口,为不同的数据结构提供统一的访问机制,任何数据只要定义了iterator接口,就可以完成遍历操作。
在js里,一个对象中含有next()方法,并且这个next()方法返回一个对象那么这个对象就是一个迭代器,每一次调用next()方法都会返回一个包含value和done两个属性的对象,value表示数据集合当前成员的值,done是一个布尔值,表示遍历是否结束。
let arr = [1, 2, 3, 4,5];
//模拟的迭代器,使用这个迭代器遍历上面的数组
const iterator = {
// 索引,for循环遍历里的i的作用
i : 0,
next() {
return {
value : arr[this.i],
// 设置迭代状态 (后面还有没有数据)
//done为true则数组里已经没有数据结束
//false则还有数据
//i++索引自增
done : this.i++ >= arr.length
}
}
}
//来试用一下这个迭代器
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
这里要介绍一下es6的一个新遍历方法: for-of
用法和 for-in几乎一样,但是for-of无法遍历 没有iterator的数据
比如对象,数据的‘集合’Object是可以使用for-in遍历的,但是他不能使用for-of
var obj = {
name : "jack",
age : "13",
gender : "男"
}
for(const item of obj) {
console.log(item);
}
最后的结果报错: TypeError: obj is not iterable
类型错误:obj不是可以迭代的
为什么要先介绍for-of呢?
在ES6中,有些数据结构原生具备Iterator接口(比如数组)。可以被for-of遍历,但是对象就不行,原因在于,数组原生定义了Symbol.iterator属性,Symbol.iterator被称为迭代器接口,调用这个接口就可以返回一个迭代器对象
var arr = [1, 2, 3, 4];
let iter = arr[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
可以看到打印出来的对象和我们上面的自定义的迭代器返回的东西是一样的。
如果了解过解构赋值的话,就知道字符串是可以进行解构赋值的,而原理就是讲字符串转换为类数组,而类数组中是带有Symbol.iterator属性的。
function test(a,b,c){
console.log(arguments[Symbol.iterator]().next());
}
test(1,2,3);
说了那么多,我们来试一试给对象设置一个迭代器接口
var obj = {
a: '你好',
b: "我好",
c: "大家好",
[Symbol.iterator]() {
// 获取key属性名
let key = Object.keys(this);
// 设置索引
let i = 0;
return {
//防止this指想出现问题,所以使用了箭头函数
next: () => {
return {
value: {
key: key[i],
val: this[key[i]]
}
}
}
}
}
}
//这次我们再去调用for-in方法
for (const item of obj) {
console.log(item);
}
说完迭代器 那么接下来说 生成器
生成器函数可以让一个函数分段执行。
首先在function关键字和函数名之间添加一个 星号 如: function * fn()
想让函数分段执行的话,给函数中间添加yield关键字。
function* test(){
let num=0;
num+=10;
console.log(num);
console.log("这是第一段代码");
yield ;
num+=10;
console.log(num);
console.log("这是第二段代码");
yield ;
num+=10;
console.log(num);
console.log("这是第三段代码");
yield ;
num+=10;
return num;
}
var mytest=test();
console.log(mytest);
mytest.next();
mytest.next();
mytest.next();
var ret=mytest.next();
console.log("这是返回值:"+ret.value);
通常情况下 *紧挨着function写
这就是迭代器的又一个用处
生成器还是遵循原始函数的一些规则的,如果你 return的话 后面的代码就不会执行
**async function * fn();** 不可以
next是一个方法,那这个方法的参数是干什么的呢?
function* fn() {
let num = yield 2;
console.log(num);
num = yield 1 + num;
console.log(num);
yield 3;
}
const ger = fn();
console.log(ger.next(111));
console.log(ger.next(111));
console.log(ger.next(111));
也就是说传入的参数会作为yield的返回值。
在生成器内部调用其他的生成器 一定要在yield 后面加上*
function* f1(){
yield 1;
yield 2;
yield 3;
}
function* f2(){
yield* f1();
yield 4;
yield 5;
yield 6;
}
var res=f2();
console.log(res.next())
console.log(res.next())
console.log(res.next())
console.log(res.next())
console.log(res.next())
console.log(res.next())
console.log(res.next())
console.log(res.next())