What is the this keyword for when initializing variables for an entity?

Hello!

I’ve been using PlayCanvas for probably about half a year now and there is something that enters my mind every time I create a script but I never take the time to ask. I’ve seen in a lot of example code that scripts will declare a variable for an entity and access it like this:

var SomeEntityScript = pc.createScript('someEntityScript');

//initialize function here
SomeEntityScript.prototype.initialize = function() {
   this.myVariable = 1;
   this.app.on("some event", this.myFunction, this);
};
//function called on an event here
SomeEntityScript.prototype.myFunction = function() {
   this.myVariable = 2;
};

The way I have been creating variables is like the second script below where the variables sit outside of the initialization and do not use the the “this” keyword:

var SomeEntityScript = pc.createScript('someEntityScript');
var myVariable = 1;

//initialize function here
SomeEntityScript.prototype.initialize = function() {
   this.app.on("some event", this.myFunction, this);
};
//function called on an event here
SomeEntityScript.prototype.myFunction = function() {
   myVariable = 2;
};

So onto the question. The second approach has yet to cause me any issues but it doesn’t seem to be the standard way to set a script up. Which way is better and why? Are there advantages or disadvantages to either of them? I know one of the advantages of the second approach is that children of the entity can also access that variable but that could also be seen as a disadvantage depending on the size of the project. What does the “this” keyword actually mean in this situation? I know it does different things depending on its placement in javascript. Any help at all would be greatly appreciated. Thanks so much!

In general, I would recommend to using the this.variable approach. As you mentioned, it is available to other functions within the same script, and because you can access the scripts on different objects, it’s really still available project wide, there are just a couple more layers you have to dive before finding it.

The reason I recommend, again in general, the this.variable approach is because when you put variables in the global scope it affects all javascript functions everywhere. Though unlikely, there is a chance that you declare a variable that is used in another script or library. This could break something in a weird way that would be much harder to diagnose.

The other, and much larger advantage to sticking to this.variable is also scope related. When you declare that variable in a global scope it will always be the same across multiple objects even if you only intended to update one. This is where the instancing of your scripts comes into play. When you want to update something like say the color one box out of ten. In the global scope, updating the variable will update the color of all the boxes no matter what you do. this refers to the script that it resides in. It helps answer the question “Which one?” whenever you update something. If I update this.color instead of the global var color I can ensure that I am only making changes to the objects I intend to.

It boils down to remembering what when you apply a script to an object, it is effectively copy and pasted to each entity, so using this ensures you are only making changes to a specific copy of your script as opposed to everything using it.

I hope that’s helpful.

2 Likes

So lets say I have 10 boxes that are all different entities and I have assigned them all a variable using this, how would I access a specific box’s variable if it is assigned by this? I know that’s a bit general but that seems to be the only part of the situation I’m not understanding.

1 Like

@Jake_Johnson,

Sure. So in your example scenario let’s say we have a script on all of the boxes:

var BoxColor = pc.createScript('boxColor');

BoxColor.prototype.initialize = function() {
	this.color = new pc.Color().fromString('#FFFFFF');

};

BoxColor.prototype.whatsMyColor = function() {
 console.log(this.color);
};

On another object I want to check or change the this.color variable on specific boxes. As a really ineffecient example:

var BoxManager = pc.createScript('boxManager');

BoxManager.prototype.initialize = function() {
	this.Box1 = this.app.root.findByName('Box1');
	this.Box2 = this.app.root.findByName('Box2');
	this.Box3 = this.app.root.findByName('Box3');
	this.Box4 = this.app.root.findByName('Box4');
	this.Box5 = this.app.root.findByName('Box5');
	this.Box6 = this.app.root.findByName('Box6');
	this.Box7 = this.app.root.findByName('Box7');
	this.Box8 = this.app.root.findByName('Box8');
	this.Box9 = this.app.root.findByName('Box9');
	this.Box10 = this.app.root.findByName('Box10');
};

I now have 10 boxes defined in another object. From my ‘box manager’ If I want to know what color one of the boxes is, I would run something like:

this.Box1.script.boxColor.whatsMyColor();

This would specifically spit out the color of Box1. If I were to run that function on all 10 of my boxes at the start of the app, they would all return a white pc.Color object. Let’s say I wanted to change one. I would do something like:

this.Box4.script.boxColor.color = new pc.Color().fromString('#000000');

Now, if I run what’sMyColor() on all of the boxes again, All of them will return white except Box4 which will return Black.

In the global sense, after you declare var colorOfBoxes you could update it anywhere in your scripts by just running colorOfBoxes = new pc.Color().fromString('#00FF00'); . Assuming the BoxColor Scripts have already been loaded into memory, the variable will update globally, and if you ask any of the boxes whatsMyColor() they will all report back a Green pc.Color object.

The examples are a little long winded, but I hope they’re illustrative of what keeping things within the scope of a script instance can help with.

1 Like