const arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++){
console.log(arr[i]);
}
注:Array.prototype.forEach() 虽然可达到迭代目的,但不能停止
好处是无需知道被迭代对象的结构即可取得值。
如果要实现Iterable接口需做到两点:
字符串、数组、映射、集合、arguments对象、NodeList等DOM集合类型都实现了Iterable接口
写代码时也不需要显式调用工厂函数,js有一些可接收可迭代对象的原生语言特性:
let arr = [1, 2, 3];
// for...of
for(const i of arr){
console.log(i);
}
// 数组结构
let [a, b, c] = arr;
// 拓展操作符
let arr2 = [...arr];
// Array.from()
let arr3 = Array.from(arr);
// Set
let set = new Set(arr);
// Map
let arr4 = arr.map((e, i) => [i, e]);
let map = new Map(arr4);
// Map(3) {0 => 1, 1 => 2, 2 => 3}
注:如果一个类是这些类的子类,那么也支持迭代
迭代器中有一个next()方法,每次调用都返回一个IterableResult对象,包含下一个返回的值。
IterableResult有两个属性 done和value:
// 可迭代对象
let arr = [‘foo‘, ‘bar‘];
// 迭代器工厂函数
console.log(arr[Symbol.iterator]); // f values(){ [native code] }
// 迭代器
let iter = arr[Symbol.iterator]();
console.log(iter); // ArrayIterator {}
// 执行迭代
console.log(iter.next()); // { done: false, value: ‘foo‘ }
console.log(iter.next()); // { done: false, value: ‘bar‘ }
console.log(iter.next()); // { done: true, value: undefined }
console.log(iter.next()); // { done: true, value: undefined } 后面一直为true
迭代器不知道迭代何时结束,只管done为true
迭代器有以下特点:
class A{
constructor(limit){
this.limit = limit;
}
[Symbol.iterator](){
let count = 1,
limit = this.limit;
return {
next(){
if(count<=limit){
return { value:count++,done:false };
}else{
return{ value:undefined,done:true };
}
},
return(){
console.log("迭代中断");
return { done:true };
},
[Symbol.iterator](){
return this;
}
}
}
}
这里采用了迭代器自引用(让迭代器本身也可以被迭代),内置对象和生成器对象都是自引用的
当发生for...of 中执行了break、continue、return和throw,或解构未消费所有的值时会提前结束迭代。
可以在迭代器中添加一个return()方法提前关闭迭代器,这个函数只能返回{done: true}
return() {
console.log(‘Exiting early‘);
return { done: true };
}
不要尝试在原生结构中添加此方法,不能实现关闭。(自己的结构测试也没效果)
生成器是ES6新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力。
// 生成器函数声明
function* generatorFn() {}
// 生成器函数表达式
let generatorFn = function* () {}
// 作为对象字面量方法的生成器函数
let foo = {
* generatorFn() {}
}
// 作为类实例方法的生成器函数
class Foo {
* generatorFn() {}
}
// 作为类静态方法的生成器函数
class Bar {
static * generatorFn() {}
}
注:无法使用箭头函数
yield关键字可以让生成器停止和开始执行,遇到这个关键字后,执行会停止,函数作用域的状态会被保留。只能通过在生成器对象上调用next()方法来恢复执行
yield关键字类似函数的中的return语句,它生成的值会出现在next()方法返回的对象里。
通过yield关键字退出的生成器函数会处在done: false状态;通过return关键字退出的生成器函数会处于done: true状态。
function* generatorFn() {
yield ‘foo‘;
yield ‘bar‘;
return ‘baz‘;
}
let generatorObject = generatorFn();
console.log(generatorObject.next()); // { done: false, value: ‘foo‘ }
console.log(generatorObject.next()); // { done: false, value: ‘bar‘ }
console.log(generatorObject.next()); // { done: true, value: ‘baz‘ }
注:yield关键字只能出现在生成器函数内部
自定义迭代对象,控制循环次数
// 1.循环计数器
function* nTimes(n) {
let i = 0;
while(n--) {
yield i++;
}
}
for (let x of nTimes(3)) {
console.log(x);
}
// 2.填充数组
function* zeroes(n) {
while(n--) {
yield 0;
}
}
console.log(Array.from(zeroes(8)));
// [0, 0, 0, 0, 0, 0, 0, 0]
// 3.生成范围
function* range(start, end) {
while(end > start) {
yield start++;
}
}
yield 表达式的值:上一次让生成器函数暂停的yield关键字会接收到传给next()方法的值。(也就是说第一次调用next() 值传不过去)
function* generatorFn(initial) {
console.log(initial);
console.log(yield);
console.log(yield);
}
let generatorObject = generatorFn(‘foo‘);
generatorObject.next(‘bar‘); // foo 第一次无法传
generatorObject.next(‘baz‘); // baz
generatorObject.next(‘qux‘); // qux
例二:
function* generatorFn() {
return yield ‘foo‘;
}
let generatorObject = generatorFn();
console.log(generatorObject.next());
// { done: false, value: ‘foo‘ }
console.log(generatorObject.next(‘bar‘));
// { done: true, value: ‘bar‘ }
由于return返回的是后面子句整体的值,因此yield表达式的值为next()传进去的值。
可以使用星号增强yield的行为,让它能够迭代一个可迭代对象,从而一次产出一个值:
function* generatorFn() {
yield* [1, 2, 3];
}
let generatorObject = generatorFn();
for (const x of generatorFn()) {
console.log(x);
}
// 1
// 2
// 3
其实与把yield放入for...of循环中没有不同
function* generatorFnA() {
for (const x of [1, 2, 3]) {
yield x;
}
}
yield*表达式的值是关联迭代器返回done: true时的value 属性。
内置类型在done: true时的value 一般为undefinded。如果是生成器迭代器,则为return返回的值
function* innerGeneratorFn() {
yield ‘foo‘;
return ‘bar‘;
}
function* outerGeneratorFn(genObj) {
console.log(‘iter value:‘, yield* innerGeneratorFn());
}
for (const x of outerGeneratorFn()) {
console.log(‘value:‘, x);
}
// value: foo
// iter value: bar
还可以用yield*优雅的表达递归算法:
function *nTime(n){
if(n>0){
yield *nTime(n-1);
yield n-1;
}
}
for(const i of nTime(3)){
console.log(i);
}
// 1 2 3
class A{
constructor(){
this.values = [1,2,3];
}
*[Symbol.iterator](){
yield* this.values;
}
}
两种方法return()、throw() 略
原文:https://www.cnblogs.com/ku1a/p/14792035.html