问题描述
我试图将 Particle 类的函数 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");
预期输出应该是:
“我现在很高兴”“我现在很高兴”“我现在很高兴”“我现在很高兴”“我 我现在很开心”“我现在很开心”“我现在很开心”“我现在很开心”“我现在很开心” 现在很开心”“我现在很开心”
解决方法
如果粒子系统的 applyBehavior
应该调用粒子的方法,首先应该将此方法重命名为 callBehavior
、executeBehavior
或更好的是 executeParticles
和其次需要提供粒子的方法/行为名称作为第一个参数而不是函数引用。
编辑
正如 Bergi 已经指出的那样,一个原因必须假设 Particle
实例的任何方法最有可能在 Particle
实例的 this
上下文。
然后,ParticleSystem
的 executeParticles
方法必须以一种向任何可访问的 Particle
方法显式提供此类上下文的方式实现。由于函数本身就是对象,因此它们带有两种方法来实现... call
和 apply
。可以为这两种方法提供一个目标对象。此目标对象确实成为通过 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; }