关于a的索引问题

关于a的索引问题,这是我在“添加删除记录练习”中碰到的一个问题,在经过多次查阅资料和测试之后,发现了问题的答案(因为这是我本人的个人学习笔记,所以对于练习我都是直接复制粘贴自己写的代码,并没有过多的讲解编写代码的过程,而这次碰到了一个让我困扰许久的问题,在大量的测试和查阅资料之后,我发现了这其实是一个很简单的问题,单独写一章, 这是我学习js中碰到问题的一点感悟,希望碰到类似问题的初学者看到之后也能有所收获,如果是大神就当我没说。。。)

这是我碰到的问题

问题:http://t.csdn.cn/CQCQE?spm=1005.2026.3001.5622 

这是我完整的代码

添加删除记录练习:http://t.csdn.cn/f9QkN

 这是我简化后的问题模型

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        window.onload = function(){
            var alla = document.getElementsByTagName("a");
            for(var i=0;i<alla.length;i++){
                alla[i].onclick = function(){
                    //我通过不断的测试之后,发现alla[i]的类型是undefined
                    //而this的类型是object
                    //就是因为类型不一样,所以导致结果不一样
                    //使用this才能正常引用对象,而使用数组会报错
                    alert(typeof alla[i]);
                };
            }
        };
    </script>
</head>
<body>
    <a href="">123</a>
    <a href="">456</a>
    <a href="">789</a>
</body>
</html>

 为什么在事件函数里的alla[i]会是未定义?我们先来看一下代码的执行流程:

  1. 首先是onload事件,会在文档载入时触发,然后执行里面的代码块
  2. 获取了所有的超链接节点,并以数组的形式返回给了alla
  3. 执行for循环
  4. 执行for循环里的单击响应函数
  5. 然后执行函数里的alert语句

问题出现在第三步,执行for循环。

 for循环会在页面加载完成之后立即执行,而响应函数会在超链接被点击的时候才执行,当响应函数执行时,for循环已经执行完毕,for循环执行结束的条件是i<alla.length,也就是说当i等于3时,for循环结束,当执行响应函数时,i等于3,但是此时alla数组里一共有三个元素,alla[0],alla[1],和alla[2],并没有alla[3],所以当检测alla[3]时,返回的结果是未定义。

那么为什么三个超链接都返回undefined?不应该是最后一个超链接才会返回undefined吗?

正如的前面说的,当响应函数执行时,for循环已经执行完毕,此时alert语句里的i就是3,,无论哪一个超链接的响应函数里的alert语句中的i都是3,所以都会返回未定义。

当然,我在测试代码的过程中还碰到了一个问题:

为什么把alert(alla[i]);语句直接放在for循环里,它可以正常运行,而把它放在事件函数里,它的i就被固定了,一直都是3?

这是我自己对于事件函数的理解,如果不对欢迎指正,看下面的伪代码:

/*--------------------等价转换----------------------------------*/
alla[i].onclick = functiion(){
    alert(alla[i]);
};
//以上单击响应函数可以等价转换为下列的代码
var fun = functiion(){
    alert(alla[i]);
};
alla[i].onclick = fun;
//注意是fun而不是fun()
//fun是调用名字为fun的函数对象,
//而fun()是将fun函数的返回值赋值给alla[i]的单击事件

/*------------------for循环里的执行流程------------------------*/

for(var i=0;i<alla.length;i++){
//第一次循环,此时i=0
    var fun = functiion(){
        alert(alla[0]);
    };
    alla[0].onclick = fun;
//此时第一个超链接绑定了函数fun,里面的函数体为alert(alla[0]);

//第二次循环,此时i=1
    var fun = functiion(){
        alert(alla[1]);
    };
    alla[1].onclick = fun;
//此时第二个超链接绑定了函数fun,里面的函数体变为alert(alla[1]);
//这里就是关键的地方,当for循环执行时,i自增,
//而fun里的函数体跟着也变成了alert(alla[1]);
/*就像是 
    var a,b=3;  
    b=4;
    a=b;  
    //然后输出a,得到的结果为4,因为进行了第二次赋值
    //二次赋值改变了b的值
*/
//此时的第二次for循环相当于重新给fun函数赋值

//第三次循环,此时i=2
    var fun = functiion(){
        alert(alla[2]);
    };
    alla[2].onclick = fun;
//此时第三个超链接绑定了函数fun,里面的函数体变为alert(alla[2]);

//第四次,i=3,此时i=alla.length,循环结束
//当单击事件触发时,无论是哪一个超链接,调用的都是fun
//fun再次被执行,此时的i=3
    var fun = functiion(){
        alert(alla[3]);
    };
//此时已经超出了数组的原长度,值为未定义
}

也就是说在for循环里的单击事件不能直接使用数组的索引来引用对象,会导致长度溢出,而且最后的结果无论是哪一个单击事件都是同一个结果,那么该怎么解决呢?

使用this关键字引用对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        window.onload = function(){
            var alla = document.getElementsByTagName("a");
            for(var i=0;i<alla.length;i++){
                alla[i].onclick = function(){
                    alert(this.innerHTML);
                //此时this引用的是alla数组中的某个元素
                //哪一个超链接被点击,引用的就是哪个超链接
                //不用担心数组的溢出问题,也不用担心对象的指向错误问题
                };
            }
        };
    </script>
</head>
<body>
    <a href="">123</a>
    <a href="">456</a>
    <a href="">789</a>
</body>
</html>

使用let关键字声明变量

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        window.onload = function(){
            var alla = document.getElementsByTagName("a");
            for(let i=0;i<alla.length;i++){
                //使用let声明的变量无法重复声明
                //也就是说用let声明的变量不能进行二次赋值操作
                alla[i].onclick = function(){ 
                    alert(alla[i].innerHTML);
                };
            }
        }
    </script>
</head>
<body>
    <a href="">123</a>
    <a href="">456</a>
</body>
</html>

以上就是我在学习中碰到的问题,以及解决方案,希望能对一些和我一样的初学者有一定的帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值