I'm new to JavaScript so this is possibly a trivial question:
I'm trying to construct an object that stores a mapping from a set of integers to some of its methods, i.e. something like this:
'use strict';
function Foo() {
this.funcs = {
1: this.func1,
2: this.func2,
}
}
Foo.prototype.func1 = function() {
this.prop = 1;
}
Foo.prototype.func2 = function() {
this.prop = 2;
}
I'd then like to be able to call methods of Foo
like this:
foo = new Foo();
var func = foo.funcs[1];
func();
But this results in: Cannot set property 'prop' of undefined
, i.e. this
does not refer to foo
.
What's the problem here and is there a better way to implement this?
you can just call it as callback() or window. callback() .
In JavaScript, the this keyword allows us to: Reuse functions in different execution contexts. It means, a function once defined can be invoked for different objects using the this keyword.
Invoking a JavaScript Function The code inside a function is not executed when the function is defined. The code inside a function is executed when the function is invoked. It is common to use the term "call a function" instead of "invoke a function".
Your problem is this line:
var func = foo.funcs[1];
JavaScript determines the value of this
based on how a function is called. If you use dot notation, such as foo.funcs[1]();
then the value of this
will associated with the foo
object. But when you run func()
, that's just a plain function and this
will have the default value of undefined
.
It would be worth your time to read the two chapters of You Don't Know JS that discuss this
. It should take less than an hour to learn, and you'll be way ahead of most JS programmers once you learn it.
The rules might not make sense until you read the chapter, but they are summarized below:
Determining the
this
binding for an executing function requires finding the direct call-site of that function. Once examined, four rules can be applied to the call-site, in this order of precedence:Called with new? Use the newly constructed object.
Called with call or apply (or bind)? Use the specified object.
Called with a context object owning the call? Use that context object.
Default: undefined in strict mode, global object otherwise.
Based on the above rules, the code below is the simplest way you could get it to work the way you are expecting it to:
'use strict';
function Foo() {
this.funcs = {
1: this.func1,
2: this.func2,
}
}
Foo.prototype.func1 = function() {
this.prop = 1;
console.log('called func1. this.prop =', this.prop);
}
Foo.prototype.func2 = function() {
this.prop = 2;
console.log('called func2. this.prop =', this.prop);
}
const foo = new Foo();
foo.funcs[1]();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With