
Problem Statement
The objective is to create a function decorator which takes an arbitrary function fn as input and returns a new function with a very specific constraint: the original function fn can be invoked only once. The very first time this new function is called, it should execute and return the result of fn with the arguments it was called with. For any calls to this function thereafter, irrespective of the arguments provided, the return value must be undefined. This challenge essentially encapsulates creating a non-reusable function wrapper that restricts the original function to a single execution.
Examples
Example 1
Input:
fn = (a,b,c) => (a + b + c), calls = [[1,2,3],[2,3,6]]
Output:
[{"calls":1,"value":6}]Explanation:
const onceFn = once(fn); onceFn(1, 2, 3); // 6 onceFn(2, 3, 6); // undefined, fn was not called
Example 2
Input:
fn = (a,b,c) => (a * b * c), calls = [[5,7,4],[2,3,6],[4,6,8]]
Output:
[{"calls":1,"value":140}]Explanation:
const onceFn = once(fn); onceFn(5, 7, 4); // 140 onceFn(2, 3, 6); // undefined, fn was not called onceFn(4, 6, 8); // undefined, fn was not called
Constraints
callsis a valid JSON array1 <= calls.length <= 101 <= calls[i].length <= 1002 <= JSON.stringify(calls).length <= 1000
Approach and Intuition
The problem can be approached by leveraging closures in programming to retain state between function calls. Here is a step-by-step breakdown of how one can achieve the functionality of creating a function that limits fn to be called only once:
- Create a closure that encompasses
fn, ensuring that its scope allows for data retention between calls. - Within the function, implement a flag or a similar indicator which checks whether
fnhas been called before. - On the first call, the function should execute
fnusing the provided arguments and return its result while toggling the flag indicating thatfnhas been executed. - For subsequent calls, before proceeding to execution, the flag should be checked. If
fnhas already been executed (flag is toggled), then returnundefinedimmediately without callingfnagain.
This approach uses:
- Closure to maintain state (
fnhas been called or not) across multiple calls to the function. - Conditional Execution to determine if the output should be the result of
fnorundefinedbased on the number of times the function has been invoked.
By employing this approach, the function maintains simplicity in implementation while conforming to the constraint of limiting the original function's invocation to just once.
Solutions
- JavaScript
var singleCall = function(func) {
let invoked = false;
return function(...parameters){
if (!invoked) {
invoked = true;
return func.apply(this, parameters);
}
}
};
In this JavaScript solution, the goal is to create a function singleCall that controls the invocation of another function, allowing it to be executed only once, regardless of how many times it is called. The approach involves using a closure to encapsulate the state that tracks whether the function has already been called.
Here's a breakdown of how the singleCall function works:
singleCallacceptsfunc, the function to be invoked only once.- Inside
singleCall, a variableinvokedis initialized tofalse. This variable will track whetherfunchas already been executed. singleCallreturns a new function that captures bothfuncandinvokedin its scope.- When the returned function is invoked, it first checks if
invokedisfalse. - If
invokedisfalse, it setsinvokedtotrue, effectively preventing any further execution of the inner logic for subsequent calls. - It then executes
funcusingfunc.apply(this, parameters)whereparametersare the arguments passed to the function call, allowing it to maintain the same context (this) and support multiple parameters. - If an attempt is made to call the function after the first invocation, nothing happens because the execution block inside the condition will not be executed again.
This pattern is particularly useful in situations where a function must be strictly controlled to run a single time, such as initializing a component or other similar one-time-only operations.