関数の数珠つなぎ
nueでは、独立に定義された関数を数珠つなぎにしています。
その中核を担っているコードはこんなです。
function chain(functions) { return functions.reduceRight(function (next, curr) { return function () { curr.apply({next: next}, arguments); } }); }
このコード、短い割には使い勝手がいいんじゃないかと思っています。
ちょっと使ってみましょう。a, b, cという3つの関数を定義して数珠つなぎしたあと実行してみます。
var slice = Array.prototype.slice; function a() { console.log('a is called. args: ' + slice.call(arguments)); this.next('aaa', 123); } function b() { console.log('b is called. args: ' + slice.call(arguments)); this.next('bbb', 345); } function c() { console.log('c is called. args: ' + slice.call(arguments)); } var f = chain([a, b, c]); // ここで最初に示したchain関数を呼ぶ f('hoge');
実行結果はこうなります。
a is called. args: hoge b is called. args: aaa,123 c is called. args: bbb,345
この例では、this.nextしたら次の関数を呼ぶようにしていますが、returnしたら戻り値を引数にして次の関数を呼ぶようにしたり、間になんか処理を挟んだりするのも容易です。
じつは、この数珠つなぎのコード、ASP.NET MVCの次のコードからヒントを得たものだったりします。
http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266452
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation, (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
関数とクロージャの組み合わせはほんとに便利ですね。