当前位置:主页 > 网页前端 > JavaScript代码 >

ECMAScript中迭代器的深入讲解

时间:2022-02-07 10:10:51 | 栏目:JavaScript代码 | 点击:

前言

许多初级前端开发者在往中级迈进的过程中,面试经常问到的一个就是迭代器和生成器,其实在开发中都用过,但是并不知道这是什么,或者有些许了解但并不够深入。那这篇文章就对这一部分开发者会有一定的帮助,讲清楚迭代器这玩意。

较早的迭代

迭代肯定知道,简单理解起来就是循环,在JavaScript 中,计数循环便是最简单的一种。示例:

for(let i = 0; i < 9; ++i){
	console.log("[ i ]", i);
}

迭代的基础就是循环,它包含几个必要条件:

当需要循环遍历一个数组的时候,迭代是在一个有序的集合上进行的,「有序」即为数组中的所有元素都可以按照顺序从第一项到最后一项被遍历到。因为数组有确定的长度,以及每一项都可以通过索引下标去获取,也就是说可以通过索引去遍历整个数组。示例:

const arr = ["a", "b", "c"];

for(let i = 0; i < arr.length; ++i){
	console.log(arr[i]);
}

但是这种模式必须要事先知道使用的是什么数据结构,例如数组,如果换成其它数据类型,或者具有隐式顺序的数据结构,那么遍历的顺序就不可确定。

于是在 ES5 中新增了forEach()方法。示例:

const arr = ["a", "b", "c"];

arr.forEach(item=>{
	console.log(item);
});

这个方法就不用同数组索引去遍历和获取单项的取值,但无法标识迭代什么时候结束,因此仅适用于数组的遍历。为了解决这些问题,ES6 之后,JavaScript 支持了迭代器模式。

迭代器模式

迭代器模式是一种非常抽象的说法,可以把它理解成数组或者集合这一类的对象,它们的元素是有限的,且互相独立无歧义。引用红宝书的解释,即为:

迭代器模式(特别是在ECMAScript这个语境下)描述了一个方案,即可以把有些结构称为“可迭代对象”(iterable),因为它们实现了正式的Iterable接口,而且可以通过迭代器Iterator消费。

迭代器工厂函数

迭代器工厂函数,也就是 Symbol.iterator(),它是大部分内置类型都含有的默认属性,通过它暴露 Iterable 接口(可迭代协议),也就是说要想数据类型支持迭代,那么该类型必须支持可迭代协议。

ECMAScript 中规定暴露的默认迭代器,必须以“Symbol.iterator”作为键,返回一个新的迭代器。检查是否存在默认迭代器属性的方法也很简单。示例:

const obj = {};
const arr = ["a", "b", "c"];

console.log(obj[Symbol.iterator]); // underfined
console.log(arr[Symbol.iterator]); // f values() { [native code] }

console.log(arr[Symbol.iterator]()); // ArrayIterator {}

当然,我们实际开发中是不用显示调用迭代器工厂函数的,支持可迭代协议的数据类型会自动兼容接受可迭代对象的任何语言特性,例如当我们使用循环、for-of、解构、扩展操作符的时候,会自动在后台调用提供的可迭代对象的迭代器工厂函数,从而创建一个迭代器。

迭代器协议

迭代器协议约定迭代器是一种一次性使用的对象,当调用迭代器工厂函数后,返回一个next()方法,每一次迭代成功都会调用该方法,得知下一个迭代的值,如果不调用,则不确定迭代的当前位置。

next()方法返回一个对象,包含量属性:done和value,done 表示是否可以继续调用next()方法获取下一个值,意为是否「耗尽」,返回一个 Boolean 值; value 表示可迭代对象的下一个值。done 为 true 时,value 则为 underfined。done 为 false 时,则会继续调用下一个迭代。示例:

// 可迭代对象
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 }

写在最后

通过迭代器协议,你可以实现一个自定义的迭代器,比如规定迭代器可以被迭代的次数,或者提前终止迭代。

您可能感兴趣的文章:

相关文章