首页 > ES6 for 循环 let 改 var 作用域出错如何解决?

ES6 for 循环 let 改 var 作用域出错如何解决?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    * {
        padding: 0;
        margin: 0;
    }
    
    div.slider {
        width: 730px;
        height: 454px;
        position: relative;
        overflow: scroll;
    }
    
    div.slider li.slider-panel {
        position: absolute;
        transition-duration: 0.5s;
        transition-property: all;
    }
    
    div.slider ul.slider-extra {
        position: absolute;
        text-align: center;
        width: 730px;
        height: 0;
        cursor: default;
        bottom: 26px;
    }
    
    div.slider li.slider-nav {
        display: inline-block;
        width: 18px;
        height: 18px;
        line-height: 18px;
        border-radius: 50%;
        background-color: #3e3e3e;
        color: white;
        font-size: 12px;
        cursor: pointer;
    }
    
    div.slider-page a.slider-prev {
        position: absolute;
        font-size: 22px;
        height: 62px;
        width: 28px;
        top: 200px;
        background-color: rgba(0, 0, 0, 0.2);
        text-align: center;
        line-height: 62px;
        color: white;
        text-decoration: none;
    }
    
    div.slider-page a.slider-next {
        position: absolute;
        font-size: 22px;
        height: 62px;
        width: 28px;
        top: 200px;
        right: 0;
        background-color: rgba(0, 0, 0, 0.2);
        text-align: center;
        line-height: 62px;
        color: white;
        text-decoration: none;
    }
    </style>
</head>

<body>
    <div class="slider">
        <ul class="slider-main">
            <li class="slider-panel"><img src="1.jpg" alt=""></li>
            <li class="slider-panel"><img src="2.jpg" alt=""></li>
            <li class="slider-panel"><img src="3.jpg" alt=""></li>
            <li class="slider-panel"><img src="4.jpg" alt=""></li>
            <li class="slider-panel"><img src="5.jpg" alt=""></li>
            <li class="slider-panel"><img src="6.jpg" alt=""></li>
        </ul>
        <ul class="slider-extra">
            <li class="slider-nav">1</li>
            <li class="slider-nav">2</li>
            <li class="slider-nav">3</li>
            <li class="slider-nav">4</li>
            <li class="slider-nav">5</li>
            <li class="slider-nav">6</li>
        </ul>
        <div class="slider-page">
            <a href="" class="slider-prev">&#60;</a>
            <a href="" class="slider-next">&#62;</a>
        </div>
    </div>
    <script>
    window.onload = function() {
        var sliderPanels = document.querySelector("ul.slider-main").getElementsByTagName("li");
        var sliderNavs = document.querySelector("ul.slider-extra").getElementsByTagName("li");
        var sliderPage = document.querySelector("div.slider-page");
        var sliderPageButtons = document.querySelector("div.slider-page").getElementsByTagName("a");
        var timer = null;
        var currentPoint;

        /*init function*/
        changeImg(0);
        autoChange(0);

        /*slider navigator dots*/
        for (var i = 0; i < sliderNavs.length; i++) {
            sliderNavs[i].onmouseover = function() {
                if (timer) clearInterval(timer);
                changeImg(i);
            };

            sliderNavs[i].onmouseout = function() {
                autoChange(currentPoint);
            };
            sliderPanels[i].onmouseover = function() {
                if (timer) clearInterval(timer);
                sliderPage.style.display = "";

            };
            sliderPage.onmouseover = function() {
                sliderPage.style.display = "";
            };
            sliderPanels[i].onmouseout = function() {
                autoChange(currentPoint);
                sliderPage.style.display = "none";
            };
        }

        /*page slider button*/
        sliderPageButtons[0].onmouseover = function() {
            if (timer) clearInterval(timer);
        };
        sliderPageButtons[1].onmouseover = function() {
            if (timer) clearInterval(timer);
        };
        sliderPageButtons[0].onclick = function() {
            event.preventDefault();
            currentPoint--;
            if (currentPoint < 0) currentPoint = 5;
            changeImg(currentPoint);
        };
        sliderPageButtons[1].onclick = function() {
            event.preventDefault();
            currentPoint++;
            if (currentPoint >= sliderNavs.length) currentPoint = 0;
            changeImg(currentPoint);
        };

        /*change images function*/
        function changeImg(id) {
            for (var j = 0, len = sliderNavs.length; j < len; j++) {
                sliderNavs[j].style.backgroundColor = "#3e3e3e";
                sliderPanels[j].style.opacity = 0;
            }
            sliderNavs[id].style.backgroundColor = "red";
            sliderPanels[id].style.opacity = 1;
            currentPoint = id;
        }
        /*auto change images function*/
        function autoChange(currentPoint) {
            timer = setInterval(function() {
                currentPoint++
                if (currentPoint >= sliderNavs.length) currentPoint = 0;
                changeImg(currentPoint);
            }, 1000);
        }
    };
    </script>
</body>

</html>

上面是全部代码,其中第一个for循环处:

/*slider navigator dots*/
for (let /*在这里*/ i = 0; i < sliderNavs.length; i++) {
    sliderNavs[i].onmouseover = function() {
        if (timer) clearInterval(timer);
        changeImg(i);
    };

如果改为let 则不会报错,如果是var 则出现如下错误:

3js轮播3.html:162 Uncaught TypeError: Cannot read property 'style' of undefined

请问为了改为var而不是let,我应该如果修改代码?


@Erichain_Zain 解释到位了。就补充个关于let的链接好了


因为使用let定义的变量只在当前的块级作用域有效,所以,使用let就能够避免你的for循环的函数在循环结束之后执行。但是,使用var就不同了。使用var定义的变量,是不存在块级作用域的。所以,当你使用var的时候,其实循环已经执行完了,你的i的值就是sliderNavs.length,当然就会报错。所以,你需要一个闭包来保存i的值。

所以,把你的for循环的代码改成这样:

/*slider navigator dots*/
for (var i = 0; i < sliderNavs.length; i++) {
    (function ( i ) {
        sliderNavs[i].onmouseover = function() {
            if (timer) clearInterval(timer);
            changeImg(i);
        };

        sliderNavs[i].onmouseout = function() {
            autoChange(currentPoint);
        };
        sliderPanels[i].onmouseover = function() {
            if (timer) clearInterval(timer);
            sliderPage.style.display = "";

        };
        sliderPage.onmouseover = function() {
            sliderPage.style.display = "";
        };
        sliderPanels[i].onmouseout = function() {
            autoChange(currentPoint);
            sliderPage.style.display = "none";
        };
    })( i );
}

这是一个典型的闭包问题.
先看下面这段程序,看看结果为什么是这样.

var l1 = []
for (let i = 0; i < 3; i++) {
  l1.push(function () {
    console.log(i)
  })
}
for (var foo of l1) foo()
// 输出 0 1 2

var l2 = []
for (var j = 0; j < 3; j++) {
  l2.push(function () {
    console.log(j)
  })
}
for (var bar of l2) bar()
// 输出 3 3 3

你用var的时候产生了闭包. 在你那个循环最后i变成了6, 把i=6的情况传给了changeImg, 导致了错误.


你出错的是 162 行,这一句

sliderNavs[id].style.backgroundColor = "red";
【热门文章】
【热门文章】