SoFunction
Updated on 2025-04-11

Detailed explanation of currying in JS

What is Curryization/curryization?

Currying source and mathematician Haskell Curry's name (the programming language Haskell is also named after him).

Currying is also usually called partial evaluation. Its meaning is to pass parameters to a function step by step. After each parameter is passed, partially apply parameters, and return a more specific function to accept the remaining parameters. Multiple layers of such partial parameter functions can be nested in the middle until the final result is returned.

Therefore, the process of currying is a process of gradually passing parameters, gradually narrowing the scope of application of functions, and gradually solving them.

Currying a sum function

Following step-by-step evaluation, let's look at a simple example

var concat3Words = function (a, b, c) {
 return a+b+c;
};
var concat3WordsCurrying = function(a) {
 return function (b) {
  return function (c) {
   return a+b+c;
  };
 };
};
(concat3Words("foo ","bar ","baza"));   // foo bar baza
(concat3WordsCurrying("foo "));     // [Function]
(concat3WordsCurrying("foo ")("bar ")("baza")); // foo bar baza

You can see,concat3WordsCurrying("foo ") is a Function, each call returns a new function, which accepts another call, and then returns a new function until the result is returned, and the distribution is solved, progressing layer by layer. (PS: The characteristics of closures are taken advantage of here)

So now we go further. If we require more than 3 parameters to be passed, we can pass as many parameters as possible and output the result when the parameters are not passed?

First, let’s have a normal implementation:

var add = function(items){
 return (function(a,b){
  return a+b
 });
};
(add([1,2,3,4]));

But if you ask to multiply each number by 10 and then add it, then:

var add = function (items,multi) {
 return (function (item) {
  return item*multi;
 }).reduce(function (a, b) {
  return a + b
 });
};
(add([1, 2, 3, 4],10));

Fortunately, there are map and reduce functions. If we want to add 1 to each item and summarize it according to this pattern, then we need to replace the functions in map.

Let’s take a look at the Curryization implementation:

var adder = function () {
 var _args = [];
 return function () {
  if ( === 0) {
   return _args.reduce(function (a, b) {
    return a + b;
   });
  }
  [].(_args, [].(arguments));
  return ;
 }
}; 
var sum = adder();
(sum);  // Function
sum(100,200)(300); // The call format is flexible, one or more parameters can be entered at a time, and it supports chain callssum(400);
(sum()); // 1000 (Total calculation)

The above adder is a Curry-shaped function, which returns a new function, and the new function can accept new parameters in batches, delaying until the last calculation.

General Curry function

A more typical currying will encapsulate the last calculation into a function, and then pass this function as a parameter into the currying function, which is clear and flexible.

For example, if each term is multiplied by 10, we can pass the processing function as a parameter:

var currying = function (fn) {
 var _args = [];
 return function () {
  if ( === 0) {
   return (this, _args);
  }
  (_args, [].(arguments));
  return ;
 }
};
var multi=function () {
 var total = 0;
 for (var i = 0, c; c = arguments[i++];) {
  total += c;
 }
 return total;
};
var sum = currying(multi); 
sum(100,200)(300);
sum(400);
(sum());  // 1000 (Really calculate when blank calls)

so sum = currying(multi), the call is very clear and the usage effect is also brilliant. For example, to accumulate multiple values, you can use multiple values ​​as parameters sum(1,2,3), or support chain calls, sum(1)(2)(3)

The role of curryculation

  • Delay calculation. The above example is relatively low.
  • Parameter multiplexing. When the same function is called multiple times and the parameters passed are mostly the same, then the function may be a good candidate for currying.
  • Create functions dynamically.

This can be dynamically generated after partial calculation results, on this basis, a new function is dynamically generated to process the subsequent business, thus omitting repeated calculations. Or you can dynamically create a new function by applying part of the subset of parameters to be passed into the calling function, which saves the parameters passed repeatedly (not necessarily every time in the future). For example, an auxiliary method for event browsers to add events:

