Reputation: 307
If I have an object in Javascript and one of its properties is a function:
function cow() {
this.timesMooed = 0;
this.sayMoo = function () {
this.timesMooed++;
return "moo";
};
}
Say I also have another function that takes some function as an argument, calls it and records the result:
var actionResults = [];
function doAction(action) {
actionResults.push(action());
}
Now let's put this into practice and see what happens:
var jerry = new cow();
doAction(jerry.sayMoo);
console.log(actionResults);
// Outputs ["moo"] -this is correct
console.log(jerry.timesMooed);
// Outputs 0 -uh oh
How can I pass in the function so that it's Jerry
that is running the function?
Upvotes: 1
Views: 72
Reputation: 81
try creating a constructor
class cow {
constructor(){
this.timesMooed = '';
}
sayMoo() {
this.timesMooed+=1;
return "moo";
}
}
var actionResults = [];
function doAction(action) {
actionResults.push(action);
}
var jerry = new cow();
doAction(jerry.sayMoo());
console.log(actionResults);
console.log(jerry.timesMooed);
Upvotes: 1
Reputation: 1044
As @Mark_M says the better way is to use arrow function but this feature force you to use ES6 instead of ES5 because bound function introduce in ES5. Another way is to use benefits of variable scope like this:
function cow() {
this.timesMooed = 0;
var that = this;
this.sayMoo = function (){
that.timesMooed++;
return "moo";
}
}
...
Upvotes: 0
Reputation: 92440
When you pass the reference to the function doAction
and then call it with action()
, the calling context changes and this is what determines the value of this
. You need to use bind
to keep the value of this
locked to jerry
:
function cow() {
this.timesMooed = 0;
this.sayMoo = function () {
this.timesMooed++;
return "moo";
}
}
var actionResults = [];
function doAction(action) {
actionResults.push(action());
}
var jerry = new cow();
// use bind, which makes a function with `this` set properly
doAction(jerry.sayMoo.bind(jerry));
console.log(actionResults);
console.log(jerry.timesMooed);
Alternatively you can use arrow functions =>
which bind this
lexically:
function cow() {
this.timesMooed = 0;
// use arrow function here instead
this.sayMoo = () => {
this.timesMooed++;
return "moo";
}
}
var actionResults = [];
function doAction(action) {
actionResults.push(action());
}
var jerry = new cow();
// no need to bind() now
doAction(jerry.sayMoo);
console.log(actionResults);
console.log(jerry.timesMooed);
Upvotes: 3
Reputation: 1035
Problem is that this
keyword is used in a method and we call that method from a receiver object and this
is not bound to the object that we expect it to be bound to i.e. jerry in this case.
Note that this
value in methods and functions must be set explicitly when we need a specific object bound to the function’s this
value.
Solution
Solution is simple to use correct context
i.e. we want this
to refer to jerry hence while invoking doAction method with sayMoo method of jerry object use bind function call and pass jerry as this argument
doAction(jerry.sayMoo.bind(jerry));
Upvotes: 1