Javascript - 调用一个函数是另一个函数的参数?

时间:2018-02-02 15:01:11

标签: javascript

如果functionA是另一个functionB的参数,而functionB有一个调用functionA的循环,我们如何重复调用functionA而不是将functionA存储为常量var?

function rollDie() {
    var die = [1, 2, 3, 4, 5, 6];
    return die[Math.floor(Math.random() * values.length)];
}

function rollFalseDie() {
    var falseDie = [1, 1, 4, 4, 4, 4];
    return falseDie[Math.floor(Math.random() * values.length)];
}

function rollDiceNTimes (function1, function2, n) {
    if (n > 0) {
        if (function1 > function2) return 1 + rollDiceNTimes(function1, function2, n-1);
        else return rollDiceNTimes(function1, function2, n-1);
    }
    return 0;
}

我有两个函数代表一个真实和假模具的卷,一个函数将掷骰子N次并返回第一个函数的值大于第二个函数的值的次数。但是,当我运行rollDiceNTimes(rollDie(),rollFalseDie(),50)时,输出为0或50,这似乎表明存储了第一个值rollDie()和rollFalseDie()并进行了50次比较。

如何修改我的函数体,以便重复调用rollDie()和rollFalseDie(),同时仍然接受两个函数和一个数字N作为rollDiceNTimes()的参数?

2 个答案:

答案 0 :(得分:1)

您可能想要什么

执行以下2项更改:

1)实际上将函数传递给第一次调用(删除作为参数传递的函数的括号

rollDiceNTimes(rollDie, rollFalseDie, 50)

2)更改rollDiceNTimes以实际执行函数参数(通过在函数名称旁边添加括号

function rollDiceNTimes (function1, function2, n) {
    if (n > 0) {
        if (function1() > function2()) return 1 + rollDiceNTimes(function1, function2, n-1);
        else return rollDiceNTimes(function1, function2, n-1);
    }
    return 0;
}

如果你想要一些更加独立的步骤,这意味着和你一样:

function rollDiceNTimes (function1, function2, n) {
    var value1 = function1();
    var value2 = function2();
    if (n > 0) {
        if (value1 > value2) return 1 + rollDiceNTimes(function1, function2, n-1);
        else return rollDiceNTimes(function1, function2, n-1);
    }
    return 0;
}

您的错误说明

要明确:

function myFunction() { 
    return 42; 
}

myFunction - >名为“myFunction”的实际函数。将其视为“可执行对象”

myFunction() - > 42(调用myFunction的结果)。例如,可以是一个数字(虽然有些函数可以返回其他函数,但这不是这种情况)

当您编写function1 > function2时,您正在尝试比较函数对象(而不是每个函数的数字结果!),这在这里没什么意义。

但是你说你用这种方式调用主递归函数:

rollDiceNTimes(rollDie(), rollFalseDie(), 50)

所以这意味着实际参数是不是函数。它们是功能的结果。有了名字,你认为你传递了函数,但实际上并没有这样做。你在所有的递归链中传递固定值,一遍又一遍!

例如,如果第一次调用rollDie()返回3,第一次rollFalseDie()返回4,

rollDiceNTimes(rollDie(), rollFalseDie(), 50)

将是同一个电话:

rollDiceNTimes(3, 4, 50)

在这种情况下,它将运行“else”部分,因此return rollDiceNTimes(function1, function2, n-1);return rollDiceNTimes(3, 4, 49);相同(因为您的可变名称“function1”和“function2”只是固定数字,不是功能。

依此类推,直到rollDiceNTimes(3,4,0),它将返回零。

相同的逻辑将使用1 + 1 + 1 ...(50次)迭代50次,如果前两个参数处于另一个顺序,则产生50次。

你也可以写if (function1() > function2()),但我只是想把呼叫和比较分开来。

答案 1 :(得分:0)

最好有一个递归函数调用本身是函数的最后一个语句。目前尾部呼叫优化已被删除,但可能在将来再次添加。当tco回来时,编译器将实现递归调用。

因此rollDiceNTimes有一个名为recur的函数,如果1大于2并递减n(滚动次数),它将调用自身递增计数器。如果n为零,它将返回计数器。

我删除了重复的rollDie代码,并创建了一个名为dice的函数,它接受一个用于骰子面的值数组,并返回一个函数,当被调用时将返回其中一个面(滚动骰子)。

function dice(faces) {
  return function(){//return function 
    return faces[Math.floor(Math.random() * faces.length)];
  }
}

function rollDiceNTimes (roll1,roll2, n) {
  function recur(total,n){
    if(n===0){
      return total;
    }
    return recur(
      total+(
        //ternary operator (like an if statement but shorter)
        (roll1()>roll2())
          ? 1
          : 0),
      n-1
    );
  }
  return recur(0,n);
}

console.log(
  rollDiceNTimes(
    dice([1, 2, 3, 4, 5, 6]),
    dice([1, 1, 4, 4, 4, 4]),
    50
  )
);

您还可以将滚动后要执行的功能传递给rollDiceNTimes,并且不仅获得1大于2的次数,而且还获得两个滚动骰子的平均值:

function dice(faces) {
  return function(){//return function 
    return faces[Math.floor(Math.random() * faces.length)];
  }
}

function rollDiceNTimes (afterRollFn, roll1,roll2, n) {
  function recur(total,n){
    if(n===0){
      return total;
    }
    return recur(
      afterRollFn(roll1(),roll2()),
      n-1
    );
  }
  return recur(0,n);
}

console.log(
  "One larger than two",
  rollDiceNTimes(
    (function (total) {//IIFE with total in closure
      return function (one,two) {
        //ternary operator (like an if statement but shorter)
        if (one>two) {
          total = total + 1;
        }
        return total;
      }
    }(0)),
    dice([1, 2, 3, 4, 5, 6]),
    dice([1, 1, 4, 4, 4, 4]),
    50
  )
);

console.log(
  "Average of one and two",
  rollDiceNTimes(
    (function (timesRolled,totalOne,totalTwo){//IIFE with totals in closure
      return function (one,two) {
        timesRolled = timesRolled+1;
        totalOne=totalOne+one;
        totalTwo=totalTwo+two;
        //average of both
        return [totalOne/timesRolled,totalTwo/timesRolled]
      };
    }(0,0,0)),
    dice([1, 2, 3, 4, 5, 6]),
    dice([1, 1, 4, 4, 4, 4]),
    50
  )
);