警告不要在循环中使功能

时间:2018-04-16 17:22:56

标签: javascript function for-loop jslint jshint

我已经编写了一个代码来为div容器创建模态窗口。单击按钮后,我会得到按钮的编号并显示相关的模态窗口。经过测试,适用于所有浏览器。

myModalContent = new tingle.modal();
var myBtn = document.querySelectorAll("button.project__btn");
for (var i = 0; i < myBtn.length; i++) {
myBtn[i].addEventListener("click", function () {
    myModalContent.open();
    if (this.hasAttribute("data-btn")) {
        myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
    } else {
        myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
    }
});

} 一个js验证器给出一个警告“不要在循环中创建函数”。 阅读一些与此主题相关的帖子,特别是必须在循环外创建函数,我创建了一个函数:

 function handler(modalDiv, trigBtn, index){
    modalDiv.open();
    if (trigBtn[index].hasAttribute("data-btn")) {
        modalDiv.setContent(document.querySelector(".project" + trigBtn[index].getAttribute("data-btn") + "-modal").innerHTML);
    } else {
        modalDiv.setContent(document.querySelector(".project1-modal").innerHTML);
    }
}

然后从循环中调用它:

for (var i = 0; i < myBtn.length; i++) {
    myBtn[i].onclick = handler(myModalContent, myBtn, i);
}

它似乎无法正常工作,它会在网页加载后立即显示最后一个模态窗口。我的理解是该函数必须与click事件监听器连接,即当单击一个按钮时,应弹出模态窗口。现在,模式窗口弹出而没有任何点击事件。你能告诉我如何正确编写函数吗?或者,如果我只是简单地忽略这个js验证警告。

2 个答案:

答案 0 :(得分:3)

保持简单!您不必更改代码的任何内容,只需将函数表达式移动到循环体外部的命名函数声明:

var myModalContent = new tingle.modal();
var myBtn = document.querySelectorAll("button.project__btn");
function myHandler() {
    myModalContent.open();
    if (this.hasAttribute("data-btn")) {
        myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
    } else {
        myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
    }
}
for (var i = 0; i < myBtn.length; i++) {
    myBtn[i].addEventListener("click", myHandler);
}

答案 1 :(得分:2)

该警告试图阻止&#34;修改后的闭包问题&#34;。如果您的函数对变量i执行了任何操作,那么您发现用户单击按钮时变量i的值始终为myBtn.length,因为&# 39; s它在循环结束时结束的值。

此:

for (var i = 0; i < myBtn.length; i++) {
...

这样对待:

var i;
for (i = 0; i < myBtn.length; i++) {
...

由于您未在功能中的任何位置使用i,因此您在技术上是安全的,但未来其他开发人员可能会更改代码并最终运行这个问题。

为了按照您尝试修复此代码的方式修复此代码,您需要让handler函数返回一个函数本身。

myBtn[i].addEventListener("click", createHandler());

function createHandler() {
    return function() {
        myModalContent.open();
        if (this.hasAttribute("data-btn")) {
            myModalContent.setContent(document.querySelector(".project" + this.getAttribute("data-btn") + "-modal").innerHTML);
        } else {
            myModalContent.setContent(document.querySelector(".project1-modal").innerHTML);
        }
    };
}

这与您的工作代码具有相同的效果,但可以阻止某人尝试在闭包内使用i。如果有人在那里需要i,他们可以将其添加到createHandler的参数列表中,在该列表中,每次通过循环时都不会重复使用相同的变量。

或者,如果您可以使用现代版本的javascript,则可以使用let关键字代替var

此:

for (let i = 0; i < myBtn.length; i++) {
...

更像是这个代码在C#:

之类的语言中如何工作
for (var _ = 0; _ < myBtn.length; _++) {
    var i = _;
...

换句话说,i变量的范围是for循环的内部,而不是您所处的函数的全局。