Problem#
Given a function fn
, return a new function that is identical to the original function except that it ensures fn
is called at most once.
The first time the returned function is called, it should return the same result as fn
.
Every subsequent time it is called, it should return undefined
.
Examples#
Example 1#
1
2
3
4
5
6
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#
1
2
3
4
5
6
7
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#
calls
is a valid JSON array
1 <= calls.length <= 10
1 <= calls[i].length <= 100
2 <= JSON.stringify(calls).length <= 1000
Solution#
Method 1 – Using Closure to Track Calls#
Intuition#
The key idea is to use a closure to remember whether the function has already been called. By storing a flag inside the returned function, we can ensure the original function is only executed once, and subsequent calls return undefined
.
Approach#
Define a function onceWithClosure
that takes a function fn
as input.
Inside onceWithClosure
, declare a boolean variable (e.g., called
) initialized to false
.
Also declare a variable to store the result of the first call.
Return a new function that:
Checks if called
is false
.
If so, set called
to true
, call fn
with the provided arguments, store and return the result.
If called
is true
, return undefined
.
This ensures fn
is only called once, regardless of how many times the returned function is invoked.
Code#
Javascript
Typescript
1
2
3
4
5
6
7
8
9
10
11
12
function onceWithClosure (fn ) {
let called = false ;
let result ;
return function (...args ) {
if (! called ) {
called = true ;
result = fn (...args );
return result ;
}
return undefined ;
};
}
1
2
3
4
5
6
7
8
9
10
11
12
function onceWithClosure <T extends ( ...args : any []) = > any > (fn : T ): (...args : Parameters <T >) => ReturnType <T > | undefined {
let called = false ;
let result : ReturnType <T >;
return (...args : Parameters <T >): ReturnType <T > | undefined => {
if (! called ) {
called = true ;
result = fn (...args );
return result ;
}
return undefined ;
};
}
Complexity#
⏰ Time complexity: O(1)
per call, as it only checks a flag and possibly calls fn
once.
🧺 Space complexity: O(1)
, only a couple of variables are stored in the closure.