JSLint声称某些递归函数调用是“超出范围”的。

9

我有一个 JavaScript 代码片段,其中有一个递归函数调用:

(function () {
    "use strict";

    var recurse = function (x) {
        if (x <= 0) {
            return;
        }
        return recurse(x - 1);
    };

    recurse(3);
}());

这段代码只是递归调用了几次,但是可以运行。
将上面的内容粘贴到JSLint中会得到以下错误:
'recurse' is out of scope.

然而,如果我粘贴以下代码片段(使用函数声明而不是var):
(function () {
    "use strict";

    function recurse(x) {
        if (x <= 0) {
            return;
        }
        return recurse(x - 1);
    }

    recurse(3);
}());

JSLint非常喜欢它,没有错误。

我知道JSLint的目标是防止JavaScript代码中出现错误。有人知道为什么JSLint认为第一种写法是不好的JavaScript吗?通过不使用第一种递归调用方式,我可以预防哪些错误呢?

编辑:对于这个问题的任何未来访问者:在最新版本的JSLint中,这两个JavaScript片段都不会抛出任何错误。


1
JSLint很麻烦。第一个JavaScript并不差。 JSHint没有问题。ESLint也是如此。 - user1106925
我认为JSLint试图告诉你的是,在定义函数表达式时,变量'recurse'的值为未定义。当然,这不是问题,因为在你实际调用函数时,'recurse'已经被定义了。 - apsillers
1
不,刮掉那个 -- 如果您只是做 var recurse; 然后 recurse = function... ,那么这将使警告消失,而不会改变我上面描述的情况。真正的问题是,直到整个 var recurse = ... 表达式被评估之前,JSLint 并不会将 recurse 注册为在范围内(但左侧应该足以让它知道)。 - apsillers
@apsillers 叹气 - JSLint引起了很多痛苦,而在这种情况下,它甚至没有正确地进行投诉!它应该在标签上附带警告。 - Pointy
1
@squint 我不知道,JSLint 对我来说做得很好。团队应该设置什么样的设置争论要少得多,除了一些错误之外,Crockford 的规则从未被客观地错误。请参见下面的我的评论。然而,Crockford在5月份重写了JSLint,这个ES6版本还没有像旧版本那样经过充分测试。(在我看来,它仍然是一个beta版。) - ruffin
显示剩余7条评论
2个回答

4

这两种方式都没有问题。据我所知,这是一个不合适的警告。

问题似乎在于变量声明包括分配操作并不会使 JSLint 在整个赋值表达式被解析前注册该变量名在作用域中的存在。也就是说,当 JSLint 读取 var recurse = ... 时,它并不会意识到 recurse 是一个已声明的变量,直到它评估完赋值语句的右侧。在本例中,右侧包含一个使用已声明变量 recurse 的函数,但是 JSLint 还不知道 recurse 的存在,因为它还没有完成解析整个赋值表达式。

请注意,此代码与您的 var 示例完全相同,但在 JSLint 中不会产生任何警告:

(function () {
    "use strict";

    var recurse;
    recurse = function (x) {
        if (x <= 0) {
            return;
        }
        return recurse(x - 1);
    };

    recurse(3);
}());

通过将var recurse作为单独的语句提取出来,JSLint首先了解到recurse在当前作用域中被声明,然后解析赋值。如果您使用组合的var recurse = ...(虽然这并没有错),JSLint会错误地先解析赋值,然后才知道recurse的存在。

将此标记为已接受的答案,直到有人告诉我第一个示例可能出现什么问题。谢谢! - Captain Delano
1
我敢打赌这是因为在recurse定义内部使用了recurse,而且边缘情况还没有被捕获。就它的价值而言,它在旧版本的JSLint中是有效的。 在五月份进行了近乎完全的重写之后,Crockford已经将新版本从beta版中移除了一段时间,但它仍然存在许多错误。您可以在他的Google+社群上报告此问题。我认为这是一个合法的错误。 - ruffin

0

当你定义函数时,变量recurse还没有被定义,这就是为什么JSLint说它超出了作用域,并声称可能未定义的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接