Generator 函数学习笔记

// 使用 function* 定义一个 generator 函数
function* helloWorldGenerator() {
  yield ‘hello‘;  // yield 关键字作为暂停的点
  yield ‘world‘;
  return ‘ending‘;
}

var hw = helloWorldGenerator();  // 执行 generator 函数,返回一个遍历器对象。而这时,这个函数内的代码并不会执行。
// 调用遍历器对象的 next 方法,执行函数内的代码,执行到下一个 yield 的位置,并暂停执行
hw.next()
// { value: ‘hello‘, done: false }  value 是 yield 后面跟的表达式的值,done 是 genertator 函数结束状态

// 再次调用 next,执行到下一个 yield 位置
hw.next()
// { value: ‘world‘, done: false }

// 执行结束,value 值为 return 的值,没有 return 则为 undefined(函数没 return 返回 undefined),done 变为 true
hw.next()
// { value: ‘ending‘, done: true }

// 还可以无限次调用 next,但是都返回相同的对象
hw.next()
// { value: undefined, done: true }

yield 不能用在普通函数中:

var flat = function* (a) {
  // forEach 方法是个普通函数,在里面使用了 yield 会报错。解决方法是改为 for 循环
  a.forEach(function (item) {
    if (typeof item !== ‘number‘) {
      yield* flat(item);
    } else {
      yield item;
    }
  }
};

yield语句如果用在一个表达式之中,必须放在圆括号里面。

console.log(‘Hello‘ + yield); // SyntaxError
console.log(‘Hello‘ + yield 123); // SyntaxError

console.log(‘Hello‘ + (yield)); // OK
console.log(‘Hello‘ + (yield 123)); // OK

next方法的参数

function* foo(x) {
  var y = 2 * (yield (x + 1));  // yield 语句在表达式中,需要将 yield 语句括起来,否则报错
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }  调用第一次 next 开始执行,得到第一个 yield 的返回值 6。由于 next 参数为上一个 yield 语句的值,所以第一个 next 传入参数没有意义
b.next(12) // { value:8, done:false }  调用 next 方法时注入了数据,作为上一个 yield 语句的值,得到 var y = 2 * 12
b.next(13) // { value:42, done:true }  得到 var z = 13

for...of循环

for...of循环可以自动遍历Generator函数时生成的Iterator对象,且此时不再需要调用next方法。

function *foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
// 1 2 3 4 5  这里需要注意,一旦next方法的返回对象的done属性为truefor...of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for...of循环之中。

原生的JavaScript对象没有遍历接口,无法使用for...of循环,通过Generator函数为它加上这个接口,就可以用了。

// 第一种方法
function* objectEntries(obj) {
  let propKeys = Reflect.ownKeys(obj);

  for (let propKey of propKeys) {
    yield [propKey, obj[propKey]];
  }
}

let jane = { first: ‘Jane‘, last: ‘Doe‘ };

for (let [key, value] of objectEntries(jane)) {
  console.log(`${key}: ${value}`);
}

// 第二种方法
function* objectEntries() {
  let propKeys = Object.keys(this);

  for (let propKey of propKeys) {
    yield [propKey, this[propKey]];
  }
}

let jane = { first: ‘Jane‘, last: ‘Doe‘ };

jane[Symbol.iterator] = objectEntries;

for (let [key, value] of jane) {
  console.log(`${key}: ${value}`);
}
时间: 2024-10-07 02:32:18

Generator 函数学习笔记的相关文章

generator函数学习笔记

一.基本概念 Generator函数是一种可以暂停执行,返回iterator对象的函数,yield是暂停标识 function* gen(){ yield 1; yield 2; } Generator函数在function后面有一个*,内部有yield语句 function* gen(){ yield 1; yield 2; return '1' } let g = gen(); //调用Generator函数返回遍历器对象 console.log(g.next())//{"value&quo

C++运算符重载为友元函数学习笔记

初探C++运算符重载学习笔记 在上面那篇博客中,写了将运算符重载为普通函数或类的成员函数这两种情况. 下面的两种情况发生,则我们需要将运算符重载为类的友元函数 <1>成员函数不能满足要求 <2>普通函数又不能访问类的私有成员时 举例说明: class Complex{ double real, imag; public: Complex(double r, double i):real(r), imag(i){ }; Complex operator+(double r); };

contiki-main.c 中的process系列函数学习笔记 &lt;contiki学习笔记之六&gt;

说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件. ------------------------------------------------------------------------------------------------------------------------------------- 根据上一个笔记里面添加的printf()语句的打印信息提示,hello world 打印是在执行了 1 autostart_

async 函数--学习笔记一

含义: ES2017 标准引入了 async 函数,使得异步操作变得更加方便.async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generator 函数,依次读取两个文件. var fs = require('fs'); var readFile = function (fileName) { return new Promise(function (resolve, reject) { fs.readFile(fileName, function(erro

Swift2.0 函数学习笔记

最近又有点忙,忙着找工作,忙着适应这个新环境.现在好了,上班两周周了,也适应过来了,又有时间安安静静的就行我们前面的学习了.今天这篇笔记,记录的就是函数的使用.下面这些代码基本上是理清楚了函数的额使用,但还有一块“闭包”的内容,后面我们单独写一块出来. // 形参传递的过程中,由于没有写外部形参名称,第一个形参的外部形参名字可以省略,第二的的不可以省略 let zxtest = testString(1, zc: 2) print(zxtest) // 返回值是一个元组的形式返回到,参数的传递和

MYSQL存储过程和函数学习笔记

学至Tarena金牌讲师何山,金色晨曦科技公司技术总监沙利穆课程笔记的综合. 1. 什么是存储过程和函数 将SQL语句放入一个集合里,然后直接调用存储过程和函数来执行已经定义好的SQL语句,通过存储过程和函数,可以避免开发人员重复编写相同的SQL语句. MYSQL存储过程和函数是保存在服务器中,在服务器中存储和执行,可以减少客户端和服务器端之间数据传输的消耗. 存储过程就是一组已经保存在数据库中的语句,并且可以随时地调用. 存储过程允许标准组件式编程,存储过程在被创建以后可以在程序中被多次调用而

函数(学习笔记)

函数(存储函数)也是一种较为方便的存储结构,用户定义函数可以被SQL语句或者PL/SQL直接调,函数和过程最大的区别在于,函数可以有返回值,而过程只能依靠OUT 或者IN OUT返回数据定义函数语法:CREATE [OR REPLACE] FUNCTION 函数([参数,...]])RETURN 返回值类型 [AUTHID [DEFINER | CURRENT_USER]] AS || IS [PRAGMA AUTONOMOUS_TRANSACTION;] 声明部分;BEGIN 程序部分; [R

pythonの函数学习笔记(一)

函数是可以实现一些特定功能的小方法或小程序定义函数function的方法:def function_name(arg1,arg2[,...]): statement [return value]注意事项:1.def开头,代表定义函数,def和函数名中间要敲一个空格:2.返回值不是必须的,如果没有renturn语句,则默认返回值None:3.函数名必须以下划线或字母开头,可以包含任意字母.数字或下划线的组合,区分大小写且不能是保留字: py使用名称空间的概念存储对象,这个名称空间就是对象作用的区域

C++11 virtual函数学习笔记

#include<iostream> #include<string> using namespace std; class Base { public: Base(){} ~Base(){} public: virtual void f1(int x){ cout << "baseclass: f1() " << x << endl; } virtual void f2()final{ cout << "