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();
关键修改说明
- 单例控制:通过静态属性存储已创建的实例,避免重复初始化,保证constructor仅执行一次。
- 目标元素修正:使用
this.closest('.product')精准定位当前点击的产品元素,实现点击对应面板切换状态。 - 事件去重:方案二中通过先移除旧事件再添加新事件,防止多次实例化导致的重复绑定问题。
内容的提问来源于stack exchange,提问作者Marek
相关产品推荐
相关产品推荐

