Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: Access 'this' when calling function stored in variable

Tags:

javascript

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?

like image 821
Peter Avatar asked May 19 '19 22:05

Peter


People also ask

How do you call a function stored in a variable in JavaScript?

you can just call it as callback() or window. callback() .

Can you use this in a function JavaScript?

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.

What happens when you call a function in JavaScript?

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".


1 Answers

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]();
like image 104
Todd Chaffee Avatar answered Oct 06 '22 01:10

Todd Chaffee