JavaScript Partial Function Implementation
Many programming languages offer a concept called "partial application," which allows you to pre-fill some arguments of a function, creating a new function with fewer parameters. This is incredibly useful for creating specialized versions of general functions or for currying purposes. Your task is to implement a partial function in JavaScript that achieves this.
Problem Description
You need to create a JavaScript function named partial. This function will take two arguments:
func: The original function you want to partially apply....args: A variable number of arguments that will be pre-filled forfunc.
The partial function should return a new function. When this new function is called, it should invoke the original func with the pre-filled args followed by any arguments passed to the new function.
Key Requirements:
- The returned function must accept any number of additional arguments.
- The order of arguments is crucial: pre-filled arguments come first, followed by the arguments passed to the returned function.
- The
thiscontext of the originalfuncshould be preserved when it's eventually called.
Expected Behavior:
If partial(func, arg1, arg2) is called, and the returned function is then called with newArg1, newArg2, the original func should be invoked as func(arg1, arg2, newArg1, newArg2).
Edge Cases:
- What happens if no arguments are passed to
partialbeyond the function itself? - What happens if the original function (
func) is called with no arguments after partial application? - Consider the
thiscontext when calling the partially applied function.
Examples
Example 1:
function multiply(a, b, c) {
return a * b * c;
}
const multiplyByTwo = partial(multiply, 2);
const result1 = multiplyByTwo(3, 4); // This should be equivalent to multiply(2, 3, 4)
console.log(result1); // Expected Output: 24
Explanation:
partial is called with multiply and 2. It returns a new function multiplyByTwo. When multiplyByTwo(3, 4) is called, multiply is invoked with 2 (from the partial application) followed by 3 and 4 (from the call to multiplyByTwo).
Example 2:
function greet(greeting, name, punctuation) {
return `${greeting}, ${name}${punctuation}`;
}
const greetAlice = partial(greet, "Hello", "Alice");
const formalGreeting = greetAlice("!");
const informalGreeting = greetAlice("?");
console.log(formalGreeting); // Expected Output: Hello, Alice!
console.log(informalGreeting); // Expected Output: Hello, Alice?
Explanation:
partial is used to pre-fill both the greeting and name arguments of the greet function. The returned function (greetAlice) can then be called with the remaining punctuation argument.
Example 3:
function logMessage(level, message, timestamp) {
console.log(`[${level}] ${message} - ${timestamp}`);
}
const infoLogger = partial(logMessage, "INFO");
const warnLogger = partial(logMessage, "WARN");
const now = new Date().toISOString();
// Demonstrate preserving 'this' context if needed (though less common for simple functions)
const boundLogger = {
level: "DEBUG",
log: function(msg, ts) {
console.log(`[${this.level}] ${msg} - ${ts}`);
}
};
const partiallyBoundLogger = partial(boundLogger.log, boundLogger.level);
infoLogger("User logged in", now); // Expected: [INFO] User logged in - [current timestamp]
warnLogger("Disk space low", now); // Expected: [WARN] Disk space low - [current timestamp]
partiallyBoundLogger("System restart initiated", now); // Expected: [DEBUG] System restart initiated - [current timestamp]
Explanation:
This example shows how partial can be used with functions that might rely on a this context. By passing boundLogger.level as a pre-filled argument, we ensure that logMessage (when called via partiallyBoundLogger) receives the correct level. Note that for this context preservation in a more robust way, one might consider bind alongside partial, but for this challenge, handling pre-filled arguments is the primary focus. The this context of boundLogger.log itself is implicitly handled if you were to call partiallyBoundLogger.call(boundLogger, ...) where this is boundLogger. For the purpose of this challenge, we assume the this context will be the global object or undefined in strict mode if not explicitly bound.
Constraints
- The
partialfunction should be a pure function (no side effects beyond returning a new function). - The
partialfunction should not modify the originalfunc. - The implementation should be efficient and avoid unnecessary overhead.
- You should use modern JavaScript features (ES6+).
Notes
- Consider how you will collect and pass all the arguments to the original function. Array methods like
concator the spread syntax (...) will be your friends. - Think about how to handle the
thiscontext correctly. Theapplyorcallmethods of functions are relevant here. - This implementation is a foundational step towards understanding functional programming concepts like currying and higher-order functions.