以前書いた サンプルに惑わされるな!KnockoutでUIエフェクトを使う際のベター・プラクティス という記事で、エフェクタを View 側のコードとして定義する方法をおすすめしました。
window.effects = (function($) {
var root = {}
, list = root.list = {}
;
list.fadeIn = function(elm) {
$(elm).hide().fadeIn();
};
list.fadeOut = function(elm) {
$(elm).fadeOut(300, function() { $(elm).remove() });
};
return root;
})(jQuery);
今回はそのエフェクタの、もうすこし突き進めた作り方を書いてみます。
高階関数とは
いかにも難しそうな名前ですが、単なる「関数を返却する関数」のことです。
function example() {
return function() {
alert("example!");
}
}
var e = example();
e(); // -> example!
高階関数でパラメータを扱う
内側の返却される関数で受け取る引数と、外側の高階関数で受け取る引数はそれぞれ使い道があります。
返却される関数の引数
つまり関数の実行時の引数です →param
function example() {
return function(param) {
alert(param);
}
}
var e = example();
e("KnockoutJS"); // -> KnockoutJS
e("VueJS"); // -> VueJS
高階関数の引数
関数を生成するときに決定される引数です →param1
function example(param1) {
return function(param2) {
alert(param1 + param2);
}
}
var e = example("hello "); // ここで決定
e("KnockoutJS"); // -> hello KnockoutJS
e("VueJS"); // -> hello VueJS
エフェクタへ応用
高階関数を使って、以下のフェードエフェクトのスピードをバインド時に設定できるようにしてみましょう。
window.effects = (function($) {
var root = {}
, list = root.list = {}
;
list.fadeIn = function(elm) {
$(elm).hide().fadeIn();
};
list.fadeOut = function(elm) {
$(elm).fadeOut(300, function() { $(elm).remove() });
};
return root;
})(jQuery);
↓↓↓
window.effects = (function($) {
var root = {}
, list = root.list = {}
;
list.fadeIn = function(duration) {
return function(elm) {
$(elm).hide().fadeIn(duration);
};
};
list.fadeOut = function(duration) {
return function(elm) {
$(elm).fadeOut(duration, function() { $(elm).remove() });
};
};
return root;
})(jQuery);
duration という引数を受け取る高階関数に変更しました。
これをバインドするとき、以下のように引数を指定します。
<ul data-bind="foreach: {
data: items,
afterAdd: effects.list.fadeIn(200),
beforeRemove: effects.list.fadeOut(600) }">
<li data-bind="text: $data"></li>
</ul>
上記の例では、リストにアイテムが追加されると200ミリ秒でフェードイン、
アイテムが削除されると600ミリ秒かけてフェードアウトします。
つまり、「View でバインドするときに決定されるパラメータ」を設けるために高階関数というものを使いました。effects.list.fadeIn(200)
を実行すると、duration
が 200
に決定されたエフェクタ関数が返却されます。その返却されたエフェクタ関数が afterAdd
としてバインドされる、という寸法です。
フェード以外のエフェクタを実装する際にもいろいろと応用が利きますし、コンバータを実装する 際にも使えます。