Reputation: 456
I'm learning this from MDN. There is a function 'loop'
function loop(){
ctx.fillStyle='rgb(255,200,124,.35)';
ctx.fillRect(0,0,width,height);
while(balls.length<15){
var ball = new Ball();
balls.push(ball);
}
balls.forEach(function(b){
b.draw();
b.update();
b.collisionDetect();
});
requestAnimationFrame(loop);
}
balls
is an array, and in collisionDetect()
there is another use of forEach
as below. I want to make this
in collisionDetect()
refer to the caller b
in loop()
Ball.prototype.collisionDetect = function(){
balls.forEach(function(bl){
if(!(this.x===bl.x&&this.y==bl.y
&&this.velX===bl.velX&&this.velY===bl.velY)){
var dx = this.x-bl.x;
var dy = this.y-bl.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if(distance<this.size+bl.size){
bl.color = this.color = "rbg("
+ random(0,255)
+","
+random(0,255)
+","
+random(0,255)
+")";
}
}
});
}
I tried passing b
as parameter of collisionDetect()
. It does work but not what is expected.
I know two forEach
can be simply replaced by original for
loop, but I just wonder if I could make it work with forEach
.
Thank you all very much.
Upvotes: 1
Views: 1167
Reputation: 780843
You can bind a local variable to this
.
Ball.prototype.collisionDetect = function(){
var self = this;
balls.forEach(function(bl){
if(!(self.x===bl.x&&self.y==bl.y
&&self.velX===bl.velX&&self.velY===bl.velY)){
var dx = self.x-bl.x;
var dy = self.y-bl.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if(distance<self.size+bl.size){
bl.color = this.color = "rgb(" + random(0,255) +"," +random(0,255) +"," +random(0,255) +")";
}
}
});
}
Another way would be to use ES6 arrow functions, because they preserve this
.
Ball.prototype.collisionDetect = function(){
balls.forEach(b1 => {
if(!(this.x===bl.x&&this.y==bl.y
&&this.velX===bl.velX&&this.velY===bl.velY)){
var dx = this.x-bl.x;
var dy = this.y-bl.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if(distance<this.size+bl.size){
bl.color = this.color = "rbg(" + random(0,255) +"," +random(0,255) +"," +random(0,255) +")";
}
}
});
}
Upvotes: 3
Reputation: 191976
This is the signature of Array#forEach
:
arr.forEach(callback[, thisArg])
As you can see, Array#forEach
accepts a 2nd param, thisArgs
, which sets the this
of the callback when it's executed.
So, pass the current this
as the 2nd param, and it will be assigned to the callback:
Ball.prototype.collisionDetect = function(){
balls.forEach(function(bl){
if(!(this.x===bl.x&&this.y==bl.y
&&this.velX===bl.velX&&this.velY===bl.velY)){
var dx = this.x-bl.x;
var dy = this.y-bl.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if(distance<this.size+bl.size){
bl.color = this.color = "rbg("
+ random(0,255)
+","
+random(0,255)
+","
+random(0,255)
+")";
}
}
}, this); // set thisArg to this
}
Upvotes: 1
Reputation: 3164
You can bind the function to whatever context/scope you want. This way it will work:
Ball.prototype.collisionDetect = function(){
balls.forEach(function(bl){
if(!(this.x===bl.x&&this.y==bl.y
&&this.velX===bl.velX&&this.velY===bl.velY)){
var dx = this.x-bl.x;
var dy = this.y-bl.y;
var distance = Math.sqrt(dx*dx+dy*dy);
if(distance<this.size+bl.size){
bl.color = this.color = "rbg("
+ random(0,255)
+","
+random(0,255)
+","
+random(0,255)
+")";
}
}
}.bind(this));
}
Upvotes: 0