ES6 的迭代器和生成器是什么
生成器
生成器是创建迭代器的函数。生成器函数由 function 关键字和之后的星号(*)标识,同时还能使用新的 yield 关键字。
生成器(Generator)是一种特殊的函数,它能够生成一个可迭代对象。生成器函数使用function*关键字定义,并使用yield语句产生值。每次调用生成器函数时,它会返回一个迭代器对象,通过该对象可以逐步获取生成器函数产生的值。
一个简单的例子:
// 生成器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 调用生成器类似于调用函数,但是前者只返回一个迭代器,不执行函数内代码
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
迭代器(遍历器)
在JavaScript中,迭代器(Iterator)是一个带有
next()
方法的对象。通过在对象上实现next()
方法,可以实现对集合中的每个元素进行迭代。next()
方法返回一个包含两个属性的对象:value
表示当前迭代的值,done
表示迭代是否已经结束。
一个简单的例子:
// 遍历器生成函数
function createIterator(items) {
var i = 0;
return {
next: function() {
var done = (i >= items.length);
var value = !done ? items[i++] : undefined;
return {
done: done,
value: value
};
}
};
}
var iterator = createIterator([1, 2, 3]);
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 }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"
执行过程
function *foo(){
console.log('start')
yield 1
yield 2
}
const iter = foo()
iter.next()
// ---> start
// ---> {value: 1, done: false}
iter.next()
// ---> {value: 1, done: false}
iter.next()
// ---> {value: undefined, done: true}
- 1 调用生成器函数会返回一个迭代器(此时生成器内函数不会执行),这是他和普通函数的区别。
- 2 调用迭代器的next方法会执行生成器函数里面的代码,直到遇到 yield 停止,并跳出函数,返回一个含有yield后面值的对象({ value: undefined, done: true }),程序回到next执行位置。
- 3 继续调用迭代器的next方法会重复第二步,直到生成器里面的代码全部执行完毕,返回 { value: undefined, done: true }
Symbol.iterator
Symbol.iterator 属性对应一个函数,执行后返回当前对象的遍历器对象。每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。(MDN)
1. 原生迭代器
原生支持迭代器的数据结构:Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象。
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 }
上面例子中通过 arr[Symbol.iterator] 取到的就是原生数组的迭代器函数,执行后返回当前数组的遍历器对象 iter。调用该对象的 next 方法,在返回一个值的同时,自动将内部指针移到下一个实例。
2. 自定义迭代器
var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
[...myIterable] // [1, 2, 3]
不符合标准的迭代器
如果一个迭代器 @@iterator 没有返回一个迭代器对象( 带有next 方法的对象),那么它就是一个不符合标准的迭代器,这样的迭代器将会在运行期抛出异常,甚至非常诡异的 Bug。
var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
应用场景
- 遍历集合:通过使用迭代器和生成器,我们可以方便地遍历数组、Map、Set等数据结构中的每个元素,进行相应的操作和处理。
- 异步编程:生成器函数可以与Promise对象结合使用,实现更优雅的异步编程方式。通过使用
yield
语句暂停生成器函数的执行,可以在异步任务完成后恢复并继续执行下一步操作。 - 无限序列:有些序列可能是无限的,比如斐波那契数列。通过生成器函数,可以按需生成无限序列中的每个元素,而不必担心内存溢出或计算时间过长的问题。
总结
迭代器和生成器是JavaScript中强大的工具,它们为我们提供了一种便捷和高效的方式来处理和遍历数据集合。通过灵活运用迭代器和生成器,我们能够更好地组织和处理数据,使得代码更加简洁和可读。
参考
转载自:https://juejin.cn/post/7282962960212066365