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

JavaScript传递类方法作为参数时的函数计时测试报错问题

问题解决与优化建议

错误原因与修复

你遇到的TypeError核心原因有两个:

  1. 传给timeFunction的是方法名字符串(比如'fun1'),而非函数本身。代码里rand.fun试图访问实例的fun属性,但实例根本没有这个属性,结果为undefined,调用apply自然报错。
  2. 即使拿到正确方法,也需要确保方法执行时的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),效果一致。

更优的随机单元测试方法

  1. 每次迭代用随机参数:固定参数无法覆盖随机性带来的性能差异,建议每次调用方法时生成随机参数:
// 修改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`);
  }
}
  1. 增加性能统计维度:除总耗时和平均值,可统计最快、最慢运行时间及标准差,更全面了解性能波动:
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 };
}
  1. 避免计时干扰:计时循环内不要包含打印、DOM操作等无关逻辑,所有输出放在计时完成后,确保结果准确。
  2. 简化计时工具:需求简单时可直接用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:32:20