Anuj
Anuj

Reputation: 31

Function that counts how often it call another function

I have a 'twice' function that return 2 of the argument passed into it. I also have another function 'runTwice' that counts the number of times it called the 'twice' function (the idea being that I want the 'twice' function to only run 'twice' no matter how often it is called via the 'runTwice' function). Can you please help?

Functions are given below:

var count = 1;
    
function twice(num){
  return num*2;
}

function runTwice(func){
  if (count<3){
    count++;
    return func;
  } else {
    return 'Function cannot run!';
  }
}
    
var myFunc = runTwice(twice)
    
var output = [];

for (var i = 0; i < 3; i++){
  output.push(myFunc(i));
}

console.log(output);

I would like the output to be [0, 2, 'Function cannot run!'].

I can make this work if I count the 'twice' function directly but I am looking to understand why this doesn't work as presented above.

Upvotes: 3

Views: 151

Answers (2)

ibrahim mahrir
ibrahim mahrir

Reputation: 31712

The function runTwice should return another function that will decide whether to call the function func (using Function.prototype.apply) or to return a string message instead:

function twice(num){
    return num * 2;
}

function runTwice(func){
    var count = 0;                              // this will be trapped in a closure along with func
    return function() {                         // this is the function that gets called
      count++;                                  // it increments its version of the count variable
      if(count <= 2)                            // if count is less than 2
        return func.apply(this, arguments);     // then it calls the function func with whatever arguments passed into it and return the returned value of that call
      return "Not available anymore!";          // otherwise (count > 2), then it returns a string
    }
}

var myFunc = runTwice(twice);

for (var i = 0; i < 3; i++){
    console.log(myFunc(i));
}

Even better:

You can pass in the number of times allowed as well:

function double(num) {
    return num * 2;
}

function triple(num) {
    return num * 3;
}

function run(func, times){
    var count = 0;                              // this will be trapped in a closure along with func and times
    return function() {                         // this is the function that gets called
      count++;                                  // it increments its version of the count variable
      if(count <= times)                        // if count is less than times
        return func.apply(this, arguments);     // then it calls the function func with whatever arguments passed into it and return the returned value of that call
      return "Not available anymore!";          // otherwise (count > times), then it returns a string
    }
}

var double2times = run(double, 2);              // double2times can only be called 2 times
var triple5times = run(triple, 5);              // triple5times can only be called 5 times

for (var i = 0; i < 10; i++){
    console.log("Double:", double2times(i));
    console.log("Triple:", triple5times(i));
}

Upvotes: 1

Patrick Roberts
Patrick Roberts

Reputation: 51916

Just for fun I'll make a generic expireAfter(invocable[, times[, message]]) function:

function expireAfter(invocable, times = 2, message = 'Function cannot run!') {
  return function expires() {
    if (times > 0) {
      times--;

      return invocable.apply(this, arguments);
    }
    
    return message;
  }
}

function twice(n) {
  return n * 2;
}

var myFunc = expireAfter(twice);

console.log(Array(3)
  .fill()
  .map((_, index) => myFunc(index))
);

Upvotes: 1

Related Questions