闭包简单练习及分析

    xiaoxiao2026-04-07  6

    题目简述

    编写十个button,内容分别是1到10,点击其中的一个button则输出当前的序号,即点击1输出1。

    解题思路

    这里的十个button样式都是一样的,只是内容不同,显然使用js动态添加较为方便,很多人可能会这样写:

    <script type="text/javascript"> for (var i = 1; i <= 10; i++) { var doc = document.createElement('button'); doc.innerHTML = i; doc.onclick = function(){ console.log(i); }; document.body.appendChild(doc); } </script>

    输出的效果是十个并排的按钮,内容分别是1到10,看似没有问题,但是点击之后,无论点击哪一个按钮,输出的总是11,这里就发生了闭包。

    由于click不是立即执行的事件,当我们点击按钮的时候,上述代码的循环早已结束,我们输出的是最后的i值,那为什么是11呢?

    根据for循环的逻辑,初始值是1,之后每次执行过后i+1,在执行到i=10的循环体之后,i再次+1,这时候变成了11,但是不能通过i<=10的判断,所以不再继续执行循环体,i最终为11。

    为了解决这个问题,这里提供几个解题方法:

    方法一,绑定id

    <script type="text/javascript"> for (var i = 1; i <= 10; i++) { var doc = document.createElement('button'); doc.id = doc.innerHTML = i; doc.onclick = function(){ console.log(this.id); }; document.body.appendChild(doc); } </script>

    在赋值的同时把i同时给button动态添加一个id,id的值为i,虽然这样能实现我们的需求,但是很显然这不是最好的方式,这样的id是无意义的,并且很容易重复,所以如果使用绑定属性的方法,还是推荐大家使用下面的这个方法,使用dataset。

    方法二,使用dataset新特性

    dataset是HTML5里面的新特性,它叫自定义属性对象。使用方式也很简单:

    <script type="text/javascript"> for (var i = 1; i <= 10; i++) { var doc = document.createElement('button'); doc.dataset.value = doc.innerHTML = i; doc.onclick = function(){ console.log(this.dataset.value); }; document.body.appendChild(doc); } </script>

    添加dataset属性时只需要doc.dataset.value即可,这里的value是自定义属性名,其在html里面生成的代码样式为:

    <button data-value="1">1</button>

    获取它的属性值也是直接doc.dataset.value即可获取。

    方法三,使用bind

    <script type="text/javascript"> for (var i = 1; i <= 10; i++) { var doc = document.createElement('button'); doc.innerHTML = i; doc.onclick = (function(){ console.log(this.toString()); }).bind(i);//绑定i值,同时this指向i document.body.appendChild(doc); } </script>

    我们知道,上述闭包的发生是因为i值的变化,那我们可以像个办法来组织它的变化。

    使用bind函数可以使当前对象或函数绑定对应的值或对象并且将this指向它,这样的话每个button的点击事件就会被绑定i,这个i是当前的一次循环,但是我们使用bind把它和当前的button绑定住了,虽然大体的i在变化,但是每个button绑定的i不会在变化,所以这里我们可以输出当前的button序号。

    很显然,这是最简单也是最好的办法。

    转载请注明原文地址: https://ju.6miu.com/read-1308575.html
    最新回复(0)