Josh Sherick
Josh Sherick

Reputation: 2161

How to prevent "this" from being rebound by event handlers

I've got a JS object, and one of it's prototype functions is an event handler for a click. When that function gets called, the this object is set to the element that the click is bound to. I'd like this to be the instance of the object that the function belongs to. Is this possible, and if so, how do I do it? Solutions with or without jQuery are acceptable to me, although I'm sure that the rest of SO would appreciate a pure JS solution.

I've tried binding the function to this, and it gets bound to the window rather than the instance of the object.

Example of what I want: In this demo (code duplicated below), I want an alert that says "Bark" when the button is clicked.

var Dog = function () {
    this.sound = "Bark";
}

Dog.prototype = {
    sayHello: function (e) {
        if (typeof this.sound == "undefined") {
            alert("I don't know what sound I should make!\n" + this);
        } else {
            alert(this.sound);
        }
    }
}

var d = new Dog();
var elem = document.getElementById("click");
elem.addEventListener("click", d.sayHello);

Upvotes: 1

Views: 287

Answers (2)

Interrobang
Interrobang

Reputation: 17434

If you always intend for a function to be invoked with its own context, do the binding when the constructor runs instead:

var Dog = function () { 
  this.sound = "Bark";
  this.sayHello = this.sayHello.bind(this);
}

http://jsfiddle.net/04ykpsx1/1/

Something like _.bindAll can reduce the boilerplate for you.

This is a better approach than forcing your callers to always call a function with .bind, because they shouldn't need to understand your class so deeply.

Upvotes: 2

jfriend00
jfriend00

Reputation: 707876

You can use .bind() like this:

elem.addEventListener("click", d.sayHello.bind(d));

The manual way of doing it is with your own function:

elem.addEventListener("click", function(e) {
    return d.sayHello();
});

Upvotes: 5

Related Questions