JavaScriptの関数コリック化

2833 ワード

コリ化とは?
ウィキペディアでは、コリック化は、複数のパラメータを受け取る関数を単一のパラメータ(最初の関数の最初のパラメータ)を受け入れる関数に変換し、残りのパラメータを受け入れて結果を返す新しい関数の技術として説明しています.関数が呼び出された場合には、戻ってきた関数にもいくつかのパラメータを設定する必要があるという意味です.
まず簡単な例を見ます.次の関数があります.
function add(num1, num2) {
  return num1 + num2;
}
私たちはそれを次のように書き換えました.
var fn = function(a) {
  return function (b) {
    return a + b;
  }
}
このように関数を呼び出すことができます.fn(2)(3).上記では匿名関数を用いて多パラメータ関数を実現する方法がありますが、これはカリー化の関数ではありませんが、カリー化の意味を理解する助けになります.
汎用コリメート関数の実現
構造関数Function()を内蔵したプロトタイプにカーリー関数を追加できます.このようにすべての関数が呼び出されます.以下は汎用コリメート関数の実装です.
Function.prototype.currying = function () {
  var that = this;
  var args = [].slice.call(arguments);
  return function () {
    return that.apply(null, args.concat([].slice.call(arguments)));
  }
}
今はカリー化関数で上のadd関数をカリー化します.
var curriedAdd = add.currying(2);
curriedAdd(3); // 5
一度に二つのパラメータに入ることもできます.
var curriedAdd = add.currying(2, 3);
curriedAdd(); // 5
元のオブジェクトのプロトタイプに拡張する方法はあまり良くないことを知っています.ネーミングの衝突につながるかもしれません.したがって、currying関数をFunctionのプロトタイプに拡張しないほうがいいです.以下は書き換えられたcurrying関数です.
function currying(fn) {
  var args = [].slice.call(arguments, 1);
  return function () {
    return that.apply(null, args.concat([].slice.call(arguments)));
  }
}
書き換えた後のcurrying関数の最初のパラメータは、コリック化される関数であり、このように呼び出すことができる.
var curriedAdd = currying(add, 2);
curriedAdd(3); // 5
 
var curriedAdd = currying(add, 2, 3);
curriedAdd(); // 5
上のadd関数は2つの数字の加算だけです.もしn個の数字が必要なら、上のcurrying関数はもう要求を満たすことができなくなりました.以下は修正後のcurrying関数です.
function currying(fn) {
  var argsArr = [];
  return function () {
    if (arguments.length === 0) {
      return fn.apply(null, argsArr);
    } else {
      [].push.apply(argsArr, arguments);
    }
  }
}
複数の数字を足す:
var add = function () {
  var num = 0;
  [].forEach.call(arguments, function (item, i) {
    num += item;
  })
  return num;	
}

var curriedAdd = currying(add);
curriedAdd(2);
curriedAdd(3);
curriedAdd(4);
curriedAdd(5);
curriedAdd(); // 14
このようにするとどんなメリットがありますか?もし私たちは今月いくらかかりましたか?途中のある日までどれぐらいかかりましたか?私たちは知りたくないです.結果を気にして、過程を気にしないで、上のcurrying関数はよくこの問題を解決しました.このようにすれば性能が節約できるという人がいますが、性能とは関係ないと思います.あるいは、性能のためではなく、毎回計算した結果と最後に一緒に計算した結果は同じです.同じ回数を計算します.もう一つの利点は、複数のデジタル掛け算または他の動作を必要とするcurrying関数を多重化することができ、処理数はfnパラメータを変更するだけでよい.
カリー化といえば、Function.prototype.bindという方法を言わざるを得ません.関数のカリー化も実現しました.私たちは自分でbind関数を実現することができます.
function bind(fn, context) {
  var args = [].slice.call(arguments, 2);
  return function () {
    return fn.apply(context, args.concat([].slice.call(arguments)));
  }
}
fn中のthisコンテキストを変える必要があれば、bind関数を使ってもいいです.そうでなければ、currying関数を使ってもいいです.