shriek
shriek

Reputation: 5843

Context getting lost during callback in prototype

I have a simple constructor that has firstname and lastname.

function Parent(){
    this.firstName;
    this.lastName;
}

There are four functions defined in the prototype of that constructor which does it's own tasks.

Parent.prototype.flipName = function () {
    return this.lastName + ' ' + this.firstName;
}

Parent.prototype.setFirstName = function (name) {
    this.firstName = name;
}

Parent.prototype.setLastName = function (last) {
    this.lastName = last;
}

Parent.prototype.getFullName = function (callback) {
    // used alert for the sake of simplicity
    alert("Callback: " + callback());
    return this.firstName + ' ' + this.lastName;
}

To demonstrate this I have attached jsfiddle as well.

So my question is whenever I pass callback on getFullName function this somehow loses the context to the Parent object (johny in our case) and returns as undefined undefined. this however, works fine on getFullName function.

I am aware that this is pointing to the window object instead of the Parent in the callback but I can't seem to find the reason behind it.

Upvotes: 2

Views: 1296

Answers (3)

Michael Stewart
Michael Stewart

Reputation: 411

Not enough reputation to add a comment, so here is another answer. Travis has it right for how the question is asked. I think, however, that perhaps the actual use case is possibly a bit more complex. If you use

callback.call(this);

Your callback function is going to be executed with the value of "this" referencing the object that called getFullName. This may or may not be what you want "this" to refer to when you are inside your callback function. So take the following example.

function Parent() {
    var self = this;
    self.firstName;
    self.lastName;
}

function Child() {
    var self = this;
    self.firstName;
}

Child.prototype.getName = function() {
    return this.firstName;
}

Parent.prototype.getFullName = function (callback) {
    // used alert for the sake of simplicity
    alert("Callback: " + callback.call(this));
    return this.firstName + ' ' + this.lastName;
}
Parent.prototype.flipName = function () {
    return this.lastName + ' ' + this.firstName;
}
Parent.prototype.setFirstName = function (name) {
    this.firstName = name;
}

Parent.prototype.setLastName = function (last) {
    this.lastName = last;
}

var johny = new Parent();
johny.setFirstName("Johny");
johny.setLastName("Bravo");

var sue = new Parent();
sue.setFirstName("Sue");
sue.setLastName("Bravo");

// used alert for the sake of simplicity
alert("FullName: " + johny.getFullName(sue.flipName));

When you execute callback.call(this); you are actually going to get "Bravo Johny" when you are probably expecting "Bravo Sue".

I don't know if this is best practice or not, but what I would do instead would be:

alert("FullName: " + johny.getFullName(function() {
    return sue.flipName();
}));

Upvotes: 0

RobG
RobG

Reputation: 147513

In global code, this always references the global object. In function code, the value of this is set by how the function is called (e.g. direct call, as a method, using new, call, apply or bind).

If you want this within the callback to have a certain value, then set it in the call using either call or apply, e.g.

callback.apply(this, args);

If the value of this is not set, it will default to the global object (window in a browser) or in strict mode it will be undefined.

Upvotes: 0

Travis J
Travis J

Reputation: 82337

jsFiddle Demo

The reason is that when you pass in the function pointer johny.flipName it is an anonymous function. You can see this by logging it to the console. As a result, the function will execute, but under the global (window) scope.

To get around this, you must (if you wish) preserve the scope of the callback. You can do this by using callMDN

Parent.prototype.getFullName = function (callback) {
// used alert for the sake of simplicity
 alert("Callback: " + callback.call(this));
 return this.firstName + ' ' + this.lastName;
};

Upvotes: 1

Related Questions