首页 > 这段js代码哪里出错了?

这段js代码哪里出错了?


<html>    
<style>
    /* reset */
    *{margin:0;padding:0;border:0;}
    img{display:block;}
    /* 布局 */
    .container{width:400px;height:300px;position:relative;}
    img{width:100%;position:absolute;top:0;}
    /* 图像透明度&zindex */
    img:nth-child(n){filter:alpha(opacity=1);opacity: 1;z-index:999;}
</style>

<script>
var t = function(){
    var i = 0;
    while(i<6){
        i++;
        var tom = function (){document.getElementById('x'+i).style.zIndex=9999;
        setTimeout(tom,3000);
    };
};
t();


</script>
    <div class='container' id='id_container'>
            <img id='x1' src='image/1.png'>
            <img id='x2' src='image/2.png'>
            <img id='x3' src='image/3.png'>
            <img id='x4' src='image/4.png'>
            <img id='x5' src='image/5.png'>
    </div> 
</html>

为什么一加上while循环,getElementById就找不到id了?

而且,我把定时器放在while里面,不是应该执行完setTimeout(tom,3000);才进入下一轮循环吗?

while(i<6){
    i++;
    var tom = function (){document.getElementById('x'+i).style.zIndex=9999;
    setTimeout(tom,3000);
};

setTimeout 是异步机制。


首先你对i的使用就是不对的,如一楼所说,你这样写的每一个 i 都会是等于6(你可以在tom()里输出 i 试试~)

相对正确的写法是

var i = 0;
while(i<6){
    i++;
    var tom = function (k){
        document.getElementById('x'+k).style.zIndex=9999;
        //console.log(k);
    };
    /*var ct = document.getElementById('id_container').style.z-index=50;
    clearTimeout();
    */

    //setTimeout(tom(i),3000); //误,`setTimeout`内不能加函数执行语句,应该为函数名`tom`,或者如下用引号包含起来的函数执行语句
    setTimeout("tom("+ i + ")",3000);
};

此外,你这么写 while 会循环 6 遍,而你的 HTML 中只有五个元素,在最后一遍循环中会获取不到元素,也会报错。
这个修改可以 while(i<5) ,也可以 var i = 1; ,然后把 i++; 放到 while 循环的最后面。


[补充]while循环里延时不是直白的这么想就可以的,具体原因其他答案也写的很明白了,要实现效果的话,建议还是用立即调用函数表达式来搞比较方便。

var tom = function (nb){
    //document.getElementById('x'+nb).style.zIndex=9999;
    console.log(nb);
};
function test(){
    var i =0;
    (function(){
        if(i>=5){
            return;
        }
        //console.warn(i + "test");
        i++;
        tom(i);
        window.setTimeout(arguments.callee,3000);
    })();
}
test();

楼上正解。
这是一个经典的坑。
1、要理解js是没有块级作用域的,只要函数作用域,由于你的tom()函数是在定时器里触发执行的,等它执行时whlie循环实际上已经执行完毕(while此时在全局作用域中,是在程序加载阶段就解释执行完的),此时i的值已经==6(当运行到i=5时,由于其小于6,所以执行了i++,i的值变成了6),而你的html代码中并没有id=x6的节点,所以你读取不到。解决办法:闭包——将tom函数放置在一个立即执行函数中:tom = (function(i){...})(i);
2、setTimeout函数在这里的用法就是错误的。我看到你的代码意图实际上是要实现类似于轮播图的效果,即每隔三秒用后面一张图片覆盖前面的图片,这里应该用setInterval,并且放在while循环外面。因为setTimeout并不会随着while循环一起执行。

===============================================
补充:或者,你可以将setTimeout放入tom函数内部执行,也可以实现同样的效果


就是执行到i=5 的时候,马上加1 ,i就是6了,已经超出你的img访问了把


在while外读下i,你会发现是6.你这个定时器相当于在外面获取i,建议题主了解下js作用域


函数 tom 是函数 t 里面的函数, 且用了t 里面的变量 i, tom是一个闭包,tomt的变量i是一样的。

setTimeout 是异步机制,当执行到 setTimeout(tom,3000) 时并不是等待3秒后执行 tom 函数,而是循环继续,

等到3秒后调用 tom ,此时循环早已结束, i 的值为6,所以 document.getElementById('x'+i) 是找不到的。

异步和闭包在js中都是很重要的。


while(i<6){
    i++;
    var tom = function (i){
        return function(){
             document.getElementById('x'+i).style.zIndex=9999;
        }
    }
    setTimeout(tom(i),3000);
};

这样写就对了,另外 setTimeout 里面使可以直接写函数的,不一定非要写成字符串


因为你这么写,

document.getElementById('x'+i)//这里i永远是6

当然找不到啦

【热门文章】
【热门文章】