Reputation: 2189
I am trying to pass a method as a callback reference to a method of another class:
function A() {
this.callback = function(){return 0;};
}
A.prototype.set = function(cb) {
this.callback = cb;
};
A.prototype.test = function(){
console.log("test " + this.callback());
};
function B(o) {
this.prop = "blah B";
o.set(this.blah);
}
B.prototype.blah = function() {
console.log(this);
return this.prop;
};
What I would expect from the execution
a = new A();
b = new B(a);
a.test();
is the result
>B { prop="blah B", blah=function()}
>test blah B
But instead the console shows
>A { cb=function(), set=function(), test=function()}
>test undefined
as if the method blah
has been assigned to A
for the execution..
Why am I getting this result?
And how can I get the result I expected?
Upvotes: 3
Views: 239
Reputation:
"as if the method blah has been assigned to A for the execution", you almost got it, just replace "A" with "a" in your sentence. Indeed, by default, this
refers to the instance which owns the method.
As it happens, o.set(this.blah)
can be translated into a.callback = b.blah
, which means that a.callback
and b.blah
now refer to the same function. In other words, the same function is now owned by both instances a
and b
:
a.callback() // "return (this -> a).prop" -> undefined
b.blah() // "return (this -> b).prop" -> "blah B"
Roughly speaking, you need a way to "redirect" this
to b
inside callback
.
You could use either a closure :
var me = this;
o.set(function () {
// this -> a
// me -> b
return me.blah();
});
Or bind (not supported by IE8 and below) :
o.set(this.blah.bind(this));
Upvotes: 3
Reputation: 832
When blah
method is called inside the test
method, this
points to an A
instance. Since A
does not have a prop
property it returns undefined.
You need to change the line o.set(this.blah);
to this o.set(this.blah.bind(this));
Now blah
is always bound to an instance of B
and when test
is called this.prop
will return "blah B"
which is what is intended.
Upvotes: 1
Reputation: 1307
The problem is because of execution context - how this
of a function in JavaScript is bound to. When the final line a.test()
is called, the callback
looks for a property called prop
in the context of the object a
. In your case, the object a
did not have a prop
property and hence the undefined
. When you supply a prop
to a
then it works fine. Final fiddle with console.log
here. Here the callback is called twice, once without the assignment of prop
and the second with the assignment of the same:
function B(o) {
this.prop = "blah B";
o.set(this.blah);
o.prop = this.prop;
}
Upvotes: 2
Reputation: 7680
Yes, that is how JavaScript's this
keyword works - it refers to the current execution context, which is the object it is called on in this case. You are calling it as if it was a method of A
. You need to call it as a method on your B
instance. If you don't need to support IE8 or lower, you can use Function.prototype.bind to bind this
in the function so it always points to the B
instance. Otherwise, the A
instance needs a reference to the B
instance on which to call the method.
You could manually bind the method with a var self = this;
hack. You could also do this in the B
constructor:
function B(o) {
var self = this;
this.prop = "blah B";
o.set(function() { self.blah(); });
}
But if you could expand a bit on what exactly you're trying to do, there might be a more elegant solution.
Upvotes: 2