除了前2篇文章中描述的可迭代对象以外,在js语言扩展中的生成器对象,也可以作为可迭代对象。

这里用到一个新的关键字yield,该关键字在函数内部使用,用法和return类似,返回函数中的一个值;yield和return区别在于,使用yield的函数“返回”的这个值是可保持内部状态的。(我也没办法用猫的语言表达能力将其表达清楚,如果你懂得ruby之类的动态语言可能早就明白其含义,不明白的见后面的代码吧 :))

任何使用关键字yield的函数(哪怕yield在代码逻辑中是不可达的)都称为“生成器函数”(generator function),生成器函数通过yield返回值。这些函数可以通过return终止函数的执行而不带任何返回值,但不能使用return返回一个值。

然而和普通函数一样,生成器函数也通过关键字function声明,typeof运算符也返回”function”,并且可以从Function.prototype继承属性和方法。要点是:生成器函数调用并不执行生成器函数的函数体,而是返回一个生成器对象!

生成器对象包含一个next()方法,可以恢复生成器函数的执行,直到遇到下一个yield语句为止。这时生成器函数中的yield语句的参数就是next()方法的返回值值,如果生成器函数执行return或者到达函数体的末尾终止,则next()将抛出StopIteration.

function r(min,max){
   for(let i = Math.ceil(min);i <= max;i++)
     yield i*i;
}

for(let n in r(1,10))
  console.log(n);

生成器包含一个close()方法,当调用时和它相关的生成器函数就会终止执行,就像在函数运行挂起位置执行了一条return语句。如果当前挂起位置在一个或多个try语句块中,则首先运行finally从句,在执行close()返回。close()没有返回值,但若finally产生了异常则该异常会传播给close();

生成器对象还包括一个send方法,其可以带一个参数,该值将成为yield表达式的值(如果把yield看做语句或函数,则该参数就是语句或函数的返回值);

除了next()和send()之外生成器还有一个throw()方法,如果调用这个方法,yield表达式就将参数作为异常抛给throw(),见如下代码:

function cf(init){
    let next_v = init;
  while(true){
    try{
      let inc = yield next_v;
      if(inc)
        next_v += inc;
      else
        next_v++;
    }
    catch(e){
      if(e === "reset")
        next_v = init;
      else
        throw e;
    }
  }
}

var c = cf(10);
console.log(c.toString());
console.log(c.next());
console.log(c.send(10));
console.log(c.throw("reset")); //next_v == 10;
console.log(c.next());

//我们可以让reset稍微优雅点
c.reset = function(){
  return this.throw("reset");
}

/*but Generator is not defined!!!
注释中的代码会报错!!!
Generator.prototype.reset = function(){
   return this.throw("reset");
}
*/

console.log(c.reset());

