JavaScript Currying Explained: Partial Applications and Beyond

2024-07-27

Currying is a functional programming technique that transforms a function accepting multiple arguments into a sequence of functions, each taking a single argument. It allows you to create a series of "partial applications" of the original function, where each application captures a portion of the arguments and returns a new function that expects the remaining arguments.

How Currying Works

Here's how currying works in JavaScript, leveraging closures:

  1. function add(a, b) {
        return a + b;
    }
    
  2. Create a Currying Function: You write a new function that takes the first argument and returns a nested function. The nested function captures the first argument using a closure and takes the remaining arguments:

    function curry(fn) {
        return function(a) {
            return function(b) {
                return fn(a, b);
            };
        };
    }
    
  3. const addCurried = curry(add);
    
  4. Partial Applications: Call the curried function with the first argument:

    const add5 = addCurried(5); // This captures 5 as the first argument
    

    Now, add5 is a new function that expects the second argument:

    const result = add5(3); // This provides the second argument (3)
    console.log(result); // Output: 8
    

Benefits of Currying

  • Partial Application: As demonstrated above, currying allows you to create pre-configured functions with some arguments fixed, promoting code reusability.
  • Functional Composition: Curried functions can be easily combined with other functions to create more complex operations, aligning well with functional programming principles.
  • Flexibility: Currying provides flexibility in how you provide arguments to a function.

Terminology:

  • Functional Programming: A programming paradigm that emphasizes functions as first-class citizens, treating them as values that can be passed around, stored in variables, and returned from other functions.
  • Closure: A function that has access to the variable environment of its outer (enclosing) function, even after the outer function has returned. In currying, the closure captures the first argument passed to the curried function.



function add(a, b) {
  return a + b;
}

function curry(fn) {
  return function(a) {
    return function(b) {
      return fn(a, b);
    };
  };
}

const addCurried = curry(add);

const add5 = addCurried(5);
const result1 = add5(3); // Output: 8

const add10 = addCurried(10);
const result2 = add10(20); // Output: 30

This code defines the add function, then uses a curry function to create a curried version (addCurried). You can then call addCurried with the first argument, resulting in a new function that expects the second argument.

More Advanced Currying:

function multiply(a, b, c) {
  return a * b * c;
}

function curry(fn, arity = fn.length) {
  // `arity` keeps track of the expected number of arguments
  return function curried(arg) {
    const args = [arg]; // Store arguments in an array

    return function inner(nextArg) {
      if (args.length === arity) {
        return fn(...args); // Apply the original function with all arguments
      } else {
        args.push(nextArg);
        return inner; // Return itself to capture the next argument
      }
    };
  };
}

const multiplyCurried = curry(multiply);

const multiplyBy5 = multiplyCurried(5);
const result3 = multiplyBy5(3)(2); // Output: 30

const startWith4 = multiplyCurried(4);
const result4 = startWith4(2)(7); // Output: 56

This example enhances the curry function to keep track of the expected number of arguments (arity) using a default parameter. It also uses an array to store the arguments progressively. This allows currying functions that take more than two arguments.




The built-in bind method allows you to create a new function with a pre-defined set of arguments for another function. This is similar to partial application achieved through currying.

Here's an example:

function add(a, b) {
  return a + b;
}

const add5 = add.bind(null, 5); // Pre-set first argument to 5
const result = add5(3); // Only provide the second argument
console.log(result); // Output: 8

In this approach, bind creates a new function add5 that internally holds the value 5 for the first argument. When you call add5(3), you only need to provide the second argument.

Function Composition:

Functional programming heavily utilizes function composition, where functions are chained together to create complex operations. You can achieve similar results to currying by composing functions.

function add5(x) {
  return x + 5;
}

function multiply(y) {
  return function(x) {
    return x * y;
  };
}

const multiplyBy7 = multiply(7);
const result = multiplyBy7(add5(10)); // (10 + 5) * 7
console.log(result); // Output: 105

In this approach, add5 adds 5 to its argument. multiply creates a new function that takes one argument and multiplies it by a pre-defined value (captured in the closure). Chaining these functions achieves a similar outcome to a curried function.

Choosing the Right Method:

  • Currying: Suitable when you need to create pre-configured functions with varying argument combinations used frequently. It emphasizes code reusability and promotes a functional style.
  • Partial Application (bind): Simpler approach for situations where you only need to fix a few arguments and don't require a full currying setup.
  • Function Composition: Powerful for building complex operations by chaining functions together, offering flexibility in how you construct the logic flow.

javascript functional-programming terminology



Enhancing Textarea Usability: The Art of Auto-sizing

We'll create a container element, typically a <div>, to hold the actual <textarea> element and another hidden <div>. This hidden element will be used to mirror the content of the textarea...


Understanding the Example Codes

Understanding IsNumeric()In JavaScript, the isNaN() function is a built-in method used to determine if a given value is a number or not...


Alternative Methods for Escaping HTML Strings in jQuery

Understanding HTML Escaping:HTML escaping is a crucial practice to prevent malicious code injection attacks, such as cross-site scripting (XSS)...


Learning jQuery: Where to Start and Why You Might Ask

JavaScript: This is a programming language used to create interactive elements on web pages.jQuery: This is a library built on top of JavaScript...


Detecting Undefined Object Properties in JavaScript

Understanding the Problem: In JavaScript, objects can have properties. If you try to access a property that doesn't exist...



javascript functional programming terminology

Unveiling Website Fonts: Techniques for Developers and Designers

The most reliable method is using your browser's developer tools. Here's a general process (specific keys might differ slightly):


Ensuring a Smooth User Experience: Best Practices for Popups in JavaScript

Browsers have built-in popup blockers to prevent annoying ads or malicious windows from automatically opening.This can conflict with legitimate popups your website might use


Interactive Backgrounds with JavaScript: A Guide to Changing Colors on the Fly

Provides the structure and content of a web page.You create elements like <div>, <p>, etc. , to define different sections of your page


Understanding the Code Examples for JavaScript Object Length

Understanding the ConceptUnlike arrays which have a built-in length property, JavaScript objects don't directly provide a length property


Choosing the Right Tool for the Job: Graph Visualization Options in JavaScript

These libraries empower you to create interactive and informative visualizations of graphs (networks of nodes connected by edges) in web browsers