阅读 89

迭代器与生成器(迭代器与生成器的区别)

迭代器与生成器

一、迭代器

ECMAScript 5规范表示集合的数据结构有数组( Array )和对象 (Object ),ECMAScript 6规范又新增了Set 和 Map两种集合。这样在JavaScript 中就具有四种集合,需要一种统一的机制进行操作。

迭代器(Iterator)就是这样的一种机制,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。

迭代器(Iterator)具有三种作用:

  • 为各种数据结构,提供统一的、简便的访问接口。

  • 是的数据结构的成员能够按某种次序排列。

  • ECMAScript 6新增了 for…of 循环语句,用于遍历 迭代器。


Iterator 接口 ①

在javascript中迭代器 是一个对象,该对象提供 next() 方法用于返回序列中的下一项。

该方法返回包含 done 和 value 两个属性的对象。

/*     构建迭代器 -> 返回迭代器对象     * 该迭代器对象必须具备next()方法         * 作用 - 用于返回序列中的下一项         * 返回值 - 是一个对象             * done属性 - 表示是否迭代完毕                 * false - 表示当前没有迭代完毕                 * true - 表示当前迭代完毕             * value属性 - 表示当前迭代的值 */ function fn(array) {     var index = 0;     return {         next :  function () {             return index < array.length ? {                 done : false,                 value : array[index++]             } : {                 done: true             }         }     }; } let arr = [1,2,3,4]; let iterator = fn(arr); console.log(iterator.next());//{ done: false, value: 1 } console.log(iterator.next());// { done: false, value: 2 } console.log(iterator.next());// { done: false, value: 3 } console.log(iterator.next());// { done: false, value: 4 } console.log(iterator.next());// { done: true } 复制代码

迭代器对象一旦被创建,就可以反复调用 next() 方法用于一次访问对象中的键值。


Iterator 接口 ②

一种数据结构只要部署了lterator接口,就可以称这种数据结构是“可遍历的”。ECMAScript 6规范规定默认的lterator接口部署在数据结构的Symboliterator属性。换句话讲,一个数据结构只要具有Symbol.iterator 属性,就可以认为是“可遍历的”。

Symbol.iterator 属性本身就是一个函数,就是当前数据结构默认的迭代器生成函数。执行这个函数就会返回一个迭代器。


JavaScript 中原生具有 Iterator 接口的数据结构如下:

  • Array

  • Map

  • Set

  • String

  • TypedArray

  • 函数的argunents对象

  • Nodelist 对象

  • …..


二、for…of 语句

ECMAScript 6引入了for ...of 语句用于遍历迭代器。一个数据结构只要部署了Symbol.iterator 属性,就被视为具有lterator接口,就可以用for...of循环遍历它的成员。

