无法在 setTimeout 内设置 innerHTML
尝试设置 HTML 类的 innerHTML,该类有四个框,每个框每隔 3 秒设置一次。当 innerHTML 设置为加载图标时,我可以不使用 setTimeout 设置 innerHTML。当 innerHTML 放在 setTimeout 内时,会返回以下内容:“未捕获的 TypeError:无法设置未定义的属性‘innerHTML’”。
尝试调试我的代码,向控制台发送消息并搜索 stackoverflow,但没有成功。
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < 4; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
想知道为什么我的 innerHTML 不能在 setTimeout 内设置,以及我的问题的可能解决方案。
我相信这是当前范围的问题。setTimeout 函数创建了自己的范围,该范围没有对旧变量的引用。您可能需要重新定义超时内的 x 或将数组明确传递给超时。
请参阅此处了解如何操作: 如何将参数传递给 setTimeout() 回调?
我还建议阅读有关 closers 的内容: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
在 for 循环中使用
var
时,实际上会为
i
的最后一个值触发
setTimeout
,因为在
var
中绑定仅发生一次。
这是因为
setTimeout
在整个循环完成时触发,然后您的
i
将为
4
。请记住,由于您在
setTimeout
调用中传递的回调函数,因此存在一个闭包。该闭包现在将引用
i
的最终值,即 4。
因此在这种情况下,当执行完整个循环时,
i
的值为
4
,但 x 中的索引最多为
3
。这就是为什么当您尝试访问
x[4]
时会得到
undefined
并且看到
TypeError
来修复这个问题,只需在每次迭代中使用
let
与
i
的新值进行重新绑定即可:
for (let i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
此外,如果由于浏览器不兼容而无法使用
let
,您可以使用 IIFE 来解决这个问题:
for (var i = 0; i < 4; i++) {
(function(i){
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
})(i);
}
这是因为
var
具有函数作用域,因此在每次迭代中都会创建一个新的作用域以及与
i
的新值进行新绑定的函数。
由于缺少 i 参数 - 超时可能使用了超出数组的最后一个参数 (4)。
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < 4; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function (i) {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i, i);
}
function generateRandomNumbers() {
var retVal = [];
for (var i = 0; i < 4; i++) {
retVal.push(Math.random());
}
return retVal;
}
<div class="numberBox"></div>
<div class="numberBox"></div>
<div class="numberBox"></div>
<div class="numberBox"></div>