Прочтите эту статью на испанском языке.

Каррирование — это процесс декомпозиции функции с более чем одним параметром в цепочку функций, вызываемых с одинаковым количеством аргументов, но частично. Название происходит от его применения в математике.

// function add without curry
function add(a, b, c) {
  return a + b + c;
}
console.log( add(1, 2, 3) ); // 6
// Curry example.
// It calls the function three times,
// one argument at time
function curryingAdd(a) {
  return (b) => {
    return (c) => {
      return a + b + c;
    };
  };
}
console.log( curryingAdd(1)(2)(3) ); // 6

Но это решение слишком специфично. Если бы мы хотели повторить одну и ту же технику для разных случаев, нам пришлось бы генерировать новую функцию для каждого из них с правильным количеством аргументов и вызовов.

Альтернативы

Ангус Кролл делится подходом, основанным на библиотеке Prototype.js. Он добавляет метод curry в прототип функции, позволяя использовать его для всех функций.

Я внес некоторые изменения в код, чтобы добавить некоторые пояснения:

Function.prototype.curry = function() {
    // without arguments, it returns the original function (this)
if (arguments.length < 1) return this;
    // _method is the "currified" function. The first time
    // it will be the add() function, added at the bottom
    // of this example. But later, it will be the
    // anonymous function returned in each execution.
    // You can add a log here to test it.
    var __method = this;
    // Array.prototype.slice.call transforms the arguments
    // into an array. It allows to use the concat method later.
    var args = Array.prototype.slice.call(arguments);
    // Each call with .curry() returns a function, wrapping
    // the previously returned one. This anonymus function
    // will be called when all the chain of executions ends,
    // and the program starts doing the inverse path.
    return function() {
        // all collects the arguments from each call,
        // concatenating them with those from the previous call
        var all = args.concat(Array.prototype.slice.call(arguments);
        // __method saves a reference to the previous context,
        // so it will be called with the previous args, 
        // and completing all.
        var result = __method.apply( this, all );
        // When all the functions are called, the last one is the          
        // original ( add() for this case ), and it is called with
        // all the parameters.
        return result;
    }
}
// función sin curry
var add = function(a, b, c, d, e) {
    return a + b + c + d + e;
}
var a = add.curry(1); // curry is part of Function prototype
var b = a.curry(1);
var c = b.curry(1);
var d = c.curry(1);
console.log( d(1) ); // 5
var one = add.curry(1, 1, 1); // you can send more than one arg!
var two = one.curry(1);
console.log( two(1) ); // 5

Прототип.js

С Prototype просто импортируйте библиотеку, и curry будет готов к использованию, как и в предыдущем примере.

<script src="/path/to/prototype.js" ></script>
<script>
    var add = function(a, b, c, d, e) {
        return a + b + c + d + e;
    }
    var one = add.curry(1, 1, 1);
    var two = one.curry(1);
    console.log( two(1) ); // 5
</script>

Lodash.js

Lodash не изменяет прототип функции, и это заставляет нас создавать новую версию нашей функции, используя ее метод _.curry. Библиотека создает цепочку возвратов автоматически.

<script src="/path/to/lodash.js" ></script>
<script>
    var add = function(a, b, c, d, e) {
        return a + b + c + d + e;
    }
    var addCurry = _.curry(add);
    var two = addCurry(1,1,1)(1);
    console.log( two(1) ); // 5
<script>

Когда это полезно?

Как мы узнали, исходная функция больше не является единственной точкой входа. Мы можем создавать настраиваемые функции, которые можно вызывать в разных точках нашей программы, вплоть до конечного результата. Простой пример:

function bye(a, b) => `Have a ${a}, ${b}.`;
const night = bye.curry('good night');
// Have a good night, see you tomorrow
console.log( night('see you tomorrow') );
// Have a good night, sweet dreams
console.log( night('sweet dreams') );

Вопросы? @mpjme поделился очень хорошим введением в своей серии видеороликов о функциональном программировании на JavaScript.