Allow One Function Call

Updated on 21 May, 2025
Allow One Function Call header image

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

  • calls is a valid JSON array
  • 1 <= calls.length <= 10
  • 1 <= calls[i].length <= 100
  • 2 <= 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:

  1. Create a closure that encompasses fn, ensuring that its scope allows for data retention between calls.
  2. Within the function, implement a flag or a similar indicator which checks whether fn has been called before.
  3. On the first call, the function should execute fn using the provided arguments and return its result while toggling the flag indicating that fn has been executed.
  4. For subsequent calls, before proceeding to execution, the flag should be checked. If fn has already been executed (flag is toggled), then return undefined immediately without calling fn again.

This approach uses:

  • Closure to maintain state (fn has been called or not) across multiple calls to the function.
  • Conditional Execution to determine if the output should be the result of fn or undefined based 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
js
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:

  • singleCall accepts func, the function to be invoked only once.
  • Inside singleCall, a variable invoked is initialized to false. This variable will track whether func has already been executed.
  • singleCall returns a new function that captures both func and invoked in its scope.
  • When the returned function is invoked, it first checks if invoked is false.
  • If invoked is false, it sets invoked to true, effectively preventing any further execution of the inner logic for subsequent calls.
  • It then executes func using func.apply(this, parameters) where parameters are 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.

Comments

No comments yet.