如何在JavaScript循环中添加EventListener而不触发JSHint';这是令人困惑的语义错误吗?
我正在使用DOM在JavaScipt中创建一个动态项目列表。每个项目都有一个链接(一个HTML元素),链接到页面上的另一个元素;允许用户编辑团队的表单。链接工作正常,但我试图通过向链接添加eventListener使表单工作,因为表单需要获得我们正在编辑的团队作为参考 下面是有问题的代码:如何在JavaScript循环中添加EventListener而不触发JSHint';这是令人困惑的语义错误吗?,javascript,html,dom,jshint,Javascript,Html,Dom,Jshint,我正在使用DOM在JavaScipt中创建一个动态项目列表。每个项目都有一个链接(一个HTML元素),链接到页面上的另一个元素;允许用户编辑团队的表单。链接工作正常,但我试图通过向链接添加eventListener使表单工作,因为表单需要获得我们正在编辑的团队作为参考 下面是有问题的代码: for (let i = 0; i < teams.length; i++) { let row = table.insertRow(-1); //removed code th
for (let i = 0; i < teams.length; i++) {
let row = table.insertRow(-1);
//removed code that made cells under the row
let link = document.createElement("a");
link.setAttribute("href","#form");
link.team = teams[i];
link.addEventListener("click", function (e) {
updateForm(link.team);
});
link.textContent = teams[i].name;
//code that adds the link and other elements into the cells of the table
}
如果我理解正确,这是因为变量table
不在循环范围内。然而,我不明白为什么将表放入循环中会改变任何事情。我到底应该在代码中修改什么来确保JSHint会满意呢?如果添加eventListener似乎是更好的解决方案,我还可以使用其他方法
干杯
如果我理解正确,这是因为变量table存在于循环范围之外
链接
,而不是表格
我到底应该在代码中修改什么来确保JSHint会满意呢
我从另一个角度来看:您需要在JSHint/您的linting设置中更改什么,以便在回调中使用link
的完全有效的代码不会触发linting错误?如果您的代码使用的是var
,则警告将非常有用,但您的代码使用的是let
IIRC,JSHint比它最初基于的JSLint(几年前现在)更具可配置性,当您使用let
forlink
时,您可能会查看是否有一个选项可以关闭此特定警告
或者,您可以研究另一种linting解决方案(ESLint非常流行)
但是,您很可能会更改link
引用的对象的team
属性。如果您想消除这种可能性并摆脱显式函数,可以使用bind
:
link.addEventListener(“单击”,updateForm.bind(null,link.team));
这也将消除JSHint警告
或者,由于您正在元素本身上使用expando属性,因此可以使用this
:
link.addEventListener(“单击”,函数(){
updateForm(this.team);
});
…但我建议您不要在DOM元素上使用expando属性。例如:
for (const team of teams) {
const row = table.insertRow(-1);
//removed code that made cells under the row
const link = document.createElement("a");
link.setAttribute("href","#form");
link.addEventListener("click", () => { // Or:
updateForm(team); // link.addEventListener("click", updateForm.bind(null, team));
}); //
link.textContent = team.name;
//code that adds the link and other elements into the cells of the table
}
每当你在循环b/c中定义了一个你没有定义的函数时,Linters总是抱怨。(我有点惊讶JSHint没有,但JSLint似乎也不再认为这是一个错误!) 与linters的旧版本一样,我认为在循环的每次迭代中[重新]定义相同的函数在任何时候都是一种糟糕的做法。因为函数声明发生在一个循环中,所以每个单独函数的逻辑与其他函数的逻辑相同。这意味着代码不能是干的。它还允许像您这样的复杂范围设置
link.addEventListener("click", function (e) {
updateForm(link.team);
});
通常,您应该将该函数从循环中拉出,并在循环外定义对它的单个引用
但是…您通过后门将变量传递到函数中,使用了一些,嗯,创造性的闭包,这是一个更细微的错误[林特显然仍然关心]
这里有一种方法可以修复lint,使初始代码中的作用域的重要性变得明确(尽管要继续阅读!)
和繁荣。没有古怪的作用域,没有重复的函数声明。太好了
Expando警告 同样,TJ关于避免“expando properties”的警告是一个非常好的警告。是非标准的,在对象初始化后,您会将其粉碎到DOM元素上 其他库通常可以在没有警告的情况下编辑和/或删除这些属性。你最好使用 。。。或者,我的偏好是,拥有一个查找表,可以通过向每个
链接添加唯一的元素ID来访问该表
也就是说,我不喜欢TJ的解决方案,即保持您最初的范围依赖性时髦^D、 但它也能起作用
有意义吗?您使用的是最新版本的JSLint吗?对于它来说,抱怨你问题中的代码是一件令人惊讶的事情。我的错,问题中的代码检查器是JSHint,而不是JSLint。我将编辑post.Side注释:我建议不要在DOM元素(您的link.team=…
part)上使用expando属性。
link.addEventListener("click", function (e) {
updateForm(link.team);
});
/*jshint esversion: 6 */
/*global updateForm, teams, table */
// Note that this function returns a function containing a closure
// that maintains one `link` per call.
function myListenerFactory(link) {
return function (e) {
updateForm(link.team);
};
}
for (let i = 0; i < teams.length; i++) {
let row = table.insertRow(-1);
//removed code that made cells under the row
let link = document.createElement("a");
link.setAttribute("href","#form");
link.team = teams[i];
// Use the same function each time. Note that it's called IMMEDIATELY,
// returning a new function for each iteration.
link.addEventListener("click", myListenerFactory(link)()); // <<< Same function reused in the loop
link.textContent = teams[i].name;
//code that adds the link and other elements into the cells of the table
}
/*jshint esversion: 6 */
/*global updateForm, teams, table */
function myEventHandler(e) {
// No need to backdoor `link` when we can derive it from `e`!
updateForm(e.target.team);
}
for (let i = 0; i < teams.length; i++) {
let row = table.insertRow(-1);
//removed code that made cells under the row
let link = document.createElement("a");
link.setAttribute("href","#form");
link.team = teams[i];
// Use the same function each time
link.addEventListener("click", myEventHandler);
link.textContent = teams[i].name;
//code that adds the link and other elements into the cells of the table
}