JavaScript - 如何在递归期间重置局部变量?

时间:2018-05-12 10:53:32

标签: javascript recursion tree closures global

有一个"值"或/和"孩子"作为属性。问题是添加所有值并返回总和。这很有效。我用过递归。我使用全局变量来存储总和。

请参阅 - https://jsfiddle.net/ws6ty78b/1/

function sumup(node) {
  sum+=node.value;
  if (node.children && node.children.length > 0) {
    for (var i =0; i < node.children.length; i++) {
        sumup(node.children[i]);
    }
}
return sum
}

问题 - 再次调用相同的函数时,我得不到相同的结果。总和翻倍。我知道为什么会发生这种情况,因为我使用的是全局变量。

问题 - 对于上述问题,有没有办法可以为任意数量的调用获得相同的结果。

请注意限制 -

1)不要更改功能签名和声明。

2)使用&#39;总和&#39;总结里面的变量&#39;功能

3)不要使用任何额外的变量。

4)仅在总和函数中进行更改。

3 个答案:

答案 0 :(得分:2)

您可以简单地将每个子项的值与当前节点的值相加:

function sumup(node) {
      sum=node.value;
      if (node.children && node.children.length > 0) {
        for (var i =0; i < node.children.length; i++) {
          sum+=sumup(node.children[i]);
        }
      }
      return sum
    }

答案 1 :(得分:0)

为了实现目标,函数sumup()将被调用N次。我们不知道这个N是多少,因为它取决于子节点的递归次数。此外,由于这些限制,我们无法编辑函数签名,也无法在其他地方编写代码来执行任何操作,甚至不能手动将sum设置为0。

因此我们需要一种方法来区分一堆调用和NEXT串,并重置它。

我的想法是设置一个阈值,使用closure。从第一次调用开始,在示例中,您有5秒的时间来保持呼叫,之后它将重新开始。除非提供另一种区分调用的方法,否则这就是我们所能做的全部。

编辑:我在这里尝试的是将所有递归作为基本案例并且不改变对象。由于OP接受了该解决方案,我正在添加节点重置器属性。如果任何节点未定义重置器或为null或零或未定义,则将重置总和。我们必须假设它没有在已启动的对象中定义。正如我所说,这是一个弱假设。通过在递归时定义它,当前总和被转移。 我还将保留最初的时间阈值理念,以便最终获得利益。

var obj = {
  "value": 4,
  "children": [
    {
      "value": 2,
      "children": [
        {
          "value": 1
        }
      ]
    },
    {
      "value": 9
    }
  ]
}


const sumup = (function(){
  var lastTime = 0;
  var newTime = 0;
  var sum = 0;
  const timeThreshold = 5000; // 5 seconds
  return function(node) {
    newTime = new Date().getTime();
    if(!node["resetter"] || (newTime-lastTime >= timeThreshold)){
      sum=0;
      lastTime = newTime;
      }
      sum+=node.value;
      if (node.children && node.children.length > 0) {
        for (var i =0; i < node.children.length; i++) {
          sumup(Object.assign({"resetter":true},node.children[i]));
        }
      }
      return sum;
   }
})();

console.log(sumup(obj)); //16
console.log(sumup(obj)); //32! should print 16 everytime

答案 2 :(得分:0)

您可以在递归时对call进行总结,并针对自定义this进行分配/测试:

&#13;
&#13;
var obj = {
  "value": 4,
  "children": [{
      "value": 2,
      "children": [{
        "value": 1
      }]
    },
    {
      "value": 9
    }
  ]
};
var sum = 0;

function sumup(node) {
  //Only make change within this function body
  if (!this || !this.recurse) sum = 0;
  sum += node.value;
  if (node.children && node.children.length > 0) {
    for (var i = 0; i < node.children.length; i++) {
      sumup.call({ recurse: true }, node.children[i]);
    }
  }
  return sum
}

console.log(sumup(obj));
console.log(sumup(obj));
&#13;
&#13;
&#13;

或者,您可以完全取消全局变量,并在子项上使用递归reduce

&#13;
&#13;
var obj = {
  "value": 4,
  "children": [{
      "value": 2,
      "children": [{
        "value": 1
      }]
    },
    {
      "value": 9
    }
  ]
};

const sumup = (node) => (
  node.value + (node.children
    ? node.children.reduce((a, child) => a + sumup(child), 0)
    : 0
  )
);

console.log(sumup(obj));
console.log(sumup(obj));
&#13;
&#13;
&#13;