2
function MyClass() {
    this.a = "me a";
    this.b = "me b";
};

MyClass.prototype.changeB = function(callback) {
    this.a = "now me A";
    doAnotherFunction(function(err, data) {
        this.b = "now me B";
    callback(null, this.b);});
};

function doAnotherFunction(callback) {
    callback(null, null);
};

main();

function main() {
    var myclass = new MyClass();
    myclass.changeB(function(err, data) {
    console.log("B: " + myclass.b + ", data: " + data);});
    console.log(JSON.stringify(myclass));
}


When this runs:
B: me b, data: now me B
{"a":"now me A","b":"me b"}

Go easy on me, I'm new to javascript and to posting here.

My question is why does 'this.b' not get changed in the original MyClass instantiation? I've read in here where javascript does not have block scope (only function scope). If that was the reason, then why wouldn't it treat 'this.b' as 'undefined' where it sets it to "now me B"?

Thanks!

kevdev
  • 177
  • 2
  • 12
  • `this.b = "now me B"` is inside another function, and would have been invoked in a different execution context. So `this` would not mean the instance of `MyClass` in this case. – Paul Grime Apr 26 '13 at 21:24

2 Answers2

2

The anonymous callback function you pass to the method creates a new scope, so when you say this.b inside the callback, it's not the same b anymore, but a new one.

One common way to solve it is to create a reference to the this you want to access, outside the callback:

var self = this;

Then you can reference self.b inside the callback.

NilsH
  • 13,705
  • 4
  • 41
  • 59
  • Thanks Nils, I guess I can't mark both yours and Paul's answers as correct. Like I commented below, I think it is crazy that a new object is created with each function call - I don't get the reasoning behind that at all. – kevdev Apr 29 '13 at 13:11
  • well, consider if you were using the callback at different places. Then what should `this` be? – NilsH Apr 29 '13 at 13:32
  • The callback is inside the 'changeB' method of MyClass therefore the 'this' of the callback should be the 'this' of 'changeB' which should be the 'this' of 'myclass' (lowercase) which was explicitly instantiated, once and only once, in the 'main' method. There should not be two 'this's at all, one would think. – kevdev Apr 29 '13 at 14:43
2

Here is a good read to begin with.

For your specific example, you could code it like this, saving a reference to the this of the MyClass instance:

MyClass.prototype.changeB = function(callback) {
    var me = this;
    this.a = "now me A";
    doAnotherFunction(function(err, data) {
        me.b = "now me B";
        callback(null, me.b);
    });
};

Example using bind in response to the suggestion:

MyClass.prototype.changeB = function(callback) {
    this.a = "now me A";
    var fn = function(err, data) {
        this.b = "now me B";
        callback(null, this.b);
    });
    // the first parameter to bind will be the 'this'
    // visible from inside the function
    doAnotherFunction(fn.bind(this));
};

EDIT: To find out what this was in your example, try adding some logging:

MyClass.prototype.changeB = function(callback) {
    var me = this;
    this.a = "now me A";
    doAnotherFunction(function(err, data) {
        // Use this['b'] notation to avoid errors using this.b,
        // if this.b doesn't already exist.
        console.log(me, typeof me, this, typeof this, this['b']);
        this.b = "now me B";
        callback(null, this.b);
    });
};
Community
  • 1
  • 1
Paul Grime
  • 14,970
  • 4
  • 36
  • 58
  • I think it would help to explain the reason why as well. – Jivings Apr 26 '13 at 21:29
  • `bind` would be another option. – numbers1311407 Apr 26 '13 at 21:30
  • Thanks for the link Paul. I should've added to my original post that I indeed solved the problem by setting a local 'me' variable to 'this' (after much hair pulling :) as you suggest. My concern is why didn't the nested function flag the bogus 'this.b' as being 'undefined'? Did it just instantiate a new MyClass object on its own? – kevdev Apr 27 '13 at 07:01
  • The nested function didn't flag the bogus `this.b` as undefined because you were assigning to it, and therefore creating a `b` property on the `this` object. What the `this` object actually was at that point can be determined by printing it out, and maybe its `typeof`. E.g. `console.log(this, typeof this)`. I think in Node this is the module's 'global' scope, but I don't use Node so I'm not sure. – Paul Grime Apr 27 '13 at 08:19
  • Ah, I see - thanks. But that is really illogical of the 'design' of the language. The 'doAnotherFunction' is already inside an explicitly created 'this', yet it creates its own version of 'this'. It makes you wonder how many other objects are being created willy nilly in the runtime without us knowing about them. – kevdev Apr 29 '13 at 13:06
  • It's non-obvious for sure, especially when coming from Java for example. But it's also really useful in parts. You need to ask yourself *what is `this`* inside every function you see, as it might be non-obvious like you say (and also could change with every invocation!). – Paul Grime Apr 29 '13 at 13:10