var addEvent = function(el, type, fn, capture) {
  if () {
   (type, function(e) {
    (el, e);
   }, capture);
  } else if () {
   ("on" + type, function(e) {
    (el, e);
   });
  } 
 };

Every time you add an event, you have to execute it if...else.... In fact, it only takes one judgment in a browser. A new function will be generated dynamically based on the results after one judgment, and there is no need to recalculate it in the future.

var addEvent = (function(){
 if () {
  return function(el, sType, fn, capture) {
   (sType, function(e) {
    (el, e);
   }, (capture));
  };
 } else if () {
  return function(el, sType, fn, capture) {
   ("on" + sType, function(e) {
    (el, e);
   });
  };
 }
})();

This example, after the first judgment of if...else..., part of the calculation is completed, and a new function is created dynamically to process the parameters passed in later. This is a typical currylation.

The method is also a curry application

Unlike the call/apply method that executes directly, the bind method sets the first parameter to the context of function execution, and passes other parameters to the calling method in turn (the body of the function itself does not execute, which can be regarded as delayed execution), and dynamically creates and returns a new function, which conforms to the currying characteristics.

var foo = {x: 888};
var bar = function () {
 ();
}.bind(foo);    // Bindbar(); 
// 888

Unlike the call/apply method that executes directly, the bind method sets the first parameter to the context of function execution, and passes other parameters to the calling method in turn (the body of the function itself does not execute, which can be regarded as delayed execution), and dynamically creates and returns a new function, which conforms to the currying characteristics.

var foo = {x: 888};
var bar = function () {
 ();
}.bind(foo);    // Bindbar(); 
// 888

Below is a simulation of the bind function. testBind creates and returns a new function. In the new function, the function that really wants to execute the business is bound to the context passed in the actual parameter, and the execution is delayed.

 = function (scope) {
 var fn = this;     //// This points to a function that calls the testBind method. return function () {
  return (scope);
 }
};
var testBindBar = (foo); // Bind foo, delay execution(testBindBar);    // Function (see, after bind, returns a new function that is delayed execution)testBindBar();

Here we should pay attention to the understanding of this in prototype.

Example

Example 1:

var currying = function(fn) {
 // fn refers to the means by which officials digest their wives var args = [].(arguments, 1);
 // args refers to the legitimate wife return function() {
  // The existing wives and newly settled wives are integrated to facilitate control  var newArgs = ([].(arguments));
  // These wives used fn to digest and utilize it, complete the feat of senior Wei Xiaobao and return  return (null, newArgs);
 };
};
// Here is a test of how officials can handle 7 wives// Get a legitimate wifevar getWife = currying(function() {
 var allWife = [].(arguments);
 // allwife is all wives, including the wife who came in secretly through Chen Cang ((";"));
}, "Legal Wife");
// Get 6 other wivesgetWife("Big Wife","Little Wife","Pretty Wife","The Wife","Good wife","Delivery Wife");
// Change a group of wivesgetWife("Beyond Wei Xiaobao's Wife");
 result:
Legal wife;Big wife;Little wife;Pretty wife;The unruly wife;Good wife;Deliver to my wife
Legal wife;A wife who surpasses Wei Xiaobao
Example2:
var curryWeight = function(fn) {
 var _fishWeight = [];
 return function() {
  if ( === 0) {
   return (null, _fishWeight);
  } else {
   _fishWeight = _fishWeight.concat([].(arguments));
  }
 }
};
var fishWeight = 0;
var addWeight = curryWeight(function() {
 var i=0; len = ;
 for (i; i<len; i+=1) {
  fishWeight += arguments[i];
 }
});
addWeight(2.3);
addWeight(6.5);
addWeight(1.2);
addWeight(2.5);
addWeight(); // Only calculated here(fishWeight); // 12.5

Summarize

The above is the currying function in JS introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support for my website!