前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >JavaScript踩坑记录

JavaScript踩坑记录

作者头像
Tom2Code
发布2022-04-15 16:25:04
发布2022-04-15 16:25:04
38500
代码可运行
举报
文章被收录于专栏:TomTom
运行总次数:0
代码可运行

1.起因

今天在写一个页面的js的时候

想用var获取导航栏的元素

然后取成数组,然后再挨个添加函数

先移除现有的active类

然后再给被单机的那一项添加active类

代码语言:javascript
代码运行次数:0
复制
var items=document.getElementsByClassName("nav-item");
    for(var i=0;i<items.length;i++){
        items[i].onclick=function () {
            for(var p=0;p<items.length;p++){
                items[p].classList.remove("active");
            }
            items[i].classList.add("active");
        }
    }

报错:

Uncaught TypeError: Cannot read property 'classList' of undefined

at HTMLLIElement.items.<computed>.onclick ((index):103)

items.<computed>.onclick @ (index):103

2.分析

出了错就要解决,那就开始debug,

a.我觉得可能是for循环的问题

那好,我去改,可是改来改去发现不对

后来想了想,现在这个项目引用了jquery

b.是不是这么写和jquery冲突呢?

后来发现压根也没关系,因为我注释了jquery的引用照样报错

c.是不是直接取这个变量也是获取不到呢,我就尝试再用一个中间变量去获取

还是报一样的错误

.

.

.

试了n种解决办法(以上省略N种无效解决办法)

N取余无穷的那种

和ylw讨论,他的方式是把

代码语言:javascript
代码运行次数:0
复制
document.getElementsByClassName
换成
document.getElementById

然后用id去操控,这样确实可行

可是如果我的菜单栏目变多了

那就需要很多个id

然后挨个获取

然后挨个写函数,去除样式

不是很可行

最后,通过1个多小时的努力“走访”各大技术群

得到了两个正确的解法

解法1

代码语言:javascript
代码运行次数:0
复制
let items=document.getElementsByClassName("nav-item");
    for(var i=0;i<items.length;i++){
        items[i].onclick=function () {
            for(var p=0;p<items.length;p++){
                items[p].classList.remove("active");
            }
            this.classList.add("active");
        }
    }

解法2

代码语言:javascript
代码运行次数:0
复制
 var items=document.getElementsByClassName("nav-item");
    for(var i=0;i<items.length;i++){
        items[i].onclick=function () {
            for(var p=0;p<items.length;p++){
                items[p].classList.remove("active");
            }
            this.classList.add("active");
        }
    }

3.总结反思

经过一系列的走访,才发现问题出在了

js的作用域上

如果照我第一种写法,那么最终获取的i始终是5

而数列为5的下标

也就是第六个元素根本不存在

所以这里就出来了作用域的问题

我们这里来看一个博客园的例子

代码语言:javascript
代码运行次数:0
复制
for (var i = 0; i <10; i++) {  
  setTimeout(function() {  // 同步注册回调函数到 异步的 宏任务队列。
    console.log(i);        // 执行此代码时,同步代码for循环已经执行完成
  }, 0);
}
// 输出结果
10   共10个
// 这里面的知识点:JS的事件循环机制,setTimeout的机制等

===========================================

// i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) { 
  setTimeout(function() {
    console.log(i);    //  i 是循环体内局部作用域,不受外界影响。
  }, 0);
}
// 输出结果:
0  1  2  3  4  5  6  7  8 9

let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。

所以我们用了let和this就可实现我们的需求了

结果如下:

视屏

http://mpvideo.qpic.cn/0bf2dmacgaaasaahp6aeajqfag6demnqaiya.f10004.mp4?dis_k=888f40624951f5de2fe77ffcd19a9d11&dis_t=1650011069&vid=wxv_1699603327153389570&format_id=10004&support_redirect=0&mmversion=false

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Tom的小院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档