javascript
在JavaScript中实现yield,实用简洁实现方式。
原題還是老趙的:
http://blog.zhaojie.me/2010/06/code-for-fun-iterator-generator-yield-in-javascript.html
?
原以為是一個蠻復雜的題目,想了許久沒思路,當然要實現(xiàn)絕對能實現(xiàn),但如果分析JavaScript腳本或是動態(tài)產(chǎn)生代碼,都太復雜了。
?
剛才忽然靈機一動,迭代器我們很少會真的直接傻乎乎的next去遍歷的,那為什么一定要實現(xiàn)這個傻乎乎的next呢?直接實現(xiàn)each,這樣,這樣反過來,Yeah,一通百通,不一會兒就寫出了第一個超簡潔版本:
?
代碼 function yieldHost(yieldFunction){
return function (processer)
{
var yield = function (result)
{
processer(result)
};
yieldFunction(yield);
};
}
?
?
?
思路一換,代碼真簡潔。
?
?
先附上例子,然后來談原理。
首先我們需要一個函數(shù)來進行枚舉,像這樣:
function fun(yield){
for (var i = 0; i < 100; i++)
yield(i);
}
?
或是這樣:
function fun(yield){
yield(1);
yield(2);
yield(3);
}
?
由于實現(xiàn)方式與C#的不同,所以在循環(huán)體內(nèi)也不用什么yield break或是yield continue這樣的語法,直接break或是continue就好了。
?
然后是實際的運用,yieldHost函數(shù)可以將上面的符合要求的fun函數(shù)轉(zhuǎn)換為一個枚舉器:
var enumerator = yieldHost(fun);?
這個枚舉器其實也是一個函數(shù),像jQuery的each函數(shù)一樣,接收一個處理函數(shù)來處理枚舉:
enumerator(function (item){
window.alert(item);
});
?
接下來談?wù)勗怼?/p>
?
對于傳統(tǒng)的枚舉器來說,我們會認為枚舉器應(yīng)該在每次調(diào)用返回一個值,這就是next方法,但就像陳子瀚說的,這需要在yield的時候把函數(shù)停住,雖然可以實現(xiàn),但真的很麻煩。
?
但!事實上我發(fā)現(xiàn),大多數(shù)時候,我們都是用foreach這樣的語法來訪問枚舉器的。這樣一來就給了我一個非常討巧的辦法,不實現(xiàn)next方法,而是實現(xiàn)each方法。
each方法和next的方法的區(qū)別在哪里呢?熟悉jQuery的朋友就會知道,each方法其實可以視為將next倒過來,不是返回枚舉值,而是接收一個函數(shù),把枚舉值當作參數(shù)傳進去。
?
正是這一倒,所有問題都迎刃而解了。我們沒有必要去暫停一個函數(shù)的執(zhí)行,只需要將處理枚舉值的邏輯注到這個函數(shù)里面去就完了。所以事實上這里的yieldHost就是完成了一個倒裝的工作,把enumerator接收的那個函數(shù)(也就是window.alert( item ),注到了枚舉函數(shù)中(即fun)。最終執(zhí)行的效果就像是這樣:
function fun(yield){
window.alert(1);
window.alert(2);
window.alert(3);
}
?
所以就誕生了這個超簡潔的實現(xiàn)。
?
有了這個超簡潔的實現(xiàn),下一步就是實現(xiàn)像jQuery的each方法一樣的return true代表break和return false代表continue的功能了,只有具備了這樣的功能,才能處理無窮集,或是實現(xiàn)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;
}
};
}
?
顯然這并不完美,但我實在想不出更好的辦法。
接下來在這個基礎(chǔ)上實現(xiàn)Select、Where什么,其實是非常簡單的事情,給出一個我的Select的實現(xiàn):
代碼 function Select(enumerator, selector){
return function (fun)
{
enumerator(function (item)
{
return fun(selector(item));
});
}
}
?
?
至于,這個Select怎么修改成連寫的版本,即:
enumerator.Select( selector )( processor );
?
我覺得這對JavaScript而言真不是一件很難的事情啊。。。。
只是,過早的引入語法友好,會把JavaScript變得很復雜難看。所以,這個留給大家去玩吧。
?
?
公司招聘,應(yīng)老大要求在文章末尾附上順風車廣告一條,不喜勿入:http://job.cnblogs.com/offer/7490/
轉(zhuǎn)載于:https://www.cnblogs.com/Ivony/archive/2010/06/08/1754390.html
總結(jié)
以上是生活随笔為你收集整理的在JavaScript中实现yield,实用简洁实现方式。的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 域用户迁移适用的两种方法
- 下一篇: 在线聊天javascript代码