In case a particle system's applyBehavior
is supposed to invoke a particle's method, one firstly should rename this method to callBehavior
, executeBehavior
or, even better, executeParticles
and secondly needs to provide the particle's method/behavior name as first argument instead of a function reference.
Edit
As Bergi already did point to, one of cause has to assume that any method of a Particle
instance most probably operates within a Particle
instance's this
context.
A ParticleSystem
's executeParticles
method then has to be implemented in a way which explicitly provides such a context to any accessible Particle
method. Since functions are object itself, they come with two methods which achieve exactly that ... call
and apply
. A target object can be provided to both methods. This target object does become the context of any method/function which gets invoked via call
/apply
.
The example code got changed accordingly, in order to show this use case ...
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; }
The most generic implementation of executeParticles
which makes no assumptions about a particle method's arguments would utilize 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; }