对于一组实例,一个实例如何通过该方法的名称调用某个方法?

For an array of instances, how does one, for each instance, invoke a certain method by this method's name?

我正在尝试传递 Particle Class 的函数 behappy(),作为 ParticleSystem class 的 applyBehavior 函数的参数。我缺少一些语法吗?我不明白我的电话有什么问题。

最小可重现代码在这里 here

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");

预期输出应该是:

"i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now" "i am happy now"

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

编辑

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

A ParticleSystemexecuteParticles 方法必须以明确为任何可访问的 Particle 方法提供此类上下文的方式实现。由于函数本身就是对象,因此它们带有两种方法来实现这一点...... call and apply。可以为这两种方法提供目标对象。此目标对象确实成为通过 call/apply.

调用的任何 method/function 的上下文

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

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; }