You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS中getAttribute()调用报TypeError错误的原因与解决方法

报错原因

核心问题是var声明的变量不存在块级作用域,只有全局/函数级作用域,会导致循环变量被所有事件回调共享:

  • 你在for循环里用var i声明计数器,整个循环过程中全局环境下始终只有一个i变量,所有a标签的点击回调里引用的都是这同一个全局i。
  • 当循环条件为i < len时,循环结束后i的值会累加到等于len,但querySelectorAll返回的链接列表下标范围是0到len-1,allLists[len]是不存在的,值为undefined。这时候点击任意链接触发回调,执行allLists[i].getAttribute()就相当于在undefined上调用方法,直接抛出你看到的类型错误。
  • 当你把循环条件改成i < len-1时,首先循环只会给前len-1个链接绑定事件,最后一个链接根本没绑事件,点了自然没反应;其次循环结束时全局i的值固定为len-1,刚好是最后一个链接的下标。如果你测试时最后一个链接的href恰好是#,点击前len-1个链接时回调读到的是最后一个链接的href,会触发回到顶部逻辑,你就会误以为前序链接运行正常——本质上这时候逻辑也是错的,你点任何一个前序链接,拿到的都不是当前点击链接的href,只要最后一个链接的href不是#,前序链接的交互就会全部异常。
修复方案

任选一种即可,优先选前两种更简洁的写法:

  • 改循环变量声明:把var i换成let i。let是块级作用域,每一轮循环都会生成独立的i绑定,每个回调都能正确捕获到对应轮次的i值,不会出现变量污染。
    修正后的完整代码:
    const allLists = document.querySelectorAll("a:link");
    const len = allLists.length;
    
    for (let i = 0; i < len; i++) {
      allLists[i].addEventListener("click", function (e) {
        e.preventDefault();
        const href = allLists[i].getAttribute("href");
        console.log(href);
        if (href == "#") {
          window.scrollTo({
            top: 0,
            behavior: "smooth",
          });
        }
      });
    }
    
  • 不依赖循环变量:直接从事件对象上取当前触发事件的元素。回调里的e.currentTarget永远指向绑定了当前点击事件的DOM元素,完全不受循环变量作用域影响,哪怕保留var i的写法也不会出问题。
    只需要修改取href的一行代码即可:
    // 替换原代码中const href = allLists[i].getAttribute("href");
    const href = e.currentTarget.getAttribute("href");
    
  • ES5兼容旧写法(无特殊兼容需求不推荐):通过立即执行函数给每轮循环创建独立作用域,把当前轮次的i作为参数传入闭包,隔离全局i的影响。

内容的提问来源于stack exchange,提问作者user19458229

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:27:24