Implementing a Custom _.partial() Function in JavaScript



The _.partial method from Lodash allows you to create a function that pre-fills some of its arguments, leaving the rest to be provided later. This technique is known as partial application.

Let's implement a custom version of _.partial in JavaScript.


What is Partial Application?

Partial application refers to the process of fixing a number of arguments to a function, producing a new function with a smaller arity (number of arguments). It’s useful for creating more specific functions from general-purpose ones.

Real Interview Insights

Interviewers might ask you to:

  • Implement a function that mimics the behavior of Lodash’s _.partial.
  • Handle edge cases such as functions with varying numbers of arguments and placeholders.

Implementing customPartial Function

Here’s how you can implement a custom _.partial function:

function customPartial(func, ...boundArgs) {
  return function(...remainingArgs) {
    let args = boundArgs.slice();
    let i = 0;
    // Replace placeholders with actual arguments
    for (let j = 0; j < args.length; j++) {
      if (args[j] === customPartial.placeholder) {
        args[j] = remainingArgs[i++];
      }
    }
    // Concatenate remaining arguments
    args = args.concat(remainingArgs.slice(i));
    return func.apply(this, args);
  };
}
 
// Define a placeholder
customPartial.placeholder = '_';
Explanation:
  • Argument Binding: The boundArgs are the arguments provided when creating the partial function. These are stored and partially fill the function's parameters.
  • Handling Placeholders: If a placeholder is found in boundArgs, it is replaced with the corresponding argument from remainingArgs.
  • Applying the Function: The resulting arguments array is then passed to the original function using func.apply.

Practical Examples

Let's see the customPartial function in action:

function greet(greeting, name, exclamation) {
  return `${greeting}, ${name}${exclamation}`;
}
 
const greetHello = customPartial(greet, 'Hello', customPartial.placeholder, '!');
console.log(greetHello('John')); // Output: 'Hello, John!'
 
const greetHi = customPartial(greet, 'Hi', 'Sam');
console.log(greetHi('!!')); // Output: 'Hi, Sam!!'

Handling Edge Cases

  1. No Bound Arguments: If no arguments are bound, the function behaves like the original function.
  2. Multiple Placeholders: Handle cases where multiple placeholders are used, and the correct mapping of arguments is maintained.

Enhanced Implementation with Multiple Placeholders

function customPartial(func, ...boundArgs) {
  return function(...remainingArgs) {
    let args = boundArgs.slice();
    let i = 0;
    // Replace placeholders with actual arguments
    for (let j = 0; j < args.length; j++) {
      if (args[j] === customPartial.placeholder) {
        args[j] = remainingArgs[i++];
      }
    }
    // Concatenate remaining arguments
    args = args.concat(remainingArgs.slice(i));
    return func.apply(this, args);
  };
}
 
customPartial.placeholder = '_';

Use Cases for Partial Application

  1. Function Customization: Create specialized versions of general-purpose functions.
  2. Currying: Partial application can be a step towards currying, where a function with multiple arguments is transformed into a series of functions with single arguments.
  3. Code Reusability: Reuse logic by binding specific parameters and creating new functions.