话疗js的迭代器和生成器

353 阅读3分钟

1.为啥要使用迭代器

2.迭代器

可以理解为更清晰的循环语句。 迭代器都有next()方法,每次调用都会返回两个属性的结果对象。 一个是value(此次迭代返回的值),一个是done(布尔类型,如果为true则表示后续没有继续返回的值了)

function createIterator(items) {
    var i = 0;
    return {
        next: function() {
            var done = (i >= items.length);
            var value = !done ? items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
}
var 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 }"

3.生成器

专门放迭代器的。 生成器也有next()方法,通过*来表示该函数会用到yield。

function *createIterator(){
    yield 'aaa';
    yield 'bbb';
    yield 4;
}
let resa=createIterator()
console.log(resa.next().value);

每当执行完一条yield就会自动停止,直到你下次使用会调用下一次的yield。 yield关键字只能在生成器内使用,否则会报错。

可迭代对象

Symbol.iterator方法可以跟踪内部的相关问题。 例如: 可通过for-of代码多次调用next()方法

let values = [1, 2, 3];
for (let num of values) {
    //1
    //2
    //3
    console.log(num);
}

也可通过Symbol.iterator来访问对象默认的迭代器

let val=[1,2,3];
let iterator=val[Symbol.iterator]();
console.log(iterator.next());//1

检测是否是可迭代对象

function isIterable(object) {
    return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable([1,2,4]));// true
console.log(isIterable(new Map())); // true

创建可迭代对象 正常来说,对象内部的数据是不可以迭代的,但如果给Symbol.iterator添加生成器,是可以做到迭代的

let collection={
    items:[11,33,55],
    *[Symbol.iterator](){
        for(let item of this.items){
            yield item;
        }
    }
}
collection.items.push(1);
for (let x of collection){
    console.log(x);
}

内建迭代器

集合对象的迭代器:数组,map,set enteries()返回一个迭代器,值为多个键值对 values()返回一个迭代器,值为集合的值 keys()返回一个迭代器,值为集合中的所有键名 这里只演示一个entries

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ES6");
data.set("format", "ebook");
for (let entry of colors.entries()) {
    console.log(entry);
}
for (let entry of tracking.entries()) {
    console.log(entry);
}
for (let entry of data.entries()) {
    console.log(entry);
}
[0, "red"]
[1, "green"]
[2, "blue"]
[1234, 1234]
[5678, 5678]
[9012, 9012]
["title", "Understanding ES6"]
["format", "ebook"]

其实,迭代器也可以处理dom元素,dom元素有一个NodeList类型

var divs=document.getElementsByTagName('h1');
for (let h of divs)
    console.log(h);
}

高级迭代器

1.给迭代器传递参数,由于每调用一次next()方法的参数会代替上一次的yield值,所以第一次的传参没有意义。

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2
}
let iterator = createIterator();
console.log(iterator.next());
console.log(iterator.next(4);//传入4,first变量为4

2.迭代器的返回语句

function *createIterator() {
    yield 1;
    return;
    yield 2;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
//return之后,将不在进行之后的yield,值为返回参数,但也只能返回一次,之后就是undefined。

3.委托生成器

就是将多个迭代器放在生成器里

function *createNumberIterator() {
    yield 1;
    yield 2;
}
function *createColorIterator() {
    yield "red";
    yield "green";
}
function *createCombinedIterator() {
    yield *createNumberIterator();
    yield *createColorIterator();
    yield true;
}
var resa=createNumberIterator();
var iterator = createCombinedIterator();
console.log(resa.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: "red", done: false }"
console.log(iterator.next()); // "{ value: "green", done: false }"

换汤不换药,超级简单有木有~~~~

4.同步异步的迭代器

最后一个知识点,坚持住....写到这儿其实我也累了

简单的任务执行器(向任务执行器传递数据) ,因为我们的yield通过next会被不停的覆盖。通过run()方法就可以使返回的结果保存起来使用。step()会检查result.done的值,如果为true了,则不继续执行step()操作了。

好了,废话太多了,来个例子吧。

function run(taskDef) {
    let task=taskDef();
    let res=task.next();
    function  step() {
        if(!res.done){
            res=task.next(res.value);
            step()
        }
    }
    step();
}
run(function *(){
    let value=yield 1;
    console.log(value);
    value=yield value+4;
    console.log(value);//5,因为yield 1被存住了。
})