首页 > 解决方案 > 对于一组实例,对于每个实例,如何通过该方法的名称调用某个方法?

问题描述

我正在尝试将粒子类的函数 behappy() 作为 ParticleSystem 类的 applyBehavior 函数的参数传递。我错过了一些语法吗?我不明白我的电话有什么问题。

最小的可重现代码在这里和这里

class ParticleSystem{
  constructor(){
    this.particles = [];
    this.numberOfParticles = 10;
    for(let i = 0; i < this.numberOfParticles; i++){
      this.particles.push(new Particle());
    }
  }
  
  applyBehavior(behavior, message){
    for(let i = 0; i < this.numberOfParticles; i++){
      this.particles[i].behavior(message);
    }
  }
}

class Particle{
  constructor(){}
  behappy(message){
    print(message);
  }
}

let particlesys = new ParticleSystem();
particlesys.applyBehavior(behappy, "i am happy now");

预期输出应该是:

“我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心” “我现在很开心”我现在很开心” “我现在很开心”

标签: javascriptoopmethodsforwarding

解决方案


如果粒子系统applyBehavior应该调用粒子的方法,首先应该将此方法重命名为callBehaviorexecuteBehavior或者更好,executeParticles其次需要提供粒子的方法/行为名称作为第一个参数而不是函数引用。

编辑

正如Bergi已经指出的那样,其中一个原因必须假设实例的任何方法Particle最有可能在Particle实例的this上下文中运行。

AParticleSystemexecuteParticles方法必须以一种为任何可访问的方法显式提供这样一个上下文的方式来实现Particle。由于函数本身就是对象,因此它们带有两种方法可以完全实现...callapply。可以为这两种方法提供一个目标对象。call这个目标对象确实成为通过/调用的任何方法/函数的上下文apply

示例代码进行了相应更改,以显示此用例...

class ParticleSystem{
  constructor(){
    this.particles = [];
    this.numberOfParticles = 10;
    for(let i = 0; i < this.numberOfParticles; i++){
      this.particles.push(new Particle(i));
    }
  }
  executeParticles(behaviorName, message){
    // for(let i = 0; i < this.numberOfParticles; i++){
    //  this.particles[i][behaviorName](message);
    // }
    this.particles.forEach(particle => {
      const behavior = particle && particle[behaviorName];
      if (typeof behavior === 'function') {

        // MDN: "Function.prototype.call"
        // see: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call]

        behavior.call(particle, message);
      }
    });
  }
}

class Particle{
  constructor(idx){
    this.id = `particle_${ idx }`;
  }
  behappy(message){
    console.log(`${ this.id } logs ... "${ message }"`);
  }
}

let particlesys = new ParticleSystem();
particlesys.executeParticles('behappy', "I'am happy now.");
.as-console-wrapper { min-height: 100%!important; top: 0; }

最通用的实现executeParticles不假设粒子方法的参数将利用apply......

class ParticleSystem{
  constructor(){
    this.particles = [];
    this.numberOfParticles = 10;
    for(let i = 0; i < this.numberOfParticles; i++){
      this.particles.push(new Particle(i));
    }
  }
  executeParticles(behaviorName, ...args){
    this.particles.forEach(particle => {
      const behavior = particle && particle[behaviorName];
      if (typeof behavior === 'function') {

        behavior.apply(particle, args);
      }
    });
  }
}

class Particle{
  constructor(idx){
    this.id = `particle_${ idx }`;
  }
  behappy(message){
    console.log(`${ this.id } logs ... "${ message }"`);
  }
}

let particlesys = new ParticleSystem();
particlesys.executeParticles('behappy', "I'am happy now.");
.as-console-wrapper { min-height: 100%!important; top: 0; }


推荐阅读