Fork me on GitHub

JSLint Error Explanations

JSLint will hurt your feelings. It's time to make them better!


Don't make functions within a loop

什么时候会产生这个错误?

如果在一个for, while或者do循环体中包含了函数体或者表达式,JSLint和JSHint会抛出"Don't make functions within a loop"的错误。在下面这个例子中,我们尝试着给所有同一个class名称的元素添加点击事件。事件处理函数的目的是要将被点击的元素的内容覆盖为循环迭代中的i的值:

为什么会产生这个错误?

产生这个错误的原因是为了强调那些可能不会按照你预期执行的代码并且指出对这门语言如何运行的误解。如果不修改这个错误,你的代码也许可以正常运行没有任何错误,但是在某些情况下会表现的让人感到十分意外。

根本的问题在于JavaScript解释器会在每一次循环迭代的时候创建一个函数实例这样做的原因是JavaScript不知道函数对象是否会在别的地方被修改。由于函数在JavaScript里是标准对象,它们可以拥有像其他对象一样的、可以在循环过程中被改变的属性。因而在一个循环体的上下文环境中创建函数,就会让解释器产生很多函数实例,从而导致了怪异的行为以及问题。

在上面那个例子中,当你点击其中任意一个元素,随后触发了事件处理函数,元素中的内容会变成i的最终计算出来的值。如果在NodeList中有4个元素,那么每一个元素中的内容都会最终变成了"4"。

为了理解这个问题,我们需要捕获每一次循环中i的值,并确保这个值是当前循环时的点击事件产生的。 一种通常的做法就是将函数体包含在一个即时执行函数内(immediately invoked function, aka, IIFE),形成一个闭包来捕获变量的值:

这样就会如同我们预期的那样执行,每一个元素都能获得正确的i值,但是这无疑让代码变烂了、并且让人难以阅读(因此也难以维护)。但是不管怎么样,由于循环体内还是包含了函数,JSLint和JSHint仍然会提示错误。为了解决这个问题,我们需要将函数从循环体中挪出来,并维护这个闭包:

在JSHint 1.0.0及以上版本中你可以通过特定的选项语法来忽略这个警告。这个警告的标识符是W083,也就是说你可以通过/*jshint -W083*/让JSHint不提示这个问题。


comments powered by Disqus