12

I'm trying to access the member variables of a prototype class in JavaScript in an event handler -- something I'd typically use the "this" keyword for (or "that" [copy of this] in the case of event handlers). Needless to say, I'm running into some trouble.

Take, for example, this HTML snippet:

<a id="myLink" href="#">My Link</a>

And this JavaScript code:

function MyClass()
{
  this.field = "value"
  this.link = document.getElementById("myLink");
  this.link.onclick = this.EventMethod;
}

MyClass.prototype.NormalMethod = function()
{
  alert(this.field);
}

MyClass.prototype.EventMethod = function(e)
{
  alert(this.field);
}

Instantiating a MyClass object and calling NormalMethod works exactly like I expect it to (alert saying "value"), but clicking the link results in an undefined value because the "this" keyword now references the event target (the anchor () HTML element).

I'm new to the prototype JavaScript style, but in the past, with closures, I've simply made a copy of "this" in the constructor:

var that = this;

And then I could access members variables in event methods via the "that" object. That doesn't seem to work with prototype code. Is there another way to achieve this?

Thanks.

Anthony Rutledge
  • 6,980
  • 2
  • 39
  • 44
Michael
  • 1,968
  • 4
  • 24
  • 40
  • Are you referring to the Prototype library or rather straight JavaScript prototypical classes? – Crescent Fresh Sep 02 '09 at 17:24
  • 3
    Responding three years late :) But for posterity: I was referring to straight JavaScript prototypical classes. – Michael May 30 '12 at 17:25
  • Possible duplicate of [How to access the correct `this` / context inside a callback?](http://stackoverflow.com/q/20279484/1048572)? – Bergi Sep 09 '14 at 20:43
  • @Bergi: For the record, I asked this question in 2009. The question you linked was asked in 2013. – Michael Sep 10 '14 at 12:40
  • @Michael: Yeah, but that doesn't matter. Dupes are closed by quality of answers, not by date; the one I linked is the canonical question on loosing `this`. I wasn't sure whether it's an "exact" duplicate, that's why I haven't just closed it but only commented. The link is definitely helpful to everyone who visits this question. – Bergi Sep 10 '14 at 12:57

4 Answers4

13

You need:

this.link.onclick = this.EventMethod.bind(this);

...'bind' is part of Prototype, and returns a function which calls your method with 'this' set correctly.

ijw
  • 4,376
  • 3
  • 25
  • 29
  • How does `onclick` get access to the event interface? – Karl Oct 05 '14 at 20:40
  • @Karl By "access to the event interface" do you mean "receive the event object as an argument"? The `bind` method **returns a function** (with a fixed `this`), so `onclick = this.EventMethod` is basically the same as `onclick = this.EventMethod.bind(this)`. In both cases, you store a function in the `onclick` property; they're identical in terms of how their arguments are handled. If your question is more generally about how arguments are passed to listener functions, that's quite a different question than what's being asked here, and you should ask a new question. – apsillers Oct 14 '14 at 15:05
9

Your "that=this" closure idiom is still applicable:

function MyClass()
{
    ...

    var that = this;
    this.link.onclick = function() {
        return that.EventMethod.apply(that, arguments);

        // that.EventMethod() works too here, however
        // the above ensures that the function closure
        // operates exactly as EventMethod itself does.

    };
}
Crescent Fresh
  • 115,249
  • 25
  • 154
  • 140
5

You should try

this.link.onclick = this.EventMethod.bind(this);
alex.zherdev
  • 23,914
  • 8
  • 62
  • 56
0

As stated above, using bind which is a part of the Prototype library is a clean way to solve this problem. This question is a duplicate of another SO question which is answered here with implementation of the bind method without including the whole prototype library :

https://stackoverflow.com/a/2025839/1180286

Community
  • 1
  • 1
st0ne
  • 106
  • 1
  • 9