ES6--迭代器

51 阅读2分钟

深入理解ES6书中P150,有ES5实现的迭代器函数:

function creatIterator(items){
var i = 0;
return{
next:function(){
var done = (i >= items.length);
var value = !done ? items[i++] : undifined;
return{
done: done;
value: value
};
}
};
}

定义

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

  • ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费。

  • 原生具备 iterator 接口的数据(可用for of 遍历)

    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList

案例:使用 next() 方法遍历原生自带 iterator 接口的数据:

// 遍历 Map
const mp = new Map();
mp.set('a', 1);
mp.set('b', 2);
mp.set('c', 3);
let iter1 = mp[Symbol.iterator]();
// next() 方法每执行一次,指针自增
console.log(iter1.next()); // { value: [ 'a', 1 ], done: false }
console.log(iter1.next()); // { value: [ 'b', 2 ], done: false }
console.log(iter1.next()); // { value: [ 'c', 3 ], done: false }
console.log(iter1.next()); // { value: undefined, done: true }
// 遍历数组
let xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
let iter2 = xiyou[Symbol.iterator]();
console.log(iter2.next()); // { value: '唐僧', done: false }
console.log(iter2.next()); // { value: '孙悟空', done: false }
console.log(iter2.next()); // { value: '猪八戒', done: false }
console.log(iter2.next()); // { value: '沙僧', done: false }Copy to clipboardErrorCopied

上面的案例只是为了证明他们自带 iterator 接口,实际上直接使用 for...of 方法遍历即可(iterator 接口为 for...of)服务。例如,可以使用 for [k, v] of map 来遍历 Map 数据结构中的键和值。

const mp = new Map();
mp.set('a', 1);
mp.set('b', 2);
mp.set('c', 3);
for (let [k, v] of mp) {
    console.log(k, v);
}
/*
a 1
b 2
c 3
*/Copy to clipboardErrorCopied

工作原理

  • 创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
  • 每调用 next 方法返回一个包含 value 和 done 属性的对象

应用场景:需要自定义遍历数据的时候,要想到迭代器。

自定义遍历数据

我们可以通过给数据结构添加自定义 [Symbol.iterator]() 方法来使该数据结构能够直接被遍历,从而使 for...of 能够直接遍历指定数据,达到为 for...of 服务的功能。

// 需求:遍历对象中的数组
const xiaomi = {
    uname: '小明',
    course: [ '高数', '大物', '英语', '数据库' ],
    // 通过自定义 [Symbol.iterator]() 方法
    [Symbol.iterator]() {
        // 初始指针对象指向数组第一个
        let index = 0;
        // 保存 xiaomi 的 this 值
        let _this = this;
        return {
            next: function () {
                // 不断调用 next 方法,直到指向最后一个成员
                if (index < _this.course.length) {
                    return { value: _this.course[index++], done: false };
                } else {
                    // 每调用next 方法返回一个包含value 和done 属性的对象
                    return { value: undefined, done: true };
                }
            }
        }
    }
}
// for...of直接遍历达到目的
for (let v of xiaomi) {
    console.log(v);
}