原题还是老赵的:

http://blog.zhaojie.me/2010/06/code-for-fun-iterator-generator-yield-in-javascript.html

原以为是一个蛮复杂的题目,想了许久没思路,当然要实现绝对能实现,但如果分析JavaScript脚本或是动态产生代码,都太复杂了。

刚才忽然灵机一动,迭代器我们很少会真的直接傻乎乎的next去遍历的,那为什么一定要实现这个傻乎乎的next呢?直接实现each,这样,这样反过来,Yeah,一通百通,不一会儿就写出了第一个超简洁版本:

代码

    function yieldHost(yieldFunction)
{
return function (processer)
{
var yield = function (result)
{
if (processer(result))
throw exception;
}; yieldFunction(yield); };
}

思路一换,代码真简洁。

先附上例子,然后来谈原理。

首先我们需要一个函数来进行枚举,像这样:

    function fun(yield)
{ for (var i = 0; i < 100; i++)
yield(i); }

或是这样:

    function fun(yield)
{ yield(1);
yield(2);
yield(3); }

由于实现方式与C#的不同,所以在循环体内也不用什么yield break或是yield continue这样的语法,直接break或是continue就好了。

然后是实际的运用,yieldHost函数可以将上面的符合要求的fun函数转换为一个枚举器:

    var enumerator = yieldHost(fun);

这个枚举器其实也是一个函数,像jQuery的each函数一样,接收一个处理函数来处理枚举:

    enumerator(function (item)
{
window.alert(item);
});

接下来谈谈原理。

对于传统的枚举器来说,我们会认为枚举器应该在每次调用返回一个值,这就是next方法,但就像陈子瀚说的,这需要在yield的时候把函数停住,虽然可以实现,但真的很麻烦。

但!事实上我发现,大多数时候,我们都是用foreach这样的语法来访问枚举器的。这样一来就给了我一个非常讨巧的办法,不实现next方法,而是实现each方法。

each方法和next的方法的区别在哪里呢?熟悉jQuery的朋友就会知道,each方法其实可以视为将next倒过来,不是返回枚举值,而是接收一个函数,把枚举值当作参数传进去。

