カレーの実装
JS関数合成は、複数の単一パラメーター関数を1つのマルチパラメーター関数に結合する操作です。たとえば、a(x)とb(x)を組み合わせてa(b(x))にする場合、それらをまとめてf(a、b、x)と呼びます。ここでのa(x)とb(x)の両方が受け取ることができるパラメーターは1つだけであることに注意してください。a(x、y)やb(a、b、c)などの複数のパラメーターを受け取る場合、関数の合成はより面倒です。
このとき、機能カリー化を使用します。いわゆるカリー化は、マルチパラメータ関数をシングルパラメータ関数に変換することです。カリー化操作により、すべての関数が1つのパラメーターのみを受け取るようにすることができます。
var add = function (x) { //柯里化
return function (y) {
return x + y;
}
}
console.log(add(2) (6)); //8,连续调用
//柯里化函数
function curry (fn) {
var _argLen = fn.length; //记录原始函数的形参个数
var _args = [].slice.call(arguments, 1); //把传入的第2个及以后参数转换为数组
function wrap () { //curry函数
//把当前参数转换为数组,与前面参数进行合并
_args = _args.concat([].slice.call(arguments));
function act () { //参数处理函数
//把当前参数转换为数组,与前面参数进行合并
_args = _args.concat([].slice.call(arguments));
//如果传入参数总和大于等于原始参数的个数,触发执行条件
if ((_argLen == 0 && arguments.length == 0) ||
(_argLen > 0 && _args.length >= _argLen)) {
//执行原始函数,并把每次传入参数传入进去,返回执行结果,停止curry
return fn.apply(null, _args);
}
return arguments.callee;
}
//如果传入参数大于等于原始函数的参数个数,即触发了执行条件
if ((_argLen == 0 && arguments.length == 0) ||
(_argLen > 0 && _args.length >= _argLen)) {
//执行原始函数,并把每次传入参数传入进去,返回执行结果,停止curry
return fn.apply(null, _args);
}
act.toString = function () { //定义处理函数的字符串表示为原始函数的字符串表示
return fn.toString();
}
return act; //返回处理函数
}
return wrap; //返回curry函数
}
合成機能の実現
JS関数型プログラミングでは、次の式演算がよく見られます。
a(b(c(x)));
これは「キャベツスタイル」の多層関数呼び出しですが、あまりエレガントではありません。マルチレベル関数呼び出しのネストの問題を解決するには、関数合成を使用する必要があります。構文形式は次のとおりです。
var f = compose(a, b, c); //合成函数
f(x);
递归实现:
const compose = function (...funcs) {
let len = funcs.length,
count = len - 1,
result = null;
// 首先compse 返回的是一个函数
return function fn(...args) {
// 函数体里就是不断执行args函数,将上一个函数的执行结果作为下一个执行函数的输入参数,需要一个count来记录args函数列表的执行情况
result = args[count].apply(this, args);
console.log(result);
// 递归退出条件
if (count <= 0) {
count = len - 1;
} else {
count--;
return fn.call(null, result);
}
};
};
反復実装:
function compose(...fns) {
let isFirst = true;
return (...args) => {
return fns.reduceRight((result, fn) => {
if (!isFirst) return fn(result);
isFirst = false;
return fn(...result);
}, args);
};
}