JavaScript中yield实用简洁实现方式


Posted in Javascript onJune 12, 2010

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

function yieldHost(yieldFunction) 
{ 
return function (processer) 
{ 
var yield = function (result) 
{ 
processer(result) 
}; 
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的功能了,只有具备了这样的功能,才能处理无穷集,或是实现TakeWhile之类的功能。
老实说我对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 相关文章推荐
jquery 操作单选框,复选框,下拉列表实现代码
Oct 27 Javascript
JavaScript Distilled 基础知识与函数
Apr 07 Javascript
javascript 模式设计之工厂模式详细说明
May 10 Javascript
利用jQuery操作对象数组的实现代码
Apr 27 Javascript
Node.js 的异步 IO 性能探讨
Oct 08 Javascript
JavaScript实现点击自动选择TextArea文本的方法
Jul 02 Javascript
JavaScript原生xmlHttp与jquery的ajax方法json数据格式实例
Dec 04 Javascript
JS获取字符串实际长度(包含汉字)的简单方法
Aug 11 Javascript
在vue项目中安装使用Mint-UI的方法
Dec 27 Javascript
Vue中父子组件通讯之todolist组件功能开发
May 21 Javascript
Vue官方推荐AJAX组件axios.js使用方法详解与API
Oct 09 Javascript
el-table表头根据内容自适应完美解决表头错位和固定列错位
Jan 07 Javascript
EasySlider 基于jQuery功能强大简单易用的滑动门插件
Jun 11 #Javascript
JavaScript 开发规范要求(图文并茂)
Jun 11 #Javascript
cnblogs TagCloud基于jquery的实现代码
Jun 11 #Javascript
Js setInterval与setTimeout(定时执行与循环执行)的代码(可以传入参数)
Jun 11 #Javascript
js鼠标左右键 键盘值小结
Jun 11 #Javascript
JavaScript接口实现代码 (Interfaces In JavaScript)
Jun 11 #Javascript
JavaScript的单例模式 (singleton in Javascript)
Jun 11 #Javascript
You might like
session 加入redis的实现代码
2016/07/15 PHP
php封装json通信接口详解及实例
2017/03/07 PHP
visual studio code 调试php方法(图文详解)
2017/09/15 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
添加JavaScript重载函数的辅助方法2
2010/07/04 Javascript
Js判断参数(String,Array,Object)是否为undefined或者值为空
2013/11/04 Javascript
jQuery 回车事件enter使用示例
2014/02/18 Javascript
Node.js实现文件上传
2016/07/05 Javascript
JavaScript读二进制文件并用ajax传输二进制流的方法
2016/07/18 Javascript
利用python分析access日志的方法
2016/10/26 Javascript
bootstrap PrintThis打印插件使用详解
2017/02/20 Javascript
详解Angular4中路由Router类的跳转navigate
2017/06/09 Javascript
微信小程序表单验证功能完整实例
2017/12/01 Javascript
jquery写出PC端轮播图实例
2018/01/26 jQuery
layui的table中显示图片方法
2018/08/17 Javascript
NodeJS服务器实现gzip压缩的示例代码
2018/10/12 NodeJs
详解react native页面间传递数据的几种方式
2018/11/07 Javascript
vue-cli3 karma单元测试的实现
2019/01/18 Javascript
Paypal支付不完全指北
2020/06/04 Javascript
pyqt和pyside开发图形化界面
2014/01/22 Python
Python3中的2to3转换工具使用示例
2015/06/12 Python
Python中random模块生成随机数详解
2016/03/10 Python
举例讲解Python的lambda语句声明匿名函数的用法
2016/07/01 Python
python中实现迭代器(iterator)的方法示例
2017/01/19 Python
使用celery执行Django串行异步任务的方法步骤
2019/06/06 Python
python+numpy按行求一个二维数组的最大值方法
2019/07/09 Python
django有外键关系的两张表如何相互查找
2020/02/10 Python
用Python制作mini翻译器的实现示例
2020/08/17 Python
Python使用eval函数执行动态标表达式过程详解
2020/10/17 Python
德国内衣、泳装和睡衣网上商店:Bigsize Dessous
2018/07/09 全球购物
来自世界上最好大学的在线课程:edX
2018/10/16 全球购物
专科毕业生学习生活的自我评价
2013/10/26 职场文书
餐饮服务食品安全责任书
2014/07/25 职场文书
2019最新婚庆对联集锦!
2019/07/10 职场文书
原型和原型链 prototype和proto的区别详情
2021/11/02 Javascript
利用 Python 的 Pandas和 NumPy 库来清理数据
2022/04/13 Python