[javascript核心-20] 通俗易懂的迭代器🐘

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士


什么是迭代器

迭代器是一种特殊的对象,它具有一些为迭代过程设计的接口。迭代器在结构上具有如下特征:

  1. 有一个next方法,每次调用都会返回一个结果对象
  2. 结果对象有两个属性:valuedonevalue表示下一个将要返回的值,而done是一个布尔状态,表达当前迭代是否已经结束。如果迭代还未完成,则done的值为false, 反之则为true

什么是可迭代对象

具有Symbol.iterator属性的对象,即为可迭代对象。在 ES6 中,所有集合对象,包括数组字符串Set集合Map 集合

既然说到了Symbol.iterator属性,那它是什么呢?其实它是一个特殊的函数。我们可以直接来使用这个属性来进行迭代:

javascript 复制代码
let values = [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}
console.log(iterator.next()) // {value: undefined, done: true}

可以看到,Symbol.iterator其实就是一个函数,它的返回值是一个特殊的对象,这个对象有两个属性:valuedone。当迭代完成时,done的值为true,而其值为undefined。迭代完成后可以继续调用,没有次数的限制,但其返回的结果对象为{value: undefined, done: true}

如何模拟实现一个迭代器

首先Symbol.iterator是一个函数,它应该接收一个可迭代对象。因此我们可以创建一个函数:

javascript 复制代码
function createIterator(items){}

其次该函数调用的结果会返回一个拥有next方法的函数:

javascript 复制代码
function createIterator(items){
    return {
        next: function(){}
    }
}

而调用该方法会返回一个包含了valuedone属性的结果对象。且该结果对象的value迭代的,而done是表示当前迭代是否完成。因此我们需要一个能够记录当前迭代位置的指针,并且每一次的调用都去移动该指针。

javascript 复制代码
function createIterator(items){
    let i = 0;
    return {
        next: function(){
            return i < items.length ?
                {value: items[i++], done: false} :
                {value: undefined, done: true};
              }
        }
}

我们来测试一下该函数:

javascript 复制代码
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}

判断对象是否为可迭代对象

既然可迭代对象是有Symbol.iterator属性的,那么我们便可以根据该属性来判断对象是否为可迭代对象:

javascript 复制代码
function isIterable(object){
    return typeof object[Symbol.iterator] === 'function'
}

内置迭代器

ES6 为集合对象提供了内置迭代器,在大多数情况下我们无须自己手动实现。

entries(), values(), keys()都会返回一个迭代器,但是它们的表现不同。但要注意虽然字符串也是可迭代对象,但是它没有这三个内置的迭代器方法,不过它可以使用for...of进行迭代。

  • entries(),值为键值对的组合
  • values(),值为集合的值
  • keys(),值为集合的键名

我们可以使用for...of来访问迭代器。

entries迭代器

entries会返回一个数组,数组中包含两个元素,分别表示集合中每个元素的键和值。

由于集合对象的不同,返回值也有所不同。

javascript 复制代码
let map = new Map();
map.set('address', 'BeiJing');
map.set('phone', '110');

for(let m of map.entries()){
    console.log(m)
}


//['address', 'BeiJing']
//['phone', '110']

返回结果中第一个元素为键名,第二个元素为值。

javascript 复制代码
let set = new Set(['a', 'b', 'c']);
for(let s of set.entries()){
    console.log(s);
}

//['a', 'a']
//['b', 'b']
//['c', 'c']

Set 集合的返回结果中,第一个元素和第二个元素都是值,即将值作为了键。

javascript 复制代码
let arr = ['a', 'b', 'c'];
for(let item of arr.entries()){
    console.log(item)
}

//[0, 'a']
//[1, 'b']
//[2, 'c']

数组集合的返回结果中,第一个元素为数字索引,第二个值为集合的值。

javascript 复制代码
let str = 'abc';
for(let s of str.entries()){
    console.log(s);
}
// TypeError: str.entries is not a function or its return value is not iterable

即字符串是没有entries迭代器方法的。

valueskeys迭代器则分别是返回值和键。

不同集合类型的默认迭代器

如果我们直接使用for...of而不指定迭代器时,不同类型的集合会默认调用不同的迭代器。Map的默认迭代器是entries(),也很容易理解,因为对于Map来说,键和值是映射关系。而对于Set数组集合来说,默认迭代器是values

对于Map

javascript 复制代码
let map = new Map();
map.set('address', 'BeiJing');
map.set('phone', '110');

for(let m of map){
    console.log(m)
}

//['address', 'BeiJing']
//['phone', '110']

对于Set

javascript 复制代码
let set = new Set(['a', 'b', 'c']);
for(let s of set){
    console.log(s);
}

//a
//b
//c

对于数组

javascript 复制代码
let arr = ['a', 'b', 'c'];
for(let item of arr){
    console.log(item)
}

//a
//b
//c

迭代器的更多能力应该和生成器一起使用才能够体现出来,我们将在下一篇探讨迭代器与生成器的配合。


本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

相关推荐
SameX3 分钟前
初识 HarmonyOS Next 的分布式管理:设备发现与认证
前端·harmonyos
M_emory_30 分钟前
解决 git clone 出现:Failed to connect to 127.0.0.1 port 1080: Connection refused 错误
前端·vue.js·git
Ciito33 分钟前
vue项目使用eslint+prettier管理项目格式化
前端·javascript·vue.js
成都被卷死的程序员1 小时前
响应式网页设计--html
前端·html
fighting ~1 小时前
react17安装html-react-parser运行报错记录
javascript·react.js·html
老码沉思录1 小时前
React Native 全栈开发实战班 - 列表与滚动视图
javascript·react native·react.js
abments1 小时前
JavaScript逆向爬虫教程-------基础篇之常用的编码与加密介绍(python和js实现)
javascript·爬虫·python
mon_star°1 小时前
将答题成绩排行榜数据通过前端生成excel的方式实现导出下载功能
前端·excel
Zrf21913184551 小时前
前端笔试中oj算法题的解法模版
前端·readline·oj算法
老码沉思录2 小时前
React Native 全栈开发实战班 - 状态管理入门(Context API)
javascript·react native·react.js