跨原型创建过滤器及Team类kick方法同类型攻击问题排查
问题解答
一、修复Team.kick方法的错误与实现优先攻击逻辑
首先,你碰到的TypeError: sameTypeUnit.__proto__ is not a function是因为错误把__proto__当成函数调用了——__proto__是指向对象原型的属性,根本不是可执行的函数。而且原kick方法的逻辑混乱,比如遍历成员后只保留最后一个,攻击逻辑完全不符合需求,我们来一步步重构:
1. 核心逻辑明确
我们要实现的规则是:
- 团队轮流让存活成员发起攻击
- 攻击方优先锁定敌方同类型且存活的目标
- 若同类型目标全部阵亡,则随机挑选敌方任意存活目标
2. 修复后的完整kick方法代码
Team.prototype.kick = function(targetTeam) { // 先找到当前团队下一个能攻击的存活成员 let activeMember = null; do { activeMember = this.members[this.activeMember]; this.activeMember = (this.activeMember + 1) % this.members.length; } while (!activeMember.isAlive()); // 筛选敌方同类型的存活目标 const sameTypeTargets = targetTeam.members.filter(unit => { return unit.isAlive() && unit.type === activeMember.type; }); // 确定最终攻击目标:优先同类型,无则随机选存活目标 let target; if (sameTypeTargets.length > 0) { target = sameTypeTargets[Math.floor(Math.random() * sameTypeTargets.length)]; } else { const allAliveTargets = targetTeam.members.filter(unit => unit.isAlive()); if (allAliveTargets.length === 0) return; // 敌方全灭,无需攻击 target = allAliveTargets[Math.floor(Math.random() * allAliveTargets.length)]; } // 执行攻击动作 if (activeMember.isAlive() && target) { activeMember.kick(target); console.log(`${activeMember.type} from ${this.name} attacked ${target.type} from ${targetTeam.name}`); } };
3. 关键错误说明
- 原代码中
sameTypeUnit.__proto__(sameTypeUnit)是完全错误的用法,我们改用unit.type === activeMember.type判断同类型——你已经给每个Unit实例设置了type属性,这比检查原型链更直接可靠 - 原代码遍历成员后只保留最后一个,完全没有意义,我们先正确找到当前要攻击的存活成员
- 原攻击逻辑混乱,现在拆分成「找攻击方→筛选目标→执行攻击」三个清晰步骤
二、跨原型创建过滤器
跨原型创建过滤器,本质就是根据对象的原型链来筛选实例,这里有几种实用的实现方式:
1. 基于instanceof运算符
instanceof会检查对象的原型链中是否存在构造函数的原型,适合筛选某个构造函数的实例:
// 筛选所有Archer实例 function filterArchers(units) { return units.filter(unit => unit instanceof Archer); } // 筛选所有Unit的子类实例(包括Archer、Swordsman、Mage) function filterAllUnits(units) { return units.filter(unit => unit instanceof Unit); }
2. 基于原型对象直接判断
使用Object.prototype.isPrototypeOf方法,检查原型是否在对象的原型链上:
// 筛选所有继承自Unit.prototype的实例 function filterUnitsByPrototype(units) { return units.filter(unit => Unit.prototype.isPrototypeOf(unit)); } // 筛选所有Archer实例 function filterArchersByPrototype(units) { return units.filter(unit => Archer.prototype.isPrototypeOf(unit)); }
3. 基于type属性(适配你的场景)
因为你已经给每个Unit子类实例设置了唯一的type属性,直接通过type分组筛选更直观,不需要依赖原型链:
// 通用过滤器:传入要筛选的type function filterByType(units, targetType) { return units.filter(unit => unit.type === targetType); } // 使用示例:筛选所有mage类型的实例 const mages = filterByType([archer, swordsman, mage, troll, orc, druid], "mage");
额外优化小建议
- 原
Unit.prototype.kick方法里有个小错误:console.log(this.type + " hit " + this.type);应该打印攻击方和被攻击方的类型,改成console.log(${this.type} hit ${target.type}); - 在
Game.prototype.battle方法中,每次攻击后可以打印双方状态,方便调试:比如console.log(team1.toString()); console.log(team2.toString());
内容的提问来源于stack exchange,提问作者Igor Shvets
相关产品推荐
相关产品推荐

