Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The 'this' keyword returns the window object within an object's prototype in Javascript?

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?

like image 224
dallin Avatar asked Nov 05 '12 00:11

dallin


People also ask

What is prototype keyword in JavaScript?

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.

What is the this keyword in JavaScript?

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.

How do you return an object in JavaScript?

To return an object from a JavaScript function, use the return statement, with this keyword.

What is Windows object in JavaScript?

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.


1 Answers

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.

like image 190
Keith Avatar answered Oct 21 '22 07:10

Keith