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

for...of循环未绑定this致上下文丢失,触发Null类型错误

问题分析与解决方案

错误根源

报错 Uncaught TypeError: Cannot read properties of null (reading 'setSwitchHandlerFunc') 由三个核心问题导致:

  • this 上下文丢失:创建 ProjectItem 时未绑定 switchProject 方法的上下文,导致调用时 this 指向 null。
  • 逻辑错误:switchProject 方法错误地将 ProjectItem 对象传递给 setSwitchHandlerFunc,而该方法预期接收切换处理函数(如另一列表的 addProject)。
  • 选择器拼写错误:addProject 中移动元素的选择器少了一个 s,无法定位目标列表。

修复步骤

1. 绑定 switchProject 方法上下文

在 ProjectList 构造函数的循环中,将 switchProject 绑定到当前实例:

for (const pItem of pItems) {
  this.projects.push(
    new ProjectItem(pItem.id, this.switchProject.bind(this), this.type)
  );
}

2. 修正 switchProject 逻辑

改为移除当前项目并调用目标列表的添加方法:

switchProject(pId) {
  const projectToSwitch = this.projects.find(p => p.id === pId);
  if (!projectToSwitch) return;

  this.projects = this.projects.filter(p => p.id !== pId);
  this.switchHandler(projectToSwitch);
}

3. 修正选择器拼写

在 addProject 方法中,将选择器补全为正确的复数形式:

DOMHelper.moveElement(project.id, `#${this.type}-projects ul`);

完整修复后的 JavaScript 代码

class DOMHelper {
  static clearEventListeners(element) {
    const clonedElement = element.cloneNode(true);
    element.replaceWith(clonedElement);
    return clonedElement;
  }

  static moveElement(eId, newDestSelector) {
    const element = document.getElementById(eId);
    const destElement = document.querySelector(newDestSelector);
    destElement.append(element);
  }
}

class Tooltip {}

class ProjectItem {
  constructor(id, updatePListFunc, type) {
    this.id = id;
    this.updatePListHandler = updatePListFunc;
    this.connectSwitchBtn(type);
  }

  connectSwitchBtn(type) {
    const pItemElement = document.getElementById(this.id);
    let switchBtn = pItemElement.querySelector('button:last-of-type');
    switchBtn = DOMHelper.clearEventListeners(switchBtn);
    switchBtn.textContent = type === 'active' ? 'Finish' : 'Activate';
    switchBtn.addEventListener('click', this.updatePListHandler.bind(null, this.id));
  }

  update(updatePListFunc, type) {
    this.updatePListHandler = updatePListFunc;
    this.connectSwitchBtn(type);
  }
}

class ProjectList {
  projects = [];

  constructor(type) {
    this.type = type;
    const pItems = document.querySelectorAll(`#${type}-projects li`);
    for (const pItem of pItems) {
      this.projects.push(
        new ProjectItem(pItem.id, this.switchProject.bind(this), this.type)
      );
    }
  }

  setSwitchHandlerFunc(switchHandlerFunc) {
    this.switchHandler = switchHandlerFunc;
  }

  addProject(project) {
    this.projects.push(project);
    DOMHelper.moveElement(project.id, `#${this.type}-projects ul`);
    project.update(this.switchProject.bind(this), this.type);
  }

  switchProject(pId) {
    const projectToSwitch = this.projects.find(p => p.id === pId);
    if (!projectToSwitch) return;

    this.projects = this.projects.filter(p => p.id !== pId);
    this.switchHandler(projectToSwitch);
  }
}

class App {
  static init() {
    const activeProjectsList = new ProjectList('active')
    const finishedProjectsList = new ProjectList('finished');

    activeProjectsList.setSwitchHandlerFunc(
      finishedProjectsList.addProject.bind(finishedProjectsList)
    );

    finishedProjectsList.setSwitchHandlerFunc(
      activeProjectsList.addProject.bind(activeProjectsList)
    );
  }
}

App.init();

内容的提问来源于stack exchange,提问作者Mr.Unforgettable

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:46:57