使用原型方法初始化JS对象,Mocha测试遇Score非构造函数错误求解决
解决"Score不是构造函数"错误并优化计分类结构
咱们先从最直接的报错问题入手,再一步步优化你的类结构来实现「接收掷骰结果和计分规则计算得分」的目标。
第一步:修复"Score不是构造函数"的报错
这个问题完全是模块导入导出不匹配导致的:
你的源码里是通过module.exports.Score = Score把构造函数挂载到导出对象的Score属性上,但测试代码里直接把整个模块赋值给了Score变量——相当于你在尝试new一个普通对象,而不是构造函数本身。
修正导入方式即可:
// 方式1:解构导入(推荐,更清晰) const { Score } = require('../src/Score.js'); // 方式2:直接取导出对象的属性 var Score = require('../src/Score.js').Score;
第二步:修复Score类本身的基础问题
你的类目前还有两个明显的逻辑漏洞:
1. 构造函数未正确接收roll参数
现在的构造函数里硬编码了this.roll = [],完全忽略了传入的掷骰结果,改成下面这样才能正确存储传入的roll:
var Score = function (roll, category) { this.roll = roll || []; // 传入roll就用传入的,空数组兜底避免报错 this.category = category; };
2. ones方法未返回计算结果
当前的ones方法里,filter+reduce的计算结果没有被return,调用后会得到undefined。另外给reduce加初始值0,可以避免空数组时抛出错误:
Score.prototype.ones = function() { return this.roll.filter((i) => i == 1) .reduce((sum, i) => sum + i, 0); };
第三步:优化类结构实现「动态计分规则」的目标
你的核心需求是让Score类根据传入的计分规则计算得分,这里提供两种实用方案:
方案1:通过方法名指定预设计分规则
适合有固定计分规则集合的场景,比如骰子游戏的标准计分项(ones、twos、full house等):
var Score = function (roll, category) { this.roll = roll || []; this.category = category; // 传入预设的方法名,比如'ones' }; // 通用得分计算方法,自动调用对应规则 Score.prototype.calculateScore = function() { if (typeof this[this.category] === 'function') { return this[this.category](); } throw new Error(`找不到对应计分规则:${this.category}`); }; // 预设各类计分规则 Score.prototype.ones = function() { return this.roll.filter(i => i === 1).reduce((sum, i) => sum + i, 0); }; Score.prototype.twos = function() { return this.roll.filter(i => i === 2).reduce((sum, i) => sum + i, 0); }; // 可以继续扩展其他规则,比如fullHouse、yahtzee等 module.exports.Score = Score;
对应的测试代码示例:
const { expect } = require('chai'); const { Score } = require('../src/Score.js'); describe('Score', function() { describe('基础实例化', function() { it('应该是Score的实例', function() { const score = new Score([1,2,3,4,5], 'ones'); expect(score).to.be.an.instanceOf(Score); }); }); describe('计分规则测试', function() { describe('ones规则', function() { it('应该计算所有1的总和', function() { const score = new Score([1,1,2,3,5], 'ones'); expect(score.ones()).to.equal(2); expect(score.calculateScore()).to.equal(2); // 测试通用计算方法 }); it('没有1时应该返回0', function() { const score = new Score([2,3,4,5,6], 'ones'); expect(score.calculateScore()).to.equal(0); }); }); }); });
方案2:直接传入自定义计分函数
适合需要动态定义特殊计分规则的场景,灵活性更高:
var Score = function (roll, scoringFn) { this.roll = roll || []; this.scoringFn = scoringFn; // 直接传入自定义函数 }; Score.prototype.calculateScore = function() { if (typeof this.scoringFn === 'function') { return this.scoringFn(this.roll); } throw new Error('传入的计分规则不是有效函数'); }; // 依然可以保留预设规则方便复用 Score.prototype.ones = function() { return this.roll.filter(i => i === 1).reduce((sum, i) => sum + i, 0); }; module.exports.Score = Score;
自定义规则的测试示例:
describe('自定义计分规则', function() { it('应该使用自定义函数计算得分', function() { // 自定义规则:计算所有偶数的总和 const evenSumFn = (roll) => roll.filter(i => i % 2 === 0).reduce((sum, i) => sum + i, 0); const score = new Score([1,2,3,4,5], evenSumFn); expect(score.calculateScore()).to.equal(6); // 2+4=6 }); });
最后提一句:你原来测试代码里的new Score([1,2,3,4,5], this.ones)是错误的——this.ones在describe回调里是undefined,要改成对应方案的参数(比如方案1的'ones',方案2的Score.prototype.ones或自定义函数)。
内容的提问来源于stack exchange,提问作者Karl
相关产品推荐
相关产品推荐

