JavaScript中数组越界问题
1、了解数组越界
要解决数组越界问题,我们就要先了解到底什么是数组越界:
含义:
1、数组越界就是数组超过了边界。数组索引是从0开始的,你定义的数组长度为5,那么你的脚标就只能是0、1、2、3、4 。向上或向下超过了超过了都是越界。
2、数组越界就是指在进行数组操作时访问了本不属于你的位置。
3、数组越界指的是数组下标变量的取值超过了初始定义时的大小,导致对数组元素的访问出现在数组的范围之外。
2、解决数组越界
接下来通过一个案例理解一下吧!
1、案例中html代码,创建三个<li></li>
标签
<ul class="header"> //首先创建三个
<li class="active " >正在热映</li>
<li >即将上映</li>
<li >付费电影</li>
</ul>
2、css中的渲染代码
*{
margin: 0;
padding: 0;
}
ul{
list-style: none;
display: flex;
width: 100%;
}
.header li{
/* width: 50%; */
flex: 1;
height: 50px;
line-height: 50px;
text-align: center;
}
.header .active{
color:blue;
background-color: red;
border-bottom: 1px solid red;
}
运行结果:
要求:在点击每个标签时,会发生对应的渲染效果,且其他标签不显示。
我们运用css中的知识可以轻松做到,只需给标签属性加上:visited
和:hover
即可,但是这样做的缺点就是,把代码写死,后期更改代码会加大工作量且不易维护。
3、JavaScript核心代码
1、利用自定义属性解决
var res = document.querySelectorAll(".header li") //利用dom节点获取ul里的各个li标签(返回值是一个伪数组)
for(let i=0;i<res.length;i++){ //给li标签遍历三次点击事件
res[i].dataset.index = i //利用for循环给每一个li标签加上一个自定义属性index=i;
res[i].onclick=function(){ //创建点击事件,鼠标在点击标签时触发
for(var a=0;a<res.length;a++){
res[a].classList.remove("active")
}
//此时for循环的意义时,在每次点击时,把每一个标签的渲染效果都删除掉,然后通过特殊方法给要点击的找个标签加上渲染效果
//res[i].classList.add("active")
/* 此时for循环已经执行完毕啦, 此时i=res.length已经属于索引越界(数组越界)如果使用res[i]会报错未被定义。那么我们前面添加的自定义属性就生效啦 */
res[this.dataset.index].classList.add("active") //this用法。此时this指向我们所点击的li标签
}
}
利用自定义的属性的方法:重在理解如何利用循环给每个标签都加上自定义属性,并熟悉如何获取自定义属性值。
2、利用es6中的知识let解决。
let是我们在es6学习中,又一定义变量的方法,且很容易解决上述问题。
let和var的区别
1、var。
我们在es5中定义变量使用var定义。此时var定义的是全局变量。
例:
for(var i=0;i<5;i++){
console.log(i);
}
console.log(i);
运行结果:
通过上述代码我们可以两个问题:
第一:我们在for循环中定义的i值,为什么可以在for循环外还可以被使用?
答:此时我们用var定义的变量为全局变量,在for循环外也可以使用。
第二:为什么我们定义的是i<5,为什么i最后打印出来会是i=5呢?
答:这就是for循环的运行机制,先判断,后++。当运行到i=5时,判断i不小于5,此时循环结束,
i=5被打印出来。所以说for循环和数组、鼠标点击事件在一起使用时极易发生报错。
2.let
let是es6中学习的定义变量的另一方法。let定义局部变量。通俗讲就是只在当前定义的{}内生效。
例:
for(let i=0;i<5;i++){ //用let定义变量
console.log(i);
}
console.log(i);
运行结果:
我们可以轻松看到,在for循环中用let定义的i值,在循环外不可以调用。
所以说,我们要解决上述的数组越界问题,非常简单的解决。
var res = document.querySelectorAll(".header li")
for(let i=0;i<res.length;i++){
res[i].onclick=function(){ //而let是局部变量,只在本次循环中生效。
for(var a=0;a<res.length;a++){
res[a].classList.remove("active")
}
/* 1、 使用自定义属性解决方案: */
// res[this.dataset.index].classList.add("active")
// /* 2、使用let定义解决方案: */
console.log(i); //此时打印i值,和上面res[i].οnclick=function()中的i值相同
res[i].classList.add("active")
}
}
通过let定义变量的方法,我们可以轻易解决问题。后续会有更简便的方法可以解决此问题。
3、利用事件委托解决
事件委托
- 就是把我要做的事情委托给别人来做
- 因为我们的冒泡机制,点击子元素的时候,也会同步触发父元素的相同事件
- 所以我们就可以把子元素的事件委托给父元素来做
事件触发
-
点击子元素的时候,不管子元素有没有点击事件,只要父元素有点击事件,那么就可以触发父元素的点击事件
<body> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var oUl = docuemnt.querySelector('ul') oUl.addEventListener('click', function (e) { console.log('我是 ul 的点击事件,我被触发了') }) </script> </body>
- 像上面一段代码,当你点击 ul 的时候肯定会触发
- 但是当你点击 li 的时候,其实也会触发
target
-
target 这个属性是事件对象里面的属性,表示你点击的目标
-
当你触发点击事件的时候,你点击在哪个元素上,target 就是哪个元素
-
这个 target 也不兼容,在 IE 下要使用 srcElement
<body> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var oUl = docuemnt.querySelector('ul') oUl.addEventListener('click', function (e) { e = e || window.event var target = e.target || e.srcElement console.log(target) }) </script> </body>
- 上面的代码,当你点击 ul 的时候,target 就是 ul
- 当你点击在 li 上面的时候,target 就是 li
委托
-
这个时候,当我们点击 li 的时候,也可以触发 ul 的点事件
-
并且在事件内不,我们也可以拿到你点击的到底是 ul 还是 li
-
这个时候,我们就可以把 li 的事件委托给 ul 来做
<body> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var oUl = docuemnt.querySelector('ul') oUl.addEventListener('click', function (e) { e = e || window.event var target = e.target || e.srcElement // 判断你点击的是 li if (target.nodeName.toUpperCase === 'LI') { // 确定点击的是 li // 因为当你点击在 ul 上面的时候,nodeName 应该是 'UL' // 去做点击 li 的时候该做的事情了 console.log('我是 li,我被点击了') } }) </script> </body>
- 上面的代码,我们就可以把 li 要做的事情委托给 ul 来做
解决上述数组越界问题的核心JavaScrpt代码:
var res = document.querySelectorAll(".header li")
for(var i=0;i<res.length;i++){
res[i].onclick=function(evt){ //在创建点击事件时传入形参
for(var a=0;a<res.length;a++){
res[a].classList.remove("active")
}
evt.target.classList.add("active")
// console.log(evt.target); //打印的是click事件触发的节点
}
}
通过事件委托的方法解决也是比较方便的。综合上述:事件委托和let定义变量是比较方便理解的!