9.迭代器Iterator和生成器Generator

146 阅读3分钟

Iterator

Iterator:是一种新的遍历机制,它有两个核心。

  1. 迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器, 通过迭代器的next()获取迭代之后的结果。
  2. 迭代器是用于遍历数据结构的指针(相当于数据库的游标)
const items = ['one', 'two', 'three'];
//获取迭代器
const it = items[Symbol.iterator]();
console.log(it.next());//{value: "one", done: false}
console.log(it.next());//{value: "two", done: false}
console.log(it.next());//{value: "three", done: false}
console.log(it.next());//{value: undefined, done: true}

done如果为false表示遍历继续,如果为true表示遍历完成。

Generator

Generator函数可以通过yield关键字,将函数挂起,为改变执行流提供了可能,同时为做异步编程提供了方案。
Generator函数与普通函数的区别:

  1. function后面,函数名之前加一个*
  2. yield关键字只能在Generator函数内部使用

yield

  1. yield关键字使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。
  2. yield关键字实际返回一个IteratorResult对象,它有两个属性,valuedone。value属性是对yield表达式求值的结果,而done是false,表示生成器函数尚未完全完成。
  3. 一旦遇到yield表达式,生成器的代码将被暂停运行,直到生成器的next() 方法被调用。每次调用生成器的next()方法时,生成器都会恢复执行。
function* fun() {
    console.log('one');
    yield 1;
    console.log('two');
    yield 2;
    console.log('three');
}

const it = fun();//函数的调用并不会进入到程序中,它仅仅只返回一个遍历器对象
console.log(it);//fun {<suspended>}
console.log(it.next());//one {value: 1, done: false}
console.log(it.next());//two {value: 2, done: false}
console.log(it.next());//three {value: undefined, done: true}

总结:Generator函数是分段执行的,yield语句是暂停执行,而next()是恢复执行。

next()传参

function* add() {
    console.log('one');
    let x = yield 1;
    console.log('two:' + x);
    let y = yield 2;
    console.log('three:' + y);
    return x + y;
}

const it = add();
console.log(it.next());//one {value: 1, done: false}
console.log(it.next(10));//two:10 {value: 2, done: false}
console.log(it.next(20));//three:20 {value: 30, done: true}

总结: 如果将参数传递给生成器的next()方法,则该值将成为生成器当前yield操作返回的值。即x和y是next()调用,恢复当前yield执行传入的实参的值。

使用场景

为不具备Iterator接口的对象提供了遍历操作

function* objectEntries(obj) {
    //获取对象中所有的键
    let keys = Object.keys(obj);
    for (let key of keys) {
        //暂停函数执行
        yield [key, obj[key]];
    }
}

const obj = {
    name: 'tom',
    age: 20
};
console.log(obj);//普通对象 {name: "tom", age: 20}
//给对象添加迭代器,并绑定生成器函数
obj[Symbol.iterator] = objectEntries;
console.log(obj);//{name: "tom", age: 20, Symbol(Symbol.iterator): ƒ}
console.log(obj[Symbol.iterator](obj).next());//{value: Array(2), done: false}
//--------------------
for (let [key, value] of objectEntries(obj)) {
    console.log(`${key}${value}`);//name:tom age:20
    console.log(key + ":" + value);//name:tom age:20
}

部署ajax操作,让异步代码同步化

function* load() {
    loadUI();
    yield showData();
    hideUI();
}

let it = load();
it.next();

function loadUI() {
    console.log('加载loading...页面');
}

function showData() {
    //模拟异步操作
    setTimeout(() => {
        console.log('数据加载完成');
        it.next();
    }, 1000)
}

function hideUI() {
    console.log('隐藏loading...界面');
}

//输出结果
//加载loading...页面
//数据加载完成
//隐藏loading...界面