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

JS类构造函数如何保证奇数次执行?解决产品类名切换异常

解决Product实例化次数导致折叠面板失效的问题

你的代码存在两个核心问题,直接导致了偶数实例数时功能失效:

  • 重复绑定点击事件:每实例化一次Product,就会给所有.product__header绑定一次点击事件。当实例数为偶数时,点击一次会触发偶数次classList.toggle('active'),相当于状态无变化,看起来就是功能失效。
  • 目标元素错误:点击事件里用document.querySelector('.product')只会选中页面第一个产品元素,无法实现点击对应产品切换状态的需求。

下面给出两种解决方案,同时满足「constructor执行奇数次」和「正确切换产品active类」的要求:

方案一:单例模式确保constructor仅执行一次

通过单例模式限制Product类只能创建一个实例,无论调用多少次new Product(),constructor只会执行1次(奇数次):

class Product {
  static count = 0;
  static instance = null; // 存储单例实例

  constructor() {
    // 已有实例则直接返回,不执行后续逻辑
    if (Product.instance) {
      return Product.instance;
    }
    this.instanceId = ++Product.count;
    this.initAccordion();
    Product.instance = this; // 保存实例
  }

  initAccordion() {
    const clickableTriggers = document.querySelectorAll('.product__header');
    for (let clickableTrigger of clickableTriggers) {
      clickableTrigger.addEventListener('click', function (event) {
        event.preventDefault();
        // 找到当前点击header对应的.product父元素
        const product = this.closest('.product');
        product.classList.toggle('active');
      });
    }
  }
}

// 无论调用多少次,只会创建一个实例
new Product();
new Product();
new Product();
new Product();

方案二:手动控制实例化次数为奇数

如果你不想用单例,也可以在外部控制只实例化奇数次,同时修正事件绑定逻辑避免重复:

class Product {
  static count = 0;
  constructor() {
    this.instanceId = ++Product.count;
    this.initAccordion();
  }

  initAccordion() {
    const clickableTriggers = document.querySelectorAll('.product__header');
    for (let clickableTrigger of clickableTriggers) {
      // 先移除旧事件,避免重复绑定导致多次触发
      clickableTrigger.removeEventListener('click', this.handleHeaderClick);
      clickableTrigger.addEventListener('click', this.handleHeaderClick);
    }
  }

  handleHeaderClick(event) {
    event.preventDefault();
    const product = this.closest('.product');
    product.classList.toggle('active');
  }
}

// 只实例化奇数次,比如1次或3次
new Product();
// new Product(); // 注释掉该句,确保总实例数为奇数
// new Product();

关键修改说明

  1. 单例控制:通过静态属性存储已创建的实例,避免重复初始化,保证constructor仅执行一次。
  2. 目标元素修正:使用this.closest('.product')精准定位当前点击的产品元素,实现点击对应面板切换状态。
  3. 事件去重:方案二中通过先移除旧事件再添加新事件,防止多次实例化导致的重复绑定问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:25:16