JavaScript传递类方法作为参数时的函数计时测试报错问题
问题解决与优化建议
错误原因与修复
你遇到的TypeError核心原因有两个:
- 传给
timeFunction的是方法名字符串(比如'fun1'),而非函数本身。代码里rand.fun试图访问实例的fun属性,但实例根本没有这个属性,结果为undefined,调用apply自然报错。 - 即使拿到正确方法,也需要确保方法执行时的
this绑定到当前myClass实例,否则方法内的this会指向错误上下文(比如全局对象或undefined)。
修改后的timeFunction代码:
function timeFunction(methodName, params, it) { let t0, t1; let total = 0; for (let i = 1; i <= it; i++) { const rand = myClass.randomInstance(); t0 = performance.now(); // 通过方括号访问实例方法,并用apply绑定this为当前实例 rand[methodName].apply(rand, params); t1 = performance.now(); total += t1 - t0; } return total; }
同时,myClassTest里的变量要加上声明避免全局污染:
function myClassTest(it=50) { // 用const声明变量,防止全局污染 const aInputFunctions = ['fun1']; const abInputFunctions = ['fun2']; // 示例:可替换为生成随机参数的逻辑 const a = getRandomA(); // 假设你有生成随机a的函数 const b = getRandomB(); // 生成随机b的函数 for (const fun of aInputFunctions) { const time = timeFunction(fun, [a], it); console.log(`${it} 次迭代 ${fun} 耗时 ${time.toFixed(2)} 毫秒.`); console.log(`\t 单次运行平均耗时: ${(time/it).toFixed(4)} 毫秒.\n`); } for (const fun of abInputFunctions) { const time = timeFunction(fun, [a, b], it); console.log(`${it} 次迭代 ${fun} 耗时 ${time.toFixed(2)} 毫秒.`); console.log(`\t 单次运行平均耗时: ${(time/it).toFixed(4)} 毫秒.\n`); } }
传递函数参数的注意点
- 区分函数引用与字符串:你之前传递的是方法名字符串,而非实例方法的函数引用。如果要传递函数引用,需从实例或原型上获取,但因每次都是新实例,用方法名字符串+方括号访问更灵活。
- this绑定问题:JavaScript中,对象方法脱离对象单独调用时会丢失原有
this绑定,必须通过apply/call/bind指定this为实例对象,或直接在实例上调用方法(rand[methodName](...params))。 - 参数传递简化:ES6及以上环境可用展开运算符替代
apply,代码更简洁:rand[methodName](...params),效果一致。
更优的随机单元测试方法
- 每次迭代用随机参数:固定参数无法覆盖随机性带来的性能差异,建议每次调用方法时生成随机参数:
// 修改timeFunction,支持参数生成器 function timeFunction(methodName, paramGenerator, it) { let total = 0; for (let i = 1; i <= it; i++) { const rand = myClass.randomInstance(); const params = paramGenerator(); // 每次生成随机参数 const t0 = performance.now(); rand[methodName](...params); const t1 = performance.now(); total += t1 - t0; } return total; } // 测试函数中使用参数生成器 function myClassTest(it=50) { const methodTests = [ { name: 'fun1', paramGenerator: () => [Math.random() * 1000] // 生成随机a }, { name: 'fun2', paramGenerator: () => [Math.random() * 1000, Math.random() * 100] // 生成随机a和b } ]; for (const test of methodTests) { const time = timeFunction(test.name, test.paramGenerator, it); console.log(`${it} 次迭代 ${test.name} 耗时 ${time.toFixed(2)} 毫秒.`); console.log(`\t 单次运行平均耗时: ${(time/it).toFixed(4)} 毫秒.\n`); } }
- 增加性能统计维度:除总耗时和平均值,可统计最快、最慢运行时间及标准差,更全面了解性能波动:
function timeFunction(methodName, paramGenerator, it) { const times = []; for (let i = 1; i <= it; i++) { const rand = myClass.randomInstance(); const params = paramGenerator(); const t0 = performance.now(); rand[methodName](...params); const t1 = performance.now(); times.push(t1 - t0); } const total = times.reduce((sum, val) => sum + val, 0); const avg = total / it; const min = Math.min(...times); const max = Math.max(...times); // 计算标准差 const variance = times.reduce((sum, val) => sum + Math.pow(val - avg, 2), 0) / it; const stdDev = Math.sqrt(variance); return { total, avg, min, max, stdDev }; }
- 避免计时干扰:计时循环内不要包含打印、DOM操作等无关逻辑,所有输出放在计时完成后,确保结果准确。
- 简化计时工具:需求简单时可直接用
console.time/console.timeEnd快速计时:
function testFun1(it=50) { console.time('fun1'); for (let i=0; i<it; i++) { const rand = myClass.randomInstance(); rand.fun1(getRandomA()); } console.timeEnd('fun1'); }
内容的提问来源于stack exchange,提问作者Levent
相关产品推荐
相关产品推荐

