You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中递归+||运算符导致for循环索引异常跳出问题

为什么我的JavaScript树形遍历for循环没有遍历所有子节点?

问题代码

<html>
<head><head>
<body>
<script>
class Test {
        constructor(name, children) {
            this.children = [];
            this.test = () => {
                let result = false;
                for (let i = 0; i < this.children.length; i++) {
                    console.log(this.children[i].name);
                    result = result || this.children[i].test();
                }
                if (this.name.includes('2')) result = true;
                return result;
            };
            this.name = name;
            this.children = children;
        }
    }

    const t = new Test('1', [
        new Test('11', [
            new Test('111', []),
            new Test('112', []),
        ]),
        new Test('12', [
            new Test('121', []),
            new Test('122', []),
        ]),
    ]);
    const result = t.test();
    console.log(result);
</script>
</body>
</html>

问题现象

这段代码中,Test类的test()方法通过for循环遍历子节点并调用其test(),试图实现类似数组some()的逻辑(只要有一个子节点返回true,整体返回true)。但实际运行时,名称为121和122的实例的test()方法从未被调用。

同时观察到几个相关现象:

  • 将result = result || this.children[i].test();拆分为两行:const subResult = this.children[i].test(); result = result || subResult;,所有子节点都会被正常遍历。
  • 把for循环条件改为i <= this.children.length,会出现循环索引异常跳出的情况。
  • 移除if (this.name.includes('2')) result = true;后,所有子节点的test()都会被调用。
  • 该现象在Chrome、Firefox、Safari中表现一致。

解答:符合规范,原因是逻辑或的短路求值

这个行为完全符合JavaScript规范,核心原因是逻辑或运算符(||)的短路求值特性:

逻辑或运算中,如果左边的操作数是真值(truthy),则直接返回左边的值,不会执行右边的表达式——这是JavaScript的标准行为。

具体执行流程拆解

  1. 根节点t调用test(),初始result = false,开始遍历它的两个子节点(11和12)。
  2. 遍历第一个子节点11,调用11.test():
    • 11的test()初始result = false,遍历它的两个子节点(111和112)。
    • 调用111.test():111的name不含'2',返回false,11的result仍为false。
    • 调用112.test():112的name包含'2',result被设为true,返回true。此时11的result变为true,11.test()最终返回true。
  3. 回到根节点的循环中,执行result = false || 11.test()——因为右边返回true,根节点的result变为true。
  4. 循环索引i递增到1,此时执行result = true || this.children[1].test():
    • 左边的result已经是真值(true),触发短路求值,右边的this.children[1].test()(即12节点的test())完全不会被执行。
    • 因此12节点及其子节点121、122的test()都没有被调用,循环继续直到结束。

对应现象的解释

  • 现象1:拆分代码后,不管result当前是什么,都会先执行this.children[i].test()获取subResult,短路求值只影响result = result || subResult这一步,不会跳过子节点的方法调用,所以所有子节点都会被遍历。
  • 现象2:当i等于this.children.length时,this.children[i]是undefined,访问undefined.name会抛出TypeError,导致循环异常终止。
  • 现象3:移除if (this.name.includes('2')) result = true;后,所有test()都返回false,每次result = false || ...都会执行右边的表达式,不会触发短路,因此所有子节点都会被调用。

内容的提问来源于stack exchange,提问作者Hodol

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 06:52:46