How to Use the Lodash _.wrap Method

The Lodash _.wrap method is a utility that enables developers to encapsulate an existing function inside a wrapper function, providing a clean mechanism for adding custom pre-execution and post-execution logic. By supplying the target function as the first argument to the wrapper, _.wrap facilitates argument inspection, condition-based execution, and return value modification without altering the original function's codebase.

Understanding the Syntax

The syntax for _.wrap is straightforward:

_.wrap(value, [wrapper=identity])

When the wrapped function is executed, Lodash delegates the call to the wrapper, granting full control over when, how, or even if the original function is invoked.

Implementing Pre-Logic

Pre-logic refers to code that runs before the wrapped function is called. Common use cases include parameter validation, authentication checks, logging incoming parameters, or sanitizing inputs.

Because the wrapper receives the original function as its first argument and the caller's arguments as subsequent parameters, you can inspect or modify these inputs before forwarding them:

const _ = require('lodash');

function greet(name) {
  return `Hello, ${name}!`;
}

const secureGreet = _.wrap(greet, function(originalFn, name) {
  // Pre-logic: Validation
  if (!name || typeof name !== 'string') {
    return 'Hello, Guest!';
  }
  
  // Pre-logic: Input transformation
  const capitalized = name.trim().toUpperCase();
  
  // Calling the original function with modified arguments
  return originalFn(capitalized);
});

console.log(secureGreet('alice ')); // "Hello, ALICE!"
console.log(secureGreet(null));     // "Hello, Guest!"

Implementing Post-Logic

Post-logic runs after the original function has resolved. This is ideal for transforming output, logging execution metrics, caching results, or handling clean-up operations.

To implement post-logic, capture the return value of the original function inside the wrapper, execute your custom logic, and return the final processed value:

const _ = require('lodash');

function calculateTotal(subtotal, taxRate) {
  return subtotal + (subtotal * taxRate);
}

const formattedTotal = _.wrap(calculateTotal, function(originalFn, subtotal, taxRate) {
  // Execute the original logic
  const total = originalFn(subtotal, taxRate);

  // Post-logic: Format as currency string
  return `$${total.toFixed(2)}`;
});

console.log(formattedTotal(100, 0.0825)); // "$108.25"

Combining Pre- and Post-Logic

You can combine both steps into a single wrapper to create a full lifecycle interception pattern (often referred to as an Aspect-Oriented or Decorator pattern):

const _ = require('lodash');

function processOrder(orderId) {
  return { orderId, status: 'processed' };
}

const auditedProcessOrder = _.wrap(processOrder, function(originalFn, ...args) {
  // Pre-logic
  console.time('OrderProcessingTime');
  console.log(`Starting processing for: ${args[0]}`);

  // Core execution
  const result = originalFn(...args);

  // Post-logic
  console.timeEnd('OrderProcessingTime');
  return {
    ...result,
    timestamp: new Date().toISOString()
  };
});

auditedProcessOrder('ORD-12345');

Common Use Cases