资讯专栏INFORMATION COLUMN

从iterator到generator

mmy123456 / 742人阅读

摘要:迭代器协议当一个对象被认为是一个迭代器时,它实现了一个的方法。该方法返回一个对象包含和属性,的值表示迭代器是否可以产生序列中的下一个值,为迭代器返回的任何值。

iterator 可遍历(可迭代)协议

一个对象为了变成可遍历对象,比如说可以用 for ... in 结构遍历其属性值,必须实现 @@iterator 方法, 意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有一个名字是 Symbol.iterator 的属性。

属性
[Symbol.iterator] 返回一个对象的无参函数,被返回对象符合可遍历协议。
迭代器协议

当一个对象被认为是一个迭代器时,它实现了一个 next() 的方法。
该方法返回一个对象包含 donevalue 属性,done 的值表示迭代器是否可以产生序列中的下一个值,value 为迭代器返回的任何 JavaScript 值。donetrue 时可省略。

let a = {
    q: "q",
    w: "w",
    e: "e",
};
Object.defineProperty(a, length, {
    enumerable: false,
    value: 3
});

现在对 a 尝试用 for ... in 结构遍历其属性值

for (let v of a) {
    console.log(v);
}

报错:

Uncaught TypeError: a[Symbol.iterator] is not a function

定义一个函数利用闭包实现一个将 a 转变为可迭代对象

function Iterator(obj) {
    let i;

    return ()=> {
        return {
            next: ()=> {
                if (i < obj.length) {
                    for (i in obj) {
                        return {
                            done: false,
                            value: obj[i]
                        };
                    }
                }
                return {
                    done: true
                };
            }
        };
    };
}

a[Symbol.iterator] = Iterator(a);
generator

Generator 函数最大特点就是可以交出函数的执行权(即暂停执行)。异步操作需要暂停的地方,都用 yield 语句注明。调用 Generator 函数并不会执行本体,而是每次调用 next 方法的时候,执行到下一个碰到的 yield 处。

Generator 函数的数据交换
function* anotherGenerator(i) {
  yield i + 1;
  let x = yield i + 2;
  yield x + 3;
}

function* generator(i){
  yield i;
  yield* anotherGenerator(i);
  // 执行权转交给另一个 generator 函数的话 yield 后面带星号,直接调用的话是没有效果的
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next(2).value); // 5
console.log(gen.next().value); // 20
// next 的返回值和迭代器的 next 类似,yield 语句的执行结果作为 value,是否还有下一个 yield 决定 done
// next 方法可以带有参数,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果
Generator 函数的错误处理

Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误。

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){ 
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw("出错了");
// 出错了

上面代码的最后一行,Generator 函数体外,使用指针对象的 throw 方法抛出的错误,可以被函数体内的 try ... catch

Generator 函数的终止

Generator函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历Generator函数。

function* gen() {
  yield 1;
  yield 2;
  yield 3;
}

var g = gen();

g.next()        // { value: 1, done: false }
g.return("foo") // { value: "foo", done: true }
g.next()        // { value: undefined, done: true }

如果Generator函数内部有try...finally代码块,那么return方法会推迟到finally代码块执行完再执行。

function* numbers () {
  yield 1;
  try {
    yield 2;
    yield 3;
  } finally {
    yield 4;
    yield 5;
  }
  yield 6;
}
var g = numbers()
g.next() // { done: false, value: 1 }
g.next() // { done: false, value: 2 }
g.return(7) // { done: false, value: 4 }
g.next() // { done: false, value: 5 }
g.next() // { done: true, value: 7 }

上面代码中,调用return方法后,就开始执行finally代码块,然后等到finally代码块执行完,再执行return方法。

Generator 函数的自动执行

co 库是tj写的一个让Generator函数自动执行的工具。

let co = require("co");
let p = co(gen);

p.then(function (){
  console.log("ok");
})

co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数。

async 与 await

ES7 为 generator 的语法糖

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87777.html

相关文章

  • [前端漫谈_1] for of 聊 Generator

    摘要:数据的层级意味着迭代数据结构并提取它的数据。对于技术人而言技是单兵作战能力,术则是运用能力的方法。在前端娱乐圈,我想成为一名出色的人民艺术家。 聊聊 for of 说起 for of 相信每个写过 JavaScript 的人都用过 for of ,平时我们用它做什么呢?大多数情况应该就是遍历数组了,当然,更多时候,我们也会用 map() 或者 filer() 来遍历一个数组。 但是就...

    miqt 评论0 收藏0
  • es6 generator函数

    摘要:返回的遍历器对象可以依次遍历函数内部的每一个状态。示例内部捕获外部捕获内部捕获外部捕获上面代码遍历器对象连续抛出两个错误,第一个被函数体内的捕获。上面代码中,首先执行函数,获取遍历器对象,然后使用方法第二行,执行异步任务的第一阶段。 参考 来源《ecmascript6 入门》generator部分 认识generator函数 形式上,generator函数有两个特点:一是functio...

    voidking 评论0 收藏0
  • ES6之IteratorGenerator

    摘要:举个例子遍历器生成函数,作用就是返回一个遍历器对象,方法返回一个对象,表示当前数据成员的信息。该对象本身也具有属性,执行后返回自身。 Iterator的作用 一是为各种数据结构,提供一个统一的、简便的访问接口;(统一)二是使得数据结构的成员能够按某种次序排列;(按序)三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。举个例子:遍历器生...

    tuomao 评论0 收藏0
  • ES6之IteratorGenerator

    摘要:举个例子遍历器生成函数,作用就是返回一个遍历器对象,方法返回一个对象,表示当前数据成员的信息。该对象本身也具有属性,执行后返回自身。 Iterator的作用 一是为各种数据结构,提供一个统一的、简便的访问接口;(统一)二是使得数据结构的成员能够按某种次序排列;(按序)三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。举个例子:遍历器生...

    ashe 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<