闭包补充练习

案例:出现产品条,当单击第几行产品,出现对应编号在这里插入图片描述

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>JavaScript闭包属性详解</title>
    <style type="text/css">
        p {
            background: gold;
        }
    </style>
    <script type="text/javascript">
        function init() {
            var pAry = document.getElementsByTagName('p');
            for (var i = 0; i < pAry.length; i++) {
                pAry[i].onclick = function() {
                    alert(i);
                }
            }
        }
    </script>
</head>

<body onload="init();">
    <p>产品0</p>
    <p>产品1</p>
    <p>产品2</p>
    <p>产品3</p>
    <p>产品4</p>
</body>

</html>
  • 问题:无论单击哪个div,都会弹出5。

  • 原因:onclick事件是异步触发的,当事件被触发时,for循环早已结束,此时变量i的值早已经是5。

  • 解决:在闭包的帮助下,把每次循环的i值都封闭起来。当事件函数顺着作用域链从内到外查找变量i时,会先找到被封闭在闭包环境的i,单击div时,会分别输出0,1,2,3,4。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>JavaScript闭包属性详解</title>
    <style type="text/css">
        p {
            background: gold;
        }
    </style>
    <script type="text/javascript">
        function init() {
            var pAry = document.getElementsByTagName('p');


  


            for (var i = 0; i < pAry.length; i++) {

                function outer(n) {
                    var m = n;
                    return function inner() {

                        alert(m);

                    }
                }
                pAry[i].onclick = outer(i);
                


            }
        }
    </script>
</head>

<body onload="init();">
    <p>产品0</p>
    <p>产品1</p>
    <p>产品2</p>
    <p>产品3</p>
    <p>产品4</p>
</body>

</html>

更经典和简单的解决办法是使用立即执行函数。

在这里插入图片描述
为什么这样就行了呢,function()自己调用了自己,这时候onclick引用的变量变成了n,而由于立即执行函数的原因,每个onclick函数在作用域链中分别保持着对应的n(0~length-1),这时候就可以了。

补充:立即执行函数
立即执行函数案例

(function(a, b){ // 形参 
  console.log(a + b); // 3 
}(1, 2)); // 实参

此题对应

(function(n){//n是形参
                    pAry[n].onclick = function() {
                        alert(n);
                    }
                })(i);//i是实参

所以利用立即执行函数,来实现外部调用内部变量。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JavaScript闭包属性详解</title>
    <style type="text/css">
        p {
            background: gold;
        }
    </style>
    <script type="text/javascript">
        function init() {
            var pAry = document.getElementsByTagName('p');
            for(var i=0; i<pAry.length; i++) {
                (function(n){
                    pAry[n].onclick = function() {
                        alert(n);
                    }
                })(i);
            }
        }
    </script>
</head>
<body onload="init();">
<p>产品0</p>
<p>产品1</p>
<p>产品2</p>
<p>产品3</p>
<p>产品4</p>
</body>
</html>

运行后,在网页下按F12中。打开source选项
在第14行前面点击添加断点,可以观察到作用域链

代码在第14行和15行之间来回跳转,因为没有单击事件发生,所以没有alert(i)事件发生。
直到i=5,init()函数执行完成。
在这里插入图片描述

最简单的方法:把var改成let

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>JavaScript闭包属性详解</title>
    <style type="text/css">
        p {
            background: gold;
        }
    </style>
    <script type="text/javascript">
        function init() {
            var pAry = document.getElementsByTagName('p');

            for (let i = 0; i < pAry.length; i++) {

                pAry[i].onclick = function() {
                    alert(i);
                }

            }
        }
    </script>
</head>

<body onload="init();">
    <p>产品0</p>
    <p>产品1</p>
    <p>产品2</p>
    <p>产品3</p>
    <p>产品4</p>
</body>

</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

szmtjs10

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值