异步编程之——理解es6中的Iterator(迭代器)

前言

在es6的学习过程中,promise,generators,循环都遇到了Iterator,网上大部分的解释大部分都是后台语言,为了更好的理解es6系列知识,这里专门讲一下es6中的Iterator(迭代器)。

正文

什么是迭代器?

迭代器是一种接口,也可以说是一种规范。它提供了一种统一的遍历数据的方法。我们都知道数组、集合、对象都有自己的循环遍历方法。
比如数组的循环:

let ary = [1,2,3,4,5,6,7,8,9,10];

//for循环
for(let i = 0;i < ary.length;i++){
    console.log(ary[i]);
}

//forEach循环
ary.forEach(function(ele){
    console.log(ele);
});

//for-in循环
for(let i in ary){
    console.log(ary[i]);
}

//for-of循环
for(let ele of ary){
    console.log(ele);
}

集合的循环:

let list = new Set([1,2,3,4,5,6,7,8,9,10]);
for(let ele of list){
    console.log(ele);
}

对象的循环:

let obj = {
    name : 'tom',
    age : 25,
    gender : '男',
    intro : function(){
        console.log('my name is '+this.name);
    }
}

for(let attr in obj){
    console.log(attr);
}

从以上的代码可以看到,数组可以用for、forEach、for-in以及for-of来遍历。集合能用for-of。对象能用for-in。也就是说:

以上数据类型的遍历方式都各有不同,那么有没有统一的方式遍历这些数据呢?这就是迭代器存在的意义。它可以提供统一的遍历数据的方式,只要在想要遍历的数据结构中添加一个支持迭代器的属性即可。

迭代器的语法

这个属性写法是这样的:

const obj = {
    [Symbol.iterator]:function(){}
}

[Symbol.iterator] 属性名是固定的写法,只要拥有了该属性的对象,就能够用迭代器的方式进行遍历。迭代器的遍历方法是首先获得一个迭代器的指针,初始时该指针指向第一条数据之前。接着通过调用next方法,改变指针的指向,让其指向下一条数据。每一次的next都会返回一个对象,该对象有两个属性。其中value代表想要获取的数据,done是个布尔值,false表示当前指针指向的数据有值。true表示遍历已经结束。

let ary = [{num:111},2,3];
let it = ary[Symbol.iterator](); // 获取数组中的迭代器
console.log(it.next()); // {  value: Object { num: 111 }, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

数组是支持迭代器遍历的,所以可以直接获取其中的迭代器。集合也是一样。

let list = new Set([1,3,2,3]);
let it = list.entries(); // 获取set集合中自带的的迭代器
console.log(it.next()); // { value: [ 1, 1 ], done: false }
console.log(it.next()); // { value: [ 3, 3 ], done: false }
console.log(it.next()); // { value: [ 2, 2 ], done: false }
console.log(it.next()); // { value: undefined, done: true }

set集合中每次遍历出来的值是一个数组,里面的第一和第二个元素都是一样的。

由于数组和集合都支持迭代器,所以它们都可以用同一种方式来遍历。es6中提供了一种新的循环方法叫做for-of。它实际上就是使用迭代器来进行遍历,换句话说只有支持了迭代器的数据结构才能使用for-of循环。在JS中,默认支持迭代器的结构有:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

这里面并没有包含自定义的对象,所以当我们创建一个自定义对象后,是无法通过for-of来循环遍历它。除非将iterator接口加入到该对象中:

let obj = {
    name : 'tom',
    age : 25,
    gender : '男',
    intro : function(){
        console.log('my name is '+this.name);
    },
    [Symbol.iterator]:function(){
        let i = 0;
        let keys = Object.keys(this); // 获取当前对象的所有属性并形成一个数组
        return {
            next: function(){
                return {
                    value:keys[i++], // 外部每次执行next都能得到数组中的第i个元素
                    done:i > keys.length // 如果数组的数据已经遍历完则返回true
                }
            }
        }
    }
}

for(let attr of obj){
    console.log(attr);
}

通过自定义迭代器就能让自定义对象使用for-of循环。

迭代器的应用场景

有一些场合会默认调用 Iterator 接口(即Symbol.iterator方法)

  • 解构赋值
    对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法。
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;  // x='a'; y='b'
let [first, ...rest] = set;  // first='a'; rest=['b','c'];
  • 扩展运算符
    扩展运算符(…)也会调用默认的 Iterator 接口。
var str = 'hello';
[...str] //  ['h','e','l','l','o']

let arr = ['b', 'c'];
['a', ...arr, 'd']   // ['a', 'b', 'c', 'd']
  • 生成器 yield*
    yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。
let generator = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
};

var iterator = generator();

iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
  • 其他场合
    由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。比如:
    • for…of
    • Array.from()
    • Map(), Set(), WeakMap(), WeakSet()(比如new Map([[‘a’,1],[‘b’,2]]))
    • Promise.all()
    • Promise.race()
    • 字符串遍历

总结

Iterator 的作用有三个:

  • 一是为各种数据结构,提供一个统一的、简便的访问接口;
  • 二是使得数据结构的成员能够按某种次序排列;
  • 三是 ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费。

over 有问题留言

借鉴:https://zhuanlan.zhihu.com/p/66593213
http://es6.ruanyifeng.com/#docs/iterator

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值