当var遇到回调

83 阅读1分钟

需求

我现在需要实现一个需求:为许多个li绑定上一个点击事件。

上代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div class="a">
      <ul class="b">
        <li>我是li标签1</li>
        <li>我是li标签2</li>
        <li>我是li标签3</li>
        <li>我是li标签4</li>
        <li>我是li标签5</li>
      </ul>
    </div>

    <script>
      // 记得要用 querySelectorAll
      var lis = document.querySelectorAll('.a .b li')
      // console.log(lis[0])

      // 现在我需要为每一个li都绑定上一个点击事件
      for (var i = 0; i < lis.length; i++) {
        // console.log(lis[i])
        lis[i].onclick = function () {
          console.log(`下标为${i}的li标签被点击了!`)
        }
      }
    </script>
  </body>
</html>

结果如下所示:不管点击哪一个li标签,都会显示下标为5的li标签被点击了!

image.png

解释

首先,for循环是一个同步执行代码,而回调函数onclick是一个异步执行代码。同步函数与异步函数之间,同步函数是先执行的。也就是说,整个for循环都执行完毕了,当for循环中i的值自增到5的时候,for循环结束。i的值停留在了5。这就是上面执行结果出现的原因。

如何解决

1. 采用let

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div class="a">
      <ul class="b">
        <li>我是li标签1</li>
        <li>我是li标签2</li>
        <li>我是li标签3</li>
        <li>我是li标签4</li>
        <li>我是li标签5</li>
      </ul>
    </div>

    <script>
      // 记得要用 querySelectorAll
      var lis = document.querySelectorAll('.a .b li')
      // console.log(lis[0])

      // 现在我需要为每一个li都绑定上一个点击事件
-      for (var i = 0; i < lis.length; i++) {
+      for (let i = 0; i < lis.length; i++) {
        // console.log(lis[i])
        lis[i].onclick = function () {
          console.log(`下标为${i}的li标签被点击了!`)
        }
      }
    </script>
  </body>
</html>

解释

let 具备块级作用域,循环几次,就相当于出现了几个全新的i,所以不存在var所存在的问题。

var只有函数作用域全局作用域,简单来说,就是for循环管不住var定义的变量,会带来一系列的麻烦。如你已经很熟悉的变量提升

什么是变量提升

变量提升就是在变量声明前是可以使用的,并且不会报错,但是它的值会是undefined

2. 自定义下标

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div class="a">
      <ul class="b">
        <li>我是li标签1</li>
        <li>我是li标签2</li>
        <li>我是li标签3</li>
        <li>我是li标签4</li>
        <li>我是li标签5</li>
      </ul>
    </div>

    <script>
      // 记得要用 querySelectorAll
      var lis = document.querySelectorAll('.a .b li')
      // console.log(lis[0])

      // 现在我需要为每一个li都绑定上一个点击事件
      for (var i = 0; i < lis.length; i++) {
        // console.log(lis[i])
        lis[i].index = i

        lis[i].onclick = function () {
          var idx = this.index
          console.log(`下标为${idx}的li元素被点击了!`)
        }
      }
    </script>
  </body>
</html>

效果如下:

image.png

最后

平常各位小伙伴在工作中或者做项目的时候,遇到var回调函数的时候,要多留个心眼了。