开发者问题收集

无法在 setTimeout 内设置 innerHTML

2019-08-29
1291

尝试设置 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 内设置,以及我的问题的可能解决方案。

3个回答

我相信这是当前范围的问题。setTimeout 函数创建了自己的范围,该范围没有对旧变量的引用。您可能需要重新定义超时内的 x 或将数组明确传递给超时。

请参阅此处了解如何操作: 如何将参数传递给 setTimeout() 回调?

我还建议阅读有关 closers 的内容: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

adr5240
2019-08-29

在 for 循环中使用 var 时,实际上会为 i 的最后一个值触发 setTimeout ,因为在 var 中绑定仅发生一次。

这是因为 setTimeout 在整个循环完成时触发,然后您的 i 将为 4 。请记住,由于您在 setTimeout 调用中传递的回调函数,因此存在一个闭包。该闭包现在将引用 i 的最终值,即 4。

因此在这种情况下,当执行完整个循环时, i 的值为 4 ,但 x 中的索引最多为 3 。这就是为什么当您尝试访问 x[4] 时会得到 undefined 并且看到 TypeError 来修复这个问题,只需在每次迭代中使用 leti 的新值进行重新绑定即可:

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 的新值进行新绑定的函数。

Fullstack Guy
2019-08-29

由于缺少 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>
Jan
2019-08-29