1

I'm currently diving into Object-oriented programming in JavaScript and I came across a problem. I'm defining an object like below, doing some jQuery stuff inside one of the methods, and I'm wondering what is the best way to access Object properties inside a jQuery method that overrides the 'this' variable.

function MyObject() {
    this.foo = 'bar';
}

MyObject.prototype.myMethod = function () {
    $.get('myurl', function (data) {
        // how to address this.foo here ?
    });
};
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
beeb
  • 1,187
  • 11
  • 32
  • 1
    In ECAMScript 6 (though presently in Firefox), you'll be able to use this syntax: `$.get('myurl', (data) => { console.log(this.foo); })` – cookie monster Mar 26 '14 at 20:12
  • Found a similar question : http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions – beeb Mar 26 '14 at 22:58

2 Answers2

3

Save a reference to this before calling $.get.

MyObject.prototype.myMethod = function () {
    var that = this;
    $.get('myurl', function (data) {
        console.log(that.foo);
    });
};
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • The use of a variable named `that` to save a reference to an outer `this` is a common JavaScript pattern. – dgvid Mar 26 '14 at 20:01
  • This sounds a bit redundant since I'll have to do it for every method of my object but if there is no other way.. What if the method is defined inside the object function itself ? `var MyObject = function () { this.foo = 'bar'; var self = this; this.myMethod = function () { /* jQuery code here */ } }` this way the `self` variable is defined only once.. ? – beeb Mar 26 '14 at 22:23
1

Just create a variable in the scope of the outer function to preserve its context:

MyObject.prototype.myMethod = function () {
    var self;
    self = this;
    $.get('myurl', function (data) {
        // how to address this.foo here ?
        self.doStuff();
    });
};

For callbacks, you may want to make use of jQuery.proxy, which is jQuery's souped-up version of Function.prototype.bind:

function MyObject(selector) {
    this.foo = 'bar';
    $(selector).on('click', $.proxy(this, 'myMethod'));
}
MyObject.prototype.myMethod = function (e) {
    console.log(this.foo); //'bar'
};

For your case specifically, you can make use of jQuery.proxy to generate a callback for the $.get success function:

MyObject.prototype.myMethod = function () {
    $.get('myurl', $.proxy(this, 'myCallback'));
};
MyObject.prototype.myCallback = function (data) {
    console.log(this.foo); //'bar'
};

Alternatively, you can write the proxy inline:

MyObject.prototype.myMethod = function () {
    $.get('myurl', $.proxy(function (data) {
        console.log(this.foo); //'bar'
    }, this));
};
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • 1
    Thanks for the comments. The specific case solution passing `this` to the callback via `jQuery.proxy` is not a bad idea but gets quite messy when multiple jQuery methods are nested and `this` must be available at every level. – beeb Mar 26 '14 at 22:27
  • @beeb, that's why I first showed it using a prototype method. It helps to [flatten arrow code](http://blog.codinghorror.com/flattening-arrow-code/). Otherwise I'd recommend taking advantage of queueing and promises, which also help to flatten asynchronous arrow code. – zzzzBov Mar 26 '14 at 22:46