看下以下代码为何会出错误


<body onload="init()">
    <p>1</p>

    <p>2</p>

    <p>3</p>

    <p>4</p>

    <p>5</p>
</body>

<script>
      var pAry = document.getElementsByTagName('p');

      function init(){
          for(var i=0;i<pAry.length;i++){
              pAry[i].i = i;
              pAry[i].onclick =function () {
                  console.log(pAry[i].i)
              };
          }
      }
</script>

代码倒数第五行 为什么我这样写浏览器会报Cannot read property 'i' of undefined
而换成this之后 就能正常运行
这两者的区别在哪?


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

//引用的i是他父函数init函数的变量i,init里的函数i经过循环后值变成了5,pAry[i]就数组越界了,越界了就是undefined

function 是匿名函数,i在外面,你又没有当参数传进来,当然没定义了

pAry是你查到的Dom数组,不应该pAry[i].i,这里的dom节点上不存在可以"."的i,因为for循环几乎是瞬间完成的,此时变量i已经是5了,下标为5的p节点并不存在,建议不要通过for循环这样绑定点击事件

  1. 错误1,你不应该是在点击body时触发init,因为你的init是想要给五个p添加事件,因此你可以在声明完init就在下面执行。
  2. 错误2,pAry[i]获取到的是dom,它没有i属性,你也最好不要在他上面加上这个属性来赋值,你想要给对应的p添加输出,直接用循环的i就可以了。
  3. 错误3,用var i在循环中添加事件,由于声明提升,会导致全部都会输出出循环的最后一个值,这个很典型的错误,面试题也考过,建议改成let i。

<body>
  <p>1</p>

  <p>2</p>

  <p>3</p>

  <p>4</p>

  <p>5</p>
</body>

<script>
  var pAry = document.getElementsByTagName('p');

  function init() {
    for (let i = 0; i < pAry.length; i++) {
      pAry[i].onclick = function () {
        console.log(i)
      };
    }
  }
  
  init()
</script>