迭代器与生成器

132 阅读4分钟

迭代 iteration

迭代:按照顺序反复多次执行一段程序,通常会有明确的终止条件,会在一个有序集合上进行。

迭代器的优点

  • 开发者无需事先知道如何迭代,就能实现迭代操作。
  • 为各种不同的数据结构,提供统一的访问机制。详细来说,实现Iterator接口的结构---都可以消费---实现Iterable接口(可迭代协议)的数据结构。迭代器无需了解与其关联的可迭代对象的结构,只需要知道如何取得连续的值。

如何实现Interable接口(可迭代协议)?

  • 使数据结构具有Symbol.iterator属性。 一个数据结构只要具有Symbol.iterator属性,就是可遍历的。
  • Symbol.iterator属性值为一个函数,执行这个函数就会返回一个遍历器对象
  • 遍历器对象必须具有next()方法 (return()和throw()是可选的),每次调用next方法,都会返回一个代表当前成员的信息对象
  • 这个当前成员的信息对象具有valuedone两个属性。

原生具备Iterable接口的数据结构(7):

  • Array数组
  • Map映射
  • Set集合
  • String字符串
  • TypedArray类数组
  • 函数的arguments对象
  • NodeList等DOM集合

通过Iterable接口实现的迭代语言结构:

  • for-of
  • 解构赋值(对数组解构赋值、对Set解构赋值) 对数组和Set解构赋值时,会默认调用Symbol.iterator方法。
  • 扩展操作符(...) 扩展运算符会调用默认的Symbol.iterator方法。
  • Array.from()
  • 创建集合 ( new Set() )
  • 创建映射 ( new Map(['a', 1]) )
  • Promise.all() 接收由Promise组成的可迭代对象
  • Promise.racel() 接收由Promise组成的可迭代对象
  • yield操作符 yield操作符,在生成器中使用,后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

使用Generator函数实现Symbol.iterator()方法,是最简单的Symbol.iterator()方法实现

遍历器对象的 return(),throw()

遍历器对象除了具有next()方法,还可以具有return()方法和throw()方法。如果你自己写遍历器对象生成函数,那么next()方法是必须部署的,return()方法和throw()方法是否部署是可选的。

return()方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句),就会调用return()方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return()方法。

注意,return()方法必须返回一个对象,这是 Generator 语法决定的。

throw()方法主要是配合 Generator 函数使用,一般的遍历器对象用不到这个方法。请参阅《Generator 函数》一章。

迭代和遍历、循环、递归 的区别

迭代器模式

​ 迭代器模式:开发者无须事先知道如何迭代就能实现迭代操作。

​ 迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。

可迭代对象

实现了[Symbol.iterator]方法。

实现了Iterable接口,而且可以通过迭代器Iterator消费。

==实现了[Symbol.iterator]方法的可迭代对象才可以被迭代型语言结构操作/使用/消费。==

可迭代协议

实现Iterable接口必须:支持迭代的自我识别能力、创建实现Iterator接口对象 的能力。

​ 1.具有Symbol.iterator属性

​ 2.Symbol.iterator属性的属性值为一个函数。

​ 此函数返回值为next()函数,next()返回值为一个包含两个属性的对象,done表示是否还有更多值可以访问,true表示已经遍历完,函数停止执行。false表示下一次仍执行next()函数。value表示当前值,默认undefined。

//迭代器实现原理 (取value值)
//对象没有实现Iterable接口,所以需要手动添加Symbol.iterator属性
let obj = {
	a:1,
	b:2,
	c:3
};
obj[Symbol.iterator] = function() {
	let values = Object.values(obj);
	let index = 0;
	return {
		next() {
			if(index >= values.length){
				return {
					done:true
				}
			} else {
				return {
					done:false,
					value:values[index++] //++:以便下次index指向values下一项
				}
			}
		}
	}
};
//for-of这种迭代型语言结构就是通过调用数据结构的Symbol.iterator属性的函数实现的
for (let val of obj){
	console.log(val);
}
//输出:1
//     2
//     3
//迭代器实现原理 (取key:value值)
//对象没有实现Iterable接口,所以需要手动添加Symbol.iterator属性
let obj = {
	a:1,
	b:2,
	c:3
};
obj[Symbol.iterator] = function() {
	let keys = Object.keys(obj);
	let index = 0;
	return {
		next() {
			if(index >= values.length){
				return {
					done:true
				}
			} else {
				return {
					done:false,
					value:{
						key:keys[index],
						value:obj[keys[index++]] //++:以便下次index指向values下一项
					}
				}
			}
		}
	}
};
//for-of这种迭代型语言结构就是通过调用数据结构的Symbol.iterator属性的函数实现的
for (let val of obj){
	console.log(val);
}
//输出:{key:"a", value: 1}
//     {key:"b", value: 2}
//     {key:"c", value: 3}