Introduction

Functional array methods in JavaScript like Map, Filter, and Reduce are both elegant and maintainable. While they are exceedingly powerful, when first starting out I commonly ran into the problem of needing shared context/data within the inner function. A naive solution would be to bundle the needed shared data with each element in the starting structure. This however, adds an unnecessary bundling step and wastes space. A better solution would be to flip the problem around. Instead of adding context on the data side, why not add it to the inner function itself? This approach, called partial application, is much more flexible.

Partial Application Example

Lets say we are writing a program to generate email addresses from a list of names. Each email has the same domain and this will be the shared context. (Names generated via: www.behindthename.com)

First, lets specify an example domain and a list of names:

const exampleDomain = "example.com";

const names = [
    "Freya Hirsch",
    "Emilia Tso",
    "Nolene Ayodele",
    "Artyom Utkin",
    "Eutimio Penn"
];

Next, lets craft a generic function that generates an email from a domain and a name:

const genEmail = (name, domain) => {
    const [firstName, lastName] = name.toLowerCase().split(" ");
    const firstInitial = firstName[0];

    return `${firstInitial}${lastName}@${domain}`;
};

Finally, lets create a more specific function that generates an email based off of our example domain by partially applying the generic function above:

const genExampleEmail = (name) => {
    return genEmail(name, exampleDomain);
};

This process "fills in" some of the data needed and gives shared context to any calling function. For example, to see the emails we can map over the names with our new function and log them:

console.log(names.map(genExampleEmail));
// ["fhirsch@example.com", "etso@example.com", ...]

Conclusion

Partial application can effectively add context to functions. This is especially useful when working with higher-order functions such as map, filter, or reduce. This approach is flexible as it allows for the creation of many specific, "filled in" functions and retains maintainability by separating data from application logic.

(P.S. If higher order functions are of interest to you, I would recommend checking out currying. Currying builds on the idea of partial application and is very important in functional programming.)

Futher Reading