如何修复jslint错误'不要在循环中创建函数'.

Ern*_*lli 60 javascript jslint

我正在努力使我们所有的JS代码都通过jslint传递,有时需要进行大量的调整以获得遗留代码的选项,以便稍后正确修复它.

jslint有一件事抱怨我没有工作.那就是当使用这样的结构时,我们得到错误'不要在循环中创建函数'.

for (prop in newObject) {
    // Check if we're overwriting an existing function
    if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" &&
        fnTest.test(newObject[prop])) {
        prototype[prop] = (function(name, func) {
            return function() {
                var result, old_super;

                old_super = this._super;
                this._super = _super[name];
                result = func.apply(this, arguments);
                this._super = old_super;

                return result;
            };
        })(prop, newObject[prop]);
    }
}
Run Code Online (Sandbox Code Playgroud)

此循环是经典继承的JS实现的一部分,其中扩展现有类的类在调用扩展类的成员时保留扩展类的超级属性.只是为了澄清,上面的实现受到了John Resig的博客文章的启发.

但是我们还在循环中创建了其他函数实例.

到目前为止,唯一的解决方法是从jslint中排除这些JS文件,但我们希望使用jslint进行代码验证和语法检查,作为我们持续集成和构建工作流程的一部分.

有没有更好的方法来实现这样的功能或有没有办法通过jslint调整这样的代码?

Ski*_*ick 65

Douglas Crockford有一种新的惯用方法来实现上述目标 - 他的旧技术是使用内部函数来绑定变量,但新技术使用函数制作器.请参阅幻灯片中的幻灯片74到他的"功能终极"谈话.[此幻灯片不再存在]

对于懒惰,这里是代码:

function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}
Run Code Online (Sandbox Code Playgroud)

  • @AshClarke对于循环的每次迭代都没有重新创建`make_handler`是正确的,但是对于循环的每次迭代,它仍然是这样的,`make_handler`返回的值是一个新的函数对象**.这个答案中的代码只是*从代码检查器中隐藏*,每次迭代都会创建一个新函数,但不会*阻止*每次迭代创建一个新函数.将`make_handler`的多次调用的返回值与`===`进行比较,并亲自查看. (21认同)
  • "函数制造者"如何比每次循环迭代创建一个新函数更好?这不是一回事吗? (20认同)
  • @Gili:创建make_handler函数的代码在`function make_handler(div_id)`的位置执行.一旦进入`for`循环,`make_handler`现在是对该函数的引用,并且不会为循环的每次迭代重新创建. (11认同)
  • @Louis是的,是的; 我本来应该更明确.我确实试图了解到`make_handler`函数的创建没有被反复评估,但这是我应该对返回值做出的一个好点. (2认同)

Zha*_*ami 12

(我发布这个问题几个月后我偶然发现了这个问题...)

如果在循环中创建函数,则为循环的每次迭代创建函数的实例.除非正在进行的函数实际上对于每次迭代都是不同的,否则使用将函数生成器放在循环之外的方法 - 这样做不仅仅是Crockery,它让其他阅读代码的人都知道这是你的意图.

如果函数实际上是在迭代(或迭代中生成的对象)中分配给不同值的相同函数,那么您需要将函数分配给命名变量,并在函数中使用该函数的单个实例.环:

handler = function (div_id) {
    return function() { alert(div_id); }
}

for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = handler(div_id);
}
Run Code Online (Sandbox Code Playgroud)

这个大评/讨论由其他人比我聪明做,当我在堆栈溢出这里提出了一个类似的问题: JSLint的错误"不要在循环中做出的功能." 引出有关Javascript本身的问题

至于JSLint:是的,这是教条和惯用语.也就是说,它通常是"正确的" - 我发现许多对JSLint负面发声的人实际上并不理解(微妙的)Javascript,它们很多而且很迟钝.


lif*_*nce 10

从字面上看,通过执行以下操作解决问题:

  1. 创建一个.jshintrc文件
  2. 将以下行添加到您的.jshintrc文件中

    {"loopfunc" : true, // tolerate functions being defined in loops }


Eva*_*oli 7

JSLint只是一个指南,您并不总是必须遵守规则.问题是,你不是在它所指的意义上在循环中创建函数.您只在应用程序中创建一次类,而不是一次又一次.

  • 当然,但是如果你看下面的答案,你仍然在循环中创建一个函数.您只是为了安抚JSLint而添加额外的代码.你为什么要这样做? (11认同)
  • 当然,这些解决方案是显而易见的.关键在于,你仍然在循环中创建函数,你只是以一种特别的方式编写它,这可能更复杂,只是为了安抚一些工具.无论如何,如果你想做什么,那就去吧. (8认同)

jev*_*von 5

如果您使用的是JQuery,您可能希望在循环中执行以下操作:

for (var i = 0; i < 100; i++) {
  $("#button").click(function() {
    alert(i);
  });
}
Run Code Online (Sandbox Code Playgroud)

为了满足JSLint,解决此问题的一种方法是(在JQuery 1.4.3+中)使用额外的处理程序数据参数.click():

function new_function(e) {
  var data = e.data; // from handler
  alert(data); // do whatever
}

for (var i = 0; i < 100; i++) {
  $("#button").click(i, new_function);
}
Run Code Online (Sandbox Code Playgroud)