【JavaScript 1.7】【Ruby】JavaScript とRuby、yield の違い
■topic summary
study about "yield" in JavaScript.
The function containing the yield keyword is a generator.
yieldはRubyにあるから楽勝ー。
と思っていたけれど、JavaScript とRubyでは考え方が違うみたい。
JavaScript1.7は「開発者向けツール」で試さないこと
こんなコードを書いて↓
function f(max){ var cur=1; for(var n=1; n<=max; n++){ cur *= n; yield(cur*10); console.log('cur= ' + cur); } } f(4);
開発者向けツールで実行。
あれれ。
本と挙動が違う。
fを普通の関数のように呼び出しても何も出力されません。
と書いてあるけど。
chrome上のletもコンソール上では認識できなかったから、
コンソールで試しているのが良くないのかもしれない。
ファイルに書いてブラウザに読み込ませよう。
JavaScript 1.7 の一部の新機能を使うためには、JavaScript 1.7 が使いたいという宣言が必要です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/New_in_JavaScript/1.7
ふむふむ。
■aaajs.html
<script type="application/javascript;version=1.7"> function f(max){ var cur=1; for(var n=1; n<=max; n++){ cur *= n; yield(cur); console.log('cur= ' + cur); } } f(4); console.log(f(4).next()); </script>
おー。
想定通りnext()メソッドで取得した値しか出力されていない。
Ruby
Rubyのyieldはイテレータから、
イテレータ呼び出しに付属しているブロックに制御を移すもの。
def f yield yield end f(){p "hoge"}
■実行結果
"hoge" "hoge"
JavaScript
Rubyに対して、JavaScriptのyieldは処理の中断。
<script type="application/javascript;version=1.7"> function p(obj){ console.log(obj); } function f(){ yield("hoge1"); yield("hoge2"); } var g=f(4); p(g.next()); </script>
■実行結果
hoge1
nextで処理が進むところは外部イテレータ的。。
外部イテレータに関しては前勉強したところ
(zipメソッドを実装したりしている)
でも、処理を中断して呼び出し元に制御を戻すというのは、Fiberと同じ概念だ。
ここで注意しておきたいのは、Fiber.yieldの処理とyield文の処理とがまったく異なるということだ
なるほどね。
JavaScript はFiber.yieldと同じ概念なのか。
最初からFiber.yieldについて考えていれば良かったんだ!
Fiber.yield
JavaScript のコードをRubyで再現してみる
■JavaScript(再掲)
function f(){ yield("hoge1"); yield("hoge2"); } var g=f(4); p(g.next()); p(g.next());
■実行結果
hoge1 hoge2
■Ruby
f = Fiber.new do |_| Fiber.yield("hoge1") Fiber.yield("hoge2") end p(f.resume) p(f.resume)
■実行結果
"hoge1" "hoge2"
Rubyではresumeメソッドで中断していた処理に制御を引き戻す
JavaScriptとRubyの違い
どちらも「呼び出し元」と「呼び出し先」が存在する。
どちらも「呼び出し元」に値を戻すことができる(next,resumeの戻り値)
加えてRubyのFiber.yieldは「呼び出し先」にも値を戻すことができる
f = Fiber.new do |_| response = Fiber.yield("hoge1") p(response) Fiber.yield("hoge2") end p(f.resume) #<= 最初のresumeに引数を与えるとFiberのブロック引数となる p(f.resume("omiyage"))
■実行結果
"hoge1" "omiyage" "hoge2"
なるほどね。