0

I'm having a hard time answering my question, and I think it's simply because "class" and "this" and other such terms are too generic for effective Googling.


Consider the following code:

function product (name) {
    var _productName;

    this.getProductName = function() {
        return this._productName;
    };

    this.alertProductName = function() {
        // This errors because `this` is a reference to the HTML <input> tag and not the class
        alert(this.getProductName());
    }

    this._productName = name;

    var $productButton = $('<input type="button" value="What is my name?" />');
        $productButton.on('click', this.alertProductName);

    $('body').append($productButton);
}

var widget = new product('Widget');

widget.alertProductName();

jQuery (or maybe Javascript itself) is resetting what the this keyword points to once product::alertProductName is called as a callback to an event. I can't find any other way to access a specific instance of this class from within a function used as a callback. It looks like Javascript used to have arguments.callee but that has been deprecated.

Does anyone know how I can access a specific instance of a class in this manner? If not, is there a better way to write this so that I don't have this problem to begin with?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Tyler V.
  • 2,471
  • 21
  • 44
  • 2
    Typical answer: cache `this` in the higher scope, like `var self = this` then use `self` in place of `this`. – elclanrs Dec 06 '13 at 02:48
  • or use [$.proxy()](http://api.jquery.com/jQuery.proxy/) – Arun P Johny Dec 06 '13 at 02:51
  • 1
    Stay away from variables like `$productButton` so you can use JavaScript with PHP, just use `var productButton`. `$('body')`, `$.ajax()` and the like are fine. It will save potential future headaches. Just a comment. – StackSlave Dec 06 '13 at 02:52
  • @PHPglue: It's a convention http://stackoverflow.com/questions/205853/why-would-a-javascript-variable-start-with-a-dollar-sign. I see no confusion. – elclanrs Dec 06 '13 at 02:52
  • No, I create JavaScript with PHP sometimes, so your variable within double quotes in PHP would be undefined PHP. That was just advice. – StackSlave Dec 06 '13 at 02:58
  • 1
    @PHPglue: Using jQuery $ syntax inside a PHP double-quoted string sounds like a really bad practice on it's own. I try to use 'string '. $var .' string' in PHP instead of "{$var}" anyway. Either way, I don't combine PHP and JS in ways that this is an issue. – Tyler V. Dec 06 '13 at 03:05
  • For more info about constructor functions, prototype and the value of `this` maybe the following answer will help: http://stackoverflow.com/a/16063711/1641941 (it looks like you're not using prototype at all at the moment) – HMR Dec 06 '13 at 03:46
  • Does this answer your question? [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Brian Tompsett - 汤莱恩 Jul 25 '20 at 08:28

2 Answers2

1

Since the method alertProductName is invoked by an event handler, by default this inside the event handler method refers to the dom element that triggered the event.

Since you are using an constructor my preferred solution will be is to pass a custom execution context to the alertProductName method using $.proxy() - Function.bind() doe the same but no IE < 9 support

function product(name) {
    var _productName;

    this.getProductName = function () {
        return this._productName;
    };

    this.alertProductName = function () {
        // This errors because `this` is a reference to the HTML <input> tag and not the class
        alert(this.getProductName());
    }

    this._productName = name;

    var $productButton = $('<input type="button" value="What is my name?" />');
    $productButton.on('click', $.proxy(this.alertProductName, this));//here use $.proxy()

    $('body').append($productButton);
}

var widget = new product('Widget');

widget.alertProductName();

Demo: Fiddle

Another solution is to use a closure variable to refer to the widget element, ex: fiddle - this will not work if you are planning to make sure of prototype functions for the constructor

Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • I didn't know about $.proxy() and it seems to exist specifically to combat this issue. `this` will continue to point to my class, while I must use event.target to regain access to the DOM element that was clicked. elclanrs' method of caching `this` in another variable called self works too. I can use self.getProductName() correctly and continue using `this` to access the DOM element. Is there anything you can tell me about using one over the other? – Tyler V. Dec 06 '13 at 02:59
  • @TylerV. [e.target](http://api.jquery.com/event.target/) or [e.currentTarget](http://api.jquery.com/event.currentTarget/) depending on your need – Arun P Johny Dec 06 '13 at 03:02
  • @TylerV. read the last part of the answer... other than that it is fine – Arun P Johny Dec 06 '13 at 03:02
  • 1
    @TylerV. look at this example using prototype functions http://jsfiddle.net/arunpjohny/zMH3w/2/ – Arun P Johny Dec 06 '13 at 03:05
  • I understand now. This has been very helpful. Thank you! – Tyler V. Dec 06 '13 at 03:09
0

This is not what you think it is.

This answers it nicely
How does the "this" keyword work?

Community
  • 1
  • 1
Dan Walmsley
  • 2,765
  • 7
  • 26
  • 45