JavaScript递归求和函数重复调用结果异常:如何重置变量?
解决递归求和函数重复调用结果异常的问题
问题描述
你现在有一个递归遍历包含value和children属性的对象、累加所有value值的函数,但因为依赖全局变量sum存储总和,导致重复调用时结果会叠加翻倍。原函数代码如下:
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 }
给定限制条件
- 不能修改函数的签名与声明;
- 必须在
sumup函数内部使用sum变量; - 不得使用额外的变量;
- 只能在
sumup函数内部做修改。
解决方案
核心思路是在首次调用函数时重置全局的sum为0,递归调用时则保持累加状态。我们可以通过判断函数的调用者是否为自身来区分首次调用和递归调用:
function sumup(node) { // 只有首次调用(调用者不是sumup自身)时,重置sum为0 if (sumup.caller !== sumup) { sum = 0; } 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 }
为什么这样有效?
- 当你第一次调用
sumup(rootNode)时,sumup.caller是全局作用域或者其他调用它的函数,不等于sumup,所以会把sum重置为0,然后开始正常累加; - 递归调用
sumup(node.children[i])时,调用者就是sumup自身,所以不会重置sum,继续累加子节点的value; - 每次完成调用后,下一次再调用
sumup时,又会触发首次调用的判断,重新把sum置为0,避免了之前的累加值干扰新的计算。
如果你的环境启用了严格模式(use strict),sumup.caller会被禁用,那可以换一种兼容方案,利用函数的私有属性标记调用状态:
function sumup(node) { // 首次调用时初始化sum并标记已进入调用流程 if (!sumup._isCalling) { sum = 0; sumup._isCalling = true; } sum += node.value; if (node.children && node.children.length > 0) { for (var i =0; i < node.children.length; i++) { sumup(node.children[i]); } } // 完成所有递归后,清除标记,让下一次调用可以重新初始化 if (sumup.caller !== sumup) { sumup._isCalling = false; } return sum }
这个版本用函数的_isCalling属性标记当前是否处于调用流程中,首次调用时初始化sum并标记,递归完成后清除标记,确保下一次调用不受影响。
内容的提问来源于stack exchange,提问作者Bijoy valappil
相关产品推荐
相关产品推荐

