I have the following function in a class:
MyClass.prototype.myFunction = function(item, args)
{
console.log(this);
}
This function is called from an external library that I don't have access to change. When it's called, the console is logging "this" as the window object instead of the actual instanced object. Upon searching stackoverflow I found this quote:
this is set according to how the method is called, and not according to how the method is written. So for obj.method(), this will be set to obj inside of method(). For obj.method.call(x), this inside of method() will be set to x. It is determined by how it's called. What that also means is that if you pass it as a callback to e.g. onclick, this will be set to the global window object rather than what you expect.
I'm assuming this is what is going on and I can't change the way it's called. My question is, is there anyway then to get the instance of the object its in regardless of how it's called?
Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.
In JavaScript, the this keyword refers to an object. Which object depends on how this is being invoked (used or called). The this keyword refers to different objects depending on how it is used: In an object method, this refers to the object. Alone, this refers to the global object.
To return an object from a JavaScript function, use the return statement, with this keyword.
The Window ObjectIt represents the browser's window. All global JavaScript objects, functions, and variables automatically become members of the window object. Global variables are properties of the window object. Global functions are methods of the window object.
This is a common confusion with Javascript. It's easy to think of them as behaving like extension methods do in other languages, but in Javascript it's so easy to change the context of this
that it is often done by accident.
So:
MyClass.prototype.myFunction = function(args)
{
// You expect [this] to refer to an instance of MyClass
this.somePropertyOfMyClass;
};
Then you can call this with:
var x = new MyClass();
x.myFunction(args)
However the way that a function is called in Javascript can change what this
refers to:
var y = somethingElse();
x.myFunction.call(y, args); // now in myFunction [this] refers to y
More likely is that a lot of libraries use the this
context for chaining and events - making mistakes easy to make. For instance in jQuery:
var $thing = $('.selector');
$thing.click(x.myFunction); // now in myFunction [this] refers to $thing
It probably isn't obvious to the person writing the jQuery that calling x.myFunction
in this way will break it. They can workaround that (assuming that they know about the implementation) with:
$thing.click(function() { x.myFunction(); });
If you want your MyClass
to be resilient to being called like this then don't use prototype
- instead use a property of the object:
function MyClass() {
var self = this;
// ...
this.myFunction = function(args)
{
// [self] will always refer to the current instance of MyClass
self.somePropertyOfMyClass;
};
}
Note that the more modern browser Javascript engines are pretty good as optimising these kinds of calls, so I wouldn't use the prototype
just as an optimisation unless you already identified that you need the additional performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With