I think mostly it is easy to grasp when to use this
keyword, considering there are a number of examples here.
Most of the Playcanvas scripts are an instance of an object, so when you use this
inside a script, you want to access some property of that script. Just be careful when you have inline functions, like in your example, in initialize()
you pass a function (function(entity) {...}
) inside on()
method. If you use this
inisde that function, it will point to the instance that function belongs to, which would be the global scope (window). Since window
doesn’t have an app
property (only the script has), you get the undefined
error. That is why on()
method has a third parameter you can pass, as Will mentioned, which will define the scope of the keyword this
, in case it would be used inside that function.
Here is an example:
Script.prototype.initialize = function() {
var myArray = [1, 2, 3];
myArray.forEach(function(value) {
this.print(value); // error, "this" points to window here, which has no "print" property
});
};
Script.prototype.print = function(value) {
console.log(value);
};
Most of the built in functions, like .forEach()
in Javascript accept an optional argument that specifies where this
should point to. Just like the event system in Playcanvas. You can google js array foreach
and check MDN resource to see what arguments it takes. In case of an above example, it can be fixed by:
...
myArray.forEach(function(value) {
this.print(value); // no error, "this" points to instance of Script, which has "print" property
}, this);
...
If a method doesn’t accept a scope argument, you can always “bind” the function to use the scope of your choosing. We can write it in this way instead:
...
myArray.forEach(function(value) {
this.print(value); // no error, "this" points to instance of Script, because of binding
}.bind(this));
...
One common practice in ES5 was to save the scope in some variable and access it, instead of using this
. For example, we could write it differently:
...
var self = this;
myArray.forEach(function(value) {
self.print(value); // no error, "self" variable stores the correct scope of the Script instance
});
...
And lastly, if you use Javascript ES6 syntax, the new standard introduced arrow functions, which don’t have a problem with understanding the scope they are executed from. So, the following could be then written:
...
myArray.forEach((value) => {
this.print(value); // no error, "this" points to instance of Script, because arrow function is clever
});
...