javascript语言扩展:可迭代对象(3)的更多相关文章

  1. javascript语言扩展:可迭代对象(1)

    在ECMAScript中我们知道可以通过for in语句进行对象属性的遍历,当然这些属性不包括继承而来的属性: var ary = [1,2,3,"aa",4]; for(i in ...

  2. javascript语言扩展:可迭代对象(2)

    在文章迭代器(1)中我们简单介绍了如何创建一个可迭代对象:出于某种考虑你可能想从可迭代对象中显式获取一个迭代器对象,这时你可以调用Iterator()函数(该函数是定义在JavaScript 1.7中 ...

  3. javascript语言扩展:可迭代对象(5)

    文章1-4篇说的都是js中的可迭代对象,下面让我们看看ruby中的等价物. 不可否认,ruby中对于迭代器和生成器的语法都相当简洁:ruby从一开始就有一个简洁的基因,而js后来的不断扩充使得其有些语 ...

  4. javascript语言扩展:可迭代对象(4)

    js 1.7中还包含一个数组推导(array comprehension)的特性,如果不在最后介绍它好像显得不怎么完整. 数组推导其实很简单: let a = [x*x for(x in range( ...

  5. Python Cookbook(第3版)中文版:15.20 处理C语言中的可迭代对象

    15.20 处理C语言中的可迭代对象¶ 问题¶ 你想写C扩展代码处理来自任何可迭代对象如列表.元组.文件或生成器中的元素. 解决方案¶ 下面是一个C扩展函数例子,演示了怎样处理可迭代对象中的元素: s ...

  6. python 迭代器(一):迭代器基础(一) 语言内部使用 iter(...) 内置函数处理可迭代对象的方式

    简介 在 Python 中,所有集合都可以迭代.在 Python 语言内部,迭代器用于支持: 1.for 循环2.构建和扩展集合类型3.逐行遍历文本文件4.列表推导.字典推导和集合推导5.元组拆包6. ...

  7. 扩展javascript扩展(类,对象,原型)

     扩展javascript扩展(类,对象,原型)

  8. JavaScript中对象与函数的某些事[JavaScript语言精粹-N1]

    今天在读<JavaScript语言精粹>的时候,关于函数的一个部分,始终觉得有点难以理解,代码如下: 1: var obj = (function(){ 2: var value = 0; ...

  9. JavaScript语言精粹之对象

    用object.hasOwnProperty(variable)来确定这个属性名是否为该对象成员,还是来自于原型链. for(my in obj){ if(obj.hasOwnProperty(my) ...

随机推荐

  1. 在Linux环境下实现一个非常好的bash脚本框架

    为了方便我日常工作中的编译环境,免去我敲命令行所浪费的时间,我个人写了一个非常有用而又简单的脚本框架,该框架即可以完成的工程源码编译,也可以清除,拷贝等等操作,具体需要开发者自己来实现细节,我的框架思 ...

  2. Linux系统编程---守护进程

    守护进程是什么?就是在后台运行的进程. 那么如何创建守护进程呢? 1. 创建孤儿进程 2. setsid() 创建进程会话 3. 重定向标准输入, 标准输出 4. chdir, 改当当前进程的工作目录 ...

  3. Blue Path(基于cocos2dx 3.0)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=498 iTunes下载:http ...

  4. Android 5.1.1 源码目录结构

    点击打开链接 最近公司培训新同事,我负责整理一点关于android的基础知识,遥想当年,刚接触android,也是一头雾水, 啥都不懂,就是靠看文档和视频,对android有一个初步了解,然后就通过查 ...

  5. 后端分布式系列:分布式存储-HDFS 异常处理与恢复

    在前面的文章 <HDFS DataNode 设计实现解析>中我们对文件操作进行了描述,但并未展开讲述其中涉及的异常错误处理与恢复机制.本文将深入探讨 HDFS 文件操作涉及的错误处理与恢复 ...

  6. EasyUI表单验证,自定义插件验证,自定义js插件验证,远程验证,常见手机号,中英文,qq等验证规则验证

     { field : 'startPort', title : "起始端口", editor: "text", width : 50, editor: { ...

  7. 高性能nosql ledisdb设计与实现(1)

    ledisdb是一个用go实现的基于leveldb的高性能nosql数据库,它提供多种数据结构的支持,网络交互协议参考redis,你可以很方便的将其作为redis的替代品,用来存储大于内存容量的数据( ...

  8. ROS_Kinetic_18 使用V-Rep3.3.1和Matlab2015b(vrep_ros_bridge)续

    ROS_Kinetic_18 使用V-Rep3.3.1和Matlab2015b(vrep_ros_bridge)续 上一节配置的v-rep在ros kinetic中是可以看图像,并订阅主题的,但是无法 ...

  9. Cocos2D:塔防游戏制作之旅(十一)

    是时候放一些坏家伙来搅合一下了! 打开HelloWorldLayer.h并且添加以下代码: // Add these instance variables int wave; CCLabelBMFon ...

  10. 调用awk的三种方式

    调用awk的三种方式 调用awk有三种方式,一种为Shell命令行方式,另外两种是将awk程序写入脚本文件,然后执行该脚本文件.三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用awk, ...