正是这一倒,所有问题都迎刃而解了。我们没有必要去暂停一个函数的执行,只需要将处理枚举值的逻辑注到这个函数里面去就完了。所以事实上这里的yieldHost就是完成了一个倒装的工作,把enumerator接收的那个函数(也就是window.alert( item ),注到了枚举函数中(即fun)。最终执行的效果就像是这样:

    function fun(yield)
{ window.alert(1);
window.alert(2);
window.alert(3); }

所以就诞生了这个超简洁的实现。

有了这个超简洁的实现,下一步就是实现像jQuery的each方法一样的return true代表break和return false代表continue的功能了,只有具备了这样的功能,才能处理无穷集,或是实现SkipWhile和Where之类的功能。

老实说我对JavaScript的研究并不透彻,只想到了一个使用异常打断的办法,这就是第二个版本的yieldHost:

代码

    function yieldHost(yieldFunction)
{ var exception = Math.random(); return function (processer)
{
try
{
yieldFunction(function (result)
{
if (processer(result))
throw exception;
});
}
catch (e)
{
if (e !== exception)
throw e;
} };
}

显然这并不完美,但我实在想不出更好的办法。

接下来在这个基础上实现Select、Where什么,其实是非常简单的事情,给出一个我的Select的实现:

代码

    function Select(enumerator, selector)
{
return function (fun)
{
enumerator(function (item)
{
return fun(selector(item));
});
}
}

至于,这个Select怎么修改成连写的版本,即:

enumerator.Select( selector )( processor );

我觉得这对JavaScript而言真不是一件很难的事情啊。。。。

只是,过早的引入语法友好,会把JavaScript变得很复杂难看。所以,这个留给大家去玩吧。

在JavaScript中实现yield,实用简洁实现方式。的更多相关文章

  1. 简要描述 JavaScript 中定义函数的几种方式

    JavaScript 中,有三种定义函数的方式: 1.函数语句:即使用 function 关键字显式定义函数.如: function f(x){ return x+1; }  2.函数定义表达式:也称 ...

  2. javascript中实现继承的几种方式

    javascript中实现继承的几种方式 1.借用构造函数实现继承 function Parent1(){ this.name = "parent1" } function Chi ...

  3. JavaScript中判断为整数的多种方式

    之前记录过JavaScript中判断为数字类型的多种方式,这篇看看如何判断为整数类型(Integer). JavaScript中不区分整数和浮点数,所有数字内部都采用64位浮点格式表示,和Java的d ...

  4. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  5. javascript中定义事件的三种方式

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

  6. javascript中对象访问自身属性的方式

    在javascript中,通过对象的方法访问对象自身属性时,必须采用this.fieldName的方式. 原因是javascript中Function是无状态的,访问对象的属性时,必须指定当前的上下文 ...

  7. JavaScript中定义对象的四种方式

    最近在阅读< JavaScript 高级程序设计>,未免遗忘读过的内容,就打算以博客的形式做些读书笔记.今天介绍的是 JavaScript 中的四种定义对象的方法,除了这四种方法,还有工厂 ...

  8. javascript中定义事件的三种方式 分类: C1_HTML/JS/JQUERY 2014-08-07 10:27 634人阅读 评论(0) 收藏

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

  9. JavaScript 中事件绑定的三种方式

    以下是在 JS 中事件绑定的三种方式.   1. HTML onclick attribute     <button type="button" id="uplo ...

随机推荐

  1. for xml path('') 引发的数据不完整

    When you read Extensible Markup Language (XML) data from Microsoft SQL Server by using the SqlDataRe ...

  2. 十天学会单片机Day5 IIC总线AT2402芯片(EEPROM)应用

    1.采用串行总线技术可以使系统的硬件设计大大简化.系统的体积减小.可靠性提高.同时,系统的更改和扩充极为容易. 常用的串行扩展总线有: IIC (Inter IC BUS)总线.单总线(1-WIRE ...

  3. S3C2440 LCD驱动(FrameBuffer)实例开发<一>(转)

    1. 背景知识 在多媒体的推动下,彩色LCD越来越多地应用到嵌入式系统中,PDA和手机等大多都采用LCD作为显示器材,因此学习LCD的应用很有实际意义! LCD工作的硬件需求:要使一块LCD正常的显示 ...

  4. python自学笔记一

    之前看过一段时间的小甲鱼零基础自学python,b站上有高清免费资源[av4050443],但是作为零基础实在学得艰难,下载了python核心编程pdf,在这里做一些笔记. 虽然使用的是第二版的教材, ...

  5. DTAP street

    一个网站程序的上线一般要经过开发[Development]测试[Testing]验收[Acceptance]生产[Production].所以又叫做DTAP street.对应有开发环境.测试环境.验 ...

  6. ORA-01207: file is more recent than control file -

    OS: [root@yoon ~]# more /etc/oracle-releaseOracle Linux Server release 5.7 DB: Oracle Database 11g E ...

  7. windows 服务 安装 删除 启动 停止

    一.停止 sc stop 服务名 二.删除 sc delete 服务名 注意:有时删除不了,报什么“服务为删除标识” ,请将服务窗口关掉就好了. 三.创建 sc create XmlcSendServ ...

  8. ListView的多布局中的小问题

    今天用到了ListView的多布局,我们需要额外重写两个方法 //返回多布局的个数 @Override public int getViewTypeCount() { return 3; } //用该 ...

  9. 在.net程序中使用System.Net.Mail来发送邮件

    System.Net.Mail是微软自家提供的工具,在.net程序中可以使用该空间中的SmtpClient实例来实现邮件的发送. 使用System.Net.Mail空间与Web.config配置相配合 ...

  10. 部署git server

    http://gogs.io/docs/installation/install_from_binary.htmlwget http://gogs.dn.qbox.me/gogs_v0.6.5_lin ...