前端迭代器和生成器知多少,值得收藏~

1,207 阅读5分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

迭代器

迭代器是一种特殊的对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔值,当没有更多可返回的数据时返回true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每一次调用next()方法,都会返回下一个可用的值。 如果在最后一个值返回后在调用next()方法,那么返回对象中属性done的值为true,属性value则包含迭代器最终返回的值,这个返回值不是数据集的一部分,它与函数的返回值类似,是函数调用过程中最后一次给调用者传递信息的方法,如果没有相关数据则返回undefined。

生成器

生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。星号可以紧挨着function关键字,也可以在中间添加一个空格,比如这样:

function *createIterator() {  
yield 1;  yield 2;  yield 3;
}let iterator = createIterator();  
// 生成器的调用方式与普通函数一样,只不过返回的是一个迭代器console.log(iterator.next().value);  
// console.log(iterator.next().value);  
// console.log(iterator.next().value);  // 3

使用yield关键字可以返回任何值或表达式,所以可以通过生成器函数批量地给迭代器添加元素。例如,可以在循环中使用yield关键字

function *createIterator(items) {  
    for (let i = 0; i < items.length; i++) 
    {    
    yield items[i];  
    }}
    let 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}// 之后所有的调用都会返回相同的内容
           console.log(iterator.next());  
           // {value: undefined, done: true}

yield关键字只可在生成器内部使用,在其他地方使用会导致程序跑出语法错误,即便在生成器内部的函数里使用也是如此;

生成器函数式表达式

let createIterator = function *(items) {
// 代码块

}

这个示例和前面的是相同的

不能使用箭头函数来创建生成器

可迭代对象和for-of循环

可迭代对象具有Symbol.iterator属性,是一种与迭代器密切相关的对象。Symbol.iterator通过指定的函数可以返回一个作用于附属对象的迭代器。在ECMAScript6中,所有的集合对象(数组,Set集合和Map集合)和字符串都是可迭代对象,这些对象中都有默认的迭代器。ECMAScript中新加入的特性for-of循环需要用到可迭代对象的这些功能。

由于生成器默认会为Symbol.iterator属性赋值,因此所有通过生成器创建的迭代器都是可迭代对象

for-of循环没执行一次都会调用可迭代对象的next()方法,并将迭代器返回结果对象的value属性存储在一个变量中,循环将持续执行这一过程直到返回对象的done属性为true。比如下面这个示例:

let values = [1,2,3];
// 正常的for-or循环使用
for (let num of values) {  
    console.log(num);}
   // 打印结果: 
   // 1
   // 2
   // 3
    // 访问默认迭代器,如下
    let iterator = values[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: undefined, done: true}

检测对象是否为可迭代对象

function isIterable(object) {  
return typeof object[Symbol.iterator] === 'function';}
console.log(isIterable([1,2,3])); // true
console.log(isIterable('hello')); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // false

内建迭代器

集合对象迭代器

在ECMAScript6中有3种类型的集合对象:数组,Map集合和Set集合。为了更好地访问对象中的内容,这3种对象都内建了以下三种迭代器:

  • entries() 返回一个迭代器,其值为多个键值对。
  • values() 返回一个迭代器,其值为集合的值。
  • keys() 返回一个迭代器,其值为集合中的所有键名。
  • entries()迭代器

每次调用next()方法时,entries迭代器都会返回一个数组,数组中的两个元素分别表示集合中每个元素的键与值。如果被遍历的对象是数组,则第一个元素是数字类型的索引;如果是Set集合,则第一个元素与第二个元素都是值(Set集合中的值被同时作为键与值使用);如果是Map集合,则第一个元素为键名。下面是entries()迭代器的使用示例:

entries()迭代器

let colors = ['red', 'green', 'blur'];
let tracking = new Set([132, 465, 956]);
let data = new Map();
data.set('title', 'ECMAScript 6');
data.set('format', 'ebook');
for(let entry of colors.entries()) {  
console.log(entry);}
// 打印结果
// [0, 'red']
// [1, 'green'] 
// [2, 'blur'] 
for(let entry of tracking.entries()) { 
console.log(entry);}
// 打印结果
// [132, 132]
// [465, 465] 
// [956, 956] 
for(let entry of data.entries()) {  
console.log(entry);}
// 打印结果
// ['title', 'ECMAScript 6']// ['format', 'ebook']

values()迭代器

调用values()迭代器时会返回集合中所存的所有值,例如:

let colors = ['red', 'green', 'blur'];
let tracking = new Set([132, 465, 956]);
let data = new Map();
data.set('title', 'ECMAScript 6');
data.set('format', 'ebook');
for(let entry of colors.values()) {
console.log(entry);}
// 打印结果
// 'red'
// 'green'
// 'blur'
for(let entry of tracking.values()) { 
console.log(entry);}
// 打印结果
// 132
// 465
// 956
for(let entry of data.values()) {  
console.log(entry);}
// 打印结果
// 'ECMAScript 6'
// 'ebook'

keys()迭代器

keys()迭代器会返回集合中存在的每一个键。如果遍历的是数组,则会返回数字类型的键,数组本身的其它属性不会被返回;如果是Set集合,由于键与值是相同的,因此keys()和values()返回的也是相同的迭代器;如果是Map()集合,则keys()迭代器返回每个独立的键。看下面这个示例:

let colors = ['red', 'green', 'blur'];
let tracking = new Set([132, 465, 956]);
let data = new Map();
data.set('title', 'ECMAScript 6');
data.set('format', 'ebook');
for(let entry of colors.keys()) { 
console.log(entry);}
// 打印结果
// 0
// 1
// 2
for(let entry of tracking.keys()) {  
console.log(entry);}
// 打印结果
// 132
// 465
// 956
for(let entry of data.keys()) {  
console.log(entry);}
// 打印结果
// 'title'
// 'format'

前端路漫漫其修远兮,吾将上下而求索,一起加油,学习前端吧

欢迎留言讨论~