for(variable of iterable){     //statements } 复制代码

  • variable : 在每次迭代中,将不用属性的值分配给变量。

  • iterable : 被迭代枚举其属性的对象。

示例代码如下:

// 1.遍历数组 let arr = [1,2,3,4,5]; for (let attr of arr){     // attr得到的是数组的元素内容     console.log(attr); } // 2.遍历set集合 let set = new Set(arr); for(let attr of set){     // attr得到set集合的元素内容     console.log(attr); } // 3.遍历map集合 let map = new Map(); let num = 100,str = '迪迦',fun = function(){},obj = {}; map.set('num',num); map.set('str',str); map.set('fun',fun); map.set('obj',obj); for (let attr of map){     // attr得到map集合的键值对内容     console.log(attr); } // 4.遍历字符串集合 let string = 'nihao'; for (let attr of string){     console.log(attr); } 复制代码

(1) 返回迭代器对象的方法

ECMAScript 6 中的数组( Array ) 、Set 和 Map都具有以下方法,该方法返回一个迭代器对象。

  • entries()方法:返回一个新的迭代器对象,这个对象的元素是用来遍历[键名,键值]组成的数组。

  • keys()方法:返回一个新的迭代器对象,用来遍历所有的键名。

  • values()方法:返回一个新的迭代器对象,用来遍历所有的键值。

(2) 与 forEach() 方法的区别

ECMAScript 6 中的数组( Array ) 、Set 和 Map都具有 forEach() 方法,该方法与 for…of 语句的区别如下:

  • forEach() 方法无法跳出循环。换句话讲,break 语句和 continue 语句无效。

  • for…of 语句不仅可以使用 break 语句和 continue 语句,还可以配合return 语句使用。

(3)与for…in  语句的区别

for…in 语句主要用于遍历对象。与for…of 语句对比,for…in语句具有以下几个缺点

  • for…in 不仅遍历自身,还会遍历手动添加的,甚至包括原型链的。

  • 如果用于遍历数组的话,遍历得到的键名为字符串类型的数字值。

Object.prototype.objCustom = function(){}; Array.prototype.arrCustom = function () {}; let iterator = [3,5,7]; iterator.foo = 'hello'; for (let i in iterator){     console.log(i); }//0 1 2 foo arrCustom objCustom for (let i of     iterator){     console.log(i);//3  5  7 } 复制代码


三、生成器

(1)Generator 函数

Generator 函数 可以作为生成一个迭代器的特殊函数,该函数被调用时返回一个 Generator 对象,该对象是符合可迭代协议和迭代器协议的。

语法结构如下:

function* gen(){     yield 'nihao'; } let g = gen();//"Generator" 复制代码

Generator 函数与普通函数的区别在于:

  • function* 这种生命方式会定义一个生成器函数,它返回一个 Generator 对象。

  • yield 关键字用来暂停和恢复一个生成器函数。

function* 表达式

function* 这种声明方式( function 关键字后跟一个星号)会定义一个生成器函数(Generator function ),它返回一个Generator 对象。

生成器函数在执行时能暂停,后面又能从暂停处继续执行。

function* name([param[,param,[,...param]]]) {statements} 复制代码

  • name :表示函数名称。

  • param :表示传递给函数的一个参数的名称,一个函数最多可以有255 个参数。

  • statements : 表示iJavaScript 语句。


yield表达式

yield 关键字用来暂停和恢复一个生成器函数。

[rv] = yield [expression]; 复制代码

  • expression : 定义通过迭代器协议从生成器函数返回的值。如果省略,则返回undefined。

  • rv : 返回传递给生成器的next() 方法的可选值,以恢复其执行。

实力代码如下所示:

// 定义一个生成器函数 function* fn(){     let arr = ['1','2','3','4'];     for (let i=0; i<arr.length;i++){         yield arr[i];     } } // 生成器函数调用返回生成器对象 let generator = fn(); // 生成器对象就是ES6提供的迭代器 console.log(generator.next()); console.log(generator.next()); console.log(generator.next()); console.log(generator.next()); console.log(generator.next()); 复制代码

yield*表达式

yield* 表达式用于委托给另一个 Generator 或可迭代对象。

yield* [[expression]] 复制代码

  • expression : 返回一个可迭代对象的表达式。

示例代码如下:

function* g1() {     yield 2;     yield 3; } function* g2(){     yield 1;     yield* g1();     yield 4; } var iterator = g2(); 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: 4, done: false } console.log(iterator.next());//{ value: undefined, done: true } 复制代码


(2)Generator 对象的方法

生成的Generator 对象具有以下几个原型方法:

方法名称描述
next() 方法返回一个包含属性done和value的对象。该方法也可以通过接受一个参数用以向生成器传值
return() 方法返回给定的值并结束生成器
throw() 方法用与向生成器抛出异常,并恢复生成器的执行,返回带有done及value两个属性的对象

next() 方法  、return() 方法、throw() 方法 本质上是同一件事,可以放在一起理解。他们的作用都是让Generator 函数恢复执行,并且使用不用的语句替换 yield 表达式。


作者:不一213
链接:https://juejin.cn/post/7028849452345622565


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