21. 迭代器和生成器
1. 迭代器:
在JavaScript中,迭代器(Iterator
)是一个对象,用于在可迭代的数据结构中遍历和访问每个元素,而不必暴露该数据结构的内部结构。很多数据结构都实现了可迭代接口:字符串、数组、Map
、Set
、arguments
和NodeList
等DOM
集合类型,可以使用Symbol.iterator
方法获取它们的迭代器对象。
迭代器对象通常实现了一个next()
方法,每次调用该方法将返回一个包含两个属性的对象:value
和done
。其中,value
属性表示集合中下一个要返回的元素的值,done
属性表示是否已经到达集合的末尾。当done
属性为true
时,表示已经访问完所有元素。如:
let str = "hello"
let strIter = str[Symbol.iterator]();
console.log(strIter.next());//{value: 'h', done: false}
console.log(strIter.next());//{value: 'e', done: false}
console.log(strIter.next());//{value: 'l', done: false}
console.log(strIter.next());//{value: 'l', done: false}
console.log(strIter.next());//{value: 'o', done: false}
console.log(strIter.next());//{value: undefined, done: true}
let arr = [1,2,3]
let arrIter = arr[Symbol.iterator]();
console.log(arrIter.next());//{value: '1', done: false}
console.log(arrIter.next());//{value: '2', done: false}
console.log(arrIter.next());//{value: '3', done: false}
console.log(arrIter.next());//{value: undefined, done: true}
自定义可迭代对象
// 创建一个可迭代对象
const myObj = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return {
value: this.data[index++], done: false };
} else {
return {
value: undefined, done: true };
}
}
};
}
};
const iterator = myObj[Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
2.生成器
在JavaScript中,生成器的形式是一个函数,函数名称前面加一个星号(*)表示它是一个生成器函数。只要可以定义函数的地方,就可以定义生成器。
// 生成器函数
function* generatorFn(){
}
调用生成器函数会产成一个生成器对象,生成器对象也是迭代器,所以生成器对象也有next()方法,调用next方法会执行生成器函数中的代码,直到遇到yield关键字或者done状态为true
let gn = generatorFn()
console.log(gn);//generatorFn {<suspended>}
console.log(gn.next);//ƒ next() { [native code] }
console.log(gn.next());//{value: undefined, done: true}
function* generatorFn(){
console.log("第一段代码~");
yield "first end"
console.log("第二段代码~");
yield "second end"
console.log("第三段代码~");
return "123"
}
let gn = generatorFn()
console.log(gn.next());//第一段代码~ {value: 'first end', done: false}
console.log(gn.next());//第二段代码~ {value: 'second end', done: false}
console.log(gn.next());//第三段代码~ {value: '123', done: true}
next()方法可以传参数,这个参数会作为上一个yield语句的返回值
// next传值
function* compute(num){
console.log(num);
let n1 = yield num * 10
console.log(n1);
let n2 = yield n1 * 10
console.log(n2);
return n2
}
let numGn = compute(2)
console.log(numGn.next());//2 {value: 20, done: false}
console.log(numGn.next(3));//3 {value: 30, done: false}
console.log(numGn.next(4));//4 {value: 4, done: true}