闭包简单练习及分析

题目简述

编写十个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序号。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章