찾다

 >  Q&A  >  본문

javascript - 这段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>
    <p 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'>
    </p> 
</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);
};
PHP中文网PHP中文网2774일 전733

모든 응답(8)나는 대답할 것이다

  • 伊谢尔伦

    伊谢尔伦2017-04-11 11:06:30

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

    회신하다
    0
  • 大家讲道理

    大家讲道理2017-04-11 11:06:30

    setTimeout 是异步机制。

    회신하다
    0
  • 高洛峰

    高洛峰2017-04-11 11:06:30

    首先你对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();

    회신하다
    0
  • ringa_lee

    ringa_lee2017-04-11 11:06:30

    楼上正解。
    这是一个经典的坑。
    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函数内部执行,也可以实现同样的效果

    회신하다
    0
  • ringa_lee

    ringa_lee2017-04-11 11:06:30

    因为你这么写,

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

    当然找不到啦

    회신하다
    0
  • 迷茫

    迷茫2017-04-11 11:06:30

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

    회신하다
    0
  • PHP中文网

    PHP中文网2017-04-11 11:06:30

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

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

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

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

    회신하다
    0
  • 大家讲道理

    大家讲道理2017-04-11 11:06:30

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

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

    회신하다
    0
  • 취소회신하다