可迭代对象与迭代器(Iterator)和生成器(Generator)

用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,于是 ES6 向 JS 中添加了这个迭代器特性。新的数组方法和新的集合类型 ( 例如 Set 集合与 Map 集合 ) 都依赖迭代器实现。
你也会发现在语言的其他特性中也都有迭代器的身影:新的 for / of 循环、展开运算符 ( … ) ,甚至连异步编程都可以使用迭代器。




什么是迭代器
迭代器是一种特殊对象,它具有专门为迭代过程设计的接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。
该对象有两个属性:value => 表示下一个将要返回的值;另一个是 done => 当没有更多可返回数据时返回 true。
迭代器还会保存一个内部指针,用来指向当前集合中值得位置,每调用一次 next() 方法。都会返回下一个可用的值
迭代器需要靠生成器生成




什么是生成器
生成器是生成一个迭代器的函数,由于生成器默认会为 Symbol.iterator 赋值,因此所有通过生成器创建的迭代器都是可迭代对象
通过给 function 关键字后添加 * 号来表示该函数为生成器,函数中会通过一个关键字 yield 用来标识每次调用迭代器的 next() 方法时返回的值
每当执行完一条 yield 语句后函数就会自动停止执行,直到再次调用迭代器的 next() 方法才会继续执行 下一个 yield 语句
如果生成器中所有的 yield 执行完毕,再调用迭代器的 next() 方法,都会返回相同的内容:{ value: undefind , done: true }

		
	// 使用函数声明一个生成器
	function *createIterator(){
		yield 1;
		yield 2;
		yield 3;
	}
		
	// 调用生成器,返回一个迭代器给 iterator ,此时 iterator 具有了 next() 方法
	let iterator = createIterator();
	
	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: undefind , done: true }


	// 使用函数表达式声明一个生成器
	let createIterator = function *(items){
		for(let item of items){
			yield item;
		}
	}
	let iterator = createIterator([1, 2, 3]);
	iterator.next();								// { value: 1 , done: false }
	
	// 在对象内添加生成器的属性
	let o = {
		num: 0,
		*createIterator(items){
			for(let item of items){
				yield item + this.num;
			}
		}
	}
	let iterator = o.createIterator([1, 2, 3]);
	iterator.next();								// { value: 1 , done: false }




可迭代对象和 for / of 循环
可迭代对象具有 Symbol.iterator 属性,是一种与迭代器密切相关的对象。Symbol.iterator 通过指定的函数可以返回一个作用域附属对象的迭代器。
ES6 中所有的集合对象 ( 数组、Set集合、Map集合 ) 和字符串都是可迭代对象,这些对象都有默认的迭代器 ( 即内部存在 yield )
前面提到过循环内部索引跟踪的相关问题,要解决这个问题,需要两个工具:一个是迭代器,另一个是for / of 循环。如此一来,便不再需要跟踪整个集合的索引,只需关注集合中要处理的内容。
for / of 循环每次执行一次都会调用可迭代对象的 next() 方法,并将迭代器返回的结果对象的 value 属性存储在一个变量中,循环将持续执行这一过程直到返回对象的 done 属性的值为 true 。



访问默认迭代器
可以通过 Symbol.iterator 来访问对象默认的迭代器


	let arr = [1, 2, 3];
	let iterator = arr[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: undefind  , done: true}



创建可迭代对象
默认情况下,开发者定义的对象都是不可迭代对象,但如果给 Symbol.iterator 属性添加一个生成器,则可以将其变为可迭代对象,该方法适用于对象转数组


	let collection = {
		items: [1, 2, 3],
		*[Symbol.iterator](){
			for( let item of this.items ){
				yield item;
			}
		}
	}
	
	// 给 collection 添加了 Symbol.iterator 属性后,可以使用 for / of 来迭代了
	for( let x of collection ){
		console.log( x )		// 将输出 1 2 3
	}
	


	// 下面是对象转数组的使用方式
	let collection = {
      "葡萄干": 1,
      "荔枝干": 2,
      "芒果干": 3,
      *[Symbol.iterator]() {
        for (let key of Object.keys(this)) {
          yield {
             name:key,
             value:this[key]
          }
        }
      },
    };
    let arr = Array.from(collection);




关于迭代器还有以下高级使用方式,内容太多就不写了。
内建迭代器 ( 集合对象迭代器、字符串迭代器、NodeList迭代器 )
高级迭代器功能 ( 给迭代器传递参数、在迭代器中抛出错误、生成器 return 返回语句、委托生成器 )
异步任务执行 ( 简单任务执行器、向任务执行器传递数据、异步任务执行器 )




在生成器和迭代器的所有应用场景中,最令人兴奋的是用来创建更简洁的异步代码。这种方式无须在所有地方定义回调函数,其代码看起来像是同步代码,但实际上使用了 yield 生成的特性来等待异步操作最终完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值