3

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.

Andrew Diamond
  • 6,295
  • 1
  • 15
  • 33
Anuj
  • 31
  • 1
  • 4
  • Your runTwice method is return the parameter it was passed without doing anything to it. You want it to treat that parameter as a function, call it, then return that function's return value. – Nate Jul 05 '17 at 20:11
  • @KukicVladimir Your output isn't quite right... :) – deckeresq Jul 05 '17 at 20:13
  • 1
    @deckeresq, yes, you are correct, output is wrong, was not fully focused on output, my bad. :) – Kukic Vladimir Jul 05 '17 at 20:15
  • related: https://stackoverflow.com/questions/12713564/function-in-javascript-that-can-be-called-only-once – georg Jul 05 '17 at 20:39

2 Answers2

1

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));
}
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
1

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))
);
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153