Reputation: 131
This is probably a typical question for someone new to Javascript. I did research a number of similar questions but wasn't able to explain the behavior that I am seeing.
The code below should illustrate what I am trying to do. I have 2 objects MyObjectA and MyObjectB.
MyObjectB has a method echo
that simply logs a message. It prefixes the this.name
to the message in an attempt to know who is executing the method. It also prints the value of this
.
MyObjectA has a method called callAFunctionWithMessage
which does exactly that. It accepts a message and a function and calls it.
In the global scope , the objects are instantiated and called. What I see is this.name
is undefined
. And the this
had the value DOMWindowObject
when executed in the browser and some massive infrastructure-like object when executing in nodejs. Can someone help me with some insight on this behavior? Given that MyObjectA is calling echo, i expected 'this' to point to MyObjectA.
I also, execute MyObjectB.echo('hello')
where this
points to to MyObjectB as expected.
function MyObjectA(name) {
this.name=name;
}
MyObjectA.prototype = {
name : "",
callAFunctionWithMessage: function (msg, callback) {
callback(msg);
}
}
function MyObjectB(name) {
this.name = name;
}
MyObjectB.prototype = {
name :"",
echo: function(msg) {
var messageToPrint='[from '+this.name+']'+msg;
console.log(messageToPrint, " : " + this);
}
}
var a = new MyObjectA("ObjA");
var b = new MyObjectB("objB");
a.callAFunctionWithMessage('hello from A!', b.echo);
// => [from result]hello from A! : [object Window]
b.echo('hello!');
// => [from objB]hello! : [object Object]
Upvotes: 1
Views: 178
Reputation: 17361
When you pass b.echo
as a callback you pass the function which looses it's context. There are a few simple rules to know what this
will mean.
undefined
depending on strict mode.this
will not automatically resolve to the global object. It will be undefined
.Upvotes: 2
Reputation: 123739
When you do:
a.callAFunctionWithMessage('hello from A!', b.echo);
the function b.echo
is getting passed with a global context (window in your case). so this.name
is not going to be the name property of the object a
but it will be of the name
property of the global context, hence you see it as undefined. You can instead change it to call with the context of a
itself using function.bind
a.callAFunctionWithMessage('hello from A!', b.echo.bind(a)); //now you set the callback with the context of b itself.
In your case when inside the callback method this
would represent the global scope.
Or change the way you invoke your callback by setting a context of current, to ensure that it takes a context of no context is bound to it.
MyObjectA.prototype = {
name : "",
callAFunctionWithMessage: function (msg, callback) {
callback.call(this, msg);
}
}
Upvotes: 3
Reputation: 66334
The value of this
will change depending on how a function is invoked, i.e. what context is it given at invoke time? The only exception to this are bound functions.
I hope the following example will aid your understanding, along with the MDN page for this
function foo() {
console.log(this);
}
var bar = {
'foo': foo,
'baz': function () {foo();}
};
foo(); // -- logs the global object
// `foo` was called without context
bar.foo(); // -- logs `bar`
// `foo` was called with context `bar`
bar.baz(); // -- logs the global object
// `baz` (in context `bar`) called `foo` without context
var x = bar.foo;
x(); // -- logs the global object
// `x` was called without context, `x` is still `foo`
x.call(bar); // -- logs `bar`
// `x` was called with context `bar`
Upvotes